diff -r 000000000000 -r 6474c204b198 storage/public/mozStorageHelper.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/storage/public/mozStorageHelper.h Wed Dec 31 06:09:35 2014 +0100 @@ -0,0 +1,181 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef MOZSTORAGEHELPER_H +#define MOZSTORAGEHELPER_H + +#include "nsAutoPtr.h" + +#include "mozIStorageAsyncConnection.h" +#include "mozIStorageConnection.h" +#include "mozIStorageStatement.h" +#include "nsError.h" + +/** + * This class wraps a transaction inside a given C++ scope, guaranteeing that + * the transaction will be completed even if you have an exception or + * return early. + * + * aCommitOnComplete controls whether the transaction is committed or rolled + * back when it goes out of scope. A common use is to create an instance with + * commitOnComplete = FALSE (rollback), then call Commit on this object manually + * when your function completes successfully. + * + * Note that nested transactions are not supported by sqlite, so if a transaction + * is already in progress, this object does nothing. Note that in this case, + * you may not get the transaction type you ask for, and you won't be able + * to rollback. + * + * Note: This class is templatized to be also usable with internal data + * structures. External users of this class should generally use + * |mozStorageTransaction| instead. + */ +template +class mozStorageTransactionBase +{ +public: + mozStorageTransactionBase(T* aConnection, + bool aCommitOnComplete, + int32_t aType = mozIStorageConnection::TRANSACTION_DEFERRED) + : mConnection(aConnection), + mHasTransaction(false), + mCommitOnComplete(aCommitOnComplete), + mCompleted(false) + { + // We won't try to get a transaction if one is already in progress. + if (mConnection) + mHasTransaction = NS_SUCCEEDED(mConnection->BeginTransactionAs(aType)); + } + ~mozStorageTransactionBase() + { + if (mConnection && mHasTransaction && ! mCompleted) { + if (mCommitOnComplete) + mConnection->CommitTransaction(); + else + mConnection->RollbackTransaction(); + } + } + + /** + * Commits the transaction if one is in progress. If one is not in progress, + * this is a NOP since the actual owner of the transaction outside of our + * scope is in charge of finally comitting or rolling back the transaction. + */ + nsresult Commit() + { + if (!mConnection || mCompleted) + return NS_OK; // no connection, or already done + mCompleted = true; + if (! mHasTransaction) + return NS_OK; // transaction not ours, ignore + nsresult rv = mConnection->CommitTransaction(); + if (NS_SUCCEEDED(rv)) + mHasTransaction = false; + + return rv; + } + + /** + * Rolls back the transaction in progress. You should only call this function + * if this object has a real transaction (HasTransaction() = true) because + * otherwise, there is no transaction to roll back. + */ + nsresult Rollback() + { + if (!mConnection || mCompleted) + return NS_OK; // no connection, or already done + mCompleted = true; + if (! mHasTransaction) + return NS_ERROR_FAILURE; + + // It is possible that a rollback will return busy, so we busy wait... + nsresult rv = NS_OK; + do { + rv = mConnection->RollbackTransaction(); + if (rv == NS_ERROR_STORAGE_BUSY) + (void)PR_Sleep(PR_INTERVAL_NO_WAIT); + } while (rv == NS_ERROR_STORAGE_BUSY); + + if (NS_SUCCEEDED(rv)) + mHasTransaction = false; + + return rv; + } + + /** + * Returns whether this object wraps a real transaction. False means that + * this object doesn't do anything because there was already a transaction in + * progress when it was created. + */ + bool HasTransaction() + { + return mHasTransaction; + } + + /** + * This sets the default action (commit or rollback) when this object goes + * out of scope. + */ + void SetDefaultAction(bool aCommitOnComplete) + { + mCommitOnComplete = aCommitOnComplete; + } + +protected: + U mConnection; + bool mHasTransaction; + bool mCommitOnComplete; + bool mCompleted; +}; + +/** + * An instance of the mozStorageTransaction<> family dedicated + * to |mozIStorageConnection|. + */ +typedef mozStorageTransactionBase > +mozStorageTransaction; + + + +/** + * This class wraps a statement so that it is guaraneed to be reset when + * this object goes out of scope. + * + * Note that this always just resets the statement. If the statement doesn't + * need resetting, the reset operation is inexpensive. + */ +class MOZ_STACK_CLASS mozStorageStatementScoper +{ +public: + mozStorageStatementScoper(mozIStorageStatement* aStatement) + : mStatement(aStatement) + { + } + ~mozStorageStatementScoper() + { + if (mStatement) + mStatement->Reset(); + } + + /** + * Call this to make the statement not reset. You might do this if you know + * that the statement has been reset. + */ + void Abandon() + { + mStatement = nullptr; + } + +protected: + nsCOMPtr mStatement; +}; + +// Use this to make queries uniquely identifiable in telemetry +// statistics, especially PRAGMAs. We don't include __LINE__ so that +// queries are stable in the face of source code changes. +#define MOZ_STORAGE_UNIQUIFY_QUERY_STR "/* " __FILE__ " */ " + +#endif /* MOZSTORAGEHELPER_H */