Bug 547190 - AsInt64 (and other AsXXX cpp helpers) ignores GetInt64 failures. r=sdwilsh
--- a/storage/public/mozIStorageStatement.idl
+++ b/storage/public/mozIStorageStatement.idl
@@ -259,51 +259,68 @@ interface mozIStorageStatement : mozISto
/**
* Getters for native code that return their values as
* the return type, for convenience and sanity.
*
* Not virtual; no vtable bloat.
*/
inline PRInt32 AsInt32(PRUint32 idx) {
- PRInt32 v;
- GetInt32(idx, &v);
+ PRInt32 v = 0;
+ nsresult rv = GetInt32(idx, &v);
+ NS_ABORT_IF_FALSE(NS_SUCCEEDED(rv) || IsNull(idx),
+ "Getting value failed, wrong column index?");
return v;
}
inline PRInt64 AsInt64(PRUint32 idx) {
- PRInt64 v;
- GetInt64(idx, &v);
+ PRInt64 v = 0;
+ nsresult rv = GetInt64(idx, &v);
+ NS_ABORT_IF_FALSE(NS_SUCCEEDED(rv) || IsNull(idx),
+ "Getting value failed, wrong column index?");
return v;
}
inline double AsDouble(PRUint32 idx) {
- double v;
- GetDouble(idx, &v);
+ double v = 0.0;
+ nsresult rv = GetDouble(idx, &v);
+ NS_ABORT_IF_FALSE(NS_SUCCEEDED(rv) || IsNull(idx),
+ "Getting value failed, wrong column index?");
return v;
}
inline const char* AsSharedUTF8String(PRUint32 idx, PRUint32 *len) {
const char *str = nsnull;
- GetSharedUTF8String(idx, len, &str);
+ *len = 0;
+ nsresult rv = GetSharedUTF8String(idx, len, &str);
+ NS_ABORT_IF_FALSE(NS_SUCCEEDED(rv) || IsNull(idx),
+ "Getting value failed, wrong column index?");
return str;
}
inline const PRUnichar* AsSharedWString(PRUint32 idx, PRUint32 *len) {
const PRUnichar *str = nsnull;
- GetSharedString(idx, len, &str);
+ *len = 0;
+ nsresult rv = GetSharedString(idx, len, &str);
+ NS_ABORT_IF_FALSE(NS_SUCCEEDED(rv) || IsNull(idx),
+ "Getting value failed, wrong column index?");
return str;
}
inline const PRUint8* AsSharedBlob(PRUint32 idx, PRUint32 *len) {
const PRUint8 *blob = nsnull;
- GetSharedBlob(idx, len, &blob);
+ *len = 0;
+ nsresult rv = GetSharedBlob(idx, len, &blob);
+ NS_ABORT_IF_FALSE(NS_SUCCEEDED(rv) || IsNull(idx),
+ "Getting value failed, wrong column index?");
return blob;
}
inline PRBool IsNull(PRUint32 idx) {
PRBool b = PR_FALSE;
- GetIsNull(idx, &b);
+ nsresult rv = GetIsNull(idx, &b);
+ NS_ABORT_IF_FALSE(NS_SUCCEEDED(rv),
+ "Getting value failed, wrong column index?");
return b;
}
%}
};
--- a/storage/public/mozIStorageValueArray.idl
+++ b/storage/public/mozIStorageValueArray.idl
@@ -105,52 +105,69 @@ interface mozIStorageValueArray : nsISup
/**
* Getters for native code that return their values as
* the return type, for convenience and sanity.
*
* Not virtual; no vtable bloat.
*/
inline PRInt32 AsInt32(PRUint32 idx) {
- PRInt32 v;
- GetInt32(idx, &v);
+ PRInt32 v = 0;
+ nsresult rv = GetInt32(idx, &v);
+ NS_ABORT_IF_FALSE(NS_SUCCEEDED(rv) || IsNull(idx),
+ "Getting value failed, wrong column index?");
return v;
}
inline PRInt64 AsInt64(PRUint32 idx) {
- PRInt64 v;
- GetInt64(idx, &v);
+ PRInt64 v = 0;
+ nsresult rv = GetInt64(idx, &v);
+ NS_ABORT_IF_FALSE(NS_SUCCEEDED(rv) || IsNull(idx),
+ "Getting value failed, wrong column index?");
return v;
}
inline double AsDouble(PRUint32 idx) {
- double v;
- GetDouble(idx, &v);
+ double v = 0.0;
+ nsresult rv = GetDouble(idx, &v);
+ NS_ABORT_IF_FALSE(NS_SUCCEEDED(rv) || IsNull(idx),
+ "Getting value failed, wrong column index?");
return v;
}
inline const char* AsSharedUTF8String(PRUint32 idx, PRUint32 *len) {
const char *str = nsnull;
- GetSharedUTF8String(idx, len, &str);
+ *len = 0;
+ nsresult rv = GetSharedUTF8String(idx, len, &str);
+ NS_ABORT_IF_FALSE(NS_SUCCEEDED(rv) || IsNull(idx),
+ "Getting value failed, wrong column index?");
return str;
}
inline const PRUnichar* AsSharedWString(PRUint32 idx, PRUint32 *len) {
const PRUnichar *str = nsnull;
- GetSharedString(idx, len, &str);
+ *len = 0;
+ nsresult rv = GetSharedString(idx, len, &str);
+ NS_ABORT_IF_FALSE(NS_SUCCEEDED(rv) || IsNull(idx),
+ "Getting value failed, wrong column index?");
return str;
}
inline const PRUint8* AsSharedBlob(PRUint32 idx, PRUint32 *len) {
const PRUint8 *blob = nsnull;
- GetSharedBlob(idx, len, &blob);
+ *len = 0;
+ nsresult rv = GetSharedBlob(idx, len, &blob);
+ NS_ABORT_IF_FALSE(NS_SUCCEEDED(rv) || IsNull(idx),
+ "Getting value failed, wrong column index?");
return blob;
}
inline PRBool IsNull(PRUint32 idx) {
PRBool b = PR_FALSE;
- GetIsNull(idx, &b);
+ nsresult rv = GetIsNull(idx, &b);
+ NS_ABORT_IF_FALSE(NS_SUCCEEDED(rv),
+ "Getting value failed, wrong column index?");
return b;
}
%}
};
--- a/storage/test/Makefile.in
+++ b/storage/test/Makefile.in
@@ -51,16 +51,17 @@ XPCSHELL_TESTS = unit
CPP_UNIT_TESTS = \
test_transaction_helper.cpp \
test_statement_scoper.cpp \
test_mutex.cpp \
test_binding_params.cpp \
test_true_async.cpp \
test_unlock_notify.cpp \
test_service_init_background_thread.cpp \
+ test_AsXXX_helpers.cpp \
$(NULL)
ifdef MOZ_DEBUG
# FIXME bug 523392: test_deadlock_detector doesn't like Windows
# FIXME bug 523378: also fails on OS X
ifneq (,$(filter-out WINNT WINCE Darwin,$(OS_ARCH)))
CPP_UNIT_TESTS += \
test_deadlock_detector.cpp \
--- a/storage/test/storage_test_harness.h
+++ b/storage/test/storage_test_harness.h
@@ -38,16 +38,24 @@
* ***** END LICENSE BLOCK ***** */
#include "TestHarness.h"
#include "nsMemory.h"
#include "nsThreadUtils.h"
#include "nsDirectoryServiceDefs.h"
#include "mozIStorageService.h"
#include "mozIStorageConnection.h"
+#include "mozIStorageStatementCallback.h"
+#include "mozIStorageCompletionCallback.h"
+#include "mozIStorageBindingParamsArray.h"
+#include "mozIStorageBindingParams.h"
+#include "mozIStorageAsyncStatement.h"
+#include "mozIStorageStatement.h"
+#include "mozIStoragePendingStatement.h"
+#include "nsThreadUtils.h"
static int gTotalTests = 0;
static int gPassedTests = 0;
#define do_check_true(aCondition) \
PR_BEGIN_MACRO \
gTotalTests++; \
if (aCondition) { \
@@ -104,8 +112,78 @@ getDatabase()
do_check_success(rv);
nsCOMPtr<mozIStorageService> ss = getService();
nsCOMPtr<mozIStorageConnection> conn;
rv = ss->OpenDatabase(dbFile, getter_AddRefs(conn));
do_check_success(rv);
return conn.forget();
}
+
+
+class AsyncStatementSpinner : public mozIStorageStatementCallback
+ , public mozIStorageCompletionCallback
+{
+public:
+ NS_DECL_ISUPPORTS
+ NS_DECL_MOZISTORAGESTATEMENTCALLBACK
+ NS_DECL_MOZISTORAGECOMPLETIONCALLBACK
+
+ AsyncStatementSpinner();
+
+ void SpinUntilCompleted();
+
+ PRUint16 completionReason;
+
+protected:
+ ~AsyncStatementSpinner() {}
+ volatile bool mCompleted;
+};
+
+NS_IMPL_ISUPPORTS2(AsyncStatementSpinner,
+ mozIStorageStatementCallback,
+ mozIStorageCompletionCallback)
+
+AsyncStatementSpinner::AsyncStatementSpinner()
+: completionReason(0)
+, mCompleted(false)
+{
+}
+
+NS_IMETHODIMP
+AsyncStatementSpinner::HandleResult(mozIStorageResultSet *aResultSet)
+{
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+AsyncStatementSpinner::HandleError(mozIStorageError *aError)
+{
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+AsyncStatementSpinner::HandleCompletion(PRUint16 aReason)
+{
+ completionReason = aReason;
+ mCompleted = true;
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+AsyncStatementSpinner::Complete()
+{
+ mCompleted = true;
+ return NS_OK;
+}
+
+void AsyncStatementSpinner::SpinUntilCompleted()
+{
+ nsCOMPtr<nsIThread> thread(::do_GetCurrentThread());
+ nsresult rv = NS_OK;
+ PRBool processed = PR_TRUE;
+ while (!mCompleted && NS_SUCCEEDED(rv)) {
+ rv = thread->ProcessNextEvent(true, &processed);
+ }
+}
+
+#define NS_DECL_ASYNCSTATEMENTSPINNER \
+ NS_IMETHOD HandleResult(mozIStorageResultSet *aResultSet);
new file mode 100644
--- /dev/null
+++ b/storage/test/test_AsXXX_helpers.cpp
@@ -0,0 +1,123 @@
+/*
+ *Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+#include "storage_test_harness.h"
+#include "mozIStorageRow.h"
+#include "mozIStorageResultSet.h"
+
+/**
+ * This file tests AsXXX (AsInt32, AsInt64, ...) helpers.
+ */
+
+////////////////////////////////////////////////////////////////////////////////
+//// Event Loop Spinning
+
+class Spinner : public AsyncStatementSpinner
+{
+public:
+ NS_DECL_ISUPPORTS
+ NS_DECL_ASYNCSTATEMENTSPINNER
+ Spinner() {}
+};
+
+NS_IMPL_ISUPPORTS_INHERITED0(Spinner,
+ AsyncStatementSpinner)
+
+NS_IMETHODIMP
+Spinner::HandleResult(mozIStorageResultSet *aResultSet)
+{
+ nsCOMPtr<mozIStorageRow> row;
+ do_check_true(NS_SUCCEEDED(aResultSet->GetNextRow(getter_AddRefs(row))) && row);
+
+ do_check_eq(row->AsInt32(0), 0);
+ do_check_eq(row->AsInt64(0), 0);
+ do_check_eq(row->AsDouble(0), 0.0);
+
+ PRUint32 len = 100;
+ do_check_eq(row->AsSharedUTF8String(0, &len), nsnull);
+ do_check_eq(len, 0);
+ len = 100;
+ do_check_eq(row->AsSharedWString(0, &len), nsnull);
+ do_check_eq(len, 0);
+ len = 100;
+ do_check_eq(row->AsSharedBlob(0, &len), nsnull);
+ do_check_eq(len, 0);
+
+ do_check_eq(row->IsNull(0), PR_TRUE);
+ return NS_OK;
+}
+
+void
+test_NULLFallback()
+{
+ nsCOMPtr<mozIStorageConnection> db(getMemoryDatabase());
+
+ nsCOMPtr<mozIStorageStatement> stmt;
+ (void)db->CreateStatement(NS_LITERAL_CSTRING(
+ "SELECT NULL"
+ ), getter_AddRefs(stmt));
+
+ nsCOMPtr<mozIStorageValueArray> valueArray = do_QueryInterface(stmt);
+ do_check_true(valueArray);
+
+ PRBool hasMore;
+ do_check_true(NS_SUCCEEDED(stmt->ExecuteStep(&hasMore)) && hasMore);
+
+ do_check_eq(stmt->AsInt32(0), 0);
+ do_check_eq(stmt->AsInt64(0), 0);
+ do_check_eq(stmt->AsDouble(0), 0.0);
+ PRUint32 len = 100;
+ do_check_eq(stmt->AsSharedUTF8String(0, &len), nsnull);
+ do_check_eq(len, 0);
+ len = 100;
+ do_check_eq(stmt->AsSharedWString(0, &len), nsnull);
+ do_check_eq(len, 0);
+ len = 100;
+ do_check_eq(stmt->AsSharedBlob(0, &len), nsnull);
+ do_check_eq(len, 0);
+ do_check_eq(stmt->IsNull(0), PR_TRUE);
+
+ do_check_eq(valueArray->AsInt32(0), 0);
+ do_check_eq(valueArray->AsInt64(0), 0);
+ do_check_eq(valueArray->AsDouble(0), 0.0);
+ len = 100;
+ do_check_eq(valueArray->AsSharedUTF8String(0, &len), nsnull);
+ do_check_eq(len, 0);
+ len = 100;
+ do_check_eq(valueArray->AsSharedWString(0, &len), nsnull);
+ do_check_eq(len, 0);
+ len = 100;
+ do_check_eq(valueArray->AsSharedBlob(0, &len), nsnull);
+ do_check_eq(len, 0);
+ do_check_eq(valueArray->IsNull(0), PR_TRUE);
+}
+
+void
+test_asyncNULLFallback()
+{
+ nsCOMPtr<mozIStorageConnection> db(getMemoryDatabase());
+
+ nsCOMPtr<mozIStorageStatement> stmt;
+ (void)db->CreateStatement(NS_LITERAL_CSTRING(
+ "SELECT NULL"
+ ), getter_AddRefs(stmt));
+
+ nsRefPtr<Spinner> asyncSpin(new Spinner());
+ nsCOMPtr<mozIStoragePendingStatement> pendingStmt;
+ do_check_true(NS_SUCCEEDED(stmt->ExecuteAsync(asyncSpin, getter_AddRefs(pendingStmt))));
+ do_check_true(pendingStmt);
+ asyncSpin->SpinUntilCompleted();
+
+}
+
+void (*gTests[])(void) = {
+ test_NULLFallback
+, test_asyncNULLFallback
+};
+
+const char *file = __FILE__;
+#define TEST_NAME "AsXXX helpers"
+#define TEST_FILE file
+#include "storage_test_harness_tail.h"
--- a/storage/test/test_true_async.cpp
+++ b/storage/test/test_true_async.cpp
@@ -33,32 +33,22 @@
* 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 "storage_test_harness.h"
#include "prthread.h"
-#include "nsIThread.h"
-#include "nsThreadUtils.h"
#include "nsIEventTarget.h"
#include "sqlite3.h"
#include "mozilla/Monitor.h"
-#include "mozIStorageStatementCallback.h"
-#include "mozIStorageCompletionCallback.h"
-#include "mozIStorageBindingParamsArray.h"
-#include "mozIStorageBindingParams.h"
-#include "mozIStorageAsyncStatement.h"
-#include "mozIStorageStatement.h"
-#include "mozIStoragePendingStatement.h"
-
using mozilla::Monitor;
using mozilla::MonitorAutoEnter;
/**
* Verify that mozIStorageAsyncStatement's life-cycle never triggers a mutex on
* the caller (generally main) thread. We do this by decorating the sqlite
* mutex logic with our own code that checks what thread it is being invoked on
* and sets a flag if it is invoked on the main thread. We are able to easily
@@ -131,85 +121,16 @@ void hook_sqlite_mutex()
void watch_for_mutex_use_on_this_thread()
{
watched_thread = ::PR_GetCurrentThread();
mutex_used_on_watched_thread = false;
}
////////////////////////////////////////////////////////////////////////////////
-//// Event Loop Spinning
-
-class AsyncStatementSpinner : public mozIStorageStatementCallback,
- public mozIStorageCompletionCallback
-{
-public:
- NS_DECL_ISUPPORTS
- NS_DECL_MOZISTORAGESTATEMENTCALLBACK
- NS_DECL_MOZISTORAGECOMPLETIONCALLBACK
-
- AsyncStatementSpinner();
-
- void SpinUntilCompleted();
-
- PRUint16 completionReason;
-
-private:
- ~AsyncStatementSpinner() {}
- volatile bool mCompleted;
-};
-
-NS_IMPL_ISUPPORTS2(AsyncStatementSpinner,
- mozIStorageStatementCallback,
- mozIStorageCompletionCallback)
-
-AsyncStatementSpinner::AsyncStatementSpinner()
-: completionReason(0)
-, mCompleted(false)
-{
-}
-
-NS_IMETHODIMP
-AsyncStatementSpinner::HandleResult(mozIStorageResultSet *aResultSet)
-{
- return NS_OK;
-}
-
-NS_IMETHODIMP
-AsyncStatementSpinner::HandleError(mozIStorageError *aError)
-{
- return NS_OK;
-}
-
-NS_IMETHODIMP
-AsyncStatementSpinner::HandleCompletion(PRUint16 aReason)
-{
- completionReason = aReason;
- mCompleted = true;
- return NS_OK;
-}
-
-NS_IMETHODIMP
-AsyncStatementSpinner::Complete()
-{
- mCompleted = true;
- return NS_OK;
-}
-
-void AsyncStatementSpinner::SpinUntilCompleted()
-{
- nsCOMPtr<nsIThread> thread(::do_GetCurrentThread());
- nsresult rv = NS_OK;
- PRBool processed = PR_TRUE;
- while (!mCompleted && NS_SUCCEEDED(rv)) {
- rv = thread->ProcessNextEvent(true, &processed);
- }
-}
-
-////////////////////////////////////////////////////////////////////////////////
//// Thread Wedgers
/**
* A runnable that blocks until code on another thread invokes its unwedge
* method. By dispatching this to a thread you can ensure that no subsequent
* runnables dispatched to the thread will execute until you invoke unwedge.
*
* The wedger is self-dispatching, just construct it with its target.