Source code

Revision control

Other Tools

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
const int32_t nsAnnotationService::kAnnoIndex_ID = 0;
29
const int32_t nsAnnotationService::kAnnoIndex_PageOrItem = 1;
30
const int32_t nsAnnotationService::kAnnoIndex_NameID = 2;
31
const int32_t nsAnnotationService::kAnnoIndex_Content = 3;
32
const int32_t nsAnnotationService::kAnnoIndex_Flags = 4;
33
const int32_t nsAnnotationService::kAnnoIndex_Expiration = 5;
34
const int32_t nsAnnotationService::kAnnoIndex_Type = 6;
35
const int32_t nsAnnotationService::kAnnoIndex_DateAdded = 7;
36
const int32_t nsAnnotationService::kAnnoIndex_LastModified = 8;
37
38
PLACES_FACTORY_SINGLETON_IMPLEMENTATION(nsAnnotationService, gAnnotationService)
39
40
NS_IMPL_ISUPPORTS(nsAnnotationService, nsIAnnotationService,
41
nsISupportsWeakReference)
42
43
nsAnnotationService::nsAnnotationService() {
44
NS_ASSERTION(!gAnnotationService,
45
"Attempting to create two instances of the service!");
46
gAnnotationService = this;
47
}
48
49
nsAnnotationService::~nsAnnotationService() {
50
NS_ASSERTION(gAnnotationService == this,
51
"Deleting a non-singleton instance of the service");
52
if (gAnnotationService == this) gAnnotationService = nullptr;
53
}
54
55
nsresult nsAnnotationService::Init() {
56
mDB = Database::GetDatabase();
57
NS_ENSURE_STATE(mDB);
58
59
return NS_OK;
60
}
61
62
nsresult nsAnnotationService::SetAnnotationStringInternal(
63
int64_t aItemId, BookmarkData* aBookmark, const nsACString& aName,
64
const nsAString& aValue, int32_t aFlags, uint16_t aExpiration) {
65
mozStorageTransaction transaction(mDB->MainConn(), false);
66
nsCOMPtr<mozIStorageStatement> statement;
67
68
nsresult rv =
69
StartSetAnnotation(aItemId, aBookmark, aName, aFlags, aExpiration,
70
nsIAnnotationService::TYPE_STRING, statement);
71
NS_ENSURE_SUCCESS(rv, rv);
72
73
mozStorageStatementScoper scoper(statement);
74
75
rv = statement->BindStringByName(NS_LITERAL_CSTRING("content"), aValue);
76
NS_ENSURE_SUCCESS(rv, rv);
77
78
rv = statement->Execute();
79
NS_ENSURE_SUCCESS(rv, rv);
80
81
rv = transaction.Commit();
82
NS_ENSURE_SUCCESS(rv, rv);
83
84
return NS_OK;
85
}
86
87
NS_IMETHODIMP
88
nsAnnotationService::SetItemAnnotation(int64_t aItemId, const nsACString& aName,
89
nsIVariant* aValue, int32_t aFlags,
90
uint16_t aExpiration, uint16_t aSource,
91
bool aDontUpdateLastModified) {
92
AUTO_PROFILER_LABEL("nsAnnotationService::SetItemAnnotation", OTHER);
93
94
NS_ENSURE_ARG_MIN(aItemId, 1);
95
NS_ENSURE_ARG(aValue);
96
97
uint16_t dataType = aValue->GetDataType();
98
BookmarkData bookmark;
99
100
switch (dataType) {
101
case nsIDataType::VTYPE_INT8:
102
case nsIDataType::VTYPE_UINT8:
103
case nsIDataType::VTYPE_INT16:
104
case nsIDataType::VTYPE_UINT16:
105
case nsIDataType::VTYPE_INT32:
106
case nsIDataType::VTYPE_UINT32:
107
case nsIDataType::VTYPE_BOOL: {
108
int32_t valueInt;
109
nsresult rv = aValue->GetAsInt32(&valueInt);
110
if (NS_SUCCEEDED(rv)) {
111
NS_ENSURE_SUCCESS(rv, rv);
112
rv = SetAnnotationInt32Internal(aItemId, &bookmark, aName, valueInt,
113
aFlags, aExpiration);
114
NS_ENSURE_SUCCESS(rv, rv);
115
break;
116
}
117
// Fall through int64_t case otherwise.
118
MOZ_FALLTHROUGH;
119
}
120
case nsIDataType::VTYPE_INT64:
121
case nsIDataType::VTYPE_UINT64: {
122
int64_t valueLong;
123
nsresult rv = aValue->GetAsInt64(&valueLong);
124
if (NS_SUCCEEDED(rv)) {
125
NS_ENSURE_SUCCESS(rv, rv);
126
rv = SetAnnotationInt64Internal(aItemId, &bookmark, aName, valueLong,
127
aFlags, aExpiration);
128
NS_ENSURE_SUCCESS(rv, rv);
129
break;
130
}
131
// Fall through double case otherwise.
132
MOZ_FALLTHROUGH;
133
}
134
case nsIDataType::VTYPE_FLOAT:
135
case nsIDataType::VTYPE_DOUBLE: {
136
double valueDouble;
137
nsresult rv = aValue->GetAsDouble(&valueDouble);
138
NS_ENSURE_SUCCESS(rv, rv);
139
rv = SetAnnotationDoubleInternal(aItemId, &bookmark, aName, valueDouble,
140
aFlags, aExpiration);
141
NS_ENSURE_SUCCESS(rv, rv);
142
break;
143
}
144
case nsIDataType::VTYPE_CHAR:
145
case nsIDataType::VTYPE_WCHAR:
146
case nsIDataType::VTYPE_CHAR_STR:
147
case nsIDataType::VTYPE_WCHAR_STR:
148
case nsIDataType::VTYPE_STRING_SIZE_IS:
149
case nsIDataType::VTYPE_WSTRING_SIZE_IS:
150
case nsIDataType::VTYPE_UTF8STRING:
151
case nsIDataType::VTYPE_CSTRING:
152
case nsIDataType::VTYPE_ASTRING: {
153
nsAutoString stringValue;
154
nsresult rv = aValue->GetAsAString(stringValue);
155
NS_ENSURE_SUCCESS(rv, rv);
156
rv = SetAnnotationStringInternal(aItemId, &bookmark, aName, stringValue,
157
aFlags, aExpiration);
158
NS_ENSURE_SUCCESS(rv, rv);
159
break;
160
}
161
default:
162
return NS_ERROR_NOT_IMPLEMENTED;
163
}
164
165
return NS_OK;
166
}
167
168
nsresult nsAnnotationService::SetAnnotationInt32Internal(
169
int64_t aItemId, BookmarkData* aBookmark, const nsACString& aName,
170
int32_t aValue, int32_t aFlags, uint16_t aExpiration) {
171
mozStorageTransaction transaction(mDB->MainConn(), false);
172
nsCOMPtr<mozIStorageStatement> statement;
173
nsresult rv =
174
StartSetAnnotation(aItemId, aBookmark, aName, aFlags, aExpiration,
175
nsIAnnotationService::TYPE_INT32, statement);
176
NS_ENSURE_SUCCESS(rv, rv);
177
178
mozStorageStatementScoper scoper(statement);
179
180
rv = statement->BindInt32ByName(NS_LITERAL_CSTRING("content"), aValue);
181
NS_ENSURE_SUCCESS(rv, rv);
182
183
rv = statement->Execute();
184
NS_ENSURE_SUCCESS(rv, rv);
185
186
rv = transaction.Commit();
187
NS_ENSURE_SUCCESS(rv, rv);
188
189
return NS_OK;
190
}
191
192
nsresult nsAnnotationService::SetAnnotationInt64Internal(
193
int64_t aItemId, BookmarkData* aBookmark, const nsACString& aName,
194
int64_t aValue, int32_t aFlags, uint16_t aExpiration) {
195
mozStorageTransaction transaction(mDB->MainConn(), false);
196
nsCOMPtr<mozIStorageStatement> statement;
197
nsresult rv =
198
StartSetAnnotation(aItemId, aBookmark, aName, aFlags, aExpiration,
199
nsIAnnotationService::TYPE_INT64, statement);
200
NS_ENSURE_SUCCESS(rv, rv);
201
202
mozStorageStatementScoper scoper(statement);
203
204
rv = statement->BindInt64ByName(NS_LITERAL_CSTRING("content"), aValue);
205
NS_ENSURE_SUCCESS(rv, rv);
206
207
rv = statement->Execute();
208
NS_ENSURE_SUCCESS(rv, rv);
209
210
rv = transaction.Commit();
211
NS_ENSURE_SUCCESS(rv, rv);
212
213
return NS_OK;
214
}
215
216
nsresult nsAnnotationService::SetAnnotationDoubleInternal(
217
int64_t aItemId, BookmarkData* aBookmark, const nsACString& aName,
218
double aValue, int32_t aFlags, uint16_t aExpiration) {
219
mozStorageTransaction transaction(mDB->MainConn(), false);
220
nsCOMPtr<mozIStorageStatement> statement;
221
nsresult rv =
222
StartSetAnnotation(aItemId, aBookmark, aName, aFlags, aExpiration,
223
nsIAnnotationService::TYPE_DOUBLE, statement);
224
NS_ENSURE_SUCCESS(rv, rv);
225
226
mozStorageStatementScoper scoper(statement);
227
228
rv = statement->BindDoubleByName(NS_LITERAL_CSTRING("content"), aValue);
229
NS_ENSURE_SUCCESS(rv, rv);
230
231
rv = statement->Execute();
232
NS_ENSURE_SUCCESS(rv, rv);
233
234
rv = transaction.Commit();
235
NS_ENSURE_SUCCESS(rv, rv);
236
237
return NS_OK;
238
}
239
240
nsresult nsAnnotationService::GetValueFromStatement(
241
nsCOMPtr<mozIStorageStatement>& aStatement, nsIVariant** _retval) {
242
nsresult rv;
243
244
nsCOMPtr<nsIWritableVariant> value = new nsVariant();
245
int32_t type = aStatement->AsInt32(kAnnoIndex_Type);
246
switch (type) {
247
case nsIAnnotationService::TYPE_INT32:
248
case nsIAnnotationService::TYPE_INT64:
249
case nsIAnnotationService::TYPE_DOUBLE: {
250
rv = value->SetAsDouble(aStatement->AsDouble(kAnnoIndex_Content));
251
break;
252
}
253
case nsIAnnotationService::TYPE_STRING: {
254
nsAutoString valueString;
255
rv = aStatement->GetString(kAnnoIndex_Content, valueString);
256
if (NS_SUCCEEDED(rv)) rv = value->SetAsAString(valueString);
257
break;
258
}
259
default: {
260
rv = NS_ERROR_UNEXPECTED;
261
break;
262
}
263
}
264
if (NS_SUCCEEDED(rv)) {
265
value.forget(_retval);
266
}
267
return rv;
268
}
269
270
NS_IMETHODIMP
271
nsAnnotationService::GetItemAnnotation(int64_t aItemId, const nsACString& aName,
272
nsIVariant** _retval) {
273
NS_ENSURE_ARG_MIN(aItemId, 1);
274
NS_ENSURE_ARG_POINTER(_retval);
275
276
nsCOMPtr<mozIStorageStatement> statement;
277
nsresult rv = StartGetAnnotation(aItemId, aName, statement);
278
if (NS_FAILED(rv)) return rv;
279
280
mozStorageStatementScoper scoper(statement);
281
282
return GetValueFromStatement(statement, _retval);
283
}
284
285
/**
286
* @note We don't remove anything from the moz_anno_attributes table. If we
287
* delete the last item of a given name, that item really should go away.
288
* It will be cleaned up by expiration.
289
*/
290
nsresult nsAnnotationService::RemoveAnnotationInternal(
291
int64_t aItemId, BookmarkData* aBookmark, const nsACString& aName) {
292
nsCOMPtr<mozIStorageStatement> statement;
293
statement = mDB->GetStatement(
294
"DELETE FROM moz_items_annos "
295
"WHERE item_id = :item_id "
296
"AND anno_attribute_id = "
297
"(SELECT id FROM moz_anno_attributes WHERE name = :anno_name)");
298
NS_ENSURE_STATE(statement);
299
mozStorageStatementScoper scoper(statement);
300
301
nsresult rv;
302
rv = statement->BindInt64ByName(NS_LITERAL_CSTRING("item_id"), aItemId);
303
NS_ENSURE_SUCCESS(rv, rv);
304
305
rv = statement->BindUTF8StringByName(NS_LITERAL_CSTRING("anno_name"), aName);
306
NS_ENSURE_SUCCESS(rv, rv);
307
308
rv = statement->Execute();
309
NS_ENSURE_SUCCESS(rv, rv);
310
311
nsNavBookmarks* bookmarks = nsNavBookmarks::GetBookmarksService();
312
if (bookmarks) {
313
MOZ_ASSERT(aBookmark);
314
if (NS_FAILED(bookmarks->FetchItemInfo(aItemId, *aBookmark))) {
315
aBookmark->id = -1;
316
}
317
}
318
319
return NS_OK;
320
}
321
322
NS_IMETHODIMP
323
nsAnnotationService::RemoveItemAnnotation(int64_t aItemId,
324
const nsACString& aName,
325
uint16_t aSource) {
326
NS_ENSURE_ARG_MIN(aItemId, 1);
327
328
BookmarkData bookmark;
329
nsresult rv = RemoveAnnotationInternal(aItemId, &bookmark, aName);
330
NS_ENSURE_SUCCESS(rv, rv);
331
332
return NS_OK;
333
}
334
335
nsresult nsAnnotationService::RemoveItemAnnotations(int64_t aItemId) {
336
NS_ENSURE_ARG_MIN(aItemId, 1);
337
338
// Should this be precompiled or a getter?
339
nsCOMPtr<mozIStorageStatement> statement =
340
mDB->GetStatement("DELETE FROM moz_items_annos WHERE item_id = :item_id");
341
NS_ENSURE_STATE(statement);
342
mozStorageStatementScoper scoper(statement);
343
344
nsresult rv =
345
statement->BindInt64ByName(NS_LITERAL_CSTRING("item_id"), aItemId);
346
NS_ENSURE_SUCCESS(rv, rv);
347
348
rv = statement->Execute();
349
NS_ENSURE_SUCCESS(rv, rv);
350
351
return NS_OK;
352
}
353
354
NS_IMETHODIMP
355
nsAnnotationService::ItemHasAnnotation(int64_t aItemId, const nsACString& aName,
356
bool* _hasAnno) {
357
NS_ENSURE_ARG_MIN(aItemId, 1);
358
NS_ENSURE_ARG_POINTER(_hasAnno);
359
360
nsCOMPtr<mozIStorageStatement> stmt = mDB->GetStatement(
361
"SELECT b.id, "
362
"(SELECT id FROM moz_anno_attributes WHERE name = :anno_name) AS nameid, "
363
"a.id, a.dateAdded "
364
"FROM moz_bookmarks b "
365
"LEFT JOIN moz_items_annos a ON a.item_id = b.id "
366
"AND a.anno_attribute_id = nameid "
367
"WHERE b.id = :item_id");
368
NS_ENSURE_STATE(stmt);
369
mozStorageStatementScoper checkAnnoScoper(stmt);
370
371
nsresult rv =
372
stmt->BindUTF8StringByName(NS_LITERAL_CSTRING("anno_name"), aName);
373
NS_ENSURE_SUCCESS(rv, rv);
374
rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("item_id"), aItemId);
375
NS_ENSURE_SUCCESS(rv, rv);
376
377
bool hasResult;
378
rv = stmt->ExecuteStep(&hasResult);
379
NS_ENSURE_SUCCESS(rv, rv);
380
if (!hasResult) {
381
// We are trying to get an annotation on an invalid bookmarks or
382
// history entry.
383
// Here we preserve the old behavior, returning that we don't have the
384
// annotation, ignoring the fact itemId is invalid.
385
// Otherwise we should return NS_ERROR_INVALID_ARG, but this will somehow
386
// break the API. In future we could want to be pickier.
387
*_hasAnno = false;
388
} else {
389
int64_t annotationId = stmt->AsInt64(2);
390
*_hasAnno = (annotationId > 0);
391
}
392
393
return NS_OK;
394
}
395
396
/**
397
* This loads the statement and steps it once so you can get data out of it.
398
*
399
* @note You have to reset the statement when you're done if this succeeds.
400
* @throws NS_ERROR_NOT_AVAILABLE if the annotation is not found.
401
*/
402
403
nsresult nsAnnotationService::StartGetAnnotation(
404
int64_t aItemId, const nsACString& aName,
405
nsCOMPtr<mozIStorageStatement>& aStatement) {
406
aStatement = mDB->GetStatement(
407
"SELECT a.id, a.item_id, :anno_name, a.content, a.flags, "
408
"a.expiration, a.type "
409
"FROM moz_anno_attributes n "
410
"JOIN moz_items_annos a ON a.anno_attribute_id = n.id "
411
"WHERE a.item_id = :item_id "
412
"AND n.name = :anno_name");
413
NS_ENSURE_STATE(aStatement);
414
mozStorageStatementScoper getAnnoScoper(aStatement);
415
416
nsresult rv;
417
rv = aStatement->BindInt64ByName(NS_LITERAL_CSTRING("item_id"), aItemId);
418
NS_ENSURE_SUCCESS(rv, rv);
419
420
rv = aStatement->BindUTF8StringByName(NS_LITERAL_CSTRING("anno_name"), aName);
421
NS_ENSURE_SUCCESS(rv, rv);
422
423
bool hasResult = false;
424
rv = aStatement->ExecuteStep(&hasResult);
425
if (NS_FAILED(rv) || !hasResult) return NS_ERROR_NOT_AVAILABLE;
426
427
// on success, DON'T reset the statement, the caller needs to read from it,
428
// and it is the caller's job to reset it.
429
getAnnoScoper.Abandon();
430
431
return NS_OK;
432
}
433
434
/**
435
* This does most of the setup work needed to set an annotation, except for
436
* binding the the actual value and executing the statement.
437
* It will either update an existing annotation or insert a new one.
438
*
439
* @note The aStatement RESULT IS NOT ADDREFED. This is just one of the class
440
* vars, which control its scope. DO NOT RELEASE.
441
* The caller must take care of resetting the statement if this succeeds.
442
*/
443
nsresult nsAnnotationService::StartSetAnnotation(
444
int64_t aItemId, BookmarkData* aBookmark, const nsACString& aName,
445
int32_t aFlags, uint16_t aExpiration, uint16_t aType,
446
nsCOMPtr<mozIStorageStatement>& aStatement) {
447
MOZ_ASSERT(aExpiration == EXPIRE_NEVER, "Only EXPIRE_NEVER is supported");
448
NS_ENSURE_ARG(aExpiration == EXPIRE_NEVER);
449
450
// Ensure the annotation name exists.
451
nsCOMPtr<mozIStorageStatement> addNameStmt = mDB->GetStatement(
452
"INSERT OR IGNORE INTO moz_anno_attributes (name) VALUES (:anno_name)");
453
NS_ENSURE_STATE(addNameStmt);
454
mozStorageStatementScoper scoper(addNameStmt);
455
456
nsresult rv =
457
addNameStmt->BindUTF8StringByName(NS_LITERAL_CSTRING("anno_name"), aName);
458
NS_ENSURE_SUCCESS(rv, rv);
459
rv = addNameStmt->Execute();
460
NS_ENSURE_SUCCESS(rv, rv);
461
462
// We have to check 2 things:
463
// - if the annotation already exists we should update it.
464
// - we should not allow setting annotations on invalid URIs or itemIds.
465
// This query will tell us:
466
// - whether the item or page exists.
467
// - whether the annotation already exists.
468
// - the nameID associated with the annotation name.
469
// - the id and dateAdded of the old annotation, if it exists.
470
nsCOMPtr<mozIStorageStatement> stmt = mDB->GetStatement(
471
"SELECT b.id, "
472
"(SELECT id FROM moz_anno_attributes WHERE name = :anno_name) AS nameid, "
473
"a.id, a.dateAdded, b.parent, b.type, b.lastModified, b.guid, p.guid "
474
"FROM moz_bookmarks b "
475
"JOIN moz_bookmarks p ON p.id = b.parent "
476
"LEFT JOIN moz_items_annos a ON a.item_id = b.id "
477
"AND a.anno_attribute_id = nameid "
478
"WHERE b.id = :item_id");
479
NS_ENSURE_STATE(stmt);
480
mozStorageStatementScoper checkAnnoScoper(stmt);
481
482
rv = stmt->BindUTF8StringByName(NS_LITERAL_CSTRING("anno_name"), aName);
483
NS_ENSURE_SUCCESS(rv, rv);
484
rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("item_id"), aItemId);
485
NS_ENSURE_SUCCESS(rv, rv);
486
487
bool hasResult;
488
rv = stmt->ExecuteStep(&hasResult);
489
NS_ENSURE_SUCCESS(rv, rv);
490
if (!hasResult) {
491
// We are trying to create an annotation on an invalid bookmark
492
// or history entry.
493
return NS_ERROR_INVALID_ARG;
494
}
495
496
int64_t fkId = stmt->AsInt64(0);
497
int64_t nameID = stmt->AsInt64(1);
498
int64_t oldAnnoId = stmt->AsInt64(2);
499
int64_t oldAnnoDate = stmt->AsInt64(3);
500
501
aStatement = mDB->GetStatement(
502
"INSERT OR REPLACE INTO moz_items_annos "
503
"(id, item_id, anno_attribute_id, content, flags, "
504
"expiration, type, dateAdded, lastModified) "
505
"VALUES (:id, :fk, :name_id, :content, :flags, "
506
":expiration, :type, :date_added, :last_modified)");
507
508
// Since we're already querying `moz_bookmarks`, we fetch the changed
509
// bookmark's info here, instead of using `FetchItemInfo`.
510
MOZ_ASSERT(aBookmark);
511
aBookmark->id = fkId;
512
aBookmark->parentId = stmt->AsInt64(4);
513
aBookmark->type = stmt->AsInt64(5);
514
515
aBookmark->lastModified = static_cast<PRTime>(stmt->AsInt64(6));
516
if (NS_FAILED(stmt->GetUTF8String(7, aBookmark->guid)) ||
517
NS_FAILED(stmt->GetUTF8String(8, aBookmark->parentGuid))) {
518
aBookmark->id = -1;
519
}
520
NS_ENSURE_STATE(aStatement);
521
mozStorageStatementScoper setAnnoScoper(aStatement);
522
523
// Don't replace existing annotations.
524
if (oldAnnoId > 0) {
525
rv = aStatement->BindInt64ByName(NS_LITERAL_CSTRING("id"), oldAnnoId);
526
NS_ENSURE_SUCCESS(rv, rv);
527
rv = aStatement->BindInt64ByName(NS_LITERAL_CSTRING("date_added"),
528
oldAnnoDate);
529
NS_ENSURE_SUCCESS(rv, rv);
530
} else {
531
rv = aStatement->BindNullByName(NS_LITERAL_CSTRING("id"));
532
NS_ENSURE_SUCCESS(rv, rv);
533
rv = aStatement->BindInt64ByName(NS_LITERAL_CSTRING("date_added"),
534
RoundedPRNow());
535
NS_ENSURE_SUCCESS(rv, rv);
536
}
537
538
rv = aStatement->BindInt64ByName(NS_LITERAL_CSTRING("fk"), fkId);
539
NS_ENSURE_SUCCESS(rv, rv);
540
rv = aStatement->BindInt64ByName(NS_LITERAL_CSTRING("name_id"), nameID);
541
NS_ENSURE_SUCCESS(rv, rv);
542
543
rv = aStatement->BindInt32ByName(NS_LITERAL_CSTRING("flags"), aFlags);
544
NS_ENSURE_SUCCESS(rv, rv);
545
rv = aStatement->BindInt32ByName(NS_LITERAL_CSTRING("expiration"),
546
aExpiration);
547
NS_ENSURE_SUCCESS(rv, rv);
548
rv = aStatement->BindInt32ByName(NS_LITERAL_CSTRING("type"), aType);
549
NS_ENSURE_SUCCESS(rv, rv);
550
rv = aStatement->BindInt64ByName(NS_LITERAL_CSTRING("last_modified"),
551
RoundedPRNow());
552
NS_ENSURE_SUCCESS(rv, rv);
553
554
// On success, leave the statement open, the caller will set the value
555
// and execute the statement.
556
setAnnoScoper.Abandon();
557
558
return NS_OK;
559
}