1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 #ifndef MOZSTORAGEHELPER_H
7 #define MOZSTORAGEHELPER_H
11 #include "mozilla/DebugOnly.h"
12 #include "nsIConsoleService.h"
13 #include "nsIScriptError.h"
15 #include "mozIStorageAsyncConnection.h"
16 #include "mozIStorageConnection.h"
17 #include "mozIStorageStatement.h"
18 #include "mozIStoragePendingStatement.h"
20 #include "nsIXPConnect.h"
23 * This class wraps a transaction inside a given C++ scope, guaranteeing that
24 * the transaction will be completed even if you have an exception or
27 * A common use is to create an instance with aCommitOnComplete = false (rollback),
28 * then call Commit() on this object manually when your function completes
31 * @note nested transactions are not supported by Sqlite, so if a transaction
32 * is already in progress, this object does nothing. Note that in this case,
33 * you may not get the transaction type you asked for, and you won't be able
37 * The connection to create the transaction on.
38 * @param aCommitOnComplete
39 * Controls whether the transaction is committed or rolled back when
40 * this object goes out of scope.
41 * @param aType [optional]
42 * The transaction type, as defined in mozIStorageConnection. Uses the
43 * default transaction behavior for the connection if unspecified.
44 * @param aAsyncCommit [optional]
45 * Whether commit should be executed asynchronously on the helper thread.
46 * This is a special option introduced as an interim solution to reduce
47 * main-thread fsyncs in Places. Can only be used on main-thread.
49 * WARNING: YOU SHOULD _NOT_ WRITE NEW MAIN-THREAD CODE USING THIS!
51 * Notice that async commit might cause synchronous statements to fail
52 * with SQLITE_BUSY. A possible mitigation strategy is to use
53 * PRAGMA busy_timeout, but notice that might cause main-thread jank.
54 * Finally, if the database is using WAL journaling mode, other
55 * connections won't see the changes done in async committed transactions
56 * until commit is complete.
58 * For all of the above reasons, this should only be used as an interim
59 * solution and avoided completely if possible.
61 class mozStorageTransaction
64 mozStorageTransaction(mozIStorageConnection
* aConnection
,
65 bool aCommitOnComplete
,
66 int32_t aType
= mozIStorageConnection::TRANSACTION_DEFAULT
,
67 bool aAsyncCommit
= false)
68 : mConnection(aConnection
),
69 mHasTransaction(false),
70 mCommitOnComplete(aCommitOnComplete
),
72 mAsyncCommit(aAsyncCommit
)
75 nsAutoCString
query("BEGIN");
77 if (type
== mozIStorageConnection::TRANSACTION_DEFAULT
) {
78 MOZ_ALWAYS_SUCCEEDS(mConnection
->GetDefaultTransactionType(&type
));
81 case mozIStorageConnection::TRANSACTION_IMMEDIATE
:
82 query
.AppendLiteral(" IMMEDIATE");
84 case mozIStorageConnection::TRANSACTION_EXCLUSIVE
:
85 query
.AppendLiteral(" EXCLUSIVE");
87 case mozIStorageConnection::TRANSACTION_DEFERRED
:
88 query
.AppendLiteral(" DEFERRED");
91 MOZ_ASSERT(false, "Unknown transaction type");
93 // If a transaction is already in progress, this will fail, since Sqlite
94 // doesn't support nested transactions.
95 mHasTransaction
= NS_SUCCEEDED(mConnection
->ExecuteSimpleSQL(query
));
99 ~mozStorageTransaction()
101 if (mConnection
&& mHasTransaction
&& !mCompleted
) {
102 if (mCommitOnComplete
) {
103 mozilla::DebugOnly
<nsresult
> rv
= Commit();
104 NS_WARNING_ASSERTION(NS_SUCCEEDED(rv
),
105 "A transaction didn't commit correctly");
108 mozilla::DebugOnly
<nsresult
> rv
= Rollback();
109 NS_WARNING_ASSERTION(NS_SUCCEEDED(rv
),
110 "A transaction didn't rollback correctly");
116 * Commits the transaction if one is in progress. If one is not in progress,
117 * this is a NOP since the actual owner of the transaction outside of our
118 * scope is in charge of finally committing or rolling back the transaction.
122 if (!mConnection
|| mCompleted
|| !mHasTransaction
)
126 // TODO (bug 559659): this might fail with SQLITE_BUSY, but we don't handle
127 // it, thus the transaction might stay open until the next COMMIT.
130 nsCOMPtr
<mozIStoragePendingStatement
> ps
;
131 rv
= mConnection
->ExecuteSimpleSQLAsync(NS_LITERAL_CSTRING("COMMIT"),
132 nullptr, getter_AddRefs(ps
));
135 rv
= mConnection
->ExecuteSimpleSQL(NS_LITERAL_CSTRING("COMMIT"));
138 if (NS_SUCCEEDED(rv
))
139 mHasTransaction
= false;
145 * Rolls back the transaction if one is in progress. If one is not in progress,
146 * this is a NOP since the actual owner of the transaction outside of our
147 * scope is in charge of finally rolling back the transaction.
151 if (!mConnection
|| mCompleted
|| !mHasTransaction
)
155 // TODO (bug 1062823): from Sqlite 3.7.11 on, rollback won't ever return
156 // a busy error, so this handling can be removed.
159 rv
= mConnection
->ExecuteSimpleSQL(NS_LITERAL_CSTRING("ROLLBACK"));
160 if (rv
== NS_ERROR_STORAGE_BUSY
)
161 (void)PR_Sleep(PR_INTERVAL_NO_WAIT
);
162 } while (rv
== NS_ERROR_STORAGE_BUSY
);
164 if (NS_SUCCEEDED(rv
))
165 mHasTransaction
= false;
171 nsCOMPtr
<mozIStorageConnection
> mConnection
;
172 bool mHasTransaction
;
173 bool mCommitOnComplete
;
179 * This class wraps a statement so that it is guaraneed to be reset when
180 * this object goes out of scope.
182 * Note that this always just resets the statement. If the statement doesn't
183 * need resetting, the reset operation is inexpensive.
185 class MOZ_STACK_CLASS mozStorageStatementScoper
188 explicit mozStorageStatementScoper(mozIStorageStatement
* aStatement
)
189 : mStatement(aStatement
)
192 ~mozStorageStatementScoper()
199 * Call this to make the statement not reset. You might do this if you know
200 * that the statement has been reset.
204 mStatement
= nullptr;
208 nsCOMPtr
<mozIStorageStatement
> mStatement
;
211 // Use this to make queries uniquely identifiable in telemetry
212 // statistics, especially PRAGMAs. We don't include __LINE__ so that
213 // queries are stable in the face of source code changes.
214 #define MOZ_STORAGE_UNIQUIFY_QUERY_STR "/* " __FILE__ " */ "
216 #endif /* MOZSTORAGEHELPER_H */