Bug 547190 - AsInt64 (and other AsXXX cpp helpers) ignores GetInt64 failures. r=sdwilsh
authorMarco Bonardo <mbonardo@mozilla.com>
Tue, 22 Jun 2010 02:01:33 +0200
changeset 49032 ce14f575aff99391467a7e4f5b2ec4455b67a8fd
parent 49031 7f54a4f3efe8e01d50dab0cdd16dca0b70bc0d4e
child 49033 92a9a7c997f1d20eaab889d794e26ae825a128e0
push idunknown
push userunknown
push dateunknown
reviewerssdwilsh
bugs547190
milestone2.0b4pre
Bug 547190 - AsInt64 (and other AsXXX cpp helpers) ignores GetInt64 failures. r=sdwilsh
storage/public/mozIStorageStatement.idl
storage/public/mozIStorageValueArray.idl
storage/test/Makefile.in
storage/test/storage_test_harness.h
storage/test/test_AsXXX_helpers.cpp
storage/test/test_true_async.cpp
--- 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.