michael@0: /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- michael@0: * vim: sw=2 ts=2 et lcs=trail\:.,tab\:>~ : michael@0: * This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #include "sqlite3.h" michael@0: michael@0: #include "jsfriendapi.h" michael@0: michael@0: #include "nsPrintfCString.h" michael@0: #include "nsString.h" michael@0: #include "nsError.h" michael@0: #include "mozilla/Mutex.h" michael@0: #include "mozilla/CondVar.h" michael@0: #include "nsThreadUtils.h" michael@0: #include "nsJSUtils.h" michael@0: michael@0: #include "Variant.h" michael@0: #include "mozStoragePrivateHelpers.h" michael@0: #include "mozIStorageStatement.h" michael@0: #include "mozIStorageCompletionCallback.h" michael@0: #include "mozIStorageBindingParams.h" michael@0: michael@0: #include "prlog.h" michael@0: #ifdef PR_LOGGING michael@0: extern PRLogModuleInfo* gStorageLog; michael@0: #endif michael@0: michael@0: namespace mozilla { michael@0: namespace storage { michael@0: michael@0: nsresult michael@0: convertResultCode(int aSQLiteResultCode) michael@0: { michael@0: // Drop off the extended result bits of the result code. michael@0: int rc = aSQLiteResultCode & 0xFF; michael@0: michael@0: switch (rc) { michael@0: case SQLITE_OK: michael@0: case SQLITE_ROW: michael@0: case SQLITE_DONE: michael@0: return NS_OK; michael@0: case SQLITE_CORRUPT: michael@0: case SQLITE_NOTADB: michael@0: return NS_ERROR_FILE_CORRUPTED; michael@0: case SQLITE_PERM: michael@0: case SQLITE_CANTOPEN: michael@0: return NS_ERROR_FILE_ACCESS_DENIED; michael@0: case SQLITE_BUSY: michael@0: return NS_ERROR_STORAGE_BUSY; michael@0: case SQLITE_LOCKED: michael@0: return NS_ERROR_FILE_IS_LOCKED; michael@0: case SQLITE_READONLY: michael@0: return NS_ERROR_FILE_READ_ONLY; michael@0: case SQLITE_IOERR: michael@0: return NS_ERROR_STORAGE_IOERR; michael@0: case SQLITE_FULL: michael@0: case SQLITE_TOOBIG: michael@0: return NS_ERROR_FILE_NO_DEVICE_SPACE; michael@0: case SQLITE_NOMEM: michael@0: return NS_ERROR_OUT_OF_MEMORY; michael@0: case SQLITE_MISUSE: michael@0: return NS_ERROR_UNEXPECTED; michael@0: case SQLITE_ABORT: michael@0: case SQLITE_INTERRUPT: michael@0: return NS_ERROR_ABORT; michael@0: case SQLITE_CONSTRAINT: michael@0: return NS_ERROR_STORAGE_CONSTRAINT; michael@0: } michael@0: michael@0: // generic error michael@0: #ifdef DEBUG michael@0: nsAutoCString message; michael@0: message.AppendLiteral("SQLite returned error code "); michael@0: message.AppendInt(rc); michael@0: message.AppendLiteral(" , Storage will convert it to NS_ERROR_FAILURE"); michael@0: NS_WARNING(message.get()); michael@0: #endif michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: michael@0: void michael@0: checkAndLogStatementPerformance(sqlite3_stmt *aStatement) michael@0: { michael@0: // Check to see if the query performed sorting operations or not. If it michael@0: // did, it may need to be optimized! michael@0: int count = ::sqlite3_stmt_status(aStatement, SQLITE_STMTSTATUS_SORT, 1); michael@0: if (count <= 0) michael@0: return; michael@0: michael@0: const char *sql = ::sqlite3_sql(aStatement); michael@0: michael@0: // Check to see if this is marked to not warn michael@0: if (::strstr(sql, "/* do not warn (bug ")) michael@0: return; michael@0: michael@0: nsAutoCString message; michael@0: message.AppendInt(count); michael@0: if (count == 1) michael@0: message.Append(" sort operation has "); michael@0: else michael@0: message.Append(" sort operations have "); michael@0: message.Append("occurred for the SQL statement '"); michael@0: nsPrintfCString address("0x%p", aStatement); michael@0: message.Append(address); michael@0: message.Append("'. See https://developer.mozilla.org/En/Storage/Warnings " michael@0: "details."); michael@0: NS_WARNING(message.get()); michael@0: } michael@0: michael@0: nsIVariant * michael@0: convertJSValToVariant( michael@0: JSContext *aCtx, michael@0: JS::Value aValue) michael@0: { michael@0: if (aValue.isInt32()) michael@0: return new IntegerVariant(aValue.toInt32()); michael@0: michael@0: if (aValue.isDouble()) michael@0: return new FloatVariant(aValue.toDouble()); michael@0: michael@0: if (aValue.isString()) { michael@0: nsDependentJSString value; michael@0: if (!value.init(aCtx, aValue)) michael@0: return nullptr; michael@0: return new TextVariant(value); michael@0: } michael@0: michael@0: if (aValue.isBoolean()) michael@0: return new IntegerVariant(aValue.isTrue() ? 1 : 0); michael@0: michael@0: if (aValue.isNull()) michael@0: return new NullVariant(); michael@0: michael@0: if (aValue.isObject()) { michael@0: JSObject* obj = &aValue.toObject(); michael@0: // We only support Date instances, all others fail. michael@0: if (!::js_DateIsValid(obj)) michael@0: return nullptr; michael@0: michael@0: double msecd = ::js_DateGetMsecSinceEpoch(obj); michael@0: msecd *= 1000.0; michael@0: int64_t msec = msecd; michael@0: michael@0: return new IntegerVariant(msec); michael@0: } michael@0: michael@0: return nullptr; michael@0: } michael@0: michael@0: namespace { michael@0: class CallbackEvent : public nsRunnable michael@0: { michael@0: public: michael@0: CallbackEvent(mozIStorageCompletionCallback *aCallback) michael@0: : mCallback(aCallback) michael@0: { michael@0: } michael@0: michael@0: NS_IMETHOD Run() michael@0: { michael@0: (void)mCallback->Complete(NS_OK, nullptr); michael@0: return NS_OK; michael@0: } michael@0: private: michael@0: nsCOMPtr mCallback; michael@0: }; michael@0: } // anonymous namespace michael@0: already_AddRefed michael@0: newCompletionEvent(mozIStorageCompletionCallback *aCallback) michael@0: { michael@0: NS_ASSERTION(aCallback, "Passing a null callback is a no-no!"); michael@0: nsCOMPtr event = new CallbackEvent(aCallback); michael@0: return event.forget(); michael@0: } michael@0: michael@0: michael@0: michael@0: } // namespace storage michael@0: } // namespace mozilla