Line data Source code
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/. */
5 :
6 : #include "mozilla/ArrayUtils.h"
7 :
8 : #include "nsAnnotationService.h"
9 : #include "nsNavHistory.h"
10 : #include "nsPlacesTables.h"
11 : #include "nsPlacesIndexes.h"
12 : #include "nsPlacesMacros.h"
13 : #include "Helpers.h"
14 :
15 : #include "nsNetUtil.h"
16 : #include "nsIVariant.h"
17 : #include "nsString.h"
18 : #include "nsVariant.h"
19 : #include "mozilla/storage.h"
20 :
21 : #include "GeckoProfiler.h"
22 :
23 : #include "nsNetCID.h"
24 :
25 : using namespace mozilla;
26 : using namespace mozilla::places;
27 :
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
33 :
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
39 :
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;
49 :
50 : namespace mozilla {
51 : namespace places {
52 :
53 : ////////////////////////////////////////////////////////////////////////////////
54 : //// AnnotatedResult
55 :
56 0 : AnnotatedResult::AnnotatedResult(const nsCString& aGUID,
57 : nsIURI* aURI,
58 : int64_t aItemId,
59 : const nsACString& aAnnotationName,
60 0 : nsIVariant* aAnnotationValue)
61 : : mGUID(aGUID)
62 : , mURI(aURI)
63 : , mItemId(aItemId)
64 : , mAnnotationName(aAnnotationName)
65 0 : , mAnnotationValue(aAnnotationValue)
66 : {
67 0 : }
68 :
69 0 : AnnotatedResult::~AnnotatedResult()
70 : {
71 0 : }
72 :
73 : NS_IMETHODIMP
74 0 : AnnotatedResult::GetGuid(nsACString& _guid)
75 : {
76 0 : _guid = mGUID;
77 0 : return NS_OK;
78 : }
79 :
80 : NS_IMETHODIMP
81 0 : AnnotatedResult::GetUri(nsIURI** _uri)
82 : {
83 0 : NS_IF_ADDREF(*_uri = mURI);
84 0 : return NS_OK;
85 : }
86 :
87 : NS_IMETHODIMP
88 0 : AnnotatedResult::GetItemId(int64_t* _itemId)
89 : {
90 0 : *_itemId = mItemId;
91 0 : return NS_OK;
92 : }
93 :
94 : NS_IMETHODIMP
95 0 : AnnotatedResult::GetAnnotationName(nsACString& _annotationName)
96 : {
97 0 : _annotationName = mAnnotationName;
98 0 : return NS_OK;
99 : }
100 :
101 : NS_IMETHODIMP
102 0 : AnnotatedResult::GetAnnotationValue(nsIVariant** _annotationValue)
103 : {
104 0 : NS_IF_ADDREF(*_annotationValue = mAnnotationValue);
105 0 : return NS_OK;
106 : }
107 :
108 0 : NS_IMPL_ISUPPORTS(AnnotatedResult, mozIAnnotatedResult)
109 :
110 : } // namespace places
111 : } // namespace mozilla
112 :
113 2 : PLACES_FACTORY_SINGLETON_IMPLEMENTATION(nsAnnotationService, gAnnotationService)
114 :
115 9 : NS_IMPL_ISUPPORTS(nsAnnotationService
116 : , nsIAnnotationService
117 : , nsIObserver
118 : , nsISupportsWeakReference
119 : )
120 :
121 :
122 1 : nsAnnotationService::nsAnnotationService()
123 1 : : mHasSessionAnnotations(false)
124 : {
125 1 : NS_ASSERTION(!gAnnotationService,
126 : "Attempting to create two instances of the service!");
127 1 : gAnnotationService = this;
128 1 : }
129 :
130 :
131 0 : nsAnnotationService::~nsAnnotationService()
132 : {
133 0 : NS_ASSERTION(gAnnotationService == this,
134 : "Deleting a non-singleton instance of the service");
135 0 : if (gAnnotationService == this)
136 0 : gAnnotationService = nullptr;
137 0 : }
138 :
139 :
140 : nsresult
141 1 : nsAnnotationService::Init()
142 : {
143 1 : mDB = Database::GetDatabase();
144 1 : NS_ENSURE_STATE(mDB);
145 :
146 2 : nsCOMPtr<nsIObserverService> obsSvc = mozilla::services::GetObserverService();
147 1 : if (obsSvc) {
148 1 : (void)obsSvc->AddObserver(this, TOPIC_PLACES_SHUTDOWN, true);
149 : }
150 :
151 1 : return NS_OK;
152 : }
153 :
154 : nsresult
155 0 : nsAnnotationService::SetAnnotationStringInternal(nsIURI* aURI,
156 : int64_t aItemId,
157 : const nsACString& aName,
158 : const nsAString& aValue,
159 : int32_t aFlags,
160 : uint16_t aExpiration)
161 : {
162 0 : mozStorageTransaction transaction(mDB->MainConn(), false);
163 0 : nsCOMPtr<mozIStorageStatement> statement;
164 0 : nsresult rv = StartSetAnnotation(aURI, aItemId, aName, aFlags, aExpiration,
165 : nsIAnnotationService::TYPE_STRING,
166 0 : statement);
167 0 : NS_ENSURE_SUCCESS(rv, rv);
168 0 : mozStorageStatementScoper scoper(statement);
169 :
170 0 : rv = statement->BindStringByName(NS_LITERAL_CSTRING("content"), aValue);
171 0 : NS_ENSURE_SUCCESS(rv, rv);
172 :
173 0 : rv = statement->Execute();
174 0 : NS_ENSURE_SUCCESS(rv, rv);
175 :
176 0 : rv = transaction.Commit();
177 0 : NS_ENSURE_SUCCESS(rv, rv);
178 :
179 0 : return NS_OK;
180 : }
181 :
182 :
183 : NS_IMETHODIMP
184 0 : nsAnnotationService::SetPageAnnotation(nsIURI* aURI,
185 : const nsACString& aName,
186 : nsIVariant* aValue,
187 : int32_t aFlags,
188 : uint16_t aExpiration)
189 : {
190 0 : NS_ENSURE_ARG(aURI);
191 0 : NS_ENSURE_ARG(aValue);
192 :
193 : uint16_t dataType;
194 0 : nsresult rv = aValue->GetDataType(&dataType);
195 0 : NS_ENSURE_SUCCESS(rv, rv);
196 :
197 0 : switch (dataType) {
198 : case nsIDataType::VTYPE_INT8:
199 : case nsIDataType::VTYPE_UINT8:
200 : case nsIDataType::VTYPE_INT16:
201 : case nsIDataType::VTYPE_UINT16:
202 : case nsIDataType::VTYPE_INT32:
203 : case nsIDataType::VTYPE_UINT32:
204 : case nsIDataType::VTYPE_BOOL: {
205 : int32_t valueInt;
206 0 : rv = aValue->GetAsInt32(&valueInt);
207 0 : if (NS_SUCCEEDED(rv)) {
208 0 : NS_ENSURE_SUCCESS(rv, rv);
209 0 : rv = SetPageAnnotationInt32(aURI, aName, valueInt, aFlags, aExpiration);
210 0 : NS_ENSURE_SUCCESS(rv, rv);
211 0 : return NS_OK;
212 : }
213 : // Fall through int64_t case otherwise.
214 : MOZ_FALLTHROUGH;
215 : }
216 : case nsIDataType::VTYPE_INT64:
217 : case nsIDataType::VTYPE_UINT64: {
218 : int64_t valueLong;
219 0 : rv = aValue->GetAsInt64(&valueLong);
220 0 : if (NS_SUCCEEDED(rv)) {
221 0 : NS_ENSURE_SUCCESS(rv, rv);
222 0 : rv = SetPageAnnotationInt64(aURI, aName, valueLong, aFlags, aExpiration);
223 0 : NS_ENSURE_SUCCESS(rv, rv);
224 0 : return NS_OK;
225 : }
226 : // Fall through double case otherwise.
227 : MOZ_FALLTHROUGH;
228 : }
229 : case nsIDataType::VTYPE_FLOAT:
230 : case nsIDataType::VTYPE_DOUBLE: {
231 : double valueDouble;
232 0 : rv = aValue->GetAsDouble(&valueDouble);
233 0 : NS_ENSURE_SUCCESS(rv, rv);
234 0 : rv = SetPageAnnotationDouble(aURI, aName, valueDouble, aFlags, aExpiration);
235 0 : NS_ENSURE_SUCCESS(rv, rv);
236 0 : return NS_OK;
237 : }
238 : case nsIDataType::VTYPE_CHAR:
239 : case nsIDataType::VTYPE_WCHAR:
240 : case nsIDataType::VTYPE_DOMSTRING:
241 : case nsIDataType::VTYPE_CHAR_STR:
242 : case nsIDataType::VTYPE_WCHAR_STR:
243 : case nsIDataType::VTYPE_STRING_SIZE_IS:
244 : case nsIDataType::VTYPE_WSTRING_SIZE_IS:
245 : case nsIDataType::VTYPE_UTF8STRING:
246 : case nsIDataType::VTYPE_CSTRING:
247 : case nsIDataType::VTYPE_ASTRING: {
248 0 : nsAutoString stringValue;
249 0 : rv = aValue->GetAsAString(stringValue);
250 0 : NS_ENSURE_SUCCESS(rv, rv);
251 0 : rv = SetPageAnnotationString(aURI, aName, stringValue, aFlags, aExpiration);
252 0 : NS_ENSURE_SUCCESS(rv, rv);
253 0 : return NS_OK;
254 : }
255 : }
256 :
257 0 : return NS_ERROR_NOT_IMPLEMENTED;
258 : }
259 :
260 :
261 : NS_IMETHODIMP
262 0 : nsAnnotationService::SetItemAnnotation(int64_t aItemId,
263 : const nsACString& aName,
264 : nsIVariant* aValue,
265 : int32_t aFlags,
266 : uint16_t aExpiration,
267 : uint16_t aSource)
268 : {
269 0 : AUTO_PROFILER_LABEL("nsAnnotationService::SetItemAnnotation", OTHER);
270 :
271 0 : NS_ENSURE_ARG_MIN(aItemId, 1);
272 0 : NS_ENSURE_ARG(aValue);
273 :
274 0 : if (aExpiration == EXPIRE_WITH_HISTORY)
275 0 : return NS_ERROR_INVALID_ARG;
276 :
277 : uint16_t dataType;
278 0 : nsresult rv = aValue->GetDataType(&dataType);
279 0 : NS_ENSURE_SUCCESS(rv, rv);
280 :
281 0 : switch (dataType) {
282 : case nsIDataType::VTYPE_INT8:
283 : case nsIDataType::VTYPE_UINT8:
284 : case nsIDataType::VTYPE_INT16:
285 : case nsIDataType::VTYPE_UINT16:
286 : case nsIDataType::VTYPE_INT32:
287 : case nsIDataType::VTYPE_UINT32:
288 : case nsIDataType::VTYPE_BOOL: {
289 : int32_t valueInt;
290 0 : rv = aValue->GetAsInt32(&valueInt);
291 0 : if (NS_SUCCEEDED(rv)) {
292 0 : NS_ENSURE_SUCCESS(rv, rv);
293 0 : rv = SetItemAnnotationInt32(aItemId, aName, valueInt, aFlags, aExpiration, aSource);
294 0 : NS_ENSURE_SUCCESS(rv, rv);
295 0 : return NS_OK;
296 : }
297 : // Fall through int64_t case otherwise.
298 : MOZ_FALLTHROUGH;
299 : }
300 : case nsIDataType::VTYPE_INT64:
301 : case nsIDataType::VTYPE_UINT64: {
302 : int64_t valueLong;
303 0 : rv = aValue->GetAsInt64(&valueLong);
304 0 : if (NS_SUCCEEDED(rv)) {
305 0 : NS_ENSURE_SUCCESS(rv, rv);
306 0 : rv = SetItemAnnotationInt64(aItemId, aName, valueLong, aFlags, aExpiration, aSource);
307 0 : NS_ENSURE_SUCCESS(rv, rv);
308 0 : return NS_OK;
309 : }
310 : // Fall through double case otherwise.
311 : MOZ_FALLTHROUGH;
312 : }
313 : case nsIDataType::VTYPE_FLOAT:
314 : case nsIDataType::VTYPE_DOUBLE: {
315 : double valueDouble;
316 0 : rv = aValue->GetAsDouble(&valueDouble);
317 0 : NS_ENSURE_SUCCESS(rv, rv);
318 0 : rv = SetItemAnnotationDouble(aItemId, aName, valueDouble, aFlags, aExpiration, aSource);
319 0 : NS_ENSURE_SUCCESS(rv, rv);
320 0 : return NS_OK;
321 : }
322 : case nsIDataType::VTYPE_CHAR:
323 : case nsIDataType::VTYPE_WCHAR:
324 : case nsIDataType::VTYPE_DOMSTRING:
325 : case nsIDataType::VTYPE_CHAR_STR:
326 : case nsIDataType::VTYPE_WCHAR_STR:
327 : case nsIDataType::VTYPE_STRING_SIZE_IS:
328 : case nsIDataType::VTYPE_WSTRING_SIZE_IS:
329 : case nsIDataType::VTYPE_UTF8STRING:
330 : case nsIDataType::VTYPE_CSTRING:
331 : case nsIDataType::VTYPE_ASTRING: {
332 0 : nsAutoString stringValue;
333 0 : rv = aValue->GetAsAString(stringValue);
334 0 : NS_ENSURE_SUCCESS(rv, rv);
335 0 : rv = SetItemAnnotationString(aItemId, aName, stringValue, aFlags, aExpiration, aSource);
336 0 : NS_ENSURE_SUCCESS(rv, rv);
337 0 : return NS_OK;
338 : }
339 : }
340 :
341 0 : return NS_ERROR_NOT_IMPLEMENTED;
342 : }
343 :
344 :
345 : NS_IMETHODIMP
346 0 : nsAnnotationService::SetPageAnnotationString(nsIURI* aURI,
347 : const nsACString& aName,
348 : const nsAString& aValue,
349 : int32_t aFlags,
350 : uint16_t aExpiration)
351 : {
352 0 : NS_ENSURE_ARG(aURI);
353 :
354 0 : nsresult rv = SetAnnotationStringInternal(aURI, 0, aName, aValue,
355 0 : aFlags, aExpiration);
356 0 : NS_ENSURE_SUCCESS(rv, rv);
357 :
358 0 : NOTIFY_ANNOS_OBSERVERS(OnPageAnnotationSet(aURI, aName));
359 :
360 0 : return NS_OK;
361 : }
362 :
363 :
364 : NS_IMETHODIMP
365 0 : nsAnnotationService::SetItemAnnotationString(int64_t aItemId,
366 : const nsACString& aName,
367 : const nsAString& aValue,
368 : int32_t aFlags,
369 : uint16_t aExpiration,
370 : uint16_t aSource)
371 : {
372 0 : NS_ENSURE_ARG_MIN(aItemId, 1);
373 :
374 0 : if (aExpiration == EXPIRE_WITH_HISTORY)
375 0 : return NS_ERROR_INVALID_ARG;
376 :
377 0 : nsresult rv = SetAnnotationStringInternal(nullptr, aItemId, aName, aValue,
378 0 : aFlags, aExpiration);
379 0 : NS_ENSURE_SUCCESS(rv, rv);
380 :
381 0 : NOTIFY_ANNOS_OBSERVERS(OnItemAnnotationSet(aItemId, aName, aSource));
382 :
383 0 : return NS_OK;
384 : }
385 :
386 :
387 : nsresult
388 0 : nsAnnotationService::SetAnnotationInt32Internal(nsIURI* aURI,
389 : int64_t aItemId,
390 : const nsACString& aName,
391 : int32_t aValue,
392 : int32_t aFlags,
393 : uint16_t aExpiration)
394 : {
395 0 : mozStorageTransaction transaction(mDB->MainConn(), false);
396 0 : nsCOMPtr<mozIStorageStatement> statement;
397 0 : nsresult rv = StartSetAnnotation(aURI, aItemId, aName, aFlags, aExpiration,
398 : nsIAnnotationService::TYPE_INT32,
399 0 : statement);
400 0 : NS_ENSURE_SUCCESS(rv, rv);
401 0 : mozStorageStatementScoper scoper(statement);
402 :
403 0 : rv = statement->BindInt32ByName(NS_LITERAL_CSTRING("content"), aValue);
404 0 : NS_ENSURE_SUCCESS(rv, rv);
405 :
406 0 : rv = statement->Execute();
407 0 : NS_ENSURE_SUCCESS(rv, rv);
408 :
409 0 : rv = transaction.Commit();
410 0 : NS_ENSURE_SUCCESS(rv, rv);
411 :
412 0 : return NS_OK;
413 : }
414 :
415 :
416 : NS_IMETHODIMP
417 0 : nsAnnotationService::SetPageAnnotationInt32(nsIURI* aURI,
418 : const nsACString& aName,
419 : int32_t aValue,
420 : int32_t aFlags,
421 : uint16_t aExpiration)
422 : {
423 0 : NS_ENSURE_ARG(aURI);
424 :
425 0 : nsresult rv = SetAnnotationInt32Internal(aURI, 0, aName, aValue,
426 0 : aFlags, aExpiration);
427 0 : NS_ENSURE_SUCCESS(rv, rv);
428 :
429 0 : NOTIFY_ANNOS_OBSERVERS(OnPageAnnotationSet(aURI, aName));
430 :
431 0 : return NS_OK;
432 : }
433 :
434 :
435 : NS_IMETHODIMP
436 0 : nsAnnotationService::SetItemAnnotationInt32(int64_t aItemId,
437 : const nsACString& aName,
438 : int32_t aValue,
439 : int32_t aFlags,
440 : uint16_t aExpiration,
441 : uint16_t aSource)
442 : {
443 0 : NS_ENSURE_ARG_MIN(aItemId, 1);
444 :
445 0 : if (aExpiration == EXPIRE_WITH_HISTORY)
446 0 : return NS_ERROR_INVALID_ARG;
447 :
448 0 : nsresult rv = SetAnnotationInt32Internal(nullptr, aItemId, aName, aValue,
449 0 : aFlags, aExpiration);
450 0 : NS_ENSURE_SUCCESS(rv, rv);
451 :
452 0 : NOTIFY_ANNOS_OBSERVERS(OnItemAnnotationSet(aItemId, aName, aSource));
453 :
454 0 : return NS_OK;
455 : }
456 :
457 :
458 : nsresult
459 0 : nsAnnotationService::SetAnnotationInt64Internal(nsIURI* aURI,
460 : int64_t aItemId,
461 : const nsACString& aName,
462 : int64_t aValue,
463 : int32_t aFlags,
464 : uint16_t aExpiration)
465 : {
466 0 : mozStorageTransaction transaction(mDB->MainConn(), false);
467 0 : nsCOMPtr<mozIStorageStatement> statement;
468 0 : nsresult rv = StartSetAnnotation(aURI, aItemId, aName, aFlags, aExpiration,
469 : nsIAnnotationService::TYPE_INT64,
470 0 : statement);
471 0 : NS_ENSURE_SUCCESS(rv, rv);
472 0 : mozStorageStatementScoper scoper(statement);
473 :
474 0 : rv = statement->BindInt64ByName(NS_LITERAL_CSTRING("content"), aValue);
475 0 : NS_ENSURE_SUCCESS(rv, rv);
476 :
477 0 : rv = statement->Execute();
478 0 : NS_ENSURE_SUCCESS(rv, rv);
479 :
480 0 : rv = transaction.Commit();
481 0 : NS_ENSURE_SUCCESS(rv, rv);
482 :
483 0 : return NS_OK;
484 : }
485 :
486 :
487 : NS_IMETHODIMP
488 0 : nsAnnotationService::SetPageAnnotationInt64(nsIURI* aURI,
489 : const nsACString& aName,
490 : int64_t aValue,
491 : int32_t aFlags,
492 : uint16_t aExpiration)
493 : {
494 0 : NS_ENSURE_ARG(aURI);
495 :
496 0 : nsresult rv = SetAnnotationInt64Internal(aURI, 0, aName, aValue,
497 0 : aFlags, aExpiration);
498 0 : NS_ENSURE_SUCCESS(rv, rv);
499 :
500 0 : NOTIFY_ANNOS_OBSERVERS(OnPageAnnotationSet(aURI, aName));
501 :
502 0 : return NS_OK;
503 : }
504 :
505 :
506 : NS_IMETHODIMP
507 0 : nsAnnotationService::SetItemAnnotationInt64(int64_t aItemId,
508 : const nsACString& aName,
509 : int64_t aValue,
510 : int32_t aFlags,
511 : uint16_t aExpiration,
512 : uint16_t aSource)
513 : {
514 0 : NS_ENSURE_ARG_MIN(aItemId, 1);
515 :
516 0 : if (aExpiration == EXPIRE_WITH_HISTORY)
517 0 : return NS_ERROR_INVALID_ARG;
518 :
519 0 : nsresult rv = SetAnnotationInt64Internal(nullptr, aItemId, aName, aValue,
520 0 : aFlags, aExpiration);
521 0 : NS_ENSURE_SUCCESS(rv, rv);
522 :
523 0 : NOTIFY_ANNOS_OBSERVERS(OnItemAnnotationSet(aItemId, aName, aSource));
524 :
525 0 : return NS_OK;
526 : }
527 :
528 :
529 : nsresult
530 0 : nsAnnotationService::SetAnnotationDoubleInternal(nsIURI* aURI,
531 : int64_t aItemId,
532 : const nsACString& aName,
533 : double aValue,
534 : int32_t aFlags,
535 : uint16_t aExpiration)
536 : {
537 0 : mozStorageTransaction transaction(mDB->MainConn(), false);
538 0 : nsCOMPtr<mozIStorageStatement> statement;
539 0 : nsresult rv = StartSetAnnotation(aURI, aItemId, aName, aFlags, aExpiration,
540 : nsIAnnotationService::TYPE_DOUBLE,
541 0 : statement);
542 0 : NS_ENSURE_SUCCESS(rv, rv);
543 0 : mozStorageStatementScoper scoper(statement);
544 :
545 0 : rv = statement->BindDoubleByName(NS_LITERAL_CSTRING("content"), aValue);
546 0 : NS_ENSURE_SUCCESS(rv, rv);
547 :
548 0 : rv = statement->Execute();
549 0 : NS_ENSURE_SUCCESS(rv, rv);
550 :
551 0 : rv = transaction.Commit();
552 0 : NS_ENSURE_SUCCESS(rv, rv);
553 :
554 0 : return NS_OK;
555 : }
556 :
557 :
558 : NS_IMETHODIMP
559 0 : nsAnnotationService::SetPageAnnotationDouble(nsIURI* aURI,
560 : const nsACString& aName,
561 : double aValue,
562 : int32_t aFlags,
563 : uint16_t aExpiration)
564 : {
565 0 : NS_ENSURE_ARG(aURI);
566 :
567 0 : nsresult rv = SetAnnotationDoubleInternal(aURI, 0, aName, aValue,
568 0 : aFlags, aExpiration);
569 0 : NS_ENSURE_SUCCESS(rv, rv);
570 :
571 0 : NOTIFY_ANNOS_OBSERVERS(OnPageAnnotationSet(aURI, aName));
572 :
573 0 : return NS_OK;
574 : }
575 :
576 :
577 : NS_IMETHODIMP
578 0 : nsAnnotationService::SetItemAnnotationDouble(int64_t aItemId,
579 : const nsACString& aName,
580 : double aValue,
581 : int32_t aFlags,
582 : uint16_t aExpiration,
583 : uint16_t aSource)
584 : {
585 0 : NS_ENSURE_ARG_MIN(aItemId, 1);
586 :
587 0 : if (aExpiration == EXPIRE_WITH_HISTORY)
588 0 : return NS_ERROR_INVALID_ARG;
589 :
590 0 : nsresult rv = SetAnnotationDoubleInternal(nullptr, aItemId, aName, aValue,
591 0 : aFlags, aExpiration);
592 0 : NS_ENSURE_SUCCESS(rv, rv);
593 :
594 0 : NOTIFY_ANNOS_OBSERVERS(OnItemAnnotationSet(aItemId, aName, aSource));
595 :
596 0 : return NS_OK;
597 : }
598 :
599 : NS_IMETHODIMP
600 0 : nsAnnotationService::GetPageAnnotationString(nsIURI* aURI,
601 : const nsACString& aName,
602 : nsAString& _retval)
603 : {
604 0 : NS_ENSURE_ARG(aURI);
605 :
606 0 : nsCOMPtr<mozIStorageStatement> statement;
607 0 : nsresult rv = StartGetAnnotation(aURI, 0, aName, statement);
608 0 : if (NS_FAILED(rv))
609 0 : return rv;
610 :
611 0 : mozStorageStatementScoper scoper(statement);
612 0 : ENSURE_ANNO_TYPE(TYPE_STRING, statement);
613 0 : rv = statement->GetString(kAnnoIndex_Content, _retval);
614 0 : NS_ENSURE_SUCCESS(rv, rv);
615 :
616 0 : return NS_OK;
617 : }
618 :
619 :
620 : NS_IMETHODIMP
621 0 : nsAnnotationService::GetItemAnnotationString(int64_t aItemId,
622 : const nsACString& aName,
623 : nsAString& _retval)
624 : {
625 0 : NS_ENSURE_ARG_MIN(aItemId, 1);
626 :
627 0 : nsCOMPtr<mozIStorageStatement> statement;
628 0 : nsresult rv = StartGetAnnotation(nullptr, aItemId, aName, statement);
629 0 : if (NS_FAILED(rv))
630 0 : return rv;
631 :
632 0 : mozStorageStatementScoper scoper(statement);
633 0 : ENSURE_ANNO_TYPE(TYPE_STRING, statement);
634 0 : rv = statement->GetString(kAnnoIndex_Content, _retval);
635 0 : NS_ENSURE_SUCCESS(rv, rv);
636 :
637 0 : return NS_OK;
638 : }
639 :
640 :
641 : NS_IMETHODIMP
642 0 : nsAnnotationService::GetPageAnnotation(nsIURI* aURI,
643 : const nsACString& aName,
644 : nsIVariant** _retval)
645 : {
646 0 : NS_ENSURE_ARG(aURI);
647 0 : NS_ENSURE_ARG_POINTER(_retval);
648 :
649 0 : nsCOMPtr<mozIStorageStatement> statement;
650 0 : nsresult rv = StartGetAnnotation(aURI, 0, aName, statement);
651 0 : if (NS_FAILED(rv))
652 0 : return rv;
653 :
654 0 : mozStorageStatementScoper scoper(statement);
655 :
656 0 : nsCOMPtr<nsIWritableVariant> value = new nsVariant();
657 0 : int32_t type = statement->AsInt32(kAnnoIndex_Type);
658 0 : switch (type) {
659 : case nsIAnnotationService::TYPE_INT32:
660 : case nsIAnnotationService::TYPE_INT64:
661 : case nsIAnnotationService::TYPE_DOUBLE: {
662 0 : rv = value->SetAsDouble(statement->AsDouble(kAnnoIndex_Content));
663 0 : break;
664 : }
665 : case nsIAnnotationService::TYPE_STRING: {
666 0 : nsAutoString valueString;
667 0 : rv = statement->GetString(kAnnoIndex_Content, valueString);
668 0 : if (NS_SUCCEEDED(rv))
669 0 : rv = value->SetAsAString(valueString);
670 0 : break;
671 : }
672 : default: {
673 0 : rv = NS_ERROR_UNEXPECTED;
674 0 : break;
675 : }
676 : }
677 :
678 0 : if (NS_SUCCEEDED(rv)) {
679 0 : value.forget(_retval);
680 : }
681 :
682 0 : return rv;
683 : }
684 :
685 :
686 : NS_IMETHODIMP
687 0 : nsAnnotationService::GetItemAnnotation(int64_t aItemId,
688 : const nsACString& aName,
689 : nsIVariant** _retval)
690 : {
691 0 : NS_ENSURE_ARG_MIN(aItemId, 1);
692 0 : NS_ENSURE_ARG_POINTER(_retval);
693 :
694 0 : nsCOMPtr<mozIStorageStatement> statement;
695 0 : nsresult rv = StartGetAnnotation(nullptr, aItemId, aName, statement);
696 0 : if (NS_FAILED(rv))
697 0 : return rv;
698 :
699 0 : mozStorageStatementScoper scoper(statement);
700 :
701 0 : nsCOMPtr<nsIWritableVariant> value = new nsVariant();
702 0 : int32_t type = statement->AsInt32(kAnnoIndex_Type);
703 0 : switch (type) {
704 : case nsIAnnotationService::TYPE_INT32:
705 : case nsIAnnotationService::TYPE_INT64:
706 : case nsIAnnotationService::TYPE_DOUBLE: {
707 0 : rv = value->SetAsDouble(statement->AsDouble(kAnnoIndex_Content));
708 0 : break;
709 : }
710 : case nsIAnnotationService::TYPE_STRING: {
711 0 : nsAutoString valueString;
712 0 : rv = statement->GetString(kAnnoIndex_Content, valueString);
713 0 : if (NS_SUCCEEDED(rv))
714 0 : rv = value->SetAsAString(valueString);
715 0 : break;
716 : }
717 : default: {
718 0 : rv = NS_ERROR_UNEXPECTED;
719 0 : break;
720 : }
721 : }
722 :
723 0 : if (NS_SUCCEEDED(rv)) {
724 0 : value.forget(_retval);
725 : }
726 :
727 0 : return rv;
728 : }
729 :
730 :
731 : NS_IMETHODIMP
732 0 : nsAnnotationService::GetPageAnnotationInt32(nsIURI* aURI,
733 : const nsACString& aName,
734 : int32_t* _retval)
735 : {
736 0 : NS_ENSURE_ARG(aURI);
737 0 : NS_ENSURE_ARG_POINTER(_retval);
738 :
739 0 : nsCOMPtr<mozIStorageStatement> statement;
740 0 : nsresult rv = StartGetAnnotation(aURI, 0, aName, statement);
741 0 : if (NS_FAILED(rv))
742 0 : return rv;
743 :
744 0 : mozStorageStatementScoper scoper(statement);
745 0 : ENSURE_ANNO_TYPE(TYPE_INT32, statement);
746 0 : *_retval = statement->AsInt32(kAnnoIndex_Content);
747 0 : NS_ENSURE_SUCCESS(rv, rv);
748 :
749 0 : return NS_OK;
750 : }
751 :
752 :
753 : NS_IMETHODIMP
754 0 : nsAnnotationService::GetItemAnnotationInt32(int64_t aItemId,
755 : const nsACString& aName,
756 : int32_t* _retval)
757 : {
758 0 : NS_ENSURE_ARG_MIN(aItemId, 1);
759 0 : NS_ENSURE_ARG_POINTER(_retval);
760 :
761 0 : nsCOMPtr<mozIStorageStatement> statement;
762 0 : nsresult rv = StartGetAnnotation(nullptr, aItemId, aName, statement);
763 0 : if (NS_FAILED(rv))
764 0 : return rv;
765 :
766 0 : mozStorageStatementScoper scoper(statement);
767 0 : ENSURE_ANNO_TYPE(TYPE_INT32, statement);
768 0 : *_retval = statement->AsInt32(kAnnoIndex_Content);
769 :
770 0 : return NS_OK;
771 : }
772 :
773 :
774 : NS_IMETHODIMP
775 0 : nsAnnotationService::GetPageAnnotationInt64(nsIURI* aURI,
776 : const nsACString& aName,
777 : int64_t* _retval)
778 : {
779 0 : NS_ENSURE_ARG(aURI);
780 0 : NS_ENSURE_ARG_POINTER(_retval);
781 :
782 0 : nsCOMPtr<mozIStorageStatement> statement;
783 0 : nsresult rv = StartGetAnnotation(aURI, 0, aName, statement);
784 0 : if (NS_FAILED(rv))
785 0 : return rv;
786 :
787 0 : mozStorageStatementScoper scoper(statement);
788 0 : ENSURE_ANNO_TYPE(TYPE_INT64, statement);
789 0 : *_retval = statement->AsInt64(kAnnoIndex_Content);
790 :
791 0 : return NS_OK;
792 : }
793 :
794 :
795 : NS_IMETHODIMP
796 0 : nsAnnotationService::GetItemAnnotationInt64(int64_t aItemId,
797 : const nsACString& aName,
798 : int64_t* _retval)
799 : {
800 0 : NS_ENSURE_ARG_MIN(aItemId, 1);
801 0 : NS_ENSURE_ARG_POINTER(_retval);
802 :
803 0 : nsCOMPtr<mozIStorageStatement> statement;
804 0 : nsresult rv = StartGetAnnotation(nullptr, aItemId, aName, statement);
805 0 : if (NS_FAILED(rv))
806 0 : return rv;
807 :
808 0 : mozStorageStatementScoper scoper(statement);
809 0 : ENSURE_ANNO_TYPE(TYPE_INT64, statement);
810 0 : *_retval = statement->AsInt64(kAnnoIndex_Content);
811 :
812 0 : return NS_OK;
813 : }
814 :
815 :
816 : NS_IMETHODIMP
817 0 : nsAnnotationService::GetPageAnnotationType(nsIURI* aURI,
818 : const nsACString& aName,
819 : uint16_t* _retval)
820 : {
821 0 : NS_ENSURE_ARG(aURI);
822 0 : NS_ENSURE_ARG_POINTER(_retval);
823 :
824 0 : nsCOMPtr<mozIStorageStatement> statement;
825 0 : nsresult rv = StartGetAnnotation(aURI, 0, aName, statement);
826 0 : if (NS_FAILED(rv))
827 0 : return rv;
828 :
829 0 : mozStorageStatementScoper scoper(statement);
830 0 : *_retval = statement->AsInt32(kAnnoIndex_Type);
831 :
832 0 : return NS_OK;
833 : }
834 :
835 :
836 : NS_IMETHODIMP
837 0 : nsAnnotationService::GetItemAnnotationType(int64_t aItemId,
838 : const nsACString& aName,
839 : uint16_t* _retval)
840 : {
841 0 : NS_ENSURE_ARG_MIN(aItemId, 1);
842 0 : NS_ENSURE_ARG_POINTER(_retval);
843 :
844 0 : nsCOMPtr<mozIStorageStatement> statement;
845 0 : nsresult rv = StartGetAnnotation(nullptr, aItemId, aName, statement);
846 0 : if (NS_FAILED(rv))
847 0 : return rv;
848 :
849 0 : mozStorageStatementScoper scoper(statement);
850 0 : *_retval = statement->AsInt32(kAnnoIndex_Type);
851 :
852 0 : return NS_OK;
853 : }
854 :
855 :
856 : NS_IMETHODIMP
857 0 : nsAnnotationService::GetPageAnnotationDouble(nsIURI* aURI,
858 : const nsACString& aName,
859 : double* _retval)
860 : {
861 0 : NS_ENSURE_ARG(aURI);
862 0 : NS_ENSURE_ARG_POINTER(_retval);
863 :
864 0 : nsCOMPtr<mozIStorageStatement> statement;
865 0 : nsresult rv = StartGetAnnotation(aURI, 0, aName, statement);
866 0 : if (NS_FAILED(rv))
867 0 : return rv;
868 :
869 0 : mozStorageStatementScoper scoper(statement);
870 0 : ENSURE_ANNO_TYPE(TYPE_DOUBLE, statement);
871 0 : *_retval = statement->AsDouble(kAnnoIndex_Content);
872 :
873 0 : return NS_OK;
874 : }
875 :
876 :
877 : NS_IMETHODIMP
878 0 : nsAnnotationService::GetItemAnnotationDouble(int64_t aItemId,
879 : const nsACString& aName,
880 : double* _retval)
881 : {
882 0 : NS_ENSURE_ARG_MIN(aItemId, 1);
883 :
884 0 : nsCOMPtr<mozIStorageStatement> statement;
885 0 : nsresult rv = StartGetAnnotation(nullptr, aItemId, aName, statement);
886 0 : if (NS_FAILED(rv))
887 0 : return rv;
888 :
889 0 : mozStorageStatementScoper scoper(statement);
890 0 : ENSURE_ANNO_TYPE(TYPE_DOUBLE, statement);
891 0 : *_retval = statement->AsDouble(kAnnoIndex_Content);
892 :
893 0 : return NS_OK;
894 : }
895 :
896 :
897 : NS_IMETHODIMP
898 0 : nsAnnotationService::GetPageAnnotationInfo(nsIURI* aURI,
899 : const nsACString& aName,
900 : int32_t* _flags,
901 : uint16_t* _expiration,
902 : uint16_t* _storageType)
903 : {
904 0 : NS_ENSURE_ARG(aURI);
905 0 : NS_ENSURE_ARG_POINTER(_flags);
906 0 : NS_ENSURE_ARG_POINTER(_expiration);
907 0 : NS_ENSURE_ARG_POINTER(_storageType);
908 :
909 0 : nsCOMPtr<mozIStorageStatement> statement;
910 0 : nsresult rv = StartGetAnnotation(aURI, 0, aName, statement);
911 0 : if (NS_FAILED(rv))
912 0 : return rv;
913 :
914 0 : mozStorageStatementScoper scoper(statement);
915 0 : *_flags = statement->AsInt32(kAnnoIndex_Flags);
916 0 : *_expiration = (uint16_t)statement->AsInt32(kAnnoIndex_Expiration);
917 0 : int32_t type = (uint16_t)statement->AsInt32(kAnnoIndex_Type);
918 0 : if (type == 0) {
919 : // For annotations created before explicit typing,
920 : // we can't determine type, just return as string type.
921 0 : *_storageType = nsIAnnotationService::TYPE_STRING;
922 : }
923 : else
924 0 : *_storageType = type;
925 :
926 0 : return NS_OK;
927 : }
928 :
929 :
930 : NS_IMETHODIMP
931 0 : nsAnnotationService::GetItemAnnotationInfo(int64_t aItemId,
932 : const nsACString& aName,
933 : int32_t* _flags,
934 : uint16_t* _expiration,
935 : uint16_t* _storageType)
936 : {
937 0 : NS_ENSURE_ARG_MIN(aItemId, 1);
938 0 : NS_ENSURE_ARG_POINTER(_flags);
939 0 : NS_ENSURE_ARG_POINTER(_expiration);
940 0 : NS_ENSURE_ARG_POINTER(_storageType);
941 :
942 0 : nsCOMPtr<mozIStorageStatement> statement;
943 0 : nsresult rv = StartGetAnnotation(nullptr, aItemId, aName, statement);
944 0 : if (NS_FAILED(rv))
945 0 : return rv;
946 :
947 0 : mozStorageStatementScoper scoper(statement);
948 0 : *_flags = statement->AsInt32(kAnnoIndex_Flags);
949 0 : *_expiration = (uint16_t)statement->AsInt32(kAnnoIndex_Expiration);
950 0 : int32_t type = (uint16_t)statement->AsInt32(kAnnoIndex_Type);
951 0 : if (type == 0) {
952 : // For annotations created before explicit typing,
953 : // we can't determine type, just return as string type.
954 0 : *_storageType = nsIAnnotationService::TYPE_STRING;
955 : }
956 : else {
957 0 : *_storageType = type;
958 : }
959 :
960 0 : return NS_OK;
961 : }
962 :
963 :
964 : NS_IMETHODIMP
965 0 : nsAnnotationService::GetPagesWithAnnotation(const nsACString& aName,
966 : uint32_t* _resultCount,
967 : nsIURI*** _results)
968 : {
969 0 : NS_ENSURE_TRUE(!aName.IsEmpty(), NS_ERROR_INVALID_ARG);
970 0 : NS_ENSURE_ARG_POINTER(_resultCount);
971 0 : NS_ENSURE_ARG_POINTER(_results);
972 :
973 0 : *_resultCount = 0;
974 0 : *_results = nullptr;
975 0 : nsCOMArray<nsIURI> results;
976 :
977 0 : nsresult rv = GetPagesWithAnnotationCOMArray(aName, &results);
978 0 : NS_ENSURE_SUCCESS(rv, rv);
979 :
980 : // Convert to raw array.
981 0 : if (results.Count() == 0)
982 0 : return NS_OK;
983 :
984 0 : *_resultCount = results.Count();
985 0 : results.Forget(_results);
986 :
987 0 : return NS_OK;
988 : }
989 :
990 :
991 : nsresult
992 0 : nsAnnotationService::GetPagesWithAnnotationCOMArray(const nsACString& aName,
993 : nsCOMArray<nsIURI>* _results)
994 : {
995 0 : nsCOMPtr<mozIStorageStatement> stmt = mDB->GetStatement(
996 : "SELECT h.url "
997 : "FROM moz_anno_attributes n "
998 : "JOIN moz_annos a ON n.id = a.anno_attribute_id "
999 : "JOIN moz_places h ON h.id = a.place_id "
1000 : "WHERE n.name = :anno_name"
1001 0 : );
1002 0 : NS_ENSURE_STATE(stmt);
1003 0 : mozStorageStatementScoper scoper(stmt);
1004 :
1005 0 : nsresult rv = stmt->BindUTF8StringByName(NS_LITERAL_CSTRING("anno_name"), aName);
1006 0 : NS_ENSURE_SUCCESS(rv, rv);
1007 :
1008 0 : bool hasMore = false;
1009 0 : while (NS_SUCCEEDED(rv = stmt->ExecuteStep(&hasMore)) &&
1010 : hasMore) {
1011 0 : nsAutoCString uristring;
1012 0 : rv = stmt->GetUTF8String(0, uristring);
1013 0 : NS_ENSURE_SUCCESS(rv, rv);
1014 :
1015 : // convert to a URI, in case of some invalid URI, just ignore this row
1016 : // so we can mostly continue.
1017 0 : nsCOMPtr<nsIURI> uri;
1018 0 : rv = NS_NewURI(getter_AddRefs(uri), uristring);
1019 0 : if (NS_FAILED(rv))
1020 0 : continue;
1021 :
1022 0 : bool added = _results->AppendObject(uri);
1023 0 : NS_ENSURE_TRUE(added, NS_ERROR_OUT_OF_MEMORY);
1024 : }
1025 :
1026 0 : return NS_OK;
1027 : }
1028 :
1029 :
1030 : NS_IMETHODIMP
1031 0 : nsAnnotationService::GetItemsWithAnnotation(const nsACString& aName,
1032 : uint32_t* _resultCount,
1033 : int64_t** _results)
1034 : {
1035 0 : NS_ENSURE_TRUE(!aName.IsEmpty(), NS_ERROR_INVALID_ARG);
1036 0 : NS_ENSURE_ARG_POINTER(_resultCount);
1037 0 : NS_ENSURE_ARG_POINTER(_results);
1038 :
1039 0 : *_resultCount = 0;
1040 0 : *_results = nullptr;
1041 0 : nsTArray<int64_t> results;
1042 :
1043 0 : nsresult rv = GetItemsWithAnnotationTArray(aName, &results);
1044 0 : NS_ENSURE_SUCCESS(rv, rv);
1045 :
1046 : // Convert to raw array.
1047 0 : if (results.Length() == 0)
1048 0 : return NS_OK;
1049 :
1050 0 : *_results = static_cast<int64_t*>
1051 0 : (moz_xmalloc(results.Length() * sizeof(int64_t)));
1052 0 : NS_ENSURE_TRUE(*_results, NS_ERROR_OUT_OF_MEMORY);
1053 :
1054 0 : *_resultCount = results.Length();
1055 0 : for (uint32_t i = 0; i < *_resultCount; i ++) {
1056 0 : (*_results)[i] = results[i];
1057 : }
1058 :
1059 0 : return NS_OK;
1060 : }
1061 :
1062 :
1063 : NS_IMETHODIMP
1064 0 : nsAnnotationService::GetAnnotationsWithName(const nsACString& aName,
1065 : uint32_t* _count,
1066 : mozIAnnotatedResult*** _annotations)
1067 : {
1068 0 : NS_ENSURE_ARG(!aName.IsEmpty());
1069 0 : NS_ENSURE_ARG_POINTER(_annotations);
1070 :
1071 0 : *_count = 0;
1072 0 : *_annotations = nullptr;
1073 0 : nsCOMArray<mozIAnnotatedResult> annotations;
1074 :
1075 0 : nsCOMPtr<mozIStorageStatement> stmt = mDB->GetStatement(
1076 : "SELECT h.guid, h.url, -1, a.type, a.content "
1077 : "FROM moz_anno_attributes n "
1078 : "JOIN moz_annos a ON n.id = a.anno_attribute_id "
1079 : "JOIN moz_places h ON h.id = a.place_id "
1080 : "WHERE n.name = :anno_name "
1081 : "UNION ALL "
1082 : "SELECT b.guid, h.url, b.id, a.type, a.content "
1083 : "FROM moz_anno_attributes n "
1084 : "JOIN moz_items_annos a ON n.id = a.anno_attribute_id "
1085 : "JOIN moz_bookmarks b ON b.id = a.item_id "
1086 : "LEFT JOIN moz_places h ON h.id = b.fk "
1087 : "WHERE n.name = :anno_name "
1088 0 : );
1089 0 : NS_ENSURE_STATE(stmt);
1090 0 : mozStorageStatementScoper scoper(stmt);
1091 :
1092 0 : nsresult rv = stmt->BindUTF8StringByName(NS_LITERAL_CSTRING("anno_name"),
1093 0 : aName);
1094 0 : NS_ENSURE_SUCCESS(rv, rv);
1095 :
1096 0 : bool hasMore = false;
1097 0 : while (NS_SUCCEEDED(rv = stmt->ExecuteStep(&hasMore)) && hasMore) {
1098 0 : nsAutoCString guid;
1099 0 : rv = stmt->GetUTF8String(0, guid);
1100 0 : NS_ENSURE_SUCCESS(rv, rv);
1101 :
1102 0 : nsCOMPtr<nsIURI> uri;
1103 0 : bool uriIsNull = false;
1104 0 : rv = stmt->GetIsNull(1, &uriIsNull);
1105 0 : NS_ENSURE_SUCCESS(rv, rv);
1106 0 : if (!uriIsNull) {
1107 0 : nsAutoCString url;
1108 0 : rv = stmt->GetUTF8String(1, url);
1109 0 : NS_ENSURE_SUCCESS(rv, rv);
1110 0 : rv = NS_NewURI(getter_AddRefs(uri), url);
1111 0 : NS_ENSURE_SUCCESS(rv, rv);
1112 : }
1113 :
1114 0 : int64_t itemId = stmt->AsInt64(2);
1115 0 : int32_t type = stmt->AsInt32(3);
1116 :
1117 0 : nsCOMPtr<nsIWritableVariant> variant = new nsVariant();
1118 0 : switch (type) {
1119 : case nsIAnnotationService::TYPE_INT32: {
1120 0 : rv = variant->SetAsInt32(stmt->AsInt32(4));
1121 0 : break;
1122 : }
1123 : case nsIAnnotationService::TYPE_INT64: {
1124 0 : rv = variant->SetAsInt64(stmt->AsInt64(4));
1125 0 : break;
1126 : }
1127 : case nsIAnnotationService::TYPE_DOUBLE: {
1128 0 : rv = variant->SetAsDouble(stmt->AsDouble(4));
1129 0 : break;
1130 : }
1131 : case nsIAnnotationService::TYPE_STRING: {
1132 0 : nsAutoString valueString;
1133 0 : rv = stmt->GetString(4, valueString);
1134 0 : NS_ENSURE_SUCCESS(rv, rv);
1135 :
1136 0 : rv = variant->SetAsAString(valueString);
1137 0 : break;
1138 : }
1139 : default:
1140 0 : MOZ_ASSERT(false, "Unsupported annotation type");
1141 : // Move to the next result.
1142 : continue;
1143 : }
1144 0 : NS_ENSURE_SUCCESS(rv, rv);
1145 :
1146 : nsCOMPtr<mozIAnnotatedResult> anno = new AnnotatedResult(guid, uri, itemId,
1147 0 : aName, variant);
1148 0 : NS_ENSURE_TRUE(annotations.AppendObject(anno), NS_ERROR_OUT_OF_MEMORY);
1149 : }
1150 :
1151 : // Convert to raw array.
1152 0 : if (annotations.Count() == 0)
1153 0 : return NS_OK;
1154 :
1155 0 : *_count = annotations.Count();
1156 0 : annotations.Forget(_annotations);
1157 :
1158 0 : return NS_OK;
1159 : }
1160 :
1161 :
1162 : nsresult
1163 0 : nsAnnotationService::GetItemsWithAnnotationTArray(const nsACString& aName,
1164 : nsTArray<int64_t>* _results)
1165 : {
1166 0 : nsCOMPtr<mozIStorageStatement> stmt = mDB->GetStatement(
1167 : "SELECT a.item_id "
1168 : "FROM moz_anno_attributes n "
1169 : "JOIN moz_items_annos a ON n.id = a.anno_attribute_id "
1170 : "WHERE n.name = :anno_name"
1171 0 : );
1172 0 : NS_ENSURE_STATE(stmt);
1173 0 : mozStorageStatementScoper scoper(stmt);
1174 :
1175 0 : nsresult rv = stmt->BindUTF8StringByName(NS_LITERAL_CSTRING("anno_name"), aName);
1176 0 : NS_ENSURE_SUCCESS(rv, rv);
1177 :
1178 0 : bool hasMore = false;
1179 0 : while (NS_SUCCEEDED(stmt->ExecuteStep(&hasMore)) &&
1180 : hasMore) {
1181 0 : if (!_results->AppendElement(stmt->AsInt64(0)))
1182 0 : return NS_ERROR_OUT_OF_MEMORY;
1183 : }
1184 :
1185 0 : return NS_OK;
1186 : }
1187 :
1188 :
1189 : NS_IMETHODIMP
1190 0 : nsAnnotationService::GetPageAnnotationNames(nsIURI* aURI,
1191 : uint32_t* _count,
1192 : nsIVariant*** _result)
1193 : {
1194 0 : NS_ENSURE_ARG(aURI);
1195 0 : NS_ENSURE_ARG_POINTER(_count);
1196 0 : NS_ENSURE_ARG_POINTER(_result);
1197 :
1198 0 : *_count = 0;
1199 0 : *_result = nullptr;
1200 :
1201 0 : nsTArray<nsCString> names;
1202 0 : nsresult rv = GetAnnotationNamesTArray(aURI, 0, &names);
1203 0 : NS_ENSURE_SUCCESS(rv, rv);
1204 :
1205 0 : if (names.Length() == 0)
1206 0 : return NS_OK;
1207 :
1208 0 : *_result = static_cast<nsIVariant**>
1209 0 : (moz_xmalloc(sizeof(nsIVariant*) * names.Length()));
1210 0 : NS_ENSURE_TRUE(*_result, NS_ERROR_OUT_OF_MEMORY);
1211 :
1212 0 : for (uint32_t i = 0; i < names.Length(); i ++) {
1213 0 : nsCOMPtr<nsIWritableVariant> var = new nsVariant();
1214 0 : if (!var) {
1215 : // need to release all the variants we've already created
1216 0 : for (uint32_t j = 0; j < i; j ++)
1217 0 : NS_RELEASE((*_result)[j]);
1218 0 : free(*_result);
1219 0 : *_result = nullptr;
1220 0 : return NS_ERROR_OUT_OF_MEMORY;
1221 : }
1222 0 : var->SetAsAUTF8String(names[i]);
1223 0 : NS_ADDREF((*_result)[i] = var);
1224 : }
1225 0 : *_count = names.Length();
1226 :
1227 0 : return NS_OK;
1228 : }
1229 :
1230 :
1231 : nsresult
1232 0 : nsAnnotationService::GetAnnotationNamesTArray(nsIURI* aURI,
1233 : int64_t aItemId,
1234 : nsTArray<nsCString>* _result)
1235 : {
1236 0 : _result->Clear();
1237 :
1238 0 : bool isItemAnnotation = (aItemId > 0);
1239 0 : nsCOMPtr<mozIStorageStatement> statement;
1240 0 : if (isItemAnnotation) {
1241 0 : statement = mDB->GetStatement(
1242 : "SELECT n.name "
1243 : "FROM moz_anno_attributes n "
1244 : "JOIN moz_items_annos a ON a.anno_attribute_id = n.id "
1245 : "WHERE a.item_id = :item_id"
1246 0 : );
1247 : }
1248 : else {
1249 0 : statement = mDB->GetStatement(
1250 : "SELECT n.name "
1251 : "FROM moz_anno_attributes n "
1252 : "JOIN moz_annos a ON a.anno_attribute_id = n.id "
1253 : "JOIN moz_places h ON h.id = a.place_id "
1254 : "WHERE h.url_hash = hash(:page_url) AND h.url = :page_url"
1255 0 : );
1256 : }
1257 0 : NS_ENSURE_STATE(statement);
1258 0 : mozStorageStatementScoper scoper(statement);
1259 :
1260 : nsresult rv;
1261 0 : if (isItemAnnotation)
1262 0 : rv = statement->BindInt64ByName(NS_LITERAL_CSTRING("item_id"), aItemId);
1263 : else
1264 0 : rv = URIBinder::Bind(statement, NS_LITERAL_CSTRING("page_url"), aURI);
1265 0 : NS_ENSURE_SUCCESS(rv, rv);
1266 :
1267 0 : bool hasResult = false;
1268 0 : while (NS_SUCCEEDED(statement->ExecuteStep(&hasResult)) &&
1269 : hasResult) {
1270 0 : nsAutoCString name;
1271 0 : rv = statement->GetUTF8String(0, name);
1272 0 : NS_ENSURE_SUCCESS(rv, rv);
1273 0 : if (!_result->AppendElement(name))
1274 0 : return NS_ERROR_OUT_OF_MEMORY;
1275 : }
1276 :
1277 0 : return NS_OK;
1278 : }
1279 :
1280 :
1281 : NS_IMETHODIMP
1282 0 : nsAnnotationService::GetItemAnnotationNames(int64_t aItemId,
1283 : uint32_t* _count,
1284 : nsIVariant*** _result)
1285 : {
1286 0 : NS_ENSURE_ARG_MIN(aItemId, 1);
1287 0 : NS_ENSURE_ARG_POINTER(_count);
1288 0 : NS_ENSURE_ARG_POINTER(_result);
1289 :
1290 0 : *_count = 0;
1291 0 : *_result = nullptr;
1292 :
1293 0 : nsTArray<nsCString> names;
1294 0 : nsresult rv = GetAnnotationNamesTArray(nullptr, aItemId, &names);
1295 0 : NS_ENSURE_SUCCESS(rv, rv);
1296 :
1297 0 : if (names.Length() == 0)
1298 0 : return NS_OK;
1299 :
1300 0 : *_result = static_cast<nsIVariant**>
1301 0 : (moz_xmalloc(sizeof(nsIVariant*) * names.Length()));
1302 0 : NS_ENSURE_TRUE(*_result, NS_ERROR_OUT_OF_MEMORY);
1303 :
1304 0 : for (uint32_t i = 0; i < names.Length(); i ++) {
1305 0 : nsCOMPtr<nsIWritableVariant> var = new nsVariant();
1306 0 : if (!var) {
1307 : // need to release all the variants we've already created
1308 0 : for (uint32_t j = 0; j < i; j ++)
1309 0 : NS_RELEASE((*_result)[j]);
1310 0 : free(*_result);
1311 0 : *_result = nullptr;
1312 0 : return NS_ERROR_OUT_OF_MEMORY;
1313 : }
1314 0 : var->SetAsAUTF8String(names[i]);
1315 0 : NS_ADDREF((*_result)[i] = var);
1316 : }
1317 0 : *_count = names.Length();
1318 :
1319 0 : return NS_OK;
1320 : }
1321 :
1322 :
1323 : NS_IMETHODIMP
1324 0 : nsAnnotationService::PageHasAnnotation(nsIURI* aURI,
1325 : const nsACString& aName,
1326 : bool* _retval)
1327 : {
1328 0 : NS_ENSURE_ARG(aURI);
1329 0 : NS_ENSURE_ARG_POINTER(_retval);
1330 :
1331 0 : nsresult rv = HasAnnotationInternal(aURI, 0, aName, _retval);
1332 0 : NS_ENSURE_SUCCESS(rv, rv);
1333 :
1334 0 : return NS_OK;
1335 : }
1336 :
1337 :
1338 : NS_IMETHODIMP
1339 0 : nsAnnotationService::ItemHasAnnotation(int64_t aItemId,
1340 : const nsACString& aName,
1341 : bool* _retval)
1342 : {
1343 0 : NS_ENSURE_ARG_MIN(aItemId, 1);
1344 0 : NS_ENSURE_ARG_POINTER(_retval);
1345 :
1346 0 : nsresult rv = HasAnnotationInternal(nullptr, aItemId, aName, _retval);
1347 0 : NS_ENSURE_SUCCESS(rv, rv);
1348 :
1349 0 : return NS_OK;
1350 : }
1351 :
1352 :
1353 : /**
1354 : * @note We don't remove anything from the moz_anno_attributes table. If we
1355 : * delete the last item of a given name, that item really should go away.
1356 : * It will be cleaned up by expiration.
1357 : */
1358 : nsresult
1359 0 : nsAnnotationService::RemoveAnnotationInternal(nsIURI* aURI,
1360 : int64_t aItemId,
1361 : const nsACString& aName)
1362 : {
1363 0 : bool isItemAnnotation = (aItemId > 0);
1364 0 : nsCOMPtr<mozIStorageStatement> statement;
1365 0 : if (isItemAnnotation) {
1366 0 : statement = mDB->GetStatement(
1367 : "DELETE FROM moz_items_annos "
1368 : "WHERE item_id = :item_id "
1369 : "AND anno_attribute_id = "
1370 : "(SELECT id FROM moz_anno_attributes WHERE name = :anno_name)"
1371 0 : );
1372 : }
1373 : else {
1374 0 : statement = mDB->GetStatement(
1375 : "DELETE FROM moz_annos "
1376 : "WHERE place_id = "
1377 : "(SELECT id FROM moz_places WHERE url_hash = hash(:page_url) AND url = :page_url) "
1378 : "AND anno_attribute_id = "
1379 : "(SELECT id FROM moz_anno_attributes WHERE name = :anno_name)"
1380 0 : );
1381 : }
1382 0 : NS_ENSURE_STATE(statement);
1383 0 : mozStorageStatementScoper scoper(statement);
1384 :
1385 : nsresult rv;
1386 0 : if (isItemAnnotation)
1387 0 : rv = statement->BindInt64ByName(NS_LITERAL_CSTRING("item_id"), aItemId);
1388 : else
1389 0 : rv = URIBinder::Bind(statement, NS_LITERAL_CSTRING("page_url"), aURI);
1390 0 : NS_ENSURE_SUCCESS(rv, rv);
1391 :
1392 0 : rv = statement->BindUTF8StringByName(NS_LITERAL_CSTRING("anno_name"), aName);
1393 0 : NS_ENSURE_SUCCESS(rv, rv);
1394 :
1395 0 : rv = statement->Execute();
1396 0 : NS_ENSURE_SUCCESS(rv, rv);
1397 :
1398 0 : return NS_OK;
1399 : }
1400 :
1401 :
1402 : NS_IMETHODIMP
1403 0 : nsAnnotationService::RemovePageAnnotation(nsIURI* aURI,
1404 : const nsACString& aName)
1405 : {
1406 0 : NS_ENSURE_ARG(aURI);
1407 :
1408 0 : nsresult rv = RemoveAnnotationInternal(aURI, 0, aName);
1409 0 : NS_ENSURE_SUCCESS(rv, rv);
1410 :
1411 0 : NOTIFY_ANNOS_OBSERVERS(OnPageAnnotationRemoved(aURI, aName));
1412 :
1413 0 : return NS_OK;
1414 : }
1415 :
1416 :
1417 : NS_IMETHODIMP
1418 0 : nsAnnotationService::RemoveItemAnnotation(int64_t aItemId,
1419 : const nsACString& aName,
1420 : uint16_t aSource)
1421 : {
1422 0 : NS_ENSURE_ARG_MIN(aItemId, 1);
1423 :
1424 0 : nsresult rv = RemoveAnnotationInternal(nullptr, aItemId, aName);
1425 0 : NS_ENSURE_SUCCESS(rv, rv);
1426 :
1427 0 : NOTIFY_ANNOS_OBSERVERS(OnItemAnnotationRemoved(aItemId, aName, aSource));
1428 :
1429 0 : return NS_OK;
1430 : }
1431 :
1432 :
1433 : NS_IMETHODIMP
1434 0 : nsAnnotationService::RemovePageAnnotations(nsIURI* aURI)
1435 : {
1436 0 : NS_ENSURE_ARG(aURI);
1437 :
1438 : // Should this be precompiled or a getter?
1439 0 : nsCOMPtr<mozIStorageStatement> statement = mDB->GetStatement(
1440 : "DELETE FROM moz_annos WHERE place_id = "
1441 : "(SELECT id FROM moz_places WHERE url_hash = hash(:page_url) AND url = :page_url)"
1442 0 : );
1443 0 : NS_ENSURE_STATE(statement);
1444 0 : mozStorageStatementScoper scoper(statement);
1445 :
1446 0 : nsresult rv = URIBinder::Bind(statement, NS_LITERAL_CSTRING("page_url"), aURI);
1447 0 : NS_ENSURE_SUCCESS(rv, rv);
1448 :
1449 0 : rv = statement->Execute();
1450 0 : NS_ENSURE_SUCCESS(rv, rv);
1451 :
1452 : // Update observers
1453 0 : NOTIFY_ANNOS_OBSERVERS(OnPageAnnotationRemoved(aURI, EmptyCString()));
1454 :
1455 0 : return NS_OK;
1456 : }
1457 :
1458 :
1459 : NS_IMETHODIMP
1460 0 : nsAnnotationService::RemoveItemAnnotations(int64_t aItemId,
1461 : uint16_t aSource)
1462 : {
1463 0 : NS_ENSURE_ARG_MIN(aItemId, 1);
1464 :
1465 : // Should this be precompiled or a getter?
1466 0 : nsCOMPtr<mozIStorageStatement> statement = mDB->GetStatement(
1467 : "DELETE FROM moz_items_annos WHERE item_id = :item_id"
1468 0 : );
1469 0 : NS_ENSURE_STATE(statement);
1470 0 : mozStorageStatementScoper scoper(statement);
1471 :
1472 0 : nsresult rv = statement->BindInt64ByName(NS_LITERAL_CSTRING("item_id"), aItemId);
1473 0 : NS_ENSURE_SUCCESS(rv, rv);
1474 :
1475 0 : rv = statement->Execute();
1476 0 : NS_ENSURE_SUCCESS(rv, rv);
1477 :
1478 0 : NOTIFY_ANNOS_OBSERVERS(OnItemAnnotationRemoved(aItemId, EmptyCString(),
1479 : aSource));
1480 :
1481 0 : return NS_OK;
1482 : }
1483 :
1484 :
1485 : /**
1486 : * @note If we use annotations for some standard items like GeckoFlags, it
1487 : * might be a good idea to blacklist these standard annotations from this
1488 : * copy function.
1489 : */
1490 : NS_IMETHODIMP
1491 0 : nsAnnotationService::CopyPageAnnotations(nsIURI* aSourceURI,
1492 : nsIURI* aDestURI,
1493 : bool aOverwriteDest)
1494 : {
1495 0 : NS_ENSURE_ARG(aSourceURI);
1496 0 : NS_ENSURE_ARG(aDestURI);
1497 :
1498 0 : mozStorageTransaction transaction(mDB->MainConn(), false);
1499 :
1500 0 : nsCOMPtr<mozIStorageStatement> sourceStmt = mDB->GetStatement(
1501 : "SELECT h.id, n.id, n.name, a2.id "
1502 : "FROM moz_places h "
1503 : "JOIN moz_annos a ON a.place_id = h.id "
1504 : "JOIN moz_anno_attributes n ON n.id = a.anno_attribute_id "
1505 : "LEFT JOIN moz_annos a2 ON a2.place_id = "
1506 : "(SELECT id FROM moz_places WHERE url_hash = hash(:dest_url) AND url = :dest_url) "
1507 : "AND a2.anno_attribute_id = n.id "
1508 : "WHERE url = :source_url"
1509 0 : );
1510 0 : NS_ENSURE_STATE(sourceStmt);
1511 0 : mozStorageStatementScoper sourceScoper(sourceStmt);
1512 :
1513 0 : nsresult rv = URIBinder::Bind(sourceStmt, NS_LITERAL_CSTRING("source_url"), aSourceURI);
1514 0 : NS_ENSURE_SUCCESS(rv, rv);
1515 0 : rv = URIBinder::Bind(sourceStmt, NS_LITERAL_CSTRING("dest_url"), aDestURI);
1516 0 : NS_ENSURE_SUCCESS(rv, rv);
1517 :
1518 0 : nsCOMPtr<mozIStorageStatement> copyStmt = mDB->GetStatement(
1519 : "INSERT INTO moz_annos "
1520 : "(place_id, anno_attribute_id, content, flags, expiration, "
1521 : "type, dateAdded, lastModified) "
1522 : "SELECT (SELECT id FROM moz_places WHERE url_hash = hash(:page_url) AND url = :page_url), "
1523 : "anno_attribute_id, content, flags, expiration, type, "
1524 : ":date, :date "
1525 : "FROM moz_annos "
1526 : "WHERE place_id = :page_id "
1527 : "AND anno_attribute_id = :name_id"
1528 0 : );
1529 0 : NS_ENSURE_STATE(copyStmt);
1530 0 : mozStorageStatementScoper copyScoper(copyStmt);
1531 :
1532 : bool hasResult;
1533 0 : while (NS_SUCCEEDED(sourceStmt->ExecuteStep(&hasResult)) && hasResult) {
1534 0 : int64_t sourcePlaceId = sourceStmt->AsInt64(0);
1535 0 : int64_t annoNameID = sourceStmt->AsInt64(1);
1536 0 : nsAutoCString annoName;
1537 0 : rv = sourceStmt->GetUTF8String(2, annoName);
1538 0 : NS_ENSURE_SUCCESS(rv, rv);
1539 0 : int64_t annoExistsOnDest = sourceStmt->AsInt64(3);
1540 :
1541 0 : if (annoExistsOnDest) {
1542 0 : if (!aOverwriteDest)
1543 0 : continue;
1544 0 : rv = RemovePageAnnotation(aDestURI, annoName);
1545 0 : NS_ENSURE_SUCCESS(rv, rv);
1546 : }
1547 :
1548 : // Copy the annotation.
1549 0 : mozStorageStatementScoper scoper(copyStmt);
1550 0 : rv = URIBinder::Bind(copyStmt, NS_LITERAL_CSTRING("page_url"), aDestURI);
1551 0 : NS_ENSURE_SUCCESS(rv, rv);
1552 0 : rv = copyStmt->BindInt64ByName(NS_LITERAL_CSTRING("page_id"), sourcePlaceId);
1553 0 : NS_ENSURE_SUCCESS(rv, rv);
1554 0 : rv = copyStmt->BindInt64ByName(NS_LITERAL_CSTRING("name_id"), annoNameID);
1555 0 : NS_ENSURE_SUCCESS(rv, rv);
1556 0 : rv = copyStmt->BindInt64ByName(NS_LITERAL_CSTRING("date"), PR_Now());
1557 0 : NS_ENSURE_SUCCESS(rv, rv);
1558 :
1559 0 : rv = copyStmt->Execute();
1560 0 : NS_ENSURE_SUCCESS(rv, rv);
1561 :
1562 0 : NOTIFY_ANNOS_OBSERVERS(OnPageAnnotationSet(aDestURI, annoName));
1563 : }
1564 :
1565 0 : rv = transaction.Commit();
1566 0 : NS_ENSURE_SUCCESS(rv, rv);
1567 :
1568 0 : return NS_OK;
1569 : }
1570 :
1571 :
1572 : NS_IMETHODIMP
1573 0 : nsAnnotationService::CopyItemAnnotations(int64_t aSourceItemId,
1574 : int64_t aDestItemId,
1575 : bool aOverwriteDest,
1576 : uint16_t aSource)
1577 : {
1578 0 : NS_ENSURE_ARG_MIN(aSourceItemId, 1);
1579 0 : NS_ENSURE_ARG_MIN(aDestItemId, 1);
1580 :
1581 0 : mozStorageTransaction transaction(mDB->MainConn(), false);
1582 :
1583 0 : nsCOMPtr<mozIStorageStatement> sourceStmt = mDB->GetStatement(
1584 : "SELECT n.id, n.name, a2.id "
1585 : "FROM moz_bookmarks b "
1586 : "JOIN moz_items_annos a ON a.item_id = b.id "
1587 : "JOIN moz_anno_attributes n ON n.id = a.anno_attribute_id "
1588 : "LEFT JOIN moz_items_annos a2 ON a2.item_id = :dest_item_id "
1589 : "AND a2.anno_attribute_id = n.id "
1590 : "WHERE b.id = :source_item_id"
1591 0 : );
1592 0 : NS_ENSURE_STATE(sourceStmt);
1593 0 : mozStorageStatementScoper sourceScoper(sourceStmt);
1594 :
1595 0 : nsresult rv = sourceStmt->BindInt64ByName(NS_LITERAL_CSTRING("source_item_id"), aSourceItemId);
1596 0 : NS_ENSURE_SUCCESS(rv, rv);
1597 0 : rv = sourceStmt->BindInt64ByName(NS_LITERAL_CSTRING("dest_item_id"), aDestItemId);
1598 0 : NS_ENSURE_SUCCESS(rv, rv);
1599 :
1600 0 : nsCOMPtr<mozIStorageStatement> copyStmt = mDB->GetStatement(
1601 : "INSERT OR REPLACE INTO moz_items_annos "
1602 : "(item_id, anno_attribute_id, content, flags, expiration, "
1603 : "type, dateAdded, lastModified) "
1604 : "SELECT :dest_item_id, anno_attribute_id, content, flags, expiration, "
1605 : "type, :date, :date "
1606 : "FROM moz_items_annos "
1607 : "WHERE item_id = :source_item_id "
1608 : "AND anno_attribute_id = :name_id"
1609 0 : );
1610 0 : NS_ENSURE_STATE(copyStmt);
1611 0 : mozStorageStatementScoper copyScoper(copyStmt);
1612 :
1613 : bool hasResult;
1614 0 : while (NS_SUCCEEDED(sourceStmt->ExecuteStep(&hasResult)) && hasResult) {
1615 0 : int64_t annoNameID = sourceStmt->AsInt64(0);
1616 0 : nsAutoCString annoName;
1617 0 : rv = sourceStmt->GetUTF8String(1, annoName);
1618 0 : NS_ENSURE_SUCCESS(rv, rv);
1619 0 : int64_t annoExistsOnDest = sourceStmt->AsInt64(2);
1620 :
1621 0 : if (annoExistsOnDest) {
1622 0 : if (!aOverwriteDest)
1623 0 : continue;
1624 0 : rv = RemoveItemAnnotation(aDestItemId, annoName, aSource);
1625 0 : NS_ENSURE_SUCCESS(rv, rv);
1626 : }
1627 :
1628 : // Copy the annotation.
1629 0 : mozStorageStatementScoper scoper(copyStmt);
1630 0 : rv = copyStmt->BindInt64ByName(NS_LITERAL_CSTRING("dest_item_id"), aDestItemId);
1631 0 : NS_ENSURE_SUCCESS(rv, rv);
1632 0 : rv = copyStmt->BindInt64ByName(NS_LITERAL_CSTRING("source_item_id"), aSourceItemId);
1633 0 : NS_ENSURE_SUCCESS(rv, rv);
1634 0 : rv = copyStmt->BindInt64ByName(NS_LITERAL_CSTRING("name_id"), annoNameID);
1635 0 : NS_ENSURE_SUCCESS(rv, rv);
1636 0 : rv = copyStmt->BindInt64ByName(NS_LITERAL_CSTRING("date"), PR_Now());
1637 0 : NS_ENSURE_SUCCESS(rv, rv);
1638 :
1639 0 : rv = copyStmt->Execute();
1640 0 : NS_ENSURE_SUCCESS(rv, rv);
1641 :
1642 0 : NOTIFY_ANNOS_OBSERVERS(OnItemAnnotationSet(aDestItemId, annoName, aSource));
1643 : }
1644 :
1645 0 : rv = transaction.Commit();
1646 0 : NS_ENSURE_SUCCESS(rv, rv);
1647 :
1648 0 : return NS_OK;
1649 : }
1650 :
1651 :
1652 : NS_IMETHODIMP
1653 1 : nsAnnotationService::AddObserver(nsIAnnotationObserver* aObserver)
1654 : {
1655 1 : NS_ENSURE_ARG(aObserver);
1656 :
1657 1 : if (mObservers.IndexOfObject(aObserver) >= 0)
1658 0 : return NS_ERROR_INVALID_ARG; // Already registered.
1659 1 : if (!mObservers.AppendObject(aObserver))
1660 0 : return NS_ERROR_OUT_OF_MEMORY;
1661 1 : return NS_OK;
1662 : }
1663 :
1664 :
1665 : NS_IMETHODIMP
1666 0 : nsAnnotationService::RemoveObserver(nsIAnnotationObserver* aObserver)
1667 : {
1668 0 : NS_ENSURE_ARG(aObserver);
1669 :
1670 0 : if (!mObservers.RemoveObject(aObserver))
1671 0 : return NS_ERROR_INVALID_ARG;
1672 0 : return NS_OK;
1673 : }
1674 :
1675 : NS_IMETHODIMP
1676 0 : nsAnnotationService::GetObservers(uint32_t* _count,
1677 : nsIAnnotationObserver*** _observers)
1678 : {
1679 0 : NS_ENSURE_ARG_POINTER(_count);
1680 0 : NS_ENSURE_ARG_POINTER(_observers);
1681 :
1682 0 : *_count = 0;
1683 0 : *_observers = nullptr;
1684 :
1685 0 : nsCOMArray<nsIAnnotationObserver> observers(mObservers);
1686 :
1687 0 : if (observers.Count() == 0)
1688 0 : return NS_OK;
1689 :
1690 0 : *_count = observers.Count();
1691 0 : observers.Forget(_observers);
1692 :
1693 0 : return NS_OK;
1694 : }
1695 :
1696 : nsresult
1697 0 : nsAnnotationService::HasAnnotationInternal(nsIURI* aURI,
1698 : int64_t aItemId,
1699 : const nsACString& aName,
1700 : bool* _hasAnno)
1701 : {
1702 0 : bool isItemAnnotation = (aItemId > 0);
1703 0 : nsCOMPtr<mozIStorageStatement> stmt;
1704 0 : if (isItemAnnotation) {
1705 0 : stmt = mDB->GetStatement(
1706 : "SELECT b.id, "
1707 : "(SELECT id FROM moz_anno_attributes WHERE name = :anno_name) AS nameid, "
1708 : "a.id, a.dateAdded "
1709 : "FROM moz_bookmarks b "
1710 : "LEFT JOIN moz_items_annos a ON a.item_id = b.id "
1711 : "AND a.anno_attribute_id = nameid "
1712 : "WHERE b.id = :item_id"
1713 0 : );
1714 : }
1715 : else {
1716 0 : stmt = mDB->GetStatement(
1717 : "SELECT h.id, "
1718 : "(SELECT id FROM moz_anno_attributes WHERE name = :anno_name) AS nameid, "
1719 : "a.id, a.dateAdded "
1720 : "FROM moz_places h "
1721 : "LEFT JOIN moz_annos a ON a.place_id = h.id "
1722 : "AND a.anno_attribute_id = nameid "
1723 : "WHERE h.url_hash = hash(:page_url) AND h.url = :page_url"
1724 0 : );
1725 : }
1726 0 : NS_ENSURE_STATE(stmt);
1727 0 : mozStorageStatementScoper checkAnnoScoper(stmt);
1728 :
1729 0 : nsresult rv = stmt->BindUTF8StringByName(NS_LITERAL_CSTRING("anno_name"), aName);
1730 0 : NS_ENSURE_SUCCESS(rv, rv);
1731 0 : if (isItemAnnotation)
1732 0 : rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("item_id"), aItemId);
1733 : else
1734 0 : rv = URIBinder::Bind(stmt, NS_LITERAL_CSTRING("page_url"), aURI);
1735 0 : NS_ENSURE_SUCCESS(rv, rv);
1736 :
1737 : bool hasResult;
1738 0 : rv = stmt->ExecuteStep(&hasResult);
1739 0 : NS_ENSURE_SUCCESS(rv, rv);
1740 0 : if (!hasResult) {
1741 : // We are trying to get an annotation on an invalid bookmarks or
1742 : // history entry.
1743 : // Here we preserve the old behavior, returning that we don't have the
1744 : // annotation, ignoring the fact itemId is invalid.
1745 : // Otherwise we should return NS_ERROR_INVALID_ARG, but this will somehow
1746 : // break the API. In future we could want to be pickier.
1747 0 : *_hasAnno = false;
1748 : }
1749 : else {
1750 0 : int64_t annotationId = stmt->AsInt64(2);
1751 0 : *_hasAnno = (annotationId > 0);
1752 : }
1753 :
1754 0 : return NS_OK;
1755 : }
1756 :
1757 :
1758 : /**
1759 : * This loads the statement and steps it once so you can get data out of it.
1760 : *
1761 : * @note You have to reset the statement when you're done if this succeeds.
1762 : * @throws NS_ERROR_NOT_AVAILABLE if the annotation is not found.
1763 : */
1764 :
1765 : nsresult
1766 0 : nsAnnotationService::StartGetAnnotation(nsIURI* aURI,
1767 : int64_t aItemId,
1768 : const nsACString& aName,
1769 : nsCOMPtr<mozIStorageStatement>& aStatement)
1770 : {
1771 0 : bool isItemAnnotation = (aItemId > 0);
1772 :
1773 0 : if (isItemAnnotation) {
1774 0 : aStatement = mDB->GetStatement(
1775 : "SELECT a.id, a.item_id, :anno_name, a.content, a.flags, "
1776 : "a.expiration, a.type "
1777 : "FROM moz_anno_attributes n "
1778 : "JOIN moz_items_annos a ON a.anno_attribute_id = n.id "
1779 : "WHERE a.item_id = :item_id "
1780 : "AND n.name = :anno_name"
1781 0 : );
1782 : }
1783 : else {
1784 0 : aStatement = mDB->GetStatement(
1785 : "SELECT a.id, a.place_id, :anno_name, a.content, a.flags, "
1786 : "a.expiration, a.type "
1787 : "FROM moz_anno_attributes n "
1788 : "JOIN moz_annos a ON n.id = a.anno_attribute_id "
1789 : "JOIN moz_places h ON h.id = a.place_id "
1790 : "WHERE h.url_hash = hash(:page_url) AND h.url = :page_url "
1791 : "AND n.name = :anno_name"
1792 0 : );
1793 : }
1794 0 : NS_ENSURE_STATE(aStatement);
1795 0 : mozStorageStatementScoper getAnnoScoper(aStatement);
1796 :
1797 : nsresult rv;
1798 0 : if (isItemAnnotation)
1799 0 : rv = aStatement->BindInt64ByName(NS_LITERAL_CSTRING("item_id"), aItemId);
1800 : else
1801 0 : rv = URIBinder::Bind(aStatement, NS_LITERAL_CSTRING("page_url"), aURI);
1802 0 : NS_ENSURE_SUCCESS(rv, rv);
1803 :
1804 0 : rv = aStatement->BindUTF8StringByName(NS_LITERAL_CSTRING("anno_name"), aName);
1805 0 : NS_ENSURE_SUCCESS(rv, rv);
1806 :
1807 0 : bool hasResult = false;
1808 0 : rv = aStatement->ExecuteStep(&hasResult);
1809 0 : if (NS_FAILED(rv) || !hasResult)
1810 0 : return NS_ERROR_NOT_AVAILABLE;
1811 :
1812 : // on success, DON'T reset the statement, the caller needs to read from it,
1813 : // and it is the caller's job to reset it.
1814 0 : getAnnoScoper.Abandon();
1815 :
1816 0 : return NS_OK;
1817 : }
1818 :
1819 :
1820 : /**
1821 : * This does most of the setup work needed to set an annotation, except for
1822 : * binding the the actual value and executing the statement.
1823 : * It will either update an existing annotation or insert a new one.
1824 : *
1825 : * @note The aStatement RESULT IS NOT ADDREFED. This is just one of the class
1826 : * vars, which control its scope. DO NOT RELEASE.
1827 : * The caller must take care of resetting the statement if this succeeds.
1828 : */
1829 : nsresult
1830 0 : nsAnnotationService::StartSetAnnotation(nsIURI* aURI,
1831 : int64_t aItemId,
1832 : const nsACString& aName,
1833 : int32_t aFlags,
1834 : uint16_t aExpiration,
1835 : uint16_t aType,
1836 : nsCOMPtr<mozIStorageStatement>& aStatement)
1837 : {
1838 0 : bool isItemAnnotation = (aItemId > 0);
1839 :
1840 0 : if (aExpiration == EXPIRE_SESSION) {
1841 0 : mHasSessionAnnotations = true;
1842 : }
1843 :
1844 : // Ensure the annotation name exists.
1845 0 : nsCOMPtr<mozIStorageStatement> addNameStmt = mDB->GetStatement(
1846 : "INSERT OR IGNORE INTO moz_anno_attributes (name) VALUES (:anno_name)"
1847 0 : );
1848 0 : NS_ENSURE_STATE(addNameStmt);
1849 0 : mozStorageStatementScoper scoper(addNameStmt);
1850 :
1851 0 : nsresult rv = addNameStmt->BindUTF8StringByName(NS_LITERAL_CSTRING("anno_name"), aName);
1852 0 : NS_ENSURE_SUCCESS(rv, rv);
1853 0 : rv = addNameStmt->Execute();
1854 0 : NS_ENSURE_SUCCESS(rv, rv);
1855 :
1856 : // We have to check 2 things:
1857 : // - if the annotation already exists we should update it.
1858 : // - we should not allow setting annotations on invalid URIs or itemIds.
1859 : // This query will tell us:
1860 : // - whether the item or page exists.
1861 : // - whether the annotation already exists.
1862 : // - the nameID associated with the annotation name.
1863 : // - the id and dateAdded of the old annotation, if it exists.
1864 0 : nsCOMPtr<mozIStorageStatement> stmt;
1865 0 : if (isItemAnnotation) {
1866 0 : stmt = mDB->GetStatement(
1867 : "SELECT b.id, "
1868 : "(SELECT id FROM moz_anno_attributes WHERE name = :anno_name) AS nameid, "
1869 : "a.id, a.dateAdded "
1870 : "FROM moz_bookmarks b "
1871 : "LEFT JOIN moz_items_annos a ON a.item_id = b.id "
1872 : "AND a.anno_attribute_id = nameid "
1873 : "WHERE b.id = :item_id"
1874 0 : );
1875 : }
1876 : else {
1877 0 : stmt = mDB->GetStatement(
1878 : "SELECT h.id, "
1879 : "(SELECT id FROM moz_anno_attributes WHERE name = :anno_name) AS nameid, "
1880 : "a.id, a.dateAdded "
1881 : "FROM moz_places h "
1882 : "LEFT JOIN moz_annos a ON a.place_id = h.id "
1883 : "AND a.anno_attribute_id = nameid "
1884 : "WHERE h.url_hash = hash(:page_url) AND h.url = :page_url"
1885 0 : );
1886 : }
1887 0 : NS_ENSURE_STATE(stmt);
1888 0 : mozStorageStatementScoper checkAnnoScoper(stmt);
1889 :
1890 0 : rv = stmt->BindUTF8StringByName(NS_LITERAL_CSTRING("anno_name"), aName);
1891 0 : NS_ENSURE_SUCCESS(rv, rv);
1892 0 : if (isItemAnnotation)
1893 0 : rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("item_id"), aItemId);
1894 : else
1895 0 : rv = URIBinder::Bind(stmt, NS_LITERAL_CSTRING("page_url"), aURI);
1896 0 : NS_ENSURE_SUCCESS(rv, rv);
1897 :
1898 : bool hasResult;
1899 0 : rv = stmt->ExecuteStep(&hasResult);
1900 0 : NS_ENSURE_SUCCESS(rv, rv);
1901 0 : if (!hasResult) {
1902 : // We are trying to create an annotation on an invalid bookmark
1903 : // or history entry.
1904 0 : return NS_ERROR_INVALID_ARG;
1905 : }
1906 :
1907 0 : int64_t fkId = stmt->AsInt64(0);
1908 0 : int64_t nameID = stmt->AsInt64(1);
1909 0 : int64_t oldAnnoId = stmt->AsInt64(2);
1910 0 : int64_t oldAnnoDate = stmt->AsInt64(3);
1911 :
1912 0 : if (isItemAnnotation) {
1913 0 : aStatement = mDB->GetStatement(
1914 : "INSERT OR REPLACE INTO moz_items_annos "
1915 : "(id, item_id, anno_attribute_id, content, flags, "
1916 : "expiration, type, dateAdded, lastModified) "
1917 : "VALUES (:id, :fk, :name_id, :content, :flags, "
1918 : ":expiration, :type, :date_added, :last_modified)"
1919 0 : );
1920 : }
1921 : else {
1922 0 : aStatement = mDB->GetStatement(
1923 : "INSERT OR REPLACE INTO moz_annos "
1924 : "(id, place_id, anno_attribute_id, content, flags, "
1925 : "expiration, type, dateAdded, lastModified) "
1926 : "VALUES (:id, :fk, :name_id, :content, :flags, "
1927 : ":expiration, :type, :date_added, :last_modified)"
1928 0 : );
1929 : }
1930 0 : NS_ENSURE_STATE(aStatement);
1931 0 : mozStorageStatementScoper setAnnoScoper(aStatement);
1932 :
1933 : // Don't replace existing annotations.
1934 0 : if (oldAnnoId > 0) {
1935 0 : rv = aStatement->BindInt64ByName(NS_LITERAL_CSTRING("id"), oldAnnoId);
1936 0 : NS_ENSURE_SUCCESS(rv, rv);
1937 0 : rv = aStatement->BindInt64ByName(NS_LITERAL_CSTRING("date_added"), oldAnnoDate);
1938 0 : NS_ENSURE_SUCCESS(rv, rv);
1939 : }
1940 : else {
1941 0 : rv = aStatement->BindNullByName(NS_LITERAL_CSTRING("id"));
1942 0 : NS_ENSURE_SUCCESS(rv, rv);
1943 0 : rv = aStatement->BindInt64ByName(NS_LITERAL_CSTRING("date_added"), RoundedPRNow());
1944 0 : NS_ENSURE_SUCCESS(rv, rv);
1945 : }
1946 :
1947 0 : rv = aStatement->BindInt64ByName(NS_LITERAL_CSTRING("fk"), fkId);
1948 0 : NS_ENSURE_SUCCESS(rv, rv);
1949 0 : rv = aStatement->BindInt64ByName(NS_LITERAL_CSTRING("name_id"), nameID);
1950 0 : NS_ENSURE_SUCCESS(rv, rv);
1951 :
1952 0 : rv = aStatement->BindInt32ByName(NS_LITERAL_CSTRING("flags"), aFlags);
1953 0 : NS_ENSURE_SUCCESS(rv, rv);
1954 0 : rv = aStatement->BindInt32ByName(NS_LITERAL_CSTRING("expiration"), aExpiration);
1955 0 : NS_ENSURE_SUCCESS(rv, rv);
1956 0 : rv = aStatement->BindInt32ByName(NS_LITERAL_CSTRING("type"), aType);
1957 0 : NS_ENSURE_SUCCESS(rv, rv);
1958 0 : rv = aStatement->BindInt64ByName(NS_LITERAL_CSTRING("last_modified"), RoundedPRNow());
1959 0 : NS_ENSURE_SUCCESS(rv, rv);
1960 :
1961 : // On success, leave the statement open, the caller will set the value
1962 : // and execute the statement.
1963 0 : setAnnoScoper.Abandon();
1964 :
1965 0 : return NS_OK;
1966 : }
1967 :
1968 : ////////////////////////////////////////////////////////////////////////////////
1969 : //// nsIObserver
1970 :
1971 : NS_IMETHODIMP
1972 0 : nsAnnotationService::Observe(nsISupports *aSubject,
1973 : const char *aTopic,
1974 : const char16_t *aData)
1975 : {
1976 0 : NS_ASSERTION(NS_IsMainThread(), "This can only be called on the main thread");
1977 :
1978 0 : if (strcmp(aTopic, TOPIC_PLACES_SHUTDOWN) == 0) {
1979 : // Remove all session annotations, if any.
1980 0 : if (mHasSessionAnnotations) {
1981 0 : nsCOMPtr<mozIStorageAsyncStatement> pageAnnoStmt = mDB->GetAsyncStatement(
1982 : "DELETE FROM moz_annos WHERE expiration = :expire_session"
1983 0 : );
1984 0 : NS_ENSURE_STATE(pageAnnoStmt);
1985 0 : nsresult rv = pageAnnoStmt->BindInt32ByName(NS_LITERAL_CSTRING("expire_session"),
1986 0 : EXPIRE_SESSION);
1987 0 : NS_ENSURE_SUCCESS(rv, rv);
1988 :
1989 0 : nsCOMPtr<mozIStorageAsyncStatement> itemAnnoStmt = mDB->GetAsyncStatement(
1990 : "DELETE FROM moz_items_annos WHERE expiration = :expire_session"
1991 0 : );
1992 0 : NS_ENSURE_STATE(itemAnnoStmt);
1993 0 : rv = itemAnnoStmt->BindInt32ByName(NS_LITERAL_CSTRING("expire_session"),
1994 0 : EXPIRE_SESSION);
1995 0 : NS_ENSURE_SUCCESS(rv, rv);
1996 :
1997 : mozIStorageBaseStatement *stmts[] = {
1998 0 : pageAnnoStmt.get()
1999 0 : , itemAnnoStmt.get()
2000 0 : };
2001 :
2002 0 : nsCOMPtr<mozIStorageConnection> conn = mDB->MainConn();
2003 0 : if (!conn) {
2004 0 : return NS_ERROR_UNEXPECTED;
2005 : }
2006 0 : nsCOMPtr<mozIStoragePendingStatement> ps;
2007 0 : rv = conn->ExecuteAsync(stmts, ArrayLength(stmts), nullptr,
2008 0 : getter_AddRefs(ps));
2009 0 : NS_ENSURE_SUCCESS(rv, rv);
2010 : }
2011 : }
2012 :
2013 0 : return NS_OK;
2014 : }
|