Bug 1468221 [wpt PR 11464] - Fix #11454: Set --verify-log-full to False for ci/check_...
[gecko.git] / storage / StorageBaseStatementInternal.cpp
blob819d3371bd0f3132132f7b5b36473d848ddbdd69
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 Runnable
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 : Runnable("storage::AsyncStatementFinalizer")
41 , mStatement(aStatement)
42 , mConnection(aConnection)
46 NS_IMETHOD Run() override
48 if (mStatement->mAsyncStatement) {
49 sqlite3_finalize(mStatement->mAsyncStatement);
50 mStatement->mAsyncStatement = nullptr;
53 nsCOMPtr<nsIThread> targetThread(mConnection->threadOpenedOn);
54 NS_ProxyRelease(
55 "AsyncStatementFinalizer::mStatement", targetThread, mStatement.forget());
56 return NS_OK;
58 private:
59 RefPtr<StorageBaseStatementInternal> mStatement;
60 RefPtr<Connection> mConnection;
63 /**
64 * Finalize a sqlite3_stmt on the background thread for a statement whose
65 * destructor was invoked and the statement was non-null.
67 class LastDitchSqliteStatementFinalizer : public Runnable
69 public:
70 /**
71 * Event constructor.
73 * @param aConnection
74 * Used to keep the connection alive. If we failed to do this, it
75 * is possible that the statement going out of scope invoking us
76 * might have the last reference to the connection and so trigger
77 * an attempt to close the connection which is doomed to fail
78 * (because the asynchronous execution thread must exist which will
79 * trigger the failure case).
80 * @param aStatement
81 * The sqlite3_stmt to finalize. This object takes ownership /
82 * responsibility for the instance and all other references to it
83 * should be forgotten.
85 LastDitchSqliteStatementFinalizer(RefPtr<Connection>& aConnection,
86 sqlite3_stmt* aStatement)
87 : Runnable("storage::LastDitchSqliteStatementFinalizer")
88 , mConnection(aConnection)
89 , mAsyncStatement(aStatement)
91 MOZ_ASSERT(aConnection, "You must provide a Connection");
94 NS_IMETHOD Run() override
96 (void)::sqlite3_finalize(mAsyncStatement);
97 mAsyncStatement = nullptr;
99 nsCOMPtr<nsIThread> target(mConnection->threadOpenedOn);
100 (void)::NS_ProxyRelease(
101 "LastDitchSqliteStatementFinalizer::mConnection",
102 target, mConnection.forget());
103 return NS_OK;
105 private:
106 RefPtr<Connection> mConnection;
107 sqlite3_stmt *mAsyncStatement;
110 ////////////////////////////////////////////////////////////////////////////////
111 //// StorageBaseStatementInternal
113 StorageBaseStatementInternal::StorageBaseStatementInternal()
114 : mNativeConnection(nullptr)
115 , mAsyncStatement(nullptr)
119 void
120 StorageBaseStatementInternal::asyncFinalize()
122 nsIEventTarget *target = mDBConnection->getAsyncExecutionTarget();
123 if (target) {
124 // Attempt to finalize asynchronously
125 nsCOMPtr<nsIRunnable> event =
126 new AsyncStatementFinalizer(this, mDBConnection);
128 // Dispatch. Note that dispatching can fail, typically if
129 // we have a race condition with asyncClose(). It's ok,
130 // let asyncClose() win.
131 (void)target->Dispatch(event, NS_DISPATCH_NORMAL);
133 // If we cannot get the background thread,
134 // mozStorageConnection::AsyncClose() has already been called and
135 // the statement either has been or will be cleaned up by
136 // internalClose().
139 void
140 StorageBaseStatementInternal::destructorAsyncFinalize()
142 if (!mAsyncStatement)
143 return;
145 bool isOwningThread = false;
146 (void)mDBConnection->threadOpenedOn->IsOnCurrentThread(&isOwningThread);
147 if (isOwningThread) {
148 // If we are the owning thread (currently that means we're also the
149 // main thread), then we can get the async target and just dispatch
150 // to it.
151 nsIEventTarget *target = mDBConnection->getAsyncExecutionTarget();
152 if (target) {
153 nsCOMPtr<nsIRunnable> event =
154 new LastDitchSqliteStatementFinalizer(mDBConnection, mAsyncStatement);
155 (void)target->Dispatch(event, NS_DISPATCH_NORMAL);
157 } else {
158 // If we're not the owning thread, assume we're the async thread, and
159 // just run the statement.
160 nsCOMPtr<nsIRunnable> event =
161 new LastDitchSqliteStatementFinalizer(mDBConnection, mAsyncStatement);
162 (void)event->Run();
166 // We might not be able to dispatch to the background thread,
167 // presumably because it is being shutdown. Since said shutdown will
168 // finalize the statement, we just need to clean-up around here.
169 mAsyncStatement = nullptr;
172 NS_IMETHODIMP
173 StorageBaseStatementInternal::NewBindingParamsArray(
174 mozIStorageBindingParamsArray **_array
177 nsCOMPtr<mozIStorageBindingParamsArray> array = new BindingParamsArray(this);
178 NS_ENSURE_TRUE(array, NS_ERROR_OUT_OF_MEMORY);
180 array.forget(_array);
181 return NS_OK;
184 NS_IMETHODIMP
185 StorageBaseStatementInternal::ExecuteAsync(
186 mozIStorageStatementCallback *aCallback,
187 mozIStoragePendingStatement **_stmt
190 // We used to call Connection::ExecuteAsync but it takes a
191 // mozIStorageBaseStatement signature because it is also a public API. Since
192 // our 'this' has no static concept of mozIStorageBaseStatement and Connection
193 // would just QI it back across to a StorageBaseStatementInternal and the
194 // actual logic is very simple, we now roll our own.
195 nsTArray<StatementData> stmts(1);
196 StatementData data;
197 nsresult rv = getAsynchronousStatementData(data);
198 NS_ENSURE_SUCCESS(rv, rv);
199 NS_ENSURE_TRUE(stmts.AppendElement(data), NS_ERROR_OUT_OF_MEMORY);
201 // Dispatch to the background
202 return AsyncExecuteStatements::execute(stmts, mDBConnection,
203 mNativeConnection, aCallback, _stmt);
206 NS_IMETHODIMP
207 StorageBaseStatementInternal::EscapeStringForLIKE(
208 const nsAString &aValue,
209 const char16_t aEscapeChar,
210 nsAString &_escapedString
213 const char16_t MATCH_ALL('%');
214 const char16_t MATCH_ONE('_');
216 _escapedString.Truncate(0);
218 for (uint32_t i = 0; i < aValue.Length(); i++) {
219 if (aValue[i] == aEscapeChar || aValue[i] == MATCH_ALL ||
220 aValue[i] == MATCH_ONE) {
221 _escapedString += aEscapeChar;
223 _escapedString += aValue[i];
225 return NS_OK;
228 } // namespace storage
229 } // namespace mozilla