Bug Summary

File:var/lib/jenkins/workspace/firefox-scan-build/storage/mozStorageAsyncStatementExecution.cpp
Warning:line 236, column 7
Value stored to 'busyRetry' is never read

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-pc-linux-gnu -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name Unified_cpp_storage0.cpp -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=cplusplus -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -analyzer-config-compatibility-mode=true -mrelocation-model pic -pic-level 2 -fhalf-no-semantic-interposition -mframe-pointer=all -relaxed-aliasing -ffp-contract=off -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fdebug-compilation-dir=/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/storage -fcoverage-compilation-dir=/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/storage -resource-dir /usr/lib/llvm-18/lib/clang/18 -include /var/lib/jenkins/workspace/firefox-scan-build/config/gcc_hidden.h -include /var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/mozilla-config.h -I /var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/stl_wrappers -I /var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/system_wrappers -U _FORTIFY_SOURCE -D _FORTIFY_SOURCE=2 -D DEBUG=1 -D MOZ_SQLITE_PERSIST_AUXILIARY_FILES=1 -D MOZ_HAS_MOZGLUE -D MOZILLA_INTERNAL_API -D IMPL_LIBXUL -D MOZ_SUPPORT_LEAKCHECKING -D STATIC_EXPORTABLE_JS_API -I /var/lib/jenkins/workspace/firefox-scan-build/storage -I /var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/storage -I /var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/ipc/ipdl/_ipdlheaders -I /var/lib/jenkins/workspace/firefox-scan-build/ipc/chromium/src -I /var/lib/jenkins/workspace/firefox-scan-build/dom/base -I /var/lib/jenkins/workspace/firefox-scan-build/third_party/sqlite3/src -I /var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include -I /var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/nspr -I /var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/nss -D MOZILLA_CLIENT -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/14/../../../../include/c++/14 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/14/../../../../include/x86_64-linux-gnu/c++/14 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/14/../../../../include/c++/14/backward -internal-isystem /usr/lib/llvm-18/lib/clang/18/include -internal-isystem /usr/local/include -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/14/../../../../x86_64-linux-gnu/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -O2 -Wno-error=tautological-type-limit-compare -Wno-invalid-offsetof -Wno-range-loop-analysis -Wno-deprecated-anon-enum-enum-conversion -Wno-deprecated-enum-enum-conversion -Wno-deprecated-this-capture -Wno-inline-new-delete -Wno-error=deprecated-declarations -Wno-error=array-bounds -Wno-error=free-nonheap-object -Wno-error=atomic-alignment -Wno-error=deprecated-builtins -Wno-psabi -Wno-error=builtin-macro-redefined -Wno-vla-cxx-extension -Wno-unknown-warning-option -fdeprecated-macro -ferror-limit 19 -stack-protector 2 -fstack-clash-protection -ftrivial-auto-var-init=pattern -fno-rtti -fgnuc-version=4.2.1 -fno-aligned-allocation -vectorize-loops -vectorize-slp -analyzer-checker optin.performance.Padding -analyzer-output=html -analyzer-config stable-report-filename=true -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /tmp/scan-build-2024-07-21-021012-413605-1 -x c++ Unified_cpp_storage0.cpp
1/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2 * vim: sw=2 ts=2 et lcs=trail\:.,tab\:>~ :
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/. */
6
7#include "sqlite3.h"
8
9#include "mozIStorageStatementCallback.h"
10#include "mozStorageBindingParams.h"
11#include "mozStorageHelper.h"
12#include "mozStorageResultSet.h"
13#include "mozStorageRow.h"
14#include "mozStorageConnection.h"
15#include "mozStorageError.h"
16#include "mozStoragePrivateHelpers.h"
17#include "mozStorageStatementData.h"
18#include "mozStorageAsyncStatementExecution.h"
19
20#include "mozilla/DebugOnly.h"
21#include "mozilla/Telemetry.h"
22
23#ifndef MOZ_STORAGE_SORTWARNING_SQL_DUMP
24# include "mozilla/Logging.h"
25extern mozilla::LazyLogModule gStorageLog;
26#endif
27
28namespace mozilla {
29namespace storage {
30
31/**
32 * The following constants help batch rows into result sets.
33 * MAX_MILLISECONDS_BETWEEN_RESULTS was chosen because any user-based task that
34 * takes less than 200 milliseconds is considered to feel instantaneous to end
35 * users. MAX_ROWS_PER_RESULT was arbitrarily chosen to reduce the number of
36 * dispatches to calling thread, while also providing reasonably-sized sets of
37 * data for consumers. Both of these constants are used because we assume that
38 * consumers are trying to avoid blocking their execution thread for long
39 * periods of time, and dispatching many small events to the calling thread will
40 * end up blocking it.
41 */
42#define MAX_MILLISECONDS_BETWEEN_RESULTS75 75
43#define MAX_ROWS_PER_RESULT15 15
44
45////////////////////////////////////////////////////////////////////////////////
46//// AsyncExecuteStatements
47
48/* static */
49nsresult AsyncExecuteStatements::execute(
50 StatementDataArray&& aStatements, Connection* aConnection,
51 sqlite3* aNativeConnection, mozIStorageStatementCallback* aCallback,
52 mozIStoragePendingStatement** _stmt) {
53 // Create our event to run in the background
54 RefPtr<AsyncExecuteStatements> event = new AsyncExecuteStatements(
55 std::move(aStatements), aConnection, aNativeConnection, aCallback);
56 NS_ENSURE_TRUE(event, NS_ERROR_OUT_OF_MEMORY)do { if ((__builtin_expect(!!(!(event)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "event" ") failed", nullptr
, "/var/lib/jenkins/workspace/firefox-scan-build/storage/mozStorageAsyncStatementExecution.cpp"
, 56); return NS_ERROR_OUT_OF_MEMORY; } } while (false)
;
57
58 // Dispatch it to the background
59 nsIEventTarget* target = aConnection->getAsyncExecutionTarget();
60
61 // If we don't have a valid target, this is a bug somewhere else. In the past,
62 // this assert found cases where a Run method would schedule a new statement
63 // without checking if asyncClose had been called. The caller must prevent
64 // that from happening or, if the work is not critical, just avoid creating
65 // the new statement during shutdown. See bug 718449 for an example.
66 MOZ_ASSERT(target)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(target)>::isValid, "invalid assertion condition")
; if ((__builtin_expect(!!(!(!!(target))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("target", "/var/lib/jenkins/workspace/firefox-scan-build/storage/mozStorageAsyncStatementExecution.cpp"
, 66); AnnotateMozCrashReason("MOZ_ASSERT" "(" "target" ")");
do { *((volatile int*)__null) = 66; __attribute__((nomerge))
::abort(); } while (false); } } while (false)
;
67 if (!target) {
68 return NS_ERROR_NOT_AVAILABLE;
69 }
70
71 nsresult rv = target->Dispatch(event, NS_DISPATCH_NORMALnsIEventTarget::DISPATCH_NORMAL);
72 NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/storage/mozStorageAsyncStatementExecution.cpp"
, 72); return rv; } } while (false)
;
73
74 // Return it as the pending statement object and track it.
75 event.forget(_stmt);
76 return NS_OK;
77}
78
79AsyncExecuteStatements::AsyncExecuteStatements(
80 StatementDataArray&& aStatements, Connection* aConnection,
81 sqlite3* aNativeConnection, mozIStorageStatementCallback* aCallback)
82 : Runnable("AsyncExecuteStatements"),
83 mStatements(std::move(aStatements)),
84 mConnection(aConnection),
85 mNativeConnection(aNativeConnection),
86 mHasTransaction(false),
87 mCallback(aCallback),
88 mCallingThread(::do_GetCurrentThread()),
89 mMaxWait(
90 TimeDuration::FromMilliseconds(MAX_MILLISECONDS_BETWEEN_RESULTS75)),
91 mIntervalStart(TimeStamp::Now()),
92 mState(PENDING),
93 mCancelRequested(false),
94 mMutex(aConnection->sharedAsyncExecutionMutex),
95 mDBMutex(aConnection->sharedDBMutex) {
96 NS_ASSERTION(mStatements.Length(), "We weren't given any statements!")do { if (!(mStatements.Length())) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "We weren't given any statements!", "mStatements.Length()",
"/var/lib/jenkins/workspace/firefox-scan-build/storage/mozStorageAsyncStatementExecution.cpp"
, 96); MOZ_PretendNoReturn(); } } while (0)
;
97}
98
99AsyncExecuteStatements::~AsyncExecuteStatements() {
100 MOZ_ASSERT(!mCallback, "Never called the Completion callback!")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!mCallback)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!mCallback))), 0))) { do { }
while (false); MOZ_ReportAssertionFailure("!mCallback" " (" "Never called the Completion callback!"
")", "/var/lib/jenkins/workspace/firefox-scan-build/storage/mozStorageAsyncStatementExecution.cpp"
, 100); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!mCallback" ") ("
"Never called the Completion callback!" ")"); do { *((volatile
int*)__null) = 100; __attribute__((nomerge)) ::abort(); } while
(false); } } while (false)
;
101 MOZ_ASSERT(!mHasTransaction, "There should be no transaction at this point")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!mHasTransaction)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!mHasTransaction))), 0))) { do
{ } while (false); MOZ_ReportAssertionFailure("!mHasTransaction"
" (" "There should be no transaction at this point" ")", "/var/lib/jenkins/workspace/firefox-scan-build/storage/mozStorageAsyncStatementExecution.cpp"
, 101); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!mHasTransaction"
") (" "There should be no transaction at this point" ")"); do
{ *((volatile int*)__null) = 101; __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
;
102 if (mCallback) {
103 NS_ProxyRelease("AsyncExecuteStatements::mCallback", mCallingThread,
104 mCallback.forget());
105 }
106}
107
108bool AsyncExecuteStatements::shouldNotify() {
109#ifdef DEBUG1
110 mMutex.AssertNotCurrentThreadOwns();
111
112 bool onCallingThread = false;
113 (void)mCallingThread->IsOnCurrentThread(&onCallingThread);
114 NS_ASSERTION(onCallingThread, "runEvent not running on the calling thread!")do { if (!(onCallingThread)) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "runEvent not running on the calling thread!", "onCallingThread"
, "/var/lib/jenkins/workspace/firefox-scan-build/storage/mozStorageAsyncStatementExecution.cpp"
, 114); MOZ_PretendNoReturn(); } } while (0)
;
115#endif
116
117 // We do not need to acquire mMutex here because it can only ever be written
118 // to on the calling thread, and the only thread that can call us is the
119 // calling thread, so we know that our access is serialized.
120 return !mCancelRequested;
121}
122
123bool AsyncExecuteStatements::bindExecuteAndProcessStatement(
124 StatementData& aData, bool aLastStatement) {
125 mMutex.AssertNotCurrentThreadOwns();
126
127 sqlite3_stmt* aStatement = nullptr;
128 // This cannot fail; we are only called if it's available.
129 Unused << aData.getSqliteStatement(&aStatement);
130 MOZ_DIAGNOSTIC_ASSERT(do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aStatement)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aStatement))), 0))) { do { }
while (false); MOZ_ReportAssertionFailure("aStatement" " (" "bindExecuteAndProcessStatement called without an initialized statement"
")", "/var/lib/jenkins/workspace/firefox-scan-build/storage/mozStorageAsyncStatementExecution.cpp"
, 132); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "aStatement"
") (" "bindExecuteAndProcessStatement called without an initialized statement"
")"); do { *((volatile int*)__null) = 132; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
131 aStatement,do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aStatement)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aStatement))), 0))) { do { }
while (false); MOZ_ReportAssertionFailure("aStatement" " (" "bindExecuteAndProcessStatement called without an initialized statement"
")", "/var/lib/jenkins/workspace/firefox-scan-build/storage/mozStorageAsyncStatementExecution.cpp"
, 132); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "aStatement"
") (" "bindExecuteAndProcessStatement called without an initialized statement"
")"); do { *((volatile int*)__null) = 132; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
132 "bindExecuteAndProcessStatement called without an initialized statement")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aStatement)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aStatement))), 0))) { do { }
while (false); MOZ_ReportAssertionFailure("aStatement" " (" "bindExecuteAndProcessStatement called without an initialized statement"
")", "/var/lib/jenkins/workspace/firefox-scan-build/storage/mozStorageAsyncStatementExecution.cpp"
, 132); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "aStatement"
") (" "bindExecuteAndProcessStatement called without an initialized statement"
")"); do { *((volatile int*)__null) = 132; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
133 BindingParamsArray* paramsArray(aData);
134
135 // Iterate through all of our parameters, bind them, and execute.
136 bool continueProcessing = true;
137 BindingParamsArray::iterator itr = paramsArray->begin();
138 BindingParamsArray::iterator end = paramsArray->end();
139 while (itr != end && continueProcessing) {
140 // Bind the data to our statement.
141 nsCOMPtr<IStorageBindingParamsInternal> bindingInternal =
142 do_QueryInterface(*itr);
143 nsCOMPtr<mozIStorageError> error = bindingInternal->bind(aStatement);
144 if (error) {
145 // Set our error state.
146 mState = ERROR;
147
148 // And notify.
149 (void)notifyError(error);
150 return false;
151 }
152
153 // Advance our iterator, execute, and then process the statement.
154 itr++;
155 bool lastStatement = aLastStatement && itr == end;
156 continueProcessing = executeAndProcessStatement(aData, lastStatement);
157
158 // Always reset our statement.
159 (void)::sqlite3_reset(aStatement);
160 }
161
162 return continueProcessing;
163}
164
165bool AsyncExecuteStatements::executeAndProcessStatement(StatementData& aData,
166 bool aLastStatement) {
167 mMutex.AssertNotCurrentThreadOwns();
168
169 sqlite3_stmt* aStatement = nullptr;
170 // This cannot fail; we are only called if it's available.
171 Unused << aData.getSqliteStatement(&aStatement);
172 MOZ_DIAGNOSTIC_ASSERT(do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aStatement)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aStatement))), 0))) { do { }
while (false); MOZ_ReportAssertionFailure("aStatement" " (" "executeAndProcessStatement called without an initialized statement"
")", "/var/lib/jenkins/workspace/firefox-scan-build/storage/mozStorageAsyncStatementExecution.cpp"
, 174); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "aStatement"
") (" "executeAndProcessStatement called without an initialized statement"
")"); do { *((volatile int*)__null) = 174; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
173 aStatement,do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aStatement)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aStatement))), 0))) { do { }
while (false); MOZ_ReportAssertionFailure("aStatement" " (" "executeAndProcessStatement called without an initialized statement"
")", "/var/lib/jenkins/workspace/firefox-scan-build/storage/mozStorageAsyncStatementExecution.cpp"
, 174); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "aStatement"
") (" "executeAndProcessStatement called without an initialized statement"
")"); do { *((volatile int*)__null) = 174; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
174 "executeAndProcessStatement called without an initialized statement")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aStatement)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aStatement))), 0))) { do { }
while (false); MOZ_ReportAssertionFailure("aStatement" " (" "executeAndProcessStatement called without an initialized statement"
")", "/var/lib/jenkins/workspace/firefox-scan-build/storage/mozStorageAsyncStatementExecution.cpp"
, 174); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "aStatement"
") (" "executeAndProcessStatement called without an initialized statement"
")"); do { *((volatile int*)__null) = 174; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
175
176 // Execute our statement
177 bool hasResults;
178 do {
179 hasResults = executeStatement(aData);
180
181 // If we had an error, bail.
182 if (mState == ERROR || mState == CANCELED) return false;
183
184 // If we have been canceled, there is no point in going on...
185 {
186 MutexAutoLock lockedScope(mMutex);
187 if (mCancelRequested) {
188 mState = CANCELED;
189 return false;
190 }
191 }
192
193 // Build our result set and notify if we got anything back and have a
194 // callback to notify.
195 if (mCallback && hasResults &&
196 NS_FAILED(buildAndNotifyResults(aStatement))((bool)(__builtin_expect(!!(NS_FAILED_impl(buildAndNotifyResults
(aStatement))), 0)))
) {
197 // We had an error notifying, so we notify on error and stop processing.
198 mState = ERROR;
199
200 // Notify, and stop processing statements.
201 (void)notifyError(mozIStorageError::ERROR,
202 "An error occurred while notifying about results");
203
204 return false;
205 }
206 } while (hasResults);
207
208#ifndef MOZ_STORAGE_SORTWARNING_SQL_DUMP
209 if (MOZ_LOG_TEST(gStorageLog, LogLevel::Warning)(__builtin_expect(!!(mozilla::detail::log_test(gStorageLog, LogLevel
::Warning)), 0))
)
210#endif
211 {
212 // Check to make sure that this statement was smart about what it did.
213 checkAndLogStatementPerformance(aStatement);
214 }
215
216 // If we are done, we need to set our state accordingly while we still hold
217 // our mutex. We would have already returned if we were canceled or had
218 // an error at this point.
219 if (aLastStatement) mState = COMPLETED;
220
221 return true;
222}
223
224bool AsyncExecuteStatements::executeStatement(StatementData& aData) {
225 mMutex.AssertNotCurrentThreadOwns();
226
227 sqlite3_stmt* aStatement = nullptr;
228 // This cannot fail; we are only called if it's available.
229 Unused << aData.getSqliteStatement(&aStatement);
230 MOZ_DIAGNOSTIC_ASSERT(do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aStatement)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aStatement))), 0))) { do { }
while (false); MOZ_ReportAssertionFailure("aStatement" " (" "executeStatement called without an initialized statement"
")", "/var/lib/jenkins/workspace/firefox-scan-build/storage/mozStorageAsyncStatementExecution.cpp"
, 231); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "aStatement"
") (" "executeStatement called without an initialized statement"
")"); do { *((volatile int*)__null) = 231; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
231 aStatement, "executeStatement called without an initialized statement")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aStatement)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aStatement))), 0))) { do { }
while (false); MOZ_ReportAssertionFailure("aStatement" " (" "executeStatement called without an initialized statement"
")", "/var/lib/jenkins/workspace/firefox-scan-build/storage/mozStorageAsyncStatementExecution.cpp"
, 231); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "aStatement"
") (" "executeStatement called without an initialized statement"
")"); do { *((volatile int*)__null) = 231; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
232
233 bool busyRetry = false;
234 while (true) {
235 if (busyRetry) {
236 busyRetry = false;
Value stored to 'busyRetry' is never read
237
238 // Yield, and try again
239 Unused << PR_Sleep(PR_INTERVAL_NO_WAIT0UL);
240
241 // Check for cancellation before retrying
242 {
243 MutexAutoLock lockedScope(mMutex);
244 if (mCancelRequested) {
245 mState = CANCELED;
246 return false;
247 }
248 }
249 }
250
251 // lock the sqlite mutex so sqlite3_errmsg cannot change
252 SQLiteMutexAutoLock lockedScope(mDBMutex);
253
254 int rc = mConnection->stepStatement(mNativeConnection, aStatement);
255
256 // Some errors are not fatal, and we can handle them and continue.
257 if (rc == SQLITE_BUSY5) {
258 ::sqlite3_reset(aStatement);
259 busyRetry = true;
260 continue;
261 }
262
263 aData.MaybeRecordQueryStatus(rc);
264
265 // Stop if we have no more results.
266 if (rc == SQLITE_DONE101) {
267 return false;
268 }
269
270 // If we got results, we can return now.
271 if (rc == SQLITE_ROW100) {
272 return true;
273 }
274
275 if (rc == SQLITE_INTERRUPT9) {
276 mState = CANCELED;
277 return false;
278 }
279
280 // Set an error state.
281 mState = ERROR;
282
283 // Construct the error message before giving up the mutex (which we cannot
284 // hold during the call to notifyError).
285 nsCOMPtr<mozIStorageError> errorObj(
286 new Error(rc, ::sqlite3_errmsg(mNativeConnection)));
287 // We cannot hold the DB mutex while calling notifyError.
288 SQLiteMutexAutoUnlock unlockedScope(mDBMutex);
289 (void)notifyError(errorObj);
290
291 // Finally, indicate that we should stop processing.
292 return false;
293 }
294}
295
296nsresult AsyncExecuteStatements::buildAndNotifyResults(
297 sqlite3_stmt* aStatement) {
298 NS_ASSERTION(mCallback, "Trying to dispatch results without a callback!")do { if (!(mCallback)) { NS_DebugBreak(NS_DEBUG_ASSERTION, "Trying to dispatch results without a callback!"
, "mCallback", "/var/lib/jenkins/workspace/firefox-scan-build/storage/mozStorageAsyncStatementExecution.cpp"
, 298); MOZ_PretendNoReturn(); } } while (0)
;
299 mMutex.AssertNotCurrentThreadOwns();
300
301 // Build result object if we need it.
302 if (!mResultSet) mResultSet = new ResultSet();
303 NS_ENSURE_TRUE(mResultSet, NS_ERROR_OUT_OF_MEMORY)do { if ((__builtin_expect(!!(!(mResultSet)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "mResultSet" ") failed",
nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/storage/mozStorageAsyncStatementExecution.cpp"
, 303); return NS_ERROR_OUT_OF_MEMORY; } } while (false)
;
304
305 RefPtr<Row> row(new Row());
306 NS_ENSURE_TRUE(row, NS_ERROR_OUT_OF_MEMORY)do { if ((__builtin_expect(!!(!(row)), 0))) { NS_DebugBreak(NS_DEBUG_WARNING
, "NS_ENSURE_TRUE(" "row" ") failed", nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/storage/mozStorageAsyncStatementExecution.cpp"
, 306); return NS_ERROR_OUT_OF_MEMORY; } } while (false)
;
307
308 nsresult rv = row->initialize(aStatement);
309 NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/storage/mozStorageAsyncStatementExecution.cpp"
, 309); return rv; } } while (false)
;
310
311 rv = mResultSet->add(row);
312 NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/storage/mozStorageAsyncStatementExecution.cpp"
, 312); return rv; } } while (false)
;
313
314 // If we have hit our maximum number of allowed results, or if we have hit
315 // the maximum amount of time we want to wait for results, notify the
316 // calling thread about it.
317 TimeStamp now = TimeStamp::Now();
318 TimeDuration delta = now - mIntervalStart;
319 if (mResultSet->rows() >= MAX_ROWS_PER_RESULT15 || delta > mMaxWait) {
320 // Notify the caller
321 rv = notifyResults();
322 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) return NS_OK; // we'll try again with the next result
323
324 // Reset our start time
325 mIntervalStart = now;
326 }
327
328 return NS_OK;
329}
330
331nsresult AsyncExecuteStatements::notifyComplete() {
332 mMutex.AssertNotCurrentThreadOwns();
333 NS_ASSERTION(mState != PENDING,do { if (!(mState != PENDING)) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "Still in a pending state when calling Complete!", "mState != PENDING"
, "/var/lib/jenkins/workspace/firefox-scan-build/storage/mozStorageAsyncStatementExecution.cpp"
, 334); MOZ_PretendNoReturn(); } } while (0)
334 "Still in a pending state when calling Complete!")do { if (!(mState != PENDING)) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "Still in a pending state when calling Complete!", "mState != PENDING"
, "/var/lib/jenkins/workspace/firefox-scan-build/storage/mozStorageAsyncStatementExecution.cpp"
, 334); MOZ_PretendNoReturn(); } } while (0)
;
335
336 // Reset our statements before we try to commit or rollback. If we are
337 // canceling and have statements that think they have pending work, the
338 // rollback will fail.
339 for (uint32_t i = 0; i < mStatements.Length(); i++) mStatements[i].reset();
340
341 // Release references to the statement data as soon as possible. If this
342 // is the last reference, statements will be finalized immediately on the
343 // async thread, hence avoiding several bounces between threads and possible
344 // race conditions with AsyncClose().
345 mStatements.Clear();
346
347 // Handle our transaction, if we have one
348 if (mHasTransaction) {
349 SQLiteMutexAutoLock lockedScope(mDBMutex);
350 if (mState == COMPLETED) {
351 nsresult rv = mConnection->commitTransactionInternal(lockedScope,
352 mNativeConnection);
353 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
354 mState = ERROR;
355 // We cannot hold the DB mutex while calling notifyError.
356 SQLiteMutexAutoUnlock unlockedScope(mDBMutex);
357 (void)notifyError(mozIStorageError::ERROR,
358 "Transaction failed to commit");
359 }
360 } else {
361 DebugOnly<nsresult> rv = mConnection->rollbackTransactionInternal(
362 lockedScope, mNativeConnection);
363 NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "Transaction failed to rollback")do { if (!(((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1
))))) { NS_DebugBreak(NS_DEBUG_WARNING, "Transaction failed to rollback"
, "NS_SUCCEEDED(rv)", "/var/lib/jenkins/workspace/firefox-scan-build/storage/mozStorageAsyncStatementExecution.cpp"
, 363); } } while (false)
;
364 }
365 mHasTransaction = false;
366 }
367
368 // This will take ownership of mCallback and make sure its destruction will
369 // happen on the owner thread.
370 Unused << mCallingThread->Dispatch(
371 NewRunnableMethod("AsyncExecuteStatements::notifyCompleteOnCallingThread",
372 this,
373 &AsyncExecuteStatements::notifyCompleteOnCallingThread),
374 NS_DISPATCH_NORMALnsIEventTarget::DISPATCH_NORMAL);
375
376 return NS_OK;
377}
378
379nsresult AsyncExecuteStatements::notifyCompleteOnCallingThread() {
380 MOZ_ASSERT(mCallingThread->IsOnCurrentThread())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mCallingThread->IsOnCurrentThread())>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(mCallingThread->IsOnCurrentThread()))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("mCallingThread->IsOnCurrentThread()"
, "/var/lib/jenkins/workspace/firefox-scan-build/storage/mozStorageAsyncStatementExecution.cpp"
, 380); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mCallingThread->IsOnCurrentThread()"
")"); do { *((volatile int*)__null) = 380; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
381 // Take ownership of mCallback and responsibility for freeing it when we
382 // release it. Any notifyResultsOnCallingThread and
383 // notifyErrorOnCallingThread calls on the stack spinning the event loop have
384 // guaranteed their safety by creating their own strong reference before
385 // invoking the callback.
386 nsCOMPtr<mozIStorageStatementCallback> callback = std::move(mCallback);
387 if (callback) {
388 Unused << callback->HandleCompletion(mState);
389 }
390 return NS_OK;
391}
392
393nsresult AsyncExecuteStatements::notifyError(int32_t aErrorCode,
394 const char* aMessage) {
395 mMutex.AssertNotCurrentThreadOwns();
396 mDBMutex.assertNotCurrentThreadOwns();
397
398 if (!mCallback) return NS_OK;
399
400 nsCOMPtr<mozIStorageError> errorObj(new Error(aErrorCode, aMessage));
401 NS_ENSURE_TRUE(errorObj, NS_ERROR_OUT_OF_MEMORY)do { if ((__builtin_expect(!!(!(errorObj)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "errorObj" ") failed", nullptr
, "/var/lib/jenkins/workspace/firefox-scan-build/storage/mozStorageAsyncStatementExecution.cpp"
, 401); return NS_ERROR_OUT_OF_MEMORY; } } while (false)
;
402
403 return notifyError(errorObj);
404}
405
406nsresult AsyncExecuteStatements::notifyError(mozIStorageError* aError) {
407 mMutex.AssertNotCurrentThreadOwns();
408 mDBMutex.assertNotCurrentThreadOwns();
409
410 if (!mCallback) return NS_OK;
411
412 Unused << mCallingThread->Dispatch(
413 NewRunnableMethod<nsCOMPtr<mozIStorageError>>(
414 "AsyncExecuteStatements::notifyErrorOnCallingThread", this,
415 &AsyncExecuteStatements::notifyErrorOnCallingThread, aError),
416 NS_DISPATCH_NORMALnsIEventTarget::DISPATCH_NORMAL);
417
418 return NS_OK;
419}
420
421nsresult AsyncExecuteStatements::notifyErrorOnCallingThread(
422 mozIStorageError* aError) {
423 MOZ_ASSERT(mCallingThread->IsOnCurrentThread())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mCallingThread->IsOnCurrentThread())>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(mCallingThread->IsOnCurrentThread()))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("mCallingThread->IsOnCurrentThread()"
, "/var/lib/jenkins/workspace/firefox-scan-build/storage/mozStorageAsyncStatementExecution.cpp"
, 423); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mCallingThread->IsOnCurrentThread()"
")"); do { *((volatile int*)__null) = 423; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
424 // Acquire our own strong reference so that if the callback spins a nested
425 // event loop and notifyCompleteOnCallingThread is executed, forgetting
426 // mCallback, we still have a valid/strong reference that won't be freed until
427 // we exit.
428 nsCOMPtr<mozIStorageStatementCallback> callback = mCallback;
429 if (shouldNotify() && callback) {
430 Unused << callback->HandleError(aError);
431 }
432 return NS_OK;
433}
434
435nsresult AsyncExecuteStatements::notifyResults() {
436 mMutex.AssertNotCurrentThreadOwns();
437 MOZ_ASSERT(mCallback, "notifyResults called without a callback!")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mCallback)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mCallback))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("mCallback" " (" "notifyResults called without a callback!"
")", "/var/lib/jenkins/workspace/firefox-scan-build/storage/mozStorageAsyncStatementExecution.cpp"
, 437); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mCallback" ") ("
"notifyResults called without a callback!" ")"); do { *((volatile
int*)__null) = 437; __attribute__((nomerge)) ::abort(); } while
(false); } } while (false)
;
438
439 // This takes ownership of mResultSet, a new one will be generated in
440 // buildAndNotifyResults() when further results will arrive.
441 Unused << mCallingThread->Dispatch(
442 NewRunnableMethod<RefPtr<ResultSet>>(
443 "AsyncExecuteStatements::notifyResultsOnCallingThread", this,
444 &AsyncExecuteStatements::notifyResultsOnCallingThread,
445 mResultSet.forget()),
446 NS_DISPATCH_NORMALnsIEventTarget::DISPATCH_NORMAL);
447
448 return NS_OK;
449}
450
451nsresult AsyncExecuteStatements::notifyResultsOnCallingThread(
452 ResultSet* aResultSet) {
453 MOZ_ASSERT(mCallingThread->IsOnCurrentThread())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mCallingThread->IsOnCurrentThread())>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(mCallingThread->IsOnCurrentThread()))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("mCallingThread->IsOnCurrentThread()"
, "/var/lib/jenkins/workspace/firefox-scan-build/storage/mozStorageAsyncStatementExecution.cpp"
, 453); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mCallingThread->IsOnCurrentThread()"
")"); do { *((volatile int*)__null) = 453; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
454 // Acquire our own strong reference so that if the callback spins a nested
455 // event loop and notifyCompleteOnCallingThread is executed, forgetting
456 // mCallback, we still have a valid/strong reference that won't be freed until
457 // we exit.
458 nsCOMPtr<mozIStorageStatementCallback> callback = mCallback;
459 if (shouldNotify() && callback) {
460 Unused << callback->HandleResult(aResultSet);
461 }
462 return NS_OK;
463}
464
465NS_IMPL_ISUPPORTS_INHERITED(AsyncExecuteStatements, Runnable,nsresult AsyncExecuteStatements::QueryInterface(const nsIID&
aIID, void** aInstancePtr) { do { if (!(aInstancePtr)) { NS_DebugBreak
(NS_DEBUG_ASSERTION, "QueryInterface requires a non-NULL destination!"
, "aInstancePtr", "/var/lib/jenkins/workspace/firefox-scan-build/storage/mozStorageAsyncStatementExecution.cpp"
, 466); MOZ_PretendNoReturn(); } } while (0); nsresult rv = NS_ERROR_FAILURE
; static_assert(1 > 0, "Need more arguments to NS_INTERFACE_TABLE_INHERITED"
); static const QITableEntry table[] = { {&mozilla::detail
::kImplementedIID<AsyncExecuteStatements, mozIStoragePendingStatement
>, int32_t( reinterpret_cast<char*>(static_cast<mozIStoragePendingStatement
*>((AsyncExecuteStatements*)0x1000)) - reinterpret_cast<
char*>((AsyncExecuteStatements*)0x1000))}, { nullptr, 0 } }
; static_assert((sizeof(table) / sizeof(table[0])) > 1, "need at least 1 interface"
); rv = NS_TableDrivenQI(static_cast<void*>(this), aIID
, aInstancePtr, table); if (((bool)(__builtin_expect(!!(!NS_FAILED_impl
(rv)), 1)))) return rv; return Runnable::QueryInterface(aIID,
aInstancePtr); } MozExternalRefCountType AsyncExecuteStatements
::AddRef(void) { static_assert(!std::is_destructible_v<AsyncExecuteStatements
>, "Reference-counted class " "AsyncExecuteStatements" " should not have a public destructor. "
"Make this class's destructor non-public"); nsrefcnt r = Runnable
::AddRef(); if constexpr (::mozilla::detail::ShouldLogInheritedRefcnt
<AsyncExecuteStatements>) { NS_LogAddRef((this), (r), (
"AsyncExecuteStatements"), (uint32_t)(sizeof(*this))); } return
r; } MozExternalRefCountType AsyncExecuteStatements::Release
(void) { nsrefcnt r = Runnable::Release(); if constexpr (::mozilla
::detail::ShouldLogInheritedRefcnt<AsyncExecuteStatements>
) { NS_LogRelease((this), (r), ("AsyncExecuteStatements")); }
return r; }
466 mozIStoragePendingStatement)nsresult AsyncExecuteStatements::QueryInterface(const nsIID&
aIID, void** aInstancePtr) { do { if (!(aInstancePtr)) { NS_DebugBreak
(NS_DEBUG_ASSERTION, "QueryInterface requires a non-NULL destination!"
, "aInstancePtr", "/var/lib/jenkins/workspace/firefox-scan-build/storage/mozStorageAsyncStatementExecution.cpp"
, 466); MOZ_PretendNoReturn(); } } while (0); nsresult rv = NS_ERROR_FAILURE
; static_assert(1 > 0, "Need more arguments to NS_INTERFACE_TABLE_INHERITED"
); static const QITableEntry table[] = { {&mozilla::detail
::kImplementedIID<AsyncExecuteStatements, mozIStoragePendingStatement
>, int32_t( reinterpret_cast<char*>(static_cast<mozIStoragePendingStatement
*>((AsyncExecuteStatements*)0x1000)) - reinterpret_cast<
char*>((AsyncExecuteStatements*)0x1000))}, { nullptr, 0 } }
; static_assert((sizeof(table) / sizeof(table[0])) > 1, "need at least 1 interface"
); rv = NS_TableDrivenQI(static_cast<void*>(this), aIID
, aInstancePtr, table); if (((bool)(__builtin_expect(!!(!NS_FAILED_impl
(rv)), 1)))) return rv; return Runnable::QueryInterface(aIID,
aInstancePtr); } MozExternalRefCountType AsyncExecuteStatements
::AddRef(void) { static_assert(!std::is_destructible_v<AsyncExecuteStatements
>, "Reference-counted class " "AsyncExecuteStatements" " should not have a public destructor. "
"Make this class's destructor non-public"); nsrefcnt r = Runnable
::AddRef(); if constexpr (::mozilla::detail::ShouldLogInheritedRefcnt
<AsyncExecuteStatements>) { NS_LogAddRef((this), (r), (
"AsyncExecuteStatements"), (uint32_t)(sizeof(*this))); } return
r; } MozExternalRefCountType AsyncExecuteStatements::Release
(void) { nsrefcnt r = Runnable::Release(); if constexpr (::mozilla
::detail::ShouldLogInheritedRefcnt<AsyncExecuteStatements>
) { NS_LogRelease((this), (r), ("AsyncExecuteStatements")); }
return r; }
467
468bool AsyncExecuteStatements::statementsNeedTransaction() {
469 // If there is more than one write statement, run in a transaction.
470 // Additionally, if we have only one statement but it needs a transaction, due
471 // to multiple BindingParams, we will wrap it in one.
472 for (uint32_t i = 0, transactionsCount = 0; i < mStatements.Length(); ++i) {
473 transactionsCount += mStatements[i].needsTransaction();
474 if (transactionsCount > 1) {
475 return true;
476 }
477 }
478 return false;
479}
480
481////////////////////////////////////////////////////////////////////////////////
482//// mozIStoragePendingStatement
483
484NS_IMETHODIMPnsresult
485AsyncExecuteStatements::Cancel() {
486#ifdef DEBUG1
487 bool onCallingThread = false;
488 (void)mCallingThread->IsOnCurrentThread(&onCallingThread);
489 NS_ASSERTION(onCallingThread, "Not canceling from the calling thread!")do { if (!(onCallingThread)) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "Not canceling from the calling thread!", "onCallingThread"
, "/var/lib/jenkins/workspace/firefox-scan-build/storage/mozStorageAsyncStatementExecution.cpp"
, 489); MOZ_PretendNoReturn(); } } while (0)
;
490#endif
491
492 // If we have already canceled, we have an error, but always indicate that
493 // we are trying to cancel.
494 NS_ENSURE_FALSE(mCancelRequested, NS_ERROR_UNEXPECTED)do { if ((__builtin_expect(!!(!(!(mCancelRequested))), 0))) {
NS_DebugBreak(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "!(mCancelRequested)"
") failed", nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/storage/mozStorageAsyncStatementExecution.cpp"
, 494); return NS_ERROR_UNEXPECTED; } } while (false)
;
495
496 {
497 MutexAutoLock lockedScope(mMutex);
498
499 // We need to indicate that we want to try and cancel now.
500 mCancelRequested = true;
501 }
502
503 return NS_OK;
504}
505
506////////////////////////////////////////////////////////////////////////////////
507//// nsIRunnable
508
509NS_IMETHODIMPnsresult
510AsyncExecuteStatements::Run() {
511 MOZ_ASSERT(mConnection->isConnectionReadyOnThisThread())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mConnection->isConnectionReadyOnThisThread())>
::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(mConnection->isConnectionReadyOnThisThread()))), 0
))) { do { } while (false); MOZ_ReportAssertionFailure("mConnection->isConnectionReadyOnThisThread()"
, "/var/lib/jenkins/workspace/firefox-scan-build/storage/mozStorageAsyncStatementExecution.cpp"
, 511); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mConnection->isConnectionReadyOnThisThread()"
")"); do { *((volatile int*)__null) = 511; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
512
513 // Do not run if we have been canceled.
514 {
515 MutexAutoLock lockedScope(mMutex);
516 if (mCancelRequested) mState = CANCELED;
517 }
518 if (mState == CANCELED) return notifyComplete();
519
520 if (statementsNeedTransaction()) {
521 SQLiteMutexAutoLock lockedScope(mDBMutex);
522 if (!mConnection->transactionInProgress(lockedScope)) {
523 if (NS_SUCCEEDED(mConnection->beginTransactionInternal(((bool)(__builtin_expect(!!(!NS_FAILED_impl(mConnection->beginTransactionInternal
( lockedScope, mNativeConnection, mozIStorageConnection::TRANSACTION_IMMEDIATE
))), 1)))
524 lockedScope, mNativeConnection,((bool)(__builtin_expect(!!(!NS_FAILED_impl(mConnection->beginTransactionInternal
( lockedScope, mNativeConnection, mozIStorageConnection::TRANSACTION_IMMEDIATE
))), 1)))
525 mozIStorageConnection::TRANSACTION_IMMEDIATE))((bool)(__builtin_expect(!!(!NS_FAILED_impl(mConnection->beginTransactionInternal
( lockedScope, mNativeConnection, mozIStorageConnection::TRANSACTION_IMMEDIATE
))), 1)))
) {
526 mHasTransaction = true;
527 }
528#ifdef DEBUG1
529 else {
530 NS_WARNING("Unable to create a transaction for async execution.")NS_DebugBreak(NS_DEBUG_WARNING, "Unable to create a transaction for async execution."
, nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/storage/mozStorageAsyncStatementExecution.cpp"
, 530)
;
531 }
532#endif
533 }
534 }
535
536 // Execute each statement, giving the callback results if it returns any.
537 for (uint32_t i = 0; i < mStatements.Length(); i++) {
538 bool finished = (i == (mStatements.Length() - 1));
539
540 sqlite3_stmt* stmt;
541 { // lock the sqlite mutex so sqlite3_errmsg cannot change
542 SQLiteMutexAutoLock lockedScope(mDBMutex);
543
544 int rc = mStatements[i].getSqliteStatement(&stmt);
545 if (rc != SQLITE_OK0) {
546 // Set our error state.
547 mState = ERROR;
548
549 // Build the error object; can't call notifyError with the lock held
550 nsCOMPtr<mozIStorageError> errorObj(
551 new Error(rc, ::sqlite3_errmsg(mNativeConnection)));
552 {
553 // We cannot hold the DB mutex and call notifyError.
554 SQLiteMutexAutoUnlock unlockedScope(mDBMutex);
555 (void)notifyError(errorObj);
556 }
557 break;
558 }
559 }
560
561 // If we have parameters to bind, bind them, execute, and process.
562 if (mStatements[i].hasParametersToBeBound()) {
563 if (!bindExecuteAndProcessStatement(mStatements[i], finished)) break;
564 }
565 // Otherwise, just execute and process the statement.
566 else if (!executeAndProcessStatement(mStatements[i], finished)) {
567 break;
568 }
569 }
570
571 // If we still have results that we haven't notified about, take care of
572 // them now.
573 if (mResultSet) (void)notifyResults();
574
575 // Notify about completion
576 return notifyComplete();
577}
578
579} // namespace storage
580} // namespace mozilla