diff --git a/db/sqlite3/src/sqlite.def b/db/sqlite3/src/sqlite.def index 6467955a298..2e981e91c08 100644 --- a/db/sqlite3/src/sqlite.def +++ b/db/sqlite3/src/sqlite.def @@ -151,6 +151,7 @@ EXPORTS sqlite3_snprintf sqlite3_sql sqlite3_step + sqlite3_stmt_status sqlite3_thread_cleanup sqlite3_total_changes sqlite3_trace diff --git a/storage/src/Makefile.in b/storage/src/Makefile.in index b496c03ee74..f6b3664d837 100644 --- a/storage/src/Makefile.in +++ b/storage/src/Makefile.in @@ -75,6 +75,7 @@ CPPSRCS = \ mozStorageError.cpp \ mozStorageEvents.cpp \ mozStorageStatementJSHelper.cpp \ + mozStoragePrivateHelpers.cpp \ $(NULL) LOCAL_INCLUDES = \ diff --git a/storage/src/mozStorageEvents.cpp b/storage/src/mozStorageEvents.cpp index a49b2b22c32..80fe146e140 100644 --- a/storage/src/mozStorageEvents.cpp +++ b/storage/src/mozStorageEvents.cpp @@ -52,6 +52,7 @@ #include "mozStorageRow.h" #include "mozStorageConnection.h" #include "mozStorageError.h" +#include "mozStoragePrivateHelpers.h" #include "mozStorageEvents.h" /** @@ -426,6 +427,11 @@ private: return PR_FALSE; } +#ifdef DEBUG + // Check to make sure that this statement was smart about what it did. + CheckAndLogStatementPerformance(aStatement); +#endif + // If we are done, we need to set our state accordingly while we still // hold our lock. We would have already returned if we were canceled or had // an error at this point. diff --git a/storage/src/mozStoragePrivateHelpers.cpp b/storage/src/mozStoragePrivateHelpers.cpp new file mode 100644 index 00000000000..f7a3acaccb7 --- /dev/null +++ b/storage/src/mozStoragePrivateHelpers.cpp @@ -0,0 +1,106 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * vim: sw=2 ts=2 sts=2 et + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is mozilla.org code. + * + * The Initial Developer of the Original Code is + * Mozilla Corporation + * Portions created by the Initial Developer are Copyright (C) 2009 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Vladimir Vukicevic + * Shawn Wilsher + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "sqlite3.h" + +#include "nsString.h" +#include "nsError.h" + +#include "mozStoragePrivateHelpers.h" + +nsresult +ConvertResultCode(int aSQLiteResultCode) +{ + switch (aSQLiteResultCode) { + case SQLITE_OK: + case SQLITE_ROW: + case SQLITE_DONE: + return NS_OK; + case SQLITE_CORRUPT: + case SQLITE_NOTADB: + return NS_ERROR_FILE_CORRUPTED; + case SQLITE_PERM: + case SQLITE_CANTOPEN: + return NS_ERROR_FILE_ACCESS_DENIED; + case SQLITE_BUSY: + return NS_ERROR_STORAGE_BUSY; + case SQLITE_LOCKED: + return NS_ERROR_FILE_IS_LOCKED; + case SQLITE_READONLY: + return NS_ERROR_FILE_READ_ONLY; + case SQLITE_IOERR: + return NS_ERROR_STORAGE_IOERR; + case SQLITE_FULL: + case SQLITE_TOOBIG: + return NS_ERROR_FILE_NO_DEVICE_SPACE; + case SQLITE_NOMEM: + return NS_ERROR_OUT_OF_MEMORY; + case SQLITE_MISUSE: + return NS_ERROR_UNEXPECTED; + case SQLITE_ABORT: + case SQLITE_INTERRUPT: + return NS_ERROR_ABORT; + } + + // generic error + return NS_ERROR_FAILURE; +} + +void +CheckAndLogStatementPerformance(sqlite3_stmt *aStatement) +{ + // Check to see if the query performed sorting operations or not. If it + // did, it may need to be optimized! + int count = sqlite3_stmt_status(aStatement, SQLITE_STMTSTATUS_SORT, 1); + if (count <= 0) + return; + + nsCAutoString message; + message.AppendInt(count); + if (count == 1) + message.Append(" sort operation has "); + else + message.Append(" sort operations have "); + message.Append("occurred for the SQL statement '"); + message.Append(sqlite3_sql(aStatement)); + message.Append("'. This may indicate an opportunity to improve performance " + "through the careful use of indexes."); + NS_WARNING(message.get()); +} diff --git a/storage/src/mozStoragePrivateHelpers.h b/storage/src/mozStoragePrivateHelpers.h index 25c6a2fc1d3..c75f9490bcd 100644 --- a/storage/src/mozStoragePrivateHelpers.h +++ b/storage/src/mozStoragePrivateHelpers.h @@ -50,46 +50,22 @@ /** * Converts a SQLite return code to an nsresult return code. * - * @param srv The SQLite return code. - * @return The corresponding nsresult code. + * @param aSQLiteResultCode + * The SQLite return code to convert. + * @returns the corresponding nsresult code for aSQLiteResultCode. */ -static nsresult -ConvertResultCode(int srv) -{ - switch (srv) { - case SQLITE_OK: - case SQLITE_ROW: - case SQLITE_DONE: - return NS_OK; - case SQLITE_CORRUPT: - case SQLITE_NOTADB: - return NS_ERROR_FILE_CORRUPTED; - case SQLITE_PERM: - case SQLITE_CANTOPEN: - return NS_ERROR_FILE_ACCESS_DENIED; - case SQLITE_BUSY: - return NS_ERROR_STORAGE_BUSY; - case SQLITE_LOCKED: - return NS_ERROR_FILE_IS_LOCKED; - case SQLITE_READONLY: - return NS_ERROR_FILE_READ_ONLY; - case SQLITE_IOERR: - return NS_ERROR_STORAGE_IOERR; - case SQLITE_FULL: - case SQLITE_TOOBIG: - return NS_ERROR_FILE_NO_DEVICE_SPACE; - case SQLITE_NOMEM: - return NS_ERROR_OUT_OF_MEMORY; - case SQLITE_MISUSE: - return NS_ERROR_UNEXPECTED; - case SQLITE_ABORT: - case SQLITE_INTERRUPT: - return NS_ERROR_ABORT; - } +nsresult ConvertResultCode(int aSQLiteResultCode); - // generic error - return NS_ERROR_FAILURE; -} +/** + * Checks the performance of a SQLite statement and logs a warning with + * NS_WARNING. Currently this only checks the number of sort operations done + * on a statement, and if more than zero have been done, the statement can be + * made faster with the careful use of an index. + * + * @param aStatement + * The sqlite3_stmt object to check. + */ +void CheckAndLogStatementPerformance(sqlite3_stmt *aStatement); #endif // _MOZSTORAGEPRIVATEHELPERS_H_ diff --git a/storage/src/mozStorageStatement.cpp b/storage/src/mozStorageStatement.cpp index f08e052aefa..53610bd0bbe 100644 --- a/storage/src/mozStorageStatement.cpp +++ b/storage/src/mozStorageStatement.cpp @@ -444,9 +444,13 @@ mozStorageStatement::Reset() if (!mDBConnection || !mDBStatement) return NS_ERROR_NOT_INITIALIZED; +#ifdef DEBUG PR_LOG(gStorageLog, PR_LOG_DEBUG, ("Resetting statement: '%s'", sqlite3_sql(mDBStatement))); + CheckAndLogStatementPerformance(mDBStatement); +#endif + sqlite3_reset(mDBStatement); sqlite3_clear_bindings(mDBStatement);