Sat, 03 Jan 2015 20:18:00 +0100
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);
1015 }
1017 return NS_OK;
1018 }
1021 NS_IMETHODIMP
1022 nsAnnotationService::GetItemsWithAnnotation(const nsACString& aName,
1023 uint32_t* _resultCount,
1024 int64_t** _results)
1025 {
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];
1048 }
1050 return NS_OK;
1051 }
1054 NS_IMETHODIMP
1055 nsAnnotationService::GetAnnotationsWithName(const nsACString& aName,
1056 uint32_t* _count,
1057 mozIAnnotatedResult*** _annotations)
1058 {
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);
1103 }
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;
1113 }
1114 case nsIAnnotationService::TYPE_INT64: {
1115 rv = variant->SetAsInt64(stmt->AsInt64(4));
1116 break;
1117 }
1118 case nsIAnnotationService::TYPE_DOUBLE: {
1119 rv = variant->SetAsDouble(stmt->AsDouble(4));
1120 break;
1121 }
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;
1129 }
1130 default:
1131 MOZ_ASSERT(false, "Unsupported annotation type");
1132 // Move to the next result.
1133 continue;
1134 }
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);
1140 }
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]);
1153 }
1155 return NS_OK;
1156 }
1159 nsresult
1160 nsAnnotationService::GetItemsWithAnnotationTArray(const nsACString& aName,
1161 nsTArray<int64_t>* _results)
1162 {
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;
1180 }
1182 return NS_OK;
1183 }
1186 NS_IMETHODIMP
1187 nsAnnotationService::GetPageAnnotationNames(nsIURI* aURI,
1188 uint32_t* _count,
1189 nsIVariant*** _result)
1190 {
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;
1218 }
1219 var->SetAsAUTF8String(names[i]);
1220 NS_ADDREF((*_result)[i] = var);
1221 }
1222 *_count = names.Length();
1224 return NS_OK;
1225 }
1228 nsresult
1229 nsAnnotationService::GetAnnotationNamesTArray(nsIURI* aURI,
1230 int64_t aItemId,
1231 nsTArray<nsCString>* _result)
1232 {
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 );
1244 }
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 );
1253 }
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;
1272 }
1274 return NS_OK;
1275 }
1278 NS_IMETHODIMP
1279 nsAnnotationService::GetItemAnnotationNames(int64_t aItemId,
1280 uint32_t* _count,
1281 nsIVariant*** _result)
1282 {
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;
1310 }
1311 var->SetAsAUTF8String(names[i]);
1312 NS_ADDREF((*_result)[i] = var);
1313 }
1314 *_count = names.Length();
1316 return NS_OK;
1317 }
1320 NS_IMETHODIMP
1321 nsAnnotationService::PageHasAnnotation(nsIURI* aURI,
1322 const nsACString& aName,
1323 bool* _retval)
1324 {
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;
1332 }
1335 NS_IMETHODIMP
1336 nsAnnotationService::ItemHasAnnotation(int64_t aItemId,
1337 const nsACString& aName,
1338 bool* _retval)
1339 {
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;
1347 }
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)
1359 {
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 );
1369 }
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 );
1377 }
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;
1395 }
1398 NS_IMETHODIMP
1399 nsAnnotationService::RemovePageAnnotation(nsIURI* aURI,
1400 const nsACString& aName)
1401 {
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;
1410 }
1413 NS_IMETHODIMP
1414 nsAnnotationService::RemoveItemAnnotation(int64_t aItemId,
1415 const nsACString& aName)
1416 {
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;
1425 }
1428 NS_IMETHODIMP
1429 nsAnnotationService::RemovePageAnnotations(nsIURI* aURI)
1430 {
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;
1451 }
1454 NS_IMETHODIMP
1455 nsAnnotationService::RemoveItemAnnotations(int64_t aItemId)
1456 {
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;
1475 }
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)
1487 {
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);
1539 }
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));
1556 }
1558 rv = transaction.Commit();
1559 NS_ENSURE_SUCCESS(rv, rv);
1561 return NS_OK;
1562 }
1565 NS_IMETHODIMP
1566 nsAnnotationService::CopyItemAnnotations(int64_t aSourceItemId,
1567 int64_t aDestItemId,
1568 bool aOverwriteDest)
1569 {
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);
1618 }
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));
1635 }
1637 rv = transaction.Commit();
1638 NS_ENSURE_SUCCESS(rv, rv);
1640 return NS_OK;
1641 }
1644 NS_IMETHODIMP
1645 nsAnnotationService::AddObserver(nsIAnnotationObserver* aObserver)
1646 {
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;
1654 }
1657 NS_IMETHODIMP
1658 nsAnnotationService::RemoveObserver(nsIAnnotationObserver* aObserver)
1659 {
1660 NS_ENSURE_ARG(aObserver);
1662 if (!mObservers.RemoveObject(aObserver))
1663 return NS_ERROR_INVALID_ARG;
1664 return NS_OK;
1665 }
1667 nsresult
1668 nsAnnotationService::HasAnnotationInternal(nsIURI* aURI,
1669 int64_t aItemId,
1670 const nsACString& aName,
1671 bool* _hasAnno)
1672 {
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 );
1685 }
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 );
1696 }
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;
1719 }
1720 else {
1721 int64_t annotationId = stmt->AsInt64(2);
1722 *_hasAnno = (annotationId > 0);
1723 }
1725 return NS_OK;
1726 }
1729 /**
1730 * This loads the statement and steps it once so you can get data out of it.
1731 *
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)
1741 {
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 );
1753 }
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 );
1764 }
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;
1788 }
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.
1795 *
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)
1808 {
1809 bool isItemAnnotation = (aItemId > 0);
1811 if (aExpiration == EXPIRE_SESSION) {
1812 mHasSessionAnnotations = true;
1813 }
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 );
1846 }
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 );
1857 }
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;
1876 }
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 );
1891 }
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 );
1900 }
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);
1910 }
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);
1916 }
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;
1937 }
1939 ////////////////////////////////////////////////////////////////////////////////
1940 //// nsIObserver
1942 NS_IMETHODIMP
1943 nsAnnotationService::Observe(nsISupports *aSubject,
1944 const char *aTopic,
1945 const char16_t *aData)
1946 {
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);
1977 }
1978 }
1980 return NS_OK;
1981 }