|
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 #ifndef MOZSTORAGEHELPER_H |
|
7 #define MOZSTORAGEHELPER_H |
|
8 |
|
9 #include "nsAutoPtr.h" |
|
10 |
|
11 #include "mozIStorageAsyncConnection.h" |
|
12 #include "mozIStorageConnection.h" |
|
13 #include "mozIStorageStatement.h" |
|
14 #include "nsError.h" |
|
15 |
|
16 /** |
|
17 * This class wraps a transaction inside a given C++ scope, guaranteeing that |
|
18 * the transaction will be completed even if you have an exception or |
|
19 * return early. |
|
20 * |
|
21 * aCommitOnComplete controls whether the transaction is committed or rolled |
|
22 * back when it goes out of scope. A common use is to create an instance with |
|
23 * commitOnComplete = FALSE (rollback), then call Commit on this object manually |
|
24 * when your function completes successfully. |
|
25 * |
|
26 * Note that nested transactions are not supported by sqlite, so if a transaction |
|
27 * is already in progress, this object does nothing. Note that in this case, |
|
28 * you may not get the transaction type you ask for, and you won't be able |
|
29 * to rollback. |
|
30 * |
|
31 * Note: This class is templatized to be also usable with internal data |
|
32 * structures. External users of this class should generally use |
|
33 * |mozStorageTransaction| instead. |
|
34 */ |
|
35 template<typename T, typename U> |
|
36 class mozStorageTransactionBase |
|
37 { |
|
38 public: |
|
39 mozStorageTransactionBase(T* aConnection, |
|
40 bool aCommitOnComplete, |
|
41 int32_t aType = mozIStorageConnection::TRANSACTION_DEFERRED) |
|
42 : mConnection(aConnection), |
|
43 mHasTransaction(false), |
|
44 mCommitOnComplete(aCommitOnComplete), |
|
45 mCompleted(false) |
|
46 { |
|
47 // We won't try to get a transaction if one is already in progress. |
|
48 if (mConnection) |
|
49 mHasTransaction = NS_SUCCEEDED(mConnection->BeginTransactionAs(aType)); |
|
50 } |
|
51 ~mozStorageTransactionBase() |
|
52 { |
|
53 if (mConnection && mHasTransaction && ! mCompleted) { |
|
54 if (mCommitOnComplete) |
|
55 mConnection->CommitTransaction(); |
|
56 else |
|
57 mConnection->RollbackTransaction(); |
|
58 } |
|
59 } |
|
60 |
|
61 /** |
|
62 * Commits the transaction if one is in progress. If one is not in progress, |
|
63 * this is a NOP since the actual owner of the transaction outside of our |
|
64 * scope is in charge of finally comitting or rolling back the transaction. |
|
65 */ |
|
66 nsresult Commit() |
|
67 { |
|
68 if (!mConnection || mCompleted) |
|
69 return NS_OK; // no connection, or already done |
|
70 mCompleted = true; |
|
71 if (! mHasTransaction) |
|
72 return NS_OK; // transaction not ours, ignore |
|
73 nsresult rv = mConnection->CommitTransaction(); |
|
74 if (NS_SUCCEEDED(rv)) |
|
75 mHasTransaction = false; |
|
76 |
|
77 return rv; |
|
78 } |
|
79 |
|
80 /** |
|
81 * Rolls back the transaction in progress. You should only call this function |
|
82 * if this object has a real transaction (HasTransaction() = true) because |
|
83 * otherwise, there is no transaction to roll back. |
|
84 */ |
|
85 nsresult Rollback() |
|
86 { |
|
87 if (!mConnection || mCompleted) |
|
88 return NS_OK; // no connection, or already done |
|
89 mCompleted = true; |
|
90 if (! mHasTransaction) |
|
91 return NS_ERROR_FAILURE; |
|
92 |
|
93 // It is possible that a rollback will return busy, so we busy wait... |
|
94 nsresult rv = NS_OK; |
|
95 do { |
|
96 rv = mConnection->RollbackTransaction(); |
|
97 if (rv == NS_ERROR_STORAGE_BUSY) |
|
98 (void)PR_Sleep(PR_INTERVAL_NO_WAIT); |
|
99 } while (rv == NS_ERROR_STORAGE_BUSY); |
|
100 |
|
101 if (NS_SUCCEEDED(rv)) |
|
102 mHasTransaction = false; |
|
103 |
|
104 return rv; |
|
105 } |
|
106 |
|
107 /** |
|
108 * Returns whether this object wraps a real transaction. False means that |
|
109 * this object doesn't do anything because there was already a transaction in |
|
110 * progress when it was created. |
|
111 */ |
|
112 bool HasTransaction() |
|
113 { |
|
114 return mHasTransaction; |
|
115 } |
|
116 |
|
117 /** |
|
118 * This sets the default action (commit or rollback) when this object goes |
|
119 * out of scope. |
|
120 */ |
|
121 void SetDefaultAction(bool aCommitOnComplete) |
|
122 { |
|
123 mCommitOnComplete = aCommitOnComplete; |
|
124 } |
|
125 |
|
126 protected: |
|
127 U mConnection; |
|
128 bool mHasTransaction; |
|
129 bool mCommitOnComplete; |
|
130 bool mCompleted; |
|
131 }; |
|
132 |
|
133 /** |
|
134 * An instance of the mozStorageTransaction<> family dedicated |
|
135 * to |mozIStorageConnection|. |
|
136 */ |
|
137 typedef mozStorageTransactionBase<mozIStorageConnection, |
|
138 nsCOMPtr<mozIStorageConnection> > |
|
139 mozStorageTransaction; |
|
140 |
|
141 |
|
142 |
|
143 /** |
|
144 * This class wraps a statement so that it is guaraneed to be reset when |
|
145 * this object goes out of scope. |
|
146 * |
|
147 * Note that this always just resets the statement. If the statement doesn't |
|
148 * need resetting, the reset operation is inexpensive. |
|
149 */ |
|
150 class MOZ_STACK_CLASS mozStorageStatementScoper |
|
151 { |
|
152 public: |
|
153 mozStorageStatementScoper(mozIStorageStatement* aStatement) |
|
154 : mStatement(aStatement) |
|
155 { |
|
156 } |
|
157 ~mozStorageStatementScoper() |
|
158 { |
|
159 if (mStatement) |
|
160 mStatement->Reset(); |
|
161 } |
|
162 |
|
163 /** |
|
164 * Call this to make the statement not reset. You might do this if you know |
|
165 * that the statement has been reset. |
|
166 */ |
|
167 void Abandon() |
|
168 { |
|
169 mStatement = nullptr; |
|
170 } |
|
171 |
|
172 protected: |
|
173 nsCOMPtr<mozIStorageStatement> mStatement; |
|
174 }; |
|
175 |
|
176 // Use this to make queries uniquely identifiable in telemetry |
|
177 // statistics, especially PRAGMAs. We don't include __LINE__ so that |
|
178 // queries are stable in the face of source code changes. |
|
179 #define MOZ_STORAGE_UNIQUIFY_QUERY_STR "/* " __FILE__ " */ " |
|
180 |
|
181 #endif /* MOZSTORAGEHELPER_H */ |