Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/toolkit/components/places/Database.h
Line
Count
Source (jump to first uncovered line)
1
/* This Source Code Form is subject to the terms of the Mozilla Public
2
 * License, v. 2.0. If a copy of the MPL was not distributed with this
3
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4
5
#ifndef mozilla_places_Database_h_
6
#define mozilla_places_Database_h_
7
8
#include "MainThreadUtils.h"
9
#include "nsWeakReference.h"
10
#include "nsIInterfaceRequestorUtils.h"
11
#include "nsIObserver.h"
12
#include "nsIAsyncShutdown.h"
13
#include "mozilla/storage.h"
14
#include "mozilla/storage/StatementCache.h"
15
#include "mozilla/Attributes.h"
16
#include "nsIEventTarget.h"
17
#include "Shutdown.h"
18
#include "nsCategoryCache.h"
19
20
// This is the schema version. Update it at any schema change and add a
21
// corresponding migrateVxx method below.
22
0
#define DATABASE_SCHEMA_VERSION 52
23
24
// Fired after Places inited.
25
0
#define TOPIC_PLACES_INIT_COMPLETE "places-init-complete"
26
// This topic is received when the profile is about to be lost.  Places does
27
// initial shutdown work and notifies TOPIC_PLACES_SHUTDOWN to all listeners.
28
// Any shutdown work that requires the Places APIs should happen here.
29
0
#define TOPIC_PROFILE_CHANGE_TEARDOWN "profile-change-teardown"
30
// Fired when Places is shutting down.  Any code should stop accessing Places
31
// APIs after this notification.  If you need to listen for Places shutdown
32
// you should only use this notification, next ones are intended only for
33
// internal Places use.
34
0
#define TOPIC_PLACES_SHUTDOWN "places-shutdown"
35
// Fired when the connection has gone, nothing will work from now on.
36
0
#define TOPIC_PLACES_CONNECTION_CLOSED "places-connection-closed"
37
38
// Simulate profile-before-change. This topic may only be used by
39
// calling `observe` directly on the database. Used for testing only.
40
0
#define TOPIC_SIMULATE_PLACES_SHUTDOWN "test-simulate-places-shutdown"
41
42
class nsIRunnable;
43
44
namespace mozilla {
45
namespace places {
46
47
enum JournalMode {
48
  // Default SQLite journal mode.
49
  JOURNAL_DELETE = 0
50
  // Can reduce fsyncs on Linux when journal is deleted (See bug 460315).
51
  // We fallback to this mode when WAL is unavailable.
52
, JOURNAL_TRUNCATE
53
  // Unsafe in case of crashes on database swap or low memory.
54
, JOURNAL_MEMORY
55
  // Can reduce number of fsyncs.  We try to use this mode by default.
56
, JOURNAL_WAL
57
};
58
59
class ClientsShutdownBlocker;
60
class ConnectionShutdownBlocker;
61
62
class Database final : public nsIObserver
63
                     , public nsSupportsWeakReference
64
{
65
  typedef mozilla::storage::StatementCache<mozIStorageStatement> StatementCache;
66
  typedef mozilla::storage::StatementCache<mozIStorageAsyncStatement> AsyncStatementCache;
67
68
public:
69
  NS_DECL_THREADSAFE_ISUPPORTS
70
  NS_DECL_NSIOBSERVER
71
72
  Database();
73
74
  /**
75
   * Initializes the database connection and the schema.
76
   * In case of corruption the database is copied to a backup file and replaced.
77
   */
78
  nsresult Init();
79
80
  /**
81
   * The AsyncShutdown client used by clients of this API to be informed of shutdown.
82
   */
83
  already_AddRefed<nsIAsyncShutdownClient> GetClientsShutdown();
84
85
  /**
86
   * The AsyncShutdown client used by clients of this API to be informed of connection shutdown.
87
   */
88
  already_AddRefed<nsIAsyncShutdownClient> GetConnectionShutdown();
89
90
  /**
91
   * Getter to use when instantiating the class.
92
   *
93
   * @return Singleton instance of this class.
94
   */
95
  static already_AddRefed<Database> GetDatabase();
96
97
  /**
98
   * Actually initialized the connection on first need.
99
   */
100
  nsresult EnsureConnection();
101
102
  /**
103
   * Notifies that the connection has been initialized.
104
   */
105
  nsresult NotifyConnectionInitalized();
106
107
  /**
108
   * Returns last known database status.
109
   *
110
   * @return one of the nsINavHistoryService::DATABASE_STATUS_* constants.
111
   */
112
  uint16_t GetDatabaseStatus()
113
0
  {
114
0
    mozilla::Unused << EnsureConnection();
115
0
    return mDatabaseStatus;
116
0
  }
117
118
  /**
119
   * Returns a pointer to the storage connection.
120
   *
121
   * @return The connection handle.
122
   */
123
  mozIStorageConnection* MainConn()
124
0
  {
125
0
    mozilla::Unused << EnsureConnection();
126
0
    return mMainConn;
127
0
  }
128
129
  /**
130
   * Dispatches a runnable to the connection async thread, to be serialized
131
   * with async statements.
132
   *
133
   * @param aEvent
134
   *        The runnable to be dispatched.
135
   */
136
  void DispatchToAsyncThread(nsIRunnable* aEvent)
137
0
  {
138
0
    if (mClosed || NS_FAILED(EnsureConnection())) {
139
0
      return;
140
0
    }
141
0
    nsCOMPtr<nsIEventTarget> target = do_GetInterface(mMainConn);
142
0
    if (target) {
143
0
      (void)target->Dispatch(aEvent, NS_DISPATCH_NORMAL);
144
0
    }
145
0
  }
146
147
  //////////////////////////////////////////////////////////////////////////////
148
  //// Statements Getters.
149
150
  /**
151
   * Gets a cached synchronous statement.
152
   *
153
   * @param aQuery
154
   *        SQL query literal.
155
   * @return The cached statement.
156
   * @note Always null check the result.
157
   * @note Always use a scoper to reset the statement.
158
   */
159
  template<int N>
160
  already_AddRefed<mozIStorageStatement>
161
  GetStatement(const char (&aQuery)[N])
162
0
  {
163
0
    nsDependentCString query(aQuery, N - 1);
164
0
    return GetStatement(query);
165
0
  }
Unexecuted instantiation: already_AddRefed<mozIStorageStatement> mozilla::places::Database::GetStatement<96>(char const (&) [96])
Unexecuted instantiation: already_AddRefed<mozIStorageStatement> mozilla::places::Database::GetStatement<153>(char const (&) [153])
Unexecuted instantiation: already_AddRefed<mozIStorageStatement> mozilla::places::Database::GetStatement<101>(char const (&) [101])
Unexecuted instantiation: already_AddRefed<mozIStorageStatement> mozilla::places::Database::GetStatement<503>(char const (&) [503])
Unexecuted instantiation: already_AddRefed<mozIStorageStatement> mozilla::places::Database::GetStatement<146>(char const (&) [146])
Unexecuted instantiation: already_AddRefed<mozIStorageStatement> mozilla::places::Database::GetStatement<93>(char const (&) [93])
Unexecuted instantiation: already_AddRefed<mozIStorageStatement> mozilla::places::Database::GetStatement<71>(char const (&) [71])
Unexecuted instantiation: already_AddRefed<mozIStorageStatement> mozilla::places::Database::GetStatement<63>(char const (&) [63])
Unexecuted instantiation: already_AddRefed<mozIStorageStatement> mozilla::places::Database::GetStatement<82>(char const (&) [82])
Unexecuted instantiation: already_AddRefed<mozIStorageStatement> mozilla::places::Database::GetStatement<64>(char const (&) [64])
Unexecuted instantiation: already_AddRefed<mozIStorageStatement> mozilla::places::Database::GetStatement<58>(char const (&) [58])
Unexecuted instantiation: already_AddRefed<mozIStorageStatement> mozilla::places::Database::GetStatement<208>(char const (&) [208])
Unexecuted instantiation: already_AddRefed<mozIStorageStatement> mozilla::places::Database::GetStatement<262>(char const (&) [262])
Unexecuted instantiation: already_AddRefed<mozIStorageStatement> mozilla::places::Database::GetStatement<103>(char const (&) [103])
Unexecuted instantiation: already_AddRefed<mozIStorageStatement> mozilla::places::Database::GetStatement<178>(char const (&) [178])
Unexecuted instantiation: already_AddRefed<mozIStorageStatement> mozilla::places::Database::GetStatement<209>(char const (&) [209])
Unexecuted instantiation: already_AddRefed<mozIStorageStatement> mozilla::places::Database::GetStatement<168>(char const (&) [168])
Unexecuted instantiation: already_AddRefed<mozIStorageStatement> mozilla::places::Database::GetStatement<90>(char const (&) [90])
Unexecuted instantiation: already_AddRefed<mozIStorageStatement> mozilla::places::Database::GetStatement<106>(char const (&) [106])
Unexecuted instantiation: already_AddRefed<mozIStorageStatement> mozilla::places::Database::GetStatement<260>(char const (&) [260])
Unexecuted instantiation: already_AddRefed<mozIStorageStatement> mozilla::places::Database::GetStatement<225>(char const (&) [225])
Unexecuted instantiation: already_AddRefed<mozIStorageStatement> mozilla::places::Database::GetStatement<110>(char const (&) [110])
Unexecuted instantiation: already_AddRefed<mozIStorageStatement> mozilla::places::Database::GetStatement<121>(char const (&) [121])
Unexecuted instantiation: already_AddRefed<mozIStorageStatement> mozilla::places::Database::GetStatement<138>(char const (&) [138])
Unexecuted instantiation: already_AddRefed<mozIStorageStatement> mozilla::places::Database::GetStatement<53>(char const (&) [53])
Unexecuted instantiation: already_AddRefed<mozIStorageStatement> mozilla::places::Database::GetStatement<227>(char const (&) [227])
Unexecuted instantiation: already_AddRefed<mozIStorageStatement> mozilla::places::Database::GetStatement<69>(char const (&) [69])
Unexecuted instantiation: already_AddRefed<mozIStorageStatement> mozilla::places::Database::GetStatement<317>(char const (&) [317])
Unexecuted instantiation: already_AddRefed<mozIStorageStatement> mozilla::places::Database::GetStatement<226>(char const (&) [226])
Unexecuted instantiation: already_AddRefed<mozIStorageStatement> mozilla::places::Database::GetStatement<124>(char const (&) [124])
Unexecuted instantiation: already_AddRefed<mozIStorageStatement> mozilla::places::Database::GetStatement<147>(char const (&) [147])
Unexecuted instantiation: already_AddRefed<mozIStorageStatement> mozilla::places::Database::GetStatement<275>(char const (&) [275])
Unexecuted instantiation: already_AddRefed<mozIStorageStatement> mozilla::places::Database::GetStatement<46>(char const (&) [46])
Unexecuted instantiation: already_AddRefed<mozIStorageStatement> mozilla::places::Database::GetStatement<335>(char const (&) [335])
Unexecuted instantiation: already_AddRefed<mozIStorageStatement> mozilla::places::Database::GetStatement<259>(char const (&) [259])
Unexecuted instantiation: already_AddRefed<mozIStorageStatement> mozilla::places::Database::GetStatement<255>(char const (&) [255])
Unexecuted instantiation: already_AddRefed<mozIStorageStatement> mozilla::places::Database::GetStatement<114>(char const (&) [114])
Unexecuted instantiation: already_AddRefed<mozIStorageStatement> mozilla::places::Database::GetStatement<171>(char const (&) [171])
Unexecuted instantiation: already_AddRefed<mozIStorageStatement> mozilla::places::Database::GetStatement<154>(char const (&) [154])
Unexecuted instantiation: already_AddRefed<mozIStorageStatement> mozilla::places::Database::GetStatement<84>(char const (&) [84])
Unexecuted instantiation: already_AddRefed<mozIStorageStatement> mozilla::places::Database::GetStatement<135>(char const (&) [135])
Unexecuted instantiation: already_AddRefed<mozIStorageStatement> mozilla::places::Database::GetStatement<445>(char const (&) [445])
Unexecuted instantiation: already_AddRefed<mozIStorageStatement> mozilla::places::Database::GetStatement<166>(char const (&) [166])
Unexecuted instantiation: already_AddRefed<mozIStorageStatement> mozilla::places::Database::GetStatement<306>(char const (&) [306])
Unexecuted instantiation: already_AddRefed<mozIStorageStatement> mozilla::places::Database::GetStatement<41>(char const (&) [41])
Unexecuted instantiation: already_AddRefed<mozIStorageStatement> mozilla::places::Database::GetStatement<148>(char const (&) [148])
Unexecuted instantiation: already_AddRefed<mozIStorageStatement> mozilla::places::Database::GetStatement<205>(char const (&) [205])
Unexecuted instantiation: already_AddRefed<mozIStorageStatement> mozilla::places::Database::GetStatement<326>(char const (&) [326])
166
167
  /**
168
   * Gets a cached synchronous statement.
169
   *
170
   * @param aQuery
171
   *        nsCString of SQL query.
172
   * @return The cached statement.
173
   * @note Always null check the result.
174
   * @note Always use a scoper to reset the statement.
175
   */
176
  already_AddRefed<mozIStorageStatement>  GetStatement(const nsACString& aQuery);
177
178
  /**
179
   * Gets a cached asynchronous statement.
180
   *
181
   * @param aQuery
182
   *        SQL query literal.
183
   * @return The cached statement.
184
   * @note Always null check the result.
185
   * @note AsyncStatements are automatically reset on execution.
186
   */
187
  template<int N>
188
  already_AddRefed<mozIStorageAsyncStatement>
189
  GetAsyncStatement(const char (&aQuery)[N])
190
0
  {
191
0
    nsDependentCString query(aQuery, N - 1);
192
0
    return GetAsyncStatement(query);
193
0
  }
Unexecuted instantiation: already_AddRefed<mozIStorageAsyncStatement> mozilla::places::Database::GetAsyncStatement<30>(char const (&) [30])
Unexecuted instantiation: already_AddRefed<mozIStorageAsyncStatement> mozilla::places::Database::GetAsyncStatement<22>(char const (&) [22])
Unexecuted instantiation: already_AddRefed<mozIStorageAsyncStatement> mozilla::places::Database::GetAsyncStatement<31>(char const (&) [31])
Unexecuted instantiation: already_AddRefed<mozIStorageAsyncStatement> mozilla::places::Database::GetAsyncStatement<176>(char const (&) [176])
Unexecuted instantiation: already_AddRefed<mozIStorageAsyncStatement> mozilla::places::Database::GetAsyncStatement<445>(char const (&) [445])
Unexecuted instantiation: already_AddRefed<mozIStorageAsyncStatement> mozilla::places::Database::GetAsyncStatement<292>(char const (&) [292])
Unexecuted instantiation: already_AddRefed<mozIStorageAsyncStatement> mozilla::places::Database::GetAsyncStatement<135>(char const (&) [135])
Unexecuted instantiation: already_AddRefed<mozIStorageAsyncStatement> mozilla::places::Database::GetAsyncStatement<71>(char const (&) [71])
Unexecuted instantiation: already_AddRefed<mozIStorageAsyncStatement> mozilla::places::Database::GetAsyncStatement<41>(char const (&) [41])
Unexecuted instantiation: already_AddRefed<mozIStorageAsyncStatement> mozilla::places::Database::GetAsyncStatement<263>(char const (&) [263])
194
195
  /**
196
   * Gets a cached asynchronous statement.
197
   *
198
   * @param aQuery
199
   *        nsCString of SQL query.
200
   * @return The cached statement.
201
   * @note Always null check the result.
202
   * @note AsyncStatements are automatically reset on execution.
203
   */
204
  already_AddRefed<mozIStorageAsyncStatement> GetAsyncStatement(const nsACString& aQuery);
205
206
  uint32_t MaxUrlLength();
207
208
0
  int64_t GetRootFolderId() {
209
0
    mozilla::Unused << EnsureConnection();
210
0
    return mRootId;
211
0
  }
212
0
  int64_t GetMenuFolderId() {
213
0
    mozilla::Unused << EnsureConnection();
214
0
    return mMenuRootId;
215
0
  }
216
0
  int64_t GetTagsFolderId() {
217
0
    mozilla::Unused << EnsureConnection();
218
0
    return mTagsRootId;
219
0
  }
220
0
  int64_t GetUnfiledFolderId() {
221
0
    mozilla::Unused << EnsureConnection();
222
0
    return mUnfiledRootId;
223
0
  }
224
0
  int64_t GetToolbarFolderId() {
225
0
    mozilla::Unused << EnsureConnection();
226
0
    return mToolbarRootId;
227
0
  }
228
0
  int64_t GetMobileFolderId() {
229
0
    mozilla::Unused << EnsureConnection();
230
0
    return mMobileRootId;
231
0
  }
232
233
protected:
234
  /**
235
   * Finalizes the cached statements and closes the database connection.
236
   * A TOPIC_PLACES_CONNECTION_CLOSED notification is fired when done.
237
   */
238
  void Shutdown();
239
240
  bool IsShutdownStarted() const;
241
242
  /**
243
   * Ensure the favicons database file exists.
244
   *
245
   * @param aStorage
246
   *        mozStorage service instance.
247
   */
248
  nsresult EnsureFaviconsDatabaseAttached(const nsCOMPtr<mozIStorageService>& aStorage);
249
250
  /**
251
   * Creates a database backup and replaces the original file with a new
252
   * one.
253
   *
254
   * @param aStorage
255
   *        mozStorage service instance.
256
   * @param aDbfilename
257
   *        the database file name to replace.
258
   * @param aTryToClone
259
   *        whether we should try to clone a corrupt database.
260
   * @param aReopenConnection
261
   *        whether we should open a new connection to the replaced database.
262
   */
263
  nsresult BackupAndReplaceDatabaseFile(nsCOMPtr<mozIStorageService>& aStorage,
264
                                        const nsString& aDbFilename,
265
                                        bool aTryToClone,
266
                                        bool aReopenConnection);
267
268
  /**
269
   * Tries to recover tables and their contents from a corrupt database.
270
   *
271
   * @param aStorage
272
   *        mozStorage service instance.
273
   * @param aDatabaseFile
274
   *        nsIFile pointing to the places.sqlite file considered corrupt.
275
   */
276
  nsresult TryToCloneTablesFromCorruptDatabase(const nsCOMPtr<mozIStorageService>& aStorage,
277
                                               const nsCOMPtr<nsIFile>& aDatabaseFile);
278
279
  /**
280
   * Set up the connection environment through PRAGMAs.
281
   * Will return NS_ERROR_FILE_CORRUPTED if any critical setting fails.
282
   *
283
   * @param aStorage
284
   *        mozStorage service instance.
285
   */
286
  nsresult SetupDatabaseConnection(nsCOMPtr<mozIStorageService>& aStorage);
287
288
  /**
289
   * Initializes the schema.  This performs any necessary migrations for the
290
   * database.  All migration is done inside a transaction that is rolled back
291
   * if any error occurs.
292
   * @param aDatabaseMigrated
293
   *        Whether a schema upgrade happened.
294
   */
295
  nsresult InitSchema(bool* aDatabaseMigrated);
296
297
  /**
298
   * Checks the root bookmark folders are present, and saves the IDs for them.
299
   */
300
  nsresult CheckRoots();
301
302
  /**
303
   * Creates bookmark roots in a new DB.
304
   */
305
  nsresult EnsureBookmarkRoots(const int32_t startPosition,
306
                               bool shouldReparentRoots);
307
308
  /**
309
   * Initializes additionale SQLite functions, defined in SQLFunctions.h
310
   */
311
  nsresult InitFunctions();
312
313
  /**
314
   * Initializes temp entities, like triggers, tables, views...
315
   */
316
  nsresult InitTempEntities();
317
318
  /**
319
   * Helpers used by schema upgrades.
320
   */
321
  nsresult MigrateV31Up();
322
  nsresult MigrateV32Up();
323
  nsresult MigrateV33Up();
324
  nsresult MigrateV34Up();
325
  nsresult MigrateV35Up();
326
  nsresult MigrateV36Up();
327
  nsresult MigrateV37Up();
328
  nsresult MigrateV38Up();
329
  nsresult MigrateV39Up();
330
  nsresult MigrateV40Up();
331
  nsresult MigrateV41Up();
332
  nsresult MigrateV42Up();
333
  nsresult MigrateV43Up();
334
  nsresult MigrateV44Up();
335
  nsresult MigrateV45Up();
336
  nsresult MigrateV46Up();
337
  nsresult MigrateV47Up();
338
  nsresult MigrateV48Up();
339
  nsresult MigrateV49Up();
340
  nsresult MigrateV50Up();
341
  nsresult MigrateV51Up();
342
  nsresult MigrateV52Up();
343
344
  void MigrateV52OriginFrecencies();
345
346
  nsresult UpdateBookmarkRootTitles();
347
348
  friend class ConnectionShutdownBlocker;
349
350
  int64_t CreateMobileRoot();
351
  nsresult ConvertOldStyleQuery(nsCString& aURL);
352
  nsresult GetItemsWithAnno(const nsACString& aAnnoName, int32_t aItemType,
353
                            nsTArray<int64_t>& aItemIds);
354
  nsresult DeleteBookmarkItem(int32_t aItemId);
355
356
private:
357
  ~Database();
358
359
  /**
360
   * Singleton getter, invoked by class instantiation.
361
   */
362
  static already_AddRefed<Database> GetSingleton();
363
364
  static Database* gDatabase;
365
366
  nsCOMPtr<mozIStorageConnection> mMainConn;
367
368
  mutable StatementCache mMainThreadStatements;
369
  mutable AsyncStatementCache mMainThreadAsyncStatements;
370
  mutable StatementCache mAsyncThreadStatements;
371
372
  int32_t mDBPageSize;
373
  uint16_t mDatabaseStatus;
374
  bool mClosed;
375
  // Used to track whether icon payloads should be converted at the end of
376
  // schema migration.
377
  bool mShouldConvertIconPayloads;
378
  // Used to track whether the favicons database should be vacuumed at the end
379
  // of the schema migration.
380
  bool mShouldVacuumIcons;
381
382
  /**
383
   * Phases for shutting down the Database.
384
   * See Shutdown.h for further details about the shutdown procedure.
385
   */
386
  already_AddRefed<nsIAsyncShutdownClient> GetProfileChangeTeardownPhase();
387
  already_AddRefed<nsIAsyncShutdownClient> GetProfileBeforeChangePhase();
388
389
  /**
390
   * Blockers in charge of waiting for the Places clients and then shutting
391
   * down the mozStorage connection.
392
   * See Shutdown.h for further details about the shutdown procedure.
393
   *
394
   * Cycles with these are broken in `Shutdown()`.
395
   */
396
  RefPtr<ClientsShutdownBlocker> mClientsShutdown;
397
  RefPtr<ConnectionShutdownBlocker> mConnectionShutdown;
398
399
  // Maximum length of a stored url.
400
  // For performance reasons we don't store very long urls in history, since
401
  // they are slower to search through and cause abnormal database growth,
402
  // affecting the awesomebar fetch time.
403
  uint32_t mMaxUrlLength;
404
405
  // Used to initialize components on places startup.
406
  nsCategoryCache<nsIObserver> mCacheObservers;
407
408
  // Used to cache the places folder Ids when the connection is started.
409
  int64_t mRootId;
410
  int64_t mMenuRootId;
411
  int64_t mTagsRootId;
412
  int64_t mUnfiledRootId;
413
  int64_t mToolbarRootId;
414
  int64_t mMobileRootId;
415
};
416
417
} // namespace places
418
} // namespace mozilla
419
420
#endif // mozilla_places_Database_h_