bool AsyncExecuteStatements::executeStatement(sqlite3_stmt *aStatement) { mMutex.AssertNotCurrentThreadOwns(); while (true) { // lock the sqlite mutex so sqlite3_errmsg cannot change SQLiteMutexAutoLock lockedScope(mDBMutex); int rc = stepStmt(aStatement); // Stop if we have no more results. if (rc == SQLITE_DONE) return false; // If we got results, we can return now. if (rc == SQLITE_ROW) return true; // Some errors are not fatal, and we can handle them and continue. if (rc == SQLITE_BUSY) { // Don't hold the lock while we call outside our module. SQLiteMutexAutoUnlock unlockedScope(mDBMutex); // Yield, and try again (void)::PR_Sleep(PR_INTERVAL_NO_WAIT); continue; } // Set an error state. mState = ERROR; // Construct the error message before giving up the mutex (which we cannot // hold during the call to notifyError). sqlite3 *db = mConnection->GetNativeConnection(); nsCOMPtr<mozIStorageError> errorObj(new Error(rc, ::sqlite3_errmsg(db))); // We cannot hold the DB mutex while calling notifyError. SQLiteMutexAutoUnlock unlockedScope(mDBMutex); (void)notifyError(errorObj); // Finally, indicate that we should stop processing. return false; } }
nsresult Connection::databaseElementExists(enum DatabaseElementType aElementType, const nsACString &aElementName, PRBool *_exists) { if (!mDBConn) return NS_ERROR_NOT_INITIALIZED; nsCAutoString query("SELECT name FROM sqlite_master WHERE type = '"); switch (aElementType) { case INDEX: query.Append("index"); break; case TABLE: query.Append("table"); break; } query.Append("' AND name ='"); query.Append(aElementName); query.Append("'"); sqlite3_stmt *stmt; int srv = prepareStmt(mDBConn, query, &stmt); if (srv != SQLITE_OK) return convertResultCode(srv); srv = stepStmt(stmt); // we just care about the return value from step (void)::sqlite3_finalize(stmt); if (srv == SQLITE_ROW) { *_exists = PR_TRUE; return NS_OK; } if (srv == SQLITE_DONE) { *_exists = PR_FALSE; return NS_OK; } return convertResultCode(srv); }
NS_IMETHODIMP Statement::ExecuteStep(PRBool *_moreResults) { if (!mDBStatement) return NS_ERROR_NOT_INITIALIZED; NS_TIME_FUNCTION_MIN_FMT(5, "mozIStorageStatement::ExecuteStep(%s) (0x%p)", mDBConnection->getFilename().get(), mDBStatement); // Bind any parameters first before executing. if (mParamsArray) { // If we have more than one row of parameters to bind, they shouldn't be // calling this method (and instead use executeAsync). if (mParamsArray->length() != 1) return NS_ERROR_UNEXPECTED; BindingParamsArray::iterator row = mParamsArray->begin(); nsCOMPtr<IStorageBindingParamsInternal> bindingInternal = do_QueryInterface(*row); nsCOMPtr<mozIStorageError> error = bindingInternal->bind(mDBStatement); if (error) { PRInt32 srv; (void)error->GetResult(&srv); return convertResultCode(srv); } // We have bound, so now we can clear our array. mParamsArray = nsnull; } int srv = stepStmt(mDBStatement); #ifdef PR_LOGGING if (srv != SQLITE_ROW && srv != SQLITE_DONE) { nsCAutoString errStr; (void)mDBConnection->GetLastErrorString(errStr); PR_LOG(gStorageLog, PR_LOG_DEBUG, ("Statement::ExecuteStep error: %s", errStr.get())); } #endif // SQLITE_ROW and SQLITE_DONE are non-errors if (srv == SQLITE_ROW) { // we got a row back mExecuting = true; *_moreResults = PR_TRUE; return NS_OK; } else if (srv == SQLITE_DONE) { // statement is done (no row returned) mExecuting = false; *_moreResults = PR_FALSE; return NS_OK; } else if (srv == SQLITE_BUSY || srv == SQLITE_MISUSE) { mExecuting = PR_FALSE; } else if (mExecuting) { #ifdef PR_LOGGING PR_LOG(gStorageLog, PR_LOG_ERROR, ("SQLite error after mExecuting was true!")); #endif mExecuting = PR_FALSE; } return convertResultCode(srv); }
nsresult Connection::initialize(nsIFile *aDatabaseFile) { NS_ASSERTION (!mDBConn, "Initialize called on already opened database!"); int srv; nsresult rv; mDatabaseFile = aDatabaseFile; if (aDatabaseFile) { nsAutoString path; rv = aDatabaseFile->GetPath(path); NS_ENSURE_SUCCESS(rv, rv); srv = ::sqlite3_open_v2(NS_ConvertUTF16toUTF8(path).get(), &mDBConn, mFlags, NULL); } else { // in memory database requested, sqlite uses a magic file name srv = ::sqlite3_open_v2(":memory:", &mDBConn, mFlags, NULL); } if (srv != SQLITE_OK) { mDBConn = nsnull; return convertResultCode(srv); } // Properly wrap the database handle's mutex. sharedDBMutex.initWithMutex(sqlite3_db_mutex(mDBConn)); #ifdef PR_LOGGING if (!gStorageLog) gStorageLog = ::PR_NewLogModule("mozStorage"); ::sqlite3_trace(mDBConn, tracefunc, this); nsCAutoString leafName(":memory"); if (aDatabaseFile) (void)aDatabaseFile->GetNativeLeafName(leafName); PR_LOG(gStorageLog, PR_LOG_NOTICE, ("Opening connection to '%s' (%p)", leafName.get(), this)); #endif // Switch db to preferred page size in case the user vacuums. sqlite3_stmt *stmt; srv = prepareStmt(mDBConn, NS_LITERAL_CSTRING("PRAGMA page_size = 32768"), &stmt); if (srv == SQLITE_OK) { (void)stepStmt(stmt); (void)::sqlite3_finalize(stmt); } // Register our built-in SQL functions. srv = registerFunctions(mDBConn); if (srv != SQLITE_OK) { ::sqlite3_close(mDBConn); mDBConn = nsnull; return convertResultCode(srv); } // Register our built-in SQL collating sequences. srv = registerCollations(mDBConn, mStorageService); if (srv != SQLITE_OK) { ::sqlite3_close(mDBConn); mDBConn = nsnull; return convertResultCode(srv); } // Execute a dummy statement to force the db open, and to verify if it is // valid or not. srv = prepareStmt(mDBConn, NS_LITERAL_CSTRING("SELECT * FROM sqlite_master"), &stmt); if (srv == SQLITE_OK) { srv = stepStmt(stmt); if (srv == SQLITE_DONE || srv == SQLITE_ROW) srv = SQLITE_OK; ::sqlite3_finalize(stmt); } if (srv != SQLITE_OK) { ::sqlite3_close(mDBConn); mDBConn = nsnull; return convertResultCode(srv); } // Set the synchronous PRAGMA, according to the pref nsCOMPtr<nsIPrefBranch> pref(do_GetService(NS_PREFSERVICE_CONTRACTID)); PRInt32 synchronous = 1; // Default to NORMAL if pref not set if (pref) (void)pref->GetIntPref(PREF_TS_SYNCHRONOUS, &synchronous); switch (synchronous) { case 2: (void)ExecuteSimpleSQL(NS_LITERAL_CSTRING( "PRAGMA synchronous = FULL;")); break; case 0: (void)ExecuteSimpleSQL(NS_LITERAL_CSTRING( "PRAGMA synchronous = OFF;")); break; case 1: default: (void)ExecuteSimpleSQL(NS_LITERAL_CSTRING( "PRAGMA synchronous = NORMAL;")); break; } return NS_OK; }