| File: | var/lib/jenkins/workspace/firefox-scan-build/storage/mozStorageAsyncStatementExecution.cpp |
| Warning: | line 236, column 7 Value stored to 'busyRetry' is never read |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
| 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" |
| 25 | extern mozilla::LazyLogModule gStorageLog; |
| 26 | #endif |
| 27 | |
| 28 | namespace mozilla { |
| 29 | namespace 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 */ |
| 49 | nsresult 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 | |
| 79 | AsyncExecuteStatements::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 | |
| 99 | AsyncExecuteStatements::~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 | |
| 108 | bool 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 | |
| 123 | bool 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 | |
| 165 | bool 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 | |
| 224 | bool 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 | |
| 296 | nsresult 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 | |
| 331 | nsresult 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 | |
| 379 | nsresult 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 | |
| 393 | nsresult 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 | |
| 406 | nsresult 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 | |
| 421 | nsresult 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 | |
| 435 | nsresult 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 | |
| 451 | nsresult 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 | |
| 465 | NS_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(std::size(table) > 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(std::size(table) > 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 | |
| 468 | bool 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 | |
| 484 | NS_IMETHODIMPnsresult |
| 485 | AsyncExecuteStatements::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 | |
| 509 | NS_IMETHODIMPnsresult |
| 510 | AsyncExecuteStatements::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 |