1 : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 : /* ***** BEGIN LICENSE BLOCK *****
3 : * Version: MPL 1.1/GPL 2.0/LGPL 2.1
4 : *
5 : * The contents of this file are subject to the Mozilla Public License Version
6 : * 1.1 (the "License"); you may not use this file except in compliance with
7 : * the License. You may obtain a copy of the License at
8 : * http://www.mozilla.org/MPL/
9 : *
10 : * Software distributed under the License is distributed on an "AS IS" basis,
11 : * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 : * for the specific language governing rights and limitations under the
13 : * License.
14 : *
15 : * The Original Code is Storage code
16 : *
17 : * The Initial Developer of the Original Code is
18 : * Google Inc.
19 : * Portions created by the Initial Developer are Copyright (C) 2005
20 : * the Initial Developer. All Rights Reserved.
21 : *
22 : * Contributor(s):
23 : * Brett Wilson <brettw@gmail.com>
24 : *
25 : * Alternatively, the contents of this file may be used under the terms of
26 : * either the GNU General Public License Version 2 or later (the "GPL"), or
27 : * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
28 : * in which case the provisions of the GPL or the LGPL are applicable instead
29 : * of those above. If you wish to allow use of your version of this file only
30 : * under the terms of either the GPL or the LGPL, and not to allow others to
31 : * use your version of this file under the terms of the MPL, indicate your
32 : * decision by deleting the provisions above and replace them with the notice
33 : * and other provisions required by the GPL or the LGPL. If you do not delete
34 : * the provisions above, a recipient may use your version of this file under
35 : * the terms of any one of the MPL, the GPL or the LGPL.
36 : *
37 : * ***** END LICENSE BLOCK ***** */
38 :
39 : #ifndef MOZSTORAGEHELPER_H
40 : #define MOZSTORAGEHELPER_H
41 :
42 : #include "nsAutoPtr.h"
43 :
44 : #include "mozIStorageConnection.h"
45 : #include "mozIStorageStatement.h"
46 : #include "mozStorage.h"
47 :
48 :
49 : /**
50 : * This class wraps a transaction inside a given C++ scope, guaranteeing that
51 : * the transaction will be completed even if you have an exception or
52 : * return early.
53 : *
54 : * aCommitOnComplete controls whether the transaction is committed or rolled
55 : * back when it goes out of scope. A common use is to create an instance with
56 : * commitOnComplete = FALSE (rollback), then call Commit on this object manually
57 : * when your function completes successfully.
58 : *
59 : * Note that nested transactions are not supported by sqlite, so if a transaction
60 : * is already in progress, this object does nothing. Note that in this case,
61 : * you may not get the transaction type you ask for, and you won't be able
62 : * to rollback.
63 : */
64 : class mozStorageTransaction
65 : {
66 : public:
67 12403 : mozStorageTransaction(mozIStorageConnection* aConnection,
68 : bool aCommitOnComplete,
69 : PRInt32 aType = mozIStorageConnection::TRANSACTION_DEFERRED)
70 : : mConnection(aConnection),
71 : mHasTransaction(false),
72 : mCommitOnComplete(aCommitOnComplete),
73 12403 : mCompleted(false)
74 : {
75 : // We won't try to get a transaction if one is already in progress.
76 12403 : if (mConnection)
77 12402 : mHasTransaction = NS_SUCCEEDED(mConnection->BeginTransactionAs(aType));
78 12403 : }
79 12403 : ~mozStorageTransaction()
80 12403 : {
81 12403 : if (mConnection && mHasTransaction && ! mCompleted) {
82 131 : if (mCommitOnComplete)
83 109 : mConnection->CommitTransaction();
84 : else
85 22 : mConnection->RollbackTransaction();
86 : }
87 12403 : }
88 :
89 : /**
90 : * Commits the transaction if one is in progress. If one is not in progress,
91 : * this is a NOP since the actual owner of the transaction outside of our
92 : * scope is in charge of finally comitting or rolling back the transaction.
93 : */
94 12259 : nsresult Commit()
95 : {
96 12259 : if (!mConnection || mCompleted)
97 1 : return NS_OK; // no connection, or already done
98 12258 : mCompleted = true;
99 12258 : if (! mHasTransaction)
100 5235 : return NS_OK; // transaction not ours, ignore
101 7023 : nsresult rv = mConnection->CommitTransaction();
102 7023 : if (NS_SUCCEEDED(rv))
103 7023 : mHasTransaction = false;
104 :
105 7023 : return rv;
106 : }
107 :
108 : /**
109 : * Rolls back the transaction in progress. You should only call this function
110 : * if this object has a real transaction (HasTransaction() = true) because
111 : * otherwise, there is no transaction to roll back.
112 : */
113 4 : nsresult Rollback()
114 : {
115 4 : if (!mConnection || mCompleted)
116 1 : return NS_OK; // no connection, or already done
117 3 : mCompleted = true;
118 3 : if (! mHasTransaction)
119 0 : return NS_ERROR_FAILURE;
120 :
121 : // It is possible that a rollback will return busy, so we busy wait...
122 3 : nsresult rv = NS_OK;
123 3 : do {
124 3 : rv = mConnection->RollbackTransaction();
125 3 : if (rv == NS_ERROR_STORAGE_BUSY)
126 0 : (void)PR_Sleep(PR_INTERVAL_NO_WAIT);
127 : } while (rv == NS_ERROR_STORAGE_BUSY);
128 :
129 3 : if (NS_SUCCEEDED(rv))
130 3 : mHasTransaction = false;
131 :
132 3 : return rv;
133 : }
134 :
135 : /**
136 : * Returns whether this object wraps a real transaction. False means that
137 : * this object doesn't do anything because there was already a transaction in
138 : * progress when it was created.
139 : */
140 7 : bool HasTransaction()
141 : {
142 7 : return mHasTransaction;
143 : }
144 :
145 : /**
146 : * This sets the default action (commit or rollback) when this object goes
147 : * out of scope.
148 : */
149 2 : void SetDefaultAction(bool aCommitOnComplete)
150 : {
151 2 : mCommitOnComplete = aCommitOnComplete;
152 2 : }
153 :
154 : protected:
155 : nsCOMPtr<mozIStorageConnection> mConnection;
156 : bool mHasTransaction;
157 : bool mCommitOnComplete;
158 : bool mCompleted;
159 : };
160 :
161 :
162 : /**
163 : * This class wraps a statement so that it is guaraneed to be reset when
164 : * this object goes out of scope.
165 : *
166 : * Note that this always just resets the statement. If the statement doesn't
167 : * need resetting, the reset operation is inexpensive.
168 : */
169 : class NS_STACK_CLASS mozStorageStatementScoper
170 : {
171 : public:
172 66363 : mozStorageStatementScoper(mozIStorageStatement* aStatement)
173 66363 : : mStatement(aStatement)
174 : {
175 66363 : }
176 66363 : ~mozStorageStatementScoper()
177 66363 : {
178 66363 : if (mStatement)
179 62371 : mStatement->Reset();
180 66363 : }
181 :
182 : /**
183 : * Call this to make the statement not reset. You might do this if you know
184 : * that the statement has been reset.
185 : */
186 3992 : void Abandon()
187 : {
188 3992 : mStatement = nsnull;
189 3992 : }
190 :
191 : protected:
192 : nsCOMPtr<mozIStorageStatement> mStatement;
193 : };
194 :
195 : // Use this to make queries uniquely identifiable in telemetry
196 : // statistics, especially PRAGMAs. We don't include __LINE__ so that
197 : // queries are stable in the face of source code changes.
198 : #define MOZ_STORAGE_UNIQUIFY_QUERY_STR "/* " __FILE__ " */ "
199 :
200 : #endif /* MOZSTORAGEHELPER_H */
|