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 12338 : mozStorageTransaction(mozIStorageConnection* aConnection,
68 : bool aCommitOnComplete,
69 : PRInt32 aType = mozIStorageConnection::TRANSACTION_DEFERRED)
70 : : mConnection(aConnection),
71 : mHasTransaction(false),
72 : mCommitOnComplete(aCommitOnComplete),
73 12338 : mCompleted(false)
74 : {
75 : // We won't try to get a transaction if one is already in progress.
76 12338 : if (mConnection)
77 12338 : mHasTransaction = NS_SUCCEEDED(mConnection->BeginTransactionAs(aType));
78 12338 : }
79 12338 : ~mozStorageTransaction()
80 12338 : {
81 12338 : if (mConnection && mHasTransaction && ! mCompleted) {
82 112 : if (mCommitOnComplete)
83 94 : mConnection->CommitTransaction();
84 : else
85 18 : mConnection->RollbackTransaction();
86 : }
87 12338 : }
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 12223 : nsresult Commit()
95 : {
96 12223 : if (!mConnection || mCompleted)
97 0 : return NS_OK; // no connection, or already done
98 12223 : mCompleted = true;
99 12223 : if (! mHasTransaction)
100 6248 : return NS_OK; // transaction not ours, ignore
101 5975 : nsresult rv = mConnection->CommitTransaction();
102 5975 : if (NS_SUCCEEDED(rv))
103 5975 : mHasTransaction = false;
104 :
105 5975 : 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 1 : nsresult Rollback()
114 : {
115 1 : if (!mConnection || mCompleted)
116 0 : return NS_OK; // no connection, or already done
117 1 : mCompleted = true;
118 1 : if (! mHasTransaction)
119 0 : return NS_ERROR_FAILURE;
120 :
121 : // It is possible that a rollback will return busy, so we busy wait...
122 1 : nsresult rv = NS_OK;
123 1 : do {
124 1 : rv = mConnection->RollbackTransaction();
125 1 : if (rv == NS_ERROR_STORAGE_BUSY)
126 0 : (void)PR_Sleep(PR_INTERVAL_NO_WAIT);
127 : } while (rv == NS_ERROR_STORAGE_BUSY);
128 :
129 1 : if (NS_SUCCEEDED(rv))
130 1 : mHasTransaction = false;
131 :
132 1 : 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 : bool HasTransaction()
141 : {
142 : return mHasTransaction;
143 : }
144 :
145 : /**
146 : * This sets the default action (commit or rollback) when this object goes
147 : * out of scope.
148 : */
149 : void SetDefaultAction(bool aCommitOnComplete)
150 : {
151 : mCommitOnComplete = aCommitOnComplete;
152 : }
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 65154 : mozStorageStatementScoper(mozIStorageStatement* aStatement)
173 65154 : : mStatement(aStatement)
174 : {
175 65154 : }
176 65154 : ~mozStorageStatementScoper()
177 65154 : {
178 65154 : if (mStatement)
179 61177 : mStatement->Reset();
180 65154 : }
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 3977 : void Abandon()
187 : {
188 3977 : mStatement = nsnull;
189 3977 : }
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 */
|