Bug 867089 - Validate the playbackRate before using it. r=ehsan
[gecko.git] / storage / src / StorageBaseStatementInternal.cpp
blob7160757c04e3bd572a89862e6fd045561b6a14e8
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2 * vim: sw=2 ts=2 sts=2 expandtab
3 * This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #include "StorageBaseStatementInternal.h"
9 #include "nsProxyRelease.h"
11 #include "mozStorageBindingParamsArray.h"
12 #include "mozStorageStatementData.h"
13 #include "mozStorageAsyncStatementExecution.h"
15 namespace mozilla {
16 namespace storage {
18 ////////////////////////////////////////////////////////////////////////////////
19 //// Local Classes
21 /**
22 * Used to finalize an asynchronous statement on the background thread.
24 class AsyncStatementFinalizer : public nsRunnable
26 public:
27 /**
28 * Constructor for the event.
30 * @param aStatement
31 * We need the AsyncStatement to be able to get at the sqlite3_stmt;
32 * we only access/create it on the async thread.
33 * @param aConnection
34 * We need the connection to know what thread to release the statement
35 * on. We release the statement on that thread since releasing the
36 * statement might end up releasing the connection too.
38 AsyncStatementFinalizer(StorageBaseStatementInternal *aStatement,
39 Connection *aConnection)
40 : mStatement(aStatement)
41 , mConnection(aConnection)
45 NS_IMETHOD Run()
47 if (mStatement->mAsyncStatement) {
48 (void)::sqlite3_finalize(mStatement->mAsyncStatement);
49 mStatement->mAsyncStatement = nullptr;
51 (void)::NS_ProxyRelease(mConnection->threadOpenedOn, mStatement);
52 return NS_OK;
54 private:
55 nsRefPtr<StorageBaseStatementInternal> mStatement;
56 nsRefPtr<Connection> mConnection;
59 /**
60 * Finalize a sqlite3_stmt on the background thread for a statement whose
61 * destructor was invoked and the statement was non-null.
63 class LastDitchSqliteStatementFinalizer : public nsRunnable
65 public:
66 /**
67 * Event constructor.
69 * @param aConnection
70 * Used to keep the connection alive. If we failed to do this, it
71 * is possible that the statement going out of scope invoking us
72 * might have the last reference to the connection and so trigger
73 * an attempt to close the connection which is doomed to fail
74 * (because the asynchronous execution thread must exist which will
75 * trigger the failure case).
76 * @param aStatement
77 * The sqlite3_stmt to finalize. This object takes ownership /
78 * responsibility for the instance and all other references to it
79 * should be forgotten.
81 LastDitchSqliteStatementFinalizer(nsRefPtr<Connection> &aConnection,
82 sqlite3_stmt *aStatement)
83 : mConnection(aConnection)
84 , mAsyncStatement(aStatement)
86 NS_PRECONDITION(aConnection, "You must provide a Connection");
89 NS_IMETHOD Run()
91 (void)::sqlite3_finalize(mAsyncStatement);
92 mAsyncStatement = nullptr;
94 // Because of our ambiguous nsISupports we cannot use the NS_ProxyRelease
95 // template helpers.
96 Connection *rawConnection = nullptr;
97 mConnection.swap(rawConnection);
98 (void)::NS_ProxyRelease(
99 rawConnection->threadOpenedOn,
100 NS_ISUPPORTS_CAST(mozIStorageConnection *, rawConnection));
101 return NS_OK;
103 private:
104 nsRefPtr<Connection> mConnection;
105 sqlite3_stmt *mAsyncStatement;
108 ////////////////////////////////////////////////////////////////////////////////
109 //// StorageBaseStatementInternal
111 StorageBaseStatementInternal::StorageBaseStatementInternal()
112 : mAsyncStatement(NULL)
116 void
117 StorageBaseStatementInternal::asyncFinalize()
119 nsIEventTarget *target = mDBConnection->getAsyncExecutionTarget();
120 if (!target) {
121 // If we cannot get the background thread, we have to assume it has been
122 // shutdown (or is in the process of doing so). As a result, we should
123 // just finalize it here and now.
124 destructorAsyncFinalize();
126 else {
127 nsCOMPtr<nsIRunnable> event =
128 new AsyncStatementFinalizer(this, mDBConnection);
130 // If the dispatching did not go as planned, finalize now.
131 if (NS_FAILED(target->Dispatch(event, NS_DISPATCH_NORMAL))) {
132 destructorAsyncFinalize();
137 void
138 StorageBaseStatementInternal::destructorAsyncFinalize()
140 if (!mAsyncStatement)
141 return;
143 nsIEventTarget *target = mDBConnection->getAsyncExecutionTarget();
144 if (target) {
145 nsCOMPtr<nsIRunnable> event =
146 new LastDitchSqliteStatementFinalizer(mDBConnection, mAsyncStatement);
147 if (NS_SUCCEEDED(target->Dispatch(event, NS_DISPATCH_NORMAL))) {
148 mAsyncStatement = nullptr;
149 return;
152 // (no async thread remains or we could not dispatch to it)
153 (void)::sqlite3_finalize(mAsyncStatement);
154 mAsyncStatement = nullptr;
157 NS_IMETHODIMP
158 StorageBaseStatementInternal::NewBindingParamsArray(
159 mozIStorageBindingParamsArray **_array
162 nsCOMPtr<mozIStorageBindingParamsArray> array = new BindingParamsArray(this);
163 NS_ENSURE_TRUE(array, NS_ERROR_OUT_OF_MEMORY);
165 array.forget(_array);
166 return NS_OK;
169 NS_IMETHODIMP
170 StorageBaseStatementInternal::ExecuteAsync(
171 mozIStorageStatementCallback *aCallback,
172 mozIStoragePendingStatement **_stmt
175 // We used to call Connection::ExecuteAsync but it takes a
176 // mozIStorageBaseStatement signature because it is also a public API. Since
177 // our 'this' has no static concept of mozIStorageBaseStatement and Connection
178 // would just QI it back across to a StorageBaseStatementInternal and the
179 // actual logic is very simple, we now roll our own.
180 nsTArray<StatementData> stmts(1);
181 StatementData data;
182 nsresult rv = getAsynchronousStatementData(data);
183 NS_ENSURE_SUCCESS(rv, rv);
184 NS_ENSURE_TRUE(stmts.AppendElement(data), NS_ERROR_OUT_OF_MEMORY);
186 // Dispatch to the background
187 return AsyncExecuteStatements::execute(stmts, mDBConnection, aCallback,
188 _stmt);
191 NS_IMETHODIMP
192 StorageBaseStatementInternal::EscapeStringForLIKE(
193 const nsAString &aValue,
194 const PRUnichar aEscapeChar,
195 nsAString &_escapedString
198 const PRUnichar MATCH_ALL('%');
199 const PRUnichar MATCH_ONE('_');
201 _escapedString.Truncate(0);
203 for (uint32_t i = 0; i < aValue.Length(); i++) {
204 if (aValue[i] == aEscapeChar || aValue[i] == MATCH_ALL ||
205 aValue[i] == MATCH_ONE) {
206 _escapedString += aEscapeChar;
208 _escapedString += aValue[i];
210 return NS_OK;
213 } // namespace storage
214 } // namespace mozilla