Backed out changeset d546bd2c46a4 (bug 490085) because it's broken (and thunderbird's test caught it)

This commit is contained in:
Shawn Wilsher 2009-06-17 13:43:30 -07:00
parent 82d918234b
commit 2b8dcfe38e
18 changed files with 551 additions and 2254 deletions

View File

@ -62,8 +62,6 @@ XPIDLSRCS = \
mozIStorageError.idl \
mozIStorageStatementCallback.idl \
mozIStoragePendingStatement.idl \
mozIStorageBindingParamsArray.idl \
mozIStorageBindingParams.idl \
$(NULL)
EXPORTS_NAMESPACES = mozilla

View File

@ -1,95 +0,0 @@
/* -*- 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):
* Shawn Wilsher <me@shawnwilsher.com> (Original Author)
*
* 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 "nsISupports.idl"
interface nsIVariant;
[scriptable, uuid(a8d4827c-641c-45e3-a9ea-493570b4106b)]
interface mozIStorageBindingParams : nsISupports {
/**
* Binds aValue to the parameter with the name aName.
*
* @param aName
* The name of the parameter to bind aValue to.
* @param aValue
* The value to bind.
*/
void bindByName(in AUTF8String aName,
in nsIVariant aValue);
[noscript] void bindUTF8StringByName(in AUTF8String aName,
in AUTF8String aValue);
[noscript] void bindStringByName(in AUTF8String aName,
in AString aValue);
[noscript] void bindDoubleByName(in AUTF8String aName,
in double aValue);
[noscript] void bindInt32ByName(in AUTF8String aName,
in long aValue);
[noscript] void bindInt64ByName(in AUTF8String aName,
in long long aValue);
[noscript] void bindNullByName(in AUTF8String aName);
void bindBlobByName(in AUTF8String aName,
[array, const, size_is(aValueSize)] in octet aValue,
in unsigned long aValueSize);
/**
* Binds aValue to the parameter with the index aIndex.
*
* @param aIndex
* The zero-based index of the parameter to bind aValue to.
* @param aValue
* The value to bind.
*/
void bindByIndex(in unsigned long aIndex,
in nsIVariant aValue);
[noscript] void bindUTF8StringByIndex(in unsigned long aIndex,
in AUTF8String aValue);
[noscript] void bindStringByIndex(in unsigned long aIndex,
in AString aValue);
[noscript] void bindDoubleByIndex(in unsigned long aIndex,
in double aValue);
[noscript] void bindInt32ByIndex(in unsigned long aIndex,
in long aValue);
[noscript] void bindInt64ByIndex(in unsigned long aIndex,
in long long aValue);
[noscript] void bindNullByIndex(in unsigned long aIndex);
void bindBlobByIndex(in unsigned long aIndex,
[array, const, size_is(aValueSize)] in octet aValue,
in unsigned long aValueSize);
};

View File

@ -1,62 +0,0 @@
/* -*- 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):
* Shawn Wilsher <me@shawnwilsher.com> (Original Author)
*
* 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 "nsISupports.idl"
interface mozIStorageBindingParams;
[scriptable, uuid(e676e1a3-1dc6-4802-ac03-291fa9de7f93)]
interface mozIStorageBindingParamsArray : nsISupports {
/**
* Creates a new mozIStorageBindingParams object that can be added to this
* array.
*
* @returns a mozIStorageBindingParams object that can be used to specify
* parameters that need to be bound.
*/
mozIStorageBindingParams newBindingParams();
/**
* Adds the parameters to the end of this array.
*
* @param aParameters
* The parameters to add to this array.
*/
void addParams(in mozIStorageBindingParams aParameters);
};

View File

@ -43,9 +43,8 @@
interface mozIStorageConnection;
interface mozIStorageStatementCallback;
interface mozIStoragePendingStatement;
interface mozIStorageBindingParamsArray;
[scriptable, uuid(20c45bdd-51d4-4f07-b70e-5feaa6302197)]
[scriptable, uuid(52d740cd-1c25-471f-a848-98d1a00a2963)]
interface mozIStorageStatement : mozIStorageValueArray {
/**
* Finalizes a statement so you can successfully close a database connection.
@ -130,24 +129,6 @@ interface mozIStorageStatement : mozIStorageValueArray {
[array,const,size_is(aValueSize)] in octet aValue,
in unsigned long aValueSize);
/**
* Binds the array of parameters to the statement. When executeAsync is
* called, all the parameters in aParameters are bound and then executed.
*
* @param aParameters
* The array of parameters to bind to the statement upon execution.
*/
void bindParameters(in mozIStorageBindingParamsArray aParameters);
/**
* Creates a new mozIStorageBindingParamsArray that can be used to bind
* multiple sets of data to a statement.
*
* @returns a mozIStorageBindingParamsArray that multiple sets of parameters
* can be bound to.
*/
mozIStorageBindingParamsArray newBindingParamsArray();
/**
* Execute the query, ignoring any results. This is accomplished by
* calling step() once, and then calling reset().

View File

@ -83,8 +83,6 @@ CPPSRCS = \
mozStorageAsyncStatementExecution.cpp \
mozStorageStatementJSHelper.cpp \
mozStoragePrivateHelpers.cpp \
mozStorageBindingParamsArray.cpp \
mozStorageBindingParams.cpp \
$(NULL)
LOCAL_INCLUDES = \

View File

@ -43,14 +43,12 @@
#include "sqlite3.h"
#include "mozIStorageStatementCallback.h"
#include "mozStorageBindingParams.h"
#include "mozStorageHelper.h"
#include "mozStorageResultSet.h"
#include "mozStorageRow.h"
#include "mozStorageConnection.h"
#include "mozStorageError.h"
#include "mozStoragePrivateHelpers.h"
#include "mozStorageStatementData.h"
#include "mozStorageAsyncStatementExecution.h"
namespace mozilla {
@ -174,7 +172,7 @@ private:
/* static */
nsresult
AsyncExecuteStatements::execute(StatementDataArray &aStatements,
AsyncExecuteStatements::execute(sqlite3_stmt_array &aStatements,
Connection *aConnection,
mozIStorageStatementCallback *aCallback,
mozIStoragePendingStatement **_stmt)
@ -195,7 +193,7 @@ AsyncExecuteStatements::execute(StatementDataArray &aStatements,
return NS_OK;
}
AsyncExecuteStatements::AsyncExecuteStatements(StatementDataArray &aStatements,
AsyncExecuteStatements::AsyncExecuteStatements(sqlite3_stmt_array &aStatements,
Connection *aConnection,
mozIStorageStatementCallback *aCallback)
: mConnection(aConnection)
@ -228,47 +226,6 @@ AsyncExecuteStatements::shouldNotify()
return !mCancelRequested;
}
bool
AsyncExecuteStatements::bindExecuteAndProcessStatement(StatementData &aData,
bool aLastStatement)
{
mMutex.AssertNotCurrentThreadOwns();
sqlite3_stmt *stmt(aData);
BindingParamsArray *paramsArray(aData);
// Iterate through all of our parameters, bind them, and execute.
bool continueProcessing = true;
BindingParamsArray::iterator itr = paramsArray->begin();
BindingParamsArray::iterator end = paramsArray->end();
while (itr != end && continueProcessing) {
// Bind the data to our statement.
nsCOMPtr<mozIStorageError> error;
error = (*itr)->bind(stmt);
if (error) {
// Set our error state.
{
MutexAutoLock mutex(mMutex);
mState = ERROR;
}
// And notify.
(void)notifyError(error);
return false;
}
// Advance our iterator, execute, and then process the statement.
itr++;
bool lastStatement = aLastStatement && itr == end;
continueProcessing = executeAndProcessStatement(stmt, lastStatement);
// Always reset our statement.
(void)::sqlite3_reset(stmt);
}
return continueProcessing;
}
bool
AsyncExecuteStatements::executeAndProcessStatement(sqlite3_stmt *aStatement,
bool aLastStatement)
@ -420,8 +377,10 @@ AsyncExecuteStatements::notifyComplete()
// Finalize our statements before we try to commit or rollback. If we are
// canceling and have statements that think they have pending work, the
// rollback will fail.
for (PRUint32 i = 0; i < mStatements.Length(); i++)
mStatements[i].finalize();
for (PRUint32 i = 0; i < mStatements.Length(); i++) {
(void)::sqlite3_finalize(mStatements[i]);
mStatements[i] = NULL;
}
// Handle our transaction, if we have one
if (mTransactionManager) {
@ -467,19 +426,8 @@ AsyncExecuteStatements::notifyError(PRInt32 aErrorCode,
nsCOMPtr<mozIStorageError> errorObj(new Error(aErrorCode, aMessage));
NS_ENSURE_TRUE(errorObj, NS_ERROR_OUT_OF_MEMORY);
return notifyError(errorObj);
}
nsresult
AsyncExecuteStatements::notifyError(mozIStorageError *aError)
{
mMutex.AssertNotCurrentThreadOwns();
if (!mCallback)
return NS_OK;
nsRefPtr<ErrorNotifier> notifier =
new ErrorNotifier(mCallback, aError, this);
new ErrorNotifier(mCallback, errorObj, this);
NS_ENSURE_TRUE(notifier, NS_ERROR_OUT_OF_MEMORY);
return mCallingThread->Dispatch(notifier, NS_DISPATCH_NORMAL);
@ -562,9 +510,7 @@ AsyncExecuteStatements::Run()
// If there is more than one statement, run it in a transaction. We assume
// that we have been given write statements since getting a batch of read
// statements doesn't make a whole lot of sense.
// Additionally, if we have only one statement and it has parameters to be
// bound, we assume that the consumer would want a transaction as well.
if (mStatements.Length() > 1 || mStatements[0].hasParametersToBeBound()) {
if (mStatements.Length() > 1) {
// We don't error if this failed because it's not terrible if it does.
mTransactionManager = new mozStorageTransaction(mConnection, PR_FALSE,
mozIStorageConnection::TRANSACTION_IMMEDIATE);
@ -572,17 +518,9 @@ AsyncExecuteStatements::Run()
// Execute each statement, giving the callback results if it returns any.
for (PRUint32 i = 0; i < mStatements.Length(); i++) {
bool finished = (i == (mStatements.Length() - 1));
// If we have parameters to bind, bind them, execute, and process.
if (mStatements[i].hasParametersToBeBound()) {
if (!bindExecuteAndProcessStatement(mStatements[i], finished))
break;
}
// Otherwise, just execute and process the statement.
else if (!executeAndProcessStatement(mStatements[i], finished)) {
PRBool finished = (i == (mStatements.Length() - 1));
if (!executeAndProcessStatement(mStatements[i], finished))
break;
}
}
// If we still have results that we haven't notified about, take care of

View File

@ -57,7 +57,6 @@ namespace storage {
class Connection;
class ResultSet;
class StatementData;
class AsyncExecuteStatements : public nsIRunnable
, public mozIStoragePendingStatement
@ -77,15 +76,15 @@ public:
ERROR = mozIStorageStatementCallback::REASON_ERROR
};
typedef nsTArray<StatementData> StatementDataArray;
typedef nsTArray<sqlite3_stmt *> sqlite3_stmt_array;
/**
* Executes a statement in the background, and passes results back to the
* caller.
*
* @param aStatements
* The statements to execute and possibly bind in the background.
* Ownership is transfered from the caller.
* The SQLite statements to execute in the background. Ownership is
* transfered from the caller.
* @param aConnection
* The connection that created the statements to execute.
* @param aCallback
@ -93,7 +92,7 @@ public:
* @param _stmt
* The handle to control the execution of the statements.
*/
static nsresult execute(StatementDataArray &aStatements,
static nsresult execute(sqlite3_stmt_array &aStatements,
Connection *aConnection,
mozIStorageStatementCallback *aCallback,
mozIStoragePendingStatement **_stmt);
@ -108,27 +107,10 @@ public:
bool shouldNotify();
private:
AsyncExecuteStatements(StatementDataArray &aStatements,
AsyncExecuteStatements(sqlite3_stmt_array &aStatements,
Connection *aConnection,
mozIStorageStatementCallback *aCallback);
/**
* Binds and then executes a given statement until completion, an error
* occurs, or we are canceled. If aLastStatement is true, we should set
* mState accordingly.
*
* @pre mMutex is not held
*
* @param aData
* The StatementData to bind, execute, and then process.
* @param aLastStatement
* Indicates if this is the last statement or not. If it is, we have
* to set the proper state.
* @returns true if we should continue to process statements, false otherwise.
*/
bool bindExecuteAndProcessStatement(StatementData &aData,
bool aLastStatement);
/**
* Executes a given statement until completion, an error occurs, or we are
* canceled. If aLastStatement is true, we should set mState accordingly.
@ -183,11 +165,8 @@ private:
* The error code defined in mozIStorageError for the error.
* @param aMessage
* The error string, if any.
* @param aError
* The error object to notify the caller with.
*/
nsresult notifyError(PRInt32 aErrorCode, const char *aMessage);
nsresult notifyError(mozIStorageError *aError);
/**
* Notifies the callback about a result set.
@ -196,7 +175,7 @@ private:
*/
nsresult notifyResults();
StatementDataArray mStatements;
sqlite3_stmt_array mStatements;
nsRefPtr<Connection> mConnection;
mozStorageTransaction *mTransactionManager;
mozIStorageStatementCallback *mCallback;

View File

@ -1,369 +0,0 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
* vim: sw=2 ts=2 et lcs=trail\:.,tab\:>~ :
* ***** 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):
* Shawn Wilsher <me@shawnwilsher.com> (Original Author)
*
* 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 <limits.h>
#include "nsString.h"
#include "mozStorageError.h"
#include "mozStoragePrivateHelpers.h"
#include "mozStorageBindingParams.h"
#include "mozStorageBindingParamsArray.h"
#include "Variant.h"
namespace mozilla {
namespace storage {
////////////////////////////////////////////////////////////////////////////////
//// Local Helper Objects
namespace {
struct BindingColumnData
{
BindingColumnData(sqlite3_stmt *aStmt,
int aColumn)
: stmt(aStmt)
, column(aColumn)
{
}
sqlite3_stmt *stmt;
int column;
};
} // anonymous namespace
////////////////////////////////////////////////////////////////////////////////
//// sqlite3_stmt Specialization Functions (varaintToSQLite3T)
template < >
int
sqlite3_T_int(BindingColumnData aData,
int aValue)
{
return ::sqlite3_bind_int(aData.stmt, aData.column + 1, aValue);
}
template < >
int
sqlite3_T_int64(BindingColumnData aData,
sqlite3_int64 aValue)
{
return ::sqlite3_bind_int64(aData.stmt, aData.column + 1, aValue);
}
template < >
int
sqlite3_T_double(BindingColumnData aData,
double aValue)
{
return ::sqlite3_bind_double(aData.stmt, aData.column + 1, aValue);
}
template < >
int
sqlite3_T_text16(BindingColumnData aData,
nsString aValue)
{
return ::sqlite3_bind_text16(aData.stmt,
aData.column + 1,
PromiseFlatString(aValue).get(),
aValue.Length() * 2, // Length in bytes!
SQLITE_TRANSIENT);
}
template < >
int
sqlite3_T_null(BindingColumnData aData)
{
return ::sqlite3_bind_null(aData.stmt, aData.column + 1);
}
template < >
int
sqlite3_T_blob(BindingColumnData aData,
const void *aBlob,
int aSize)
{
return ::sqlite3_bind_blob(aData.stmt, aData.column + 1, aBlob, aSize,
NS_Free);
}
////////////////////////////////////////////////////////////////////////////////
//// BindingParams
BindingParams::BindingParams(BindingParamsArray *aOwningArray,
Statement *aOwningStatement)
: mOwningArray(aOwningArray)
, mOwningStatement(aOwningStatement)
, mLocked(false)
{
(void)mOwningStatement->GetParameterCount(&mParamCount);
}
void
BindingParams::lock()
{
NS_ASSERTION(mLocked == false, "Parameters have already been locked!");
mLocked = true;
// We no longer need to hold a reference to our statement or our owning array.
// The array owns us at this point, and it will own a reference to the
// statement.
mOwningStatement = nsnull;
mOwningArray = nsnull;
}
const BindingParamsArray *
BindingParams::getOwner() const
{
return mOwningArray;
}
already_AddRefed<mozIStorageError>
BindingParams::bind(sqlite3_stmt *aStatement)
{
// Iterate through all of our stored data, and bind it.
for (PRInt32 i = 0; i < mParameters.Count(); i++) {
int rc = variantToSQLiteT(BindingColumnData(aStatement, i), mParameters[i]);
if (rc != SQLITE_OK) {
// We had an error while trying to bind. Now we need to create an error
// object with the right message. Note that we special case
// SQLITE_MISMATCH, but otherwise get the message from SQLite.
const char *msg = "Could not covert nsIVariant to SQLite type.";
if (rc != SQLITE_MISMATCH)
msg = ::sqlite3_errmsg(::sqlite3_db_handle(aStatement));
nsCOMPtr<mozIStorageError> err(new Error(rc, msg));
return err.forget();
}
}
// No error occurred, so return null!
return nsnull;
}
NS_IMPL_THREADSAFE_ISUPPORTS1(
BindingParams,
mozIStorageBindingParams
)
///////////////////////////////////////////////////////////////////////////////
//// mozIStorageBindingParams
NS_IMETHODIMP
BindingParams::BindByName(const nsACString &aName,
nsIVariant *aValue)
{
NS_ENSURE_FALSE(mLocked, NS_ERROR_UNEXPECTED);
// Get the column index that we need to store this at.
PRUint32 index;
nsresult rv = mOwningStatement->GetParameterIndex(aName, &index);
NS_ENSURE_SUCCESS(rv, rv);
return BindByIndex(index, aValue);
}
NS_IMETHODIMP
BindingParams::BindUTF8StringByName(const nsACString &aName,
const nsACString &aValue)
{
nsCOMPtr<nsIVariant> value(new UTF8TextVariant(aValue));
NS_ENSURE_TRUE(value, NS_ERROR_OUT_OF_MEMORY);
return BindByName(aName, value);
}
NS_IMETHODIMP
BindingParams::BindStringByName(const nsACString &aName,
const nsAString &aValue)
{
nsCOMPtr<nsIVariant> value(new TextVariant(aValue));
NS_ENSURE_TRUE(value, NS_ERROR_OUT_OF_MEMORY);
return BindByName(aName, value);
}
NS_IMETHODIMP
BindingParams::BindDoubleByName(const nsACString &aName,
double aValue)
{
nsCOMPtr<nsIVariant> value(new FloatVariant(aValue));
NS_ENSURE_TRUE(value, NS_ERROR_OUT_OF_MEMORY);
return BindByName(aName, value);
}
NS_IMETHODIMP
BindingParams::BindInt32ByName(const nsACString &aName,
PRInt32 aValue)
{
nsCOMPtr<nsIVariant> value(new IntegerVariant(aValue));
NS_ENSURE_TRUE(value, NS_ERROR_OUT_OF_MEMORY);
return BindByName(aName, value);
}
NS_IMETHODIMP
BindingParams::BindInt64ByName(const nsACString &aName,
PRInt64 aValue)
{
nsCOMPtr<nsIVariant> value(new IntegerVariant(aValue));
NS_ENSURE_TRUE(value, NS_ERROR_OUT_OF_MEMORY);
return BindByName(aName, value);
}
NS_IMETHODIMP
BindingParams::BindNullByName(const nsACString &aName)
{
nsCOMPtr<nsIVariant> value(new NullVariant());
NS_ENSURE_TRUE(value, NS_ERROR_OUT_OF_MEMORY);
return BindByName(aName, value);
}
NS_IMETHODIMP
BindingParams::BindBlobByName(const nsACString &aName,
const PRUint8 *aValue,
PRUint32 aValueSize)
{
NS_ENSURE_ARG_MAX(aValueSize, INT_MAX);
std::pair<const void *, int> data(
static_cast<const void *>(aValue),
int(aValueSize)
);
nsCOMPtr<nsIVariant> value(new BlobVariant(data));
NS_ENSURE_TRUE(value, NS_ERROR_OUT_OF_MEMORY);
return BindByName(aName, value);
}
NS_IMETHODIMP
BindingParams::BindByIndex(PRUint32 aIndex,
nsIVariant *aValue)
{
NS_ENSURE_FALSE(mLocked, NS_ERROR_UNEXPECTED);
ENSURE_INDEX_VALUE(aIndex, mParamCount);
// Store the variant for later use.
NS_ENSURE_TRUE(mParameters.InsertObjectAt(aValue, aIndex),
NS_ERROR_OUT_OF_MEMORY);
return NS_OK;
}
NS_IMETHODIMP
BindingParams::BindUTF8StringByIndex(PRUint32 aIndex,
const nsACString &aValue)
{
nsCOMPtr<nsIVariant> value(new UTF8TextVariant(aValue));
NS_ENSURE_TRUE(value, NS_ERROR_OUT_OF_MEMORY);
return BindByIndex(aIndex, value);
}
NS_IMETHODIMP
BindingParams::BindStringByIndex(PRUint32 aIndex,
const nsAString &aValue)
{
nsCOMPtr<nsIVariant> value(new TextVariant(aValue));
NS_ENSURE_TRUE(value, NS_ERROR_OUT_OF_MEMORY);
return BindByIndex(aIndex, value);
}
NS_IMETHODIMP
BindingParams::BindDoubleByIndex(PRUint32 aIndex,
double aValue)
{
nsCOMPtr<nsIVariant> value(new FloatVariant(aValue));
NS_ENSURE_TRUE(value, NS_ERROR_OUT_OF_MEMORY);
return BindByIndex(aIndex, value);
}
NS_IMETHODIMP
BindingParams::BindInt32ByIndex(PRUint32 aIndex,
PRInt32 aValue)
{
nsCOMPtr<nsIVariant> value(new IntegerVariant(aValue));
NS_ENSURE_TRUE(value, NS_ERROR_OUT_OF_MEMORY);
return BindByIndex(aIndex, value);
}
NS_IMETHODIMP
BindingParams::BindInt64ByIndex(PRUint32 aIndex,
PRInt64 aValue)
{
nsCOMPtr<nsIVariant> value(new IntegerVariant(aValue));
NS_ENSURE_TRUE(value, NS_ERROR_OUT_OF_MEMORY);
return BindByIndex(aIndex, value);
}
NS_IMETHODIMP
BindingParams::BindNullByIndex(PRUint32 aIndex)
{
nsCOMPtr<nsIVariant> value(new NullVariant());
NS_ENSURE_TRUE(value, NS_ERROR_OUT_OF_MEMORY);
return BindByIndex(aIndex, value);
}
NS_IMETHODIMP
BindingParams::BindBlobByIndex(PRUint32 aIndex,
const PRUint8 *aValue,
PRUint32 aValueSize)
{
NS_ENSURE_ARG_MAX(aValueSize, INT_MAX);
std::pair<const void *, int> data(
static_cast<const void *>(aValue),
int(aValueSize)
);
nsCOMPtr<nsIVariant> value(new BlobVariant(data));
NS_ENSURE_TRUE(value, NS_ERROR_OUT_OF_MEMORY);
return BindByIndex(aIndex, value);
}
} // namespace storage
} // namespace mozilla

View File

@ -1,98 +0,0 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
* vim: sw=2 ts=2 et lcs=trail\:.,tab\:>~ :
* ***** 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):
* Shawn Wilsher <me@shawnwilsher.com> (Original Author)
*
* 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 ***** */
#ifndef _mozStorageBindingParams_h_
#define _mozStorageBindingParams_h_
#include "nsAutoPtr.h"
#include "nsCOMArray.h"
#include "nsIVariant.h"
#include "mozStorageBindingParamsArray.h"
#include "mozStorageStatement.h"
#include "mozIStorageBindingParams.h"
class mozIStorageError;
struct sqlite3_stmt;
namespace mozilla {
namespace storage {
class BindingParams : public mozIStorageBindingParams
{
public:
NS_DECL_ISUPPORTS
NS_DECL_MOZISTORAGEBINDINGPARAMS
/**
* Locks the parameters and prevents further modification to it (such as
* binding more elements to it).
*/
void lock();
/**
* @returns the pointer to the owning BindingParamsArray.
*/
const BindingParamsArray *getOwner() const;
/**
* Binds our stored data to the statement.
*
* @param aStatement
* The statement to bind our data to.
* @returns nsnull on success, or a mozIStorageError object if an error
* occurred.
*/
already_AddRefed<mozIStorageError> bind(sqlite3_stmt *aStatement);
BindingParams(BindingParamsArray *aOwningArray,
Statement *aOwningStatement);
private:
nsRefPtr<BindingParamsArray> mOwningArray;
Statement *mOwningStatement;
nsCOMArray<nsIVariant> mParameters;
PRUint32 mParamCount;
bool mLocked;
};
} // namespace storage
} // namespace mozilla
#endif // _mozStorageBindingParams_h_

View File

@ -1,113 +0,0 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
* vim: sw=2 ts=2 et lcs=trail\:.,tab\:>~ :
* ***** 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):
* Shawn Wilsher <me@shawnwilsher.com> (Original Author)
*
* 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 "mozStorageBindingParamsArray.h"
#include "mozStorageBindingParams.h"
namespace mozilla {
namespace storage {
////////////////////////////////////////////////////////////////////////////////
//// BindingParamsArray
BindingParamsArray::BindingParamsArray(Statement *aOwningStatement)
: mOwningStatement(aOwningStatement)
, mLocked(false)
{
}
void
BindingParamsArray::lock()
{
NS_ASSERTION(mLocked == false, "Array has already been locked!");
mLocked = true;
// We also no longer need to hold a reference to our statement since it owns
// us.
mOwningStatement = nsnull;
}
const Statement *
BindingParamsArray::getOwner() const
{
return mOwningStatement;
}
NS_IMPL_THREADSAFE_ISUPPORTS1(
BindingParamsArray,
mozIStorageBindingParamsArray
)
///////////////////////////////////////////////////////////////////////////////
//// mozIStorageBindingParamsArray
NS_IMETHODIMP
BindingParamsArray::NewBindingParams(mozIStorageBindingParams **_params)
{
NS_ENSURE_FALSE(mLocked, NS_ERROR_UNEXPECTED);
nsCOMPtr<mozIStorageBindingParams> params =
new BindingParams(this, mOwningStatement);
NS_ENSURE_TRUE(params, NS_ERROR_OUT_OF_MEMORY);
params.forget(_params);
return NS_OK;
}
NS_IMETHODIMP
BindingParamsArray::AddParams(mozIStorageBindingParams *aParameters)
{
NS_ENSURE_FALSE(mLocked, NS_ERROR_UNEXPECTED);
BindingParams *params = static_cast<BindingParams *>(aParameters);
// Check to make sure that this set of parameters was created with us.
if (params->getOwner() != this)
return NS_ERROR_UNEXPECTED;
NS_ENSURE_TRUE(mArray.AppendElement(params), NS_ERROR_OUT_OF_MEMORY);
// Lock the parameters only after we've successfully added them.
params->lock();
return NS_OK;
}
} // namespace storage
} // namespace mozilla

View File

@ -1,136 +0,0 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
* vim: sw=2 ts=2 et lcs=trail\:.,tab\:>~ :
* ***** 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):
* Shawn Wilsher <me@shawnwilsher.com> (Original Author)
*
* 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 ***** */
#ifndef _mozStorageBindingParamsArray_h_
#define _mozStorageBindingParamsArray_h_
#include "nsAutoPtr.h"
#include "nsTArray.h"
#include "mozIStorageBindingParamsArray.h"
namespace mozilla {
namespace storage {
class BindingParams;
class Statement;
class BindingParamsArray : public mozIStorageBindingParamsArray
{
public:
NS_DECL_ISUPPORTS
NS_DECL_MOZISTORAGEBINDINGPARAMSARRAY
BindingParamsArray(Statement *aOwningStatement);
/**
* Locks the array and prevents further modification to it (such as adding
* more elements to it).
*/
void lock();
/**
* @returns the pointer to the owning BindingParamsArray.
*/
const Statement *getOwner() const;
class iterator {
public:
iterator(BindingParamsArray *aArray,
PRUint32 aIndex)
: mArray(aArray)
, mIndex(aIndex)
{
}
iterator &operator++(int)
{
mIndex++;
return *this;
}
bool operator==(const iterator &aOther) const
{
return mIndex == aOther.mIndex;
}
bool operator!=(const iterator &aOther) const
{
return !(*this == aOther);
}
BindingParams *operator*()
{
NS_ASSERTION(mIndex < mArray->mArray.Length(),
"Dereferenceing an invalid value!");
return mArray->mArray[mIndex].get();
}
private:
void operator--() { }
BindingParamsArray *mArray;
PRUint32 mIndex;
};
/**
* Obtains an iterator pointing to the beginning of the array.
*/
inline iterator begin()
{
NS_ASSERTION(mLocked, "Obtaining an iterator when we are not locked!");
return iterator(this, 0);
}
/**
* Obtains an iterator pointing to the end of the array.
*/
inline iterator end()
{
NS_ASSERTION(mLocked, "Obtaining an iterator when we are not locked!");
return iterator(this, mArray.Length());
}
private:
nsRefPtr<Statement> mOwningStatement;
nsTArray< nsRefPtr<BindingParams> > mArray;
bool mLocked;
friend class iterator;
};
} // namespace storage
} // namespace mozilla
#endif // _mozStorageBindingParamsArray_h_

View File

@ -62,7 +62,6 @@
#include "mozStorageStatement.h"
#include "mozStorageArgValueArray.h"
#include "mozStoragePrivateHelpers.h"
#include "mozStorageStatementData.h"
#include "prlog.h"
#include "prprf.h"
@ -628,7 +627,7 @@ Connection::ExecuteAsync(mozIStorageStatement **aStatements,
mozIStoragePendingStatement **_handle)
{
int rc = SQLITE_OK;
nsTArray<StatementData> stmts(aNumStatements);
nsTArray<sqlite3_stmt *> stmts(aNumStatements);
for (PRUint32 i = 0; i < aNumStatements && rc == SQLITE_OK; i++) {
sqlite3_stmt *old_stmt =
static_cast<Statement *>(aStatements[i])->nativeStatement();
@ -658,9 +657,7 @@ Connection::ExecuteAsync(mozIStorageStatement **aStatements,
if (rc != SQLITE_OK)
break;
Statement *storageStmt = static_cast<Statement *>(aStatements[i]);
StatementData data(new_stmt, storageStmt->bindingParamsArray());
if (!stmts.AppendElement(data)) {
if (!stmts.AppendElement(new_stmt)) {
rc = SQLITE_NOMEM;
break;
}

View File

@ -505,33 +505,6 @@ Statement::BindBlobParameter(PRUint32 aParamIndex,
return convertResultCode(srv);
}
NS_IMETHODIMP
Statement::BindParameters(mozIStorageBindingParamsArray *aParameters)
{
if (!mDBStatement)
return NS_ERROR_NOT_INITIALIZED;
BindingParamsArray *array = static_cast<BindingParamsArray *>(aParameters);
if (array->getOwner() != this)
return NS_ERROR_UNEXPECTED;
mParamsArray = array;
mParamsArray->lock();
return NS_OK;
}
NS_IMETHODIMP
Statement::NewBindingParamsArray(mozIStorageBindingParamsArray **_array)
{
nsCOMPtr<mozIStorageBindingParamsArray> array =
new BindingParamsArray(this);
NS_ENSURE_TRUE(array, NS_ERROR_OUT_OF_MEMORY);
array.forget(_array);
return NS_OK;
}
NS_IMETHODIMP
Statement::Execute()
{

View File

@ -45,7 +45,6 @@
#include "nsTArray.h"
#include "mozStorageBindingParamsArray.h"
#include "mozIStorageStatement.h"
class nsIXPConnectJSObjectHolder;
@ -83,15 +82,6 @@ public:
*/
inline sqlite3_stmt *nativeStatement() { return mDBStatement; }
/**
* Obtains and transfers ownership of the array of parameters that are bound
* to this statment. This can be null.
*/
inline already_AddRefed<BindingParamsArray> bindingParamsArray()
{
return mParamsArray.forget();
}
private:
~Statement();
@ -102,12 +92,6 @@ private:
nsTArray<nsCString> mColumnNames;
bool mExecuting;
/**
* Holds the array of parameters to bind to this statement when we execute
* it asynchronously.
*/
nsRefPtr<BindingParamsArray> mParamsArray;
/**
* The following two members are only used with the JS helper. They cache
* the row and params objects.

View File

@ -1,106 +0,0 @@
/* -*- 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):
* Shawn Wilsher <me@shawnwilsher.com> (Original Author)
*
* 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 ***** */
#ifndef _mozStorageStatementData_h_
#define _mozStorageStatementData_h_
#include "nsAutoPtr.h"
#include "nsTArray.h"
#include "mozStorageBindingParamsArray.h"
struct sqlite3_stmt;
namespace mozilla {
namespace storage {
class StatementData
{
public:
StatementData(sqlite3_stmt *aStatement,
already_AddRefed<BindingParamsArray> aParamsArray)
: mStatement(aStatement)
, mParamsArray(aParamsArray)
{
}
StatementData(const StatementData &aSource)
: mStatement(aSource.mStatement)
, mParamsArray(aSource.mParamsArray)
{
}
StatementData()
{
}
operator sqlite3_stmt *() const
{
NS_ASSERTION(mStatement, "NULL sqlite3_stmt being handed off!");
return mStatement;
}
operator BindingParamsArray *() const { return mParamsArray; }
/**
* Finalizes and NULLs out our sqlite3_stmt. Also releases our parameter
* array since we'll no longer need it.
*/
inline void finalize()
{
(void)::sqlite3_finalize(mStatement);
mStatement = NULL;
mParamsArray = nsnull;
}
/**
* Indicates if this statement has parameters to be bound before it is
* executed.
*
* @returns true if the statement has parameters to bind against, false
* otherwise.
*/
inline bool hasParametersToBeBound() const { return mParamsArray != nsnull; }
private:
sqlite3_stmt *mStatement;
nsRefPtr<BindingParamsArray> mParamsArray;
};
} // namespace storage
} // namespace mozilla
#endif // _mozStorageStatementData_h_

View File

@ -44,9 +44,11 @@ const BLOB = [1, 2];
function test_create_and_add()
{
dump("test_create_and_add()\n");
getOpenedDatabase().executeSimpleSQL(
"CREATE TABLE test (" +
"id INTEGER, " +
"id INTEGER PRIMARY KEY, " +
"string TEXT, " +
"number REAL, " +
"nuller NULL, " +
@ -71,6 +73,7 @@ function test_create_and_add()
stmts[1].bindNullParameter(2);
stmts[1].bindBlobParameter(3, BLOB, BLOB.length);
do_test_pending();
getOpenedDatabase().executeAsync(stmts, stmts.length, {
handleResult: function(aResultSet)
{
@ -120,8 +123,7 @@ function test_create_and_add()
stmt.finalize();
}
// Run the next test.
run_next_test();
do_test_finished();
}
});
stmts[0].finalize();
@ -130,6 +132,8 @@ function test_create_and_add()
function test_transaction_created()
{
dump("test_transaction_created()\n");
let stmts = [];
stmts[0] = getOpenedDatabase().createStatement(
"BEGIN"
@ -138,6 +142,7 @@ function test_transaction_created()
"SELECT * FROM test"
);
do_test_pending()
getOpenedDatabase().executeAsync(stmts, stmts.length, {
handleResult: function(aResultSet)
{
@ -152,116 +157,24 @@ function test_transaction_created()
{
dump("handleCompletion("+aReason+")\n");
do_check_eq(Ci.mozIStorageStatementCallback.REASON_ERROR, aReason);
// Run the next test.
run_next_test();
do_test_finished();
}
});
stmts[0].finalize();
stmts[1].finalize();
}
function test_multiple_bindings_on_statements()
{
// This tests to make sure that we pass all the statements multiply bound
// parameters when we call executeAsync.
const AMOUNT_TO_ADD = 5;
const ITERATIONS = 5;
let stmts = [];
// We run the same statement twice, and should insert 2 * AMOUNT_TO_ADD.
for (let i = 0; i < ITERATIONS; i++) {
stmts[i] = getOpenedDatabase().createStatement(
"INSERT INTO test (id, string, number, nuller, blober) " +
"VALUES (:int, :text, :real, :null, :blob)"
);
let params = stmts[i].newBindingParamsArray()
for (let j = 0; j < AMOUNT_TO_ADD; j++) {
let bp = params.newBindingParams();
bp.bindByName("int", INTEGER);
bp.bindByName("text", TEXT);
bp.bindByName("real", REAL);
bp.bindByName("null", null);
bp.bindBlobByName("blob", BLOB, BLOB.length);
params.addParams(bp);
}
stmts[i].bindParameters(params);
}
// Get our current number of rows in the table.
let currentRows = 0;
let countStmt = getOpenedDatabase().createStatement(
"SELECT COUNT(1) AS count FROM test"
);
try {
do_check_true(countStmt.executeStep());
currentRows = countStmt.row.count;
}
finally {
countStmt.reset();
}
// Execute asynchronously.
getOpenedDatabase().executeAsync(stmts, stmts.length, {
handleResult: function(aResultSet)
{
do_throw("Unexpected call to handleResult!");
},
handleError: function(aError)
{
print("Error code " + aError.result + " with message '" +
aError.message + "' returned.");
do_throw("Unexpected error!");
},
handleCompletion: function(aReason)
{
print("handleCompletion(" + aReason +
") for test_multiple_bindings_on_statements");
do_check_eq(Ci.mozIStorageStatementCallback.REASON_FINISHED, aReason);
// Check to make sure we added all of our rows.
try {
do_check_true(countStmt.executeStep());
do_check_eq(currentRows + (ITERATIONS * AMOUNT_TO_ADD),
countStmt.row.count);
}
finally {
countStmt.finalize();
}
// Run the next test.
run_next_test();
}
});
stmts.forEach(function(stmt) stmt.finalize());
}
////////////////////////////////////////////////////////////////////////////////
//// Test Runner
let tests =
[
test_create_and_add,
test_transaction_created,
test_multiple_bindings_on_statements,
];
let index = 0;
function run_next_test()
{
if (index < tests.length) {
do_test_pending();
print("Running the next test: " + tests[index].name);
tests[index++]();
}
do_test_finished();
}
function run_test()
{
cleanup();
do_test_pending();
run_next_test();
for (let i = 0; i < tests.length; i++)
tests[i]();
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,521 @@
/* ***** 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 Storage Test Code.
*
* The Initial Developer of the Original Code is
* Mozilla Corporation.
* Portions created by the Initial Developer are Copyright (C) 2008
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Shawn Wilsher <me@shawnwilsher.com> (Original Author)
*
* 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 ***** */
// This file tests the functionality of mozIStorageStatement::executeAsync
const INTEGER = 1;
const TEXT = "this is test text";
const REAL = 3.23;
const BLOB = [1, 2];
function test_create_table()
{
dump("test_create_table()\n");
// Ensure our table doesn't exists
do_check_false(getOpenedDatabase().tableExists("test"));
var stmt = getOpenedDatabase().createStatement(
"CREATE TABLE test (" +
"id INTEGER PRIMARY KEY, " +
"string TEXT, " +
"number REAL, " +
"nuller NULL, " +
"blober BLOB" +
")"
);
do_test_pending();
stmt.executeAsync({
handleResult: function(aResultSet)
{
dump("handleResult("+aResultSet+");\n");
do_throw("unexpected results obtained!");
},
handleError: function(aError)
{
dump("handleError("+aError+");\n");
do_throw("unexpected error!");
},
handleCompletion: function(aReason)
{
dump("handleCompletion("+aReason+");\n");
do_check_eq(Ci.mozIStorageStatementCallback.REASON_FINISHED, aReason);
// Check that the table has been created
do_check_true(getOpenedDatabase().tableExists("test"));
// Verify that it's created correctly (this will throw if it wasn't)
var stmt = getOpenedDatabase().createStatement(
"SELECT id, string, number, nuller, blober FROM test"
);
stmt.finalize();
// Now we run the rest of the tests
for (var i = 0; i < tests.length; i++)
tests[i]();
do_test_finished();
}
});
stmt.finalize();
}
function test_add_data()
{
dump("test_add_data()\n");
var stmt = getOpenedDatabase().createStatement(
"INSERT INTO test (id, string, number, nuller, blober) VALUES (?, ?, ?, ?, ?)"
);
stmt.bindInt32Parameter(0, INTEGER);
stmt.bindStringParameter(1, TEXT);
stmt.bindDoubleParameter(2, REAL);
stmt.bindNullParameter(3);
stmt.bindBlobParameter(4, BLOB, BLOB.length);
do_test_pending();
stmt.executeAsync({
handleResult: function(aResultSet)
{
dump("handleResult("+aResultSet+");\n");
do_throw("unexpected results obtained!");
},
handleError: function(aError)
{
dump("handleError("+aError+");\n");
do_throw("unexpected error!");
},
handleCompletion: function(aReason)
{
dump("handleCompletion("+aReason+");\n");
do_check_eq(Ci.mozIStorageStatementCallback.REASON_FINISHED, aReason);
// Check that the result is in the table
var stmt = getOpenedDatabase().createStatement(
"SELECT string, number, nuller, blober FROM test WHERE id = ?"
);
stmt.bindInt32Parameter(0, INTEGER);
try {
do_check_true(stmt.executeStep());
do_check_eq(TEXT, stmt.getString(0));
do_check_eq(REAL, stmt.getDouble(1));
do_check_true(stmt.getIsNull(2));
var count = { value: 0 };
var blob = { value: null };
stmt.getBlob(3, count, blob);
do_check_eq(BLOB.length, count.value);
for (var i = 0; i < BLOB.length; i++)
do_check_eq(BLOB[i], blob.value[i]);
}
finally {
stmt.reset();
stmt.finalize();
}
do_test_finished();
}
});
stmt.finalize();
}
function test_get_data()
{
dump("test_get_data()\n");
var stmt = getOpenedDatabase().createStatement(
"SELECT string, number, nuller, blober, id FROM test WHERE id = ?"
);
stmt.bindInt32Parameter(0, 1);
do_test_pending();
stmt.executeAsync({
resultObtained: false,
handleResult: function(aResultSet)
{
dump("handleResult("+aResultSet+");\n");
do_check_false(this.resultObtained);
this.resultObtained = true;
// Check that we have a result
var tuple = aResultSet.getNextRow();
do_check_neq(null, tuple);
// Check that it's what we expect
do_check_eq(tuple.getResultByName("string"), tuple.getResultByIndex(0));
do_check_eq(TEXT, tuple.getResultByName("string"));
do_check_eq(Ci.mozIStorageValueArray.VALUE_TYPE_TEXT,
tuple.getTypeOfIndex(0));
do_check_eq(tuple.getResultByName("number"), tuple.getResultByIndex(1));
do_check_eq(REAL, tuple.getResultByName("number"));
do_check_eq(Ci.mozIStorageValueArray.VALUE_TYPE_FLOAT,
tuple.getTypeOfIndex(1));
do_check_eq(tuple.getResultByName("nuller"), tuple.getResultByIndex(2));
do_check_eq(null, tuple.getResultByName("nuller"));
do_check_eq(Ci.mozIStorageValueArray.VALUE_TYPE_NULL,
tuple.getTypeOfIndex(2));
var blobByName = tuple.getResultByName("blober");
do_check_eq(BLOB.length, blobByName.length);
var blobByIndex = tuple.getResultByIndex(3);
do_check_eq(BLOB.length, blobByIndex.length);
for (var i = 0; i < BLOB.length; i++) {
do_check_eq(BLOB[i], blobByName[i]);
do_check_eq(BLOB[i], blobByIndex[i]);
}
var count = { value: 0 };
var blob = { value: null };
tuple.getBlob(3, count, blob);
do_check_eq(BLOB.length, count.value);
for (var i = 0; i < BLOB.length; i++)
do_check_eq(BLOB[i], blob.value[i]);
do_check_eq(Ci.mozIStorageValueArray.VALUE_TYPE_BLOB,
tuple.getTypeOfIndex(3));
do_check_eq(tuple.getResultByName("id"), tuple.getResultByIndex(4));
do_check_eq(INTEGER, tuple.getResultByName("id"));
do_check_eq(Ci.mozIStorageValueArray.VALUE_TYPE_INTEGER,
tuple.getTypeOfIndex(4));
// check that we have no more results
tuple = aResultSet.getNextRow();
do_check_eq(null, tuple);
},
handleError: function(aError)
{
dump("handleError("+aError+");\n");
do_throw("unexpected error!");
},
handleCompletion: function(aReason)
{
dump("handleCompletion("+aReason+");\n");
do_check_eq(Ci.mozIStorageStatementCallback.REASON_FINISHED, aReason);
do_check_true(this.resultObtained);
do_test_finished();
}
});
stmt.finalize();
}
function test_tuple_out_of_bounds()
{
dump("test_tuple_out_of_bounds()\n");
var stmt = getOpenedDatabase().createStatement(
"SELECT string FROM test"
);
do_test_pending();
stmt.executeAsync({
resultObtained: false,
handleResult: function(aResultSet)
{
dump("handleResult("+aResultSet+");\n");
do_check_false(this.resultObtained);
this.resultObtained = true;
// Check that we have a result
var tuple = aResultSet.getNextRow();
do_check_neq(null, tuple);
// Check all out of bounds - should throw
var methods = [
"getTypeOfIndex",
"getInt32",
"getInt64",
"getDouble",
"getUTF8String",
"getString",
"getIsNull",
];
for (var i in methods) {
try {
tuple[methods[i]](tuple.numEntries);
do_throw("did not throw :(");
}
catch (e) {
do_check_eq(Cr.NS_ERROR_ILLEGAL_VALUE, e.result);
}
}
// getBlob requires more args...
try {
var blob = { value: null };
var size = { value: 0 };
tuple.getBlob(tuple.numEntries, blob, size);
do_throw("did not throw :(");
}
catch (e) {
do_check_eq(Cr.NS_ERROR_ILLEGAL_VALUE, e.result);
}
},
handleError: function(aError)
{
dump("handleError("+aError+");\n");
do_throw("unexpected error!");
},
handleCompletion: function(aReason)
{
dump("handleCompletion("+aReason+");\n");
do_check_eq(Ci.mozIStorageStatementCallback.REASON_FINISHED, aReason);
do_check_true(this.resultObtained);
do_test_finished();
}
});
stmt.finalize();
}
function test_no_listener_works_on_success()
{
dump("test_no_listener_works_on_success()\n");
var stmt = getOpenedDatabase().createStatement(
"DELETE FROM test WHERE id = ?"
);
stmt.bindInt32Parameter(0, 0);
stmt.executeAsync();
stmt.finalize();
}
function test_no_listener_works_on_results()
{
dump("test_no_listener_works_on_results()\n");
var stmt = getOpenedDatabase().createStatement(
"SELECT ?"
);
stmt.bindInt32Parameter(0, 1);
stmt.executeAsync();
stmt.finalize();
}
function test_no_listener_works_on_error()
{
return;
dump("test_no_listener_works_on_error()\n");
// commit without a transaction will trigger an error
var stmt = getOpenedDatabase().createStatement(
"COMMIT"
);
stmt.executeAsync();
stmt.finalize();
}
function test_partial_listener_works()
{
dump("test_partial_listener_works()\n");
var stmt = getOpenedDatabase().createStatement(
"DELETE FROM test WHERE id = ?"
);
stmt.bindInt32Parameter(0, 0);
stmt.executeAsync({
handleResult: function(aResultSet)
{
}
});
stmt.executeAsync({
handleError: function(aError)
{
}
});
stmt.executeAsync({
handleCompletion: function(aReason)
{
}
});
stmt.finalize();
}
function test_immediate_cancellation()
{
dump("test_immediate_cancelation()\n");
var stmt = getOpenedDatabase().createStatement(
"DELETE FROM test WHERE id = ?"
);
stmt.bindInt32Parameter(0, 0);
let reason = Ci.mozIStorageStatementCallback.REASON_CANCELED;
var pendingStatement = stmt.executeAsync({
handleResult: function(aResultSet)
{
dump("handleResult("+aResultSet+");\n");
do_throw("unexpected result!");
},
handleError: function(aError)
{
dump("handleError("+aError+");\n");
do_throw("unexpected error!");
},
handleCompletion: function(aReason)
{
dump("handleCompletion("+aReason+");\n");
do_check_eq(reason, aReason);
do_test_finished();
}
});
do_test_pending();
// Cancel immediately
if (!pendingStatement.cancel()) {
// It is possible that we finished before we canceled
reason = Ci.mozIStorageStatementCallback.REASON_FINISHED;
}
stmt.finalize();
}
function test_double_cancellation()
{
dump("test_double_cancelation()\n");
var stmt = getOpenedDatabase().createStatement(
"DELETE FROM test WHERE id = ?"
);
stmt.bindInt32Parameter(0, 0);
let reason = Ci.mozIStorageStatementCallback.REASON_CANCELED;
var pendingStatement = stmt.executeAsync({
handleResult: function(aResultSet)
{
dump("handleResult("+aResultSet+");\n");
do_throw("unexpected result!");
},
handleError: function(aError)
{
dump("handleError("+aError+");\n");
do_throw("unexpected error!");
},
handleCompletion: function(aReason)
{
dump("handleCompletion("+aReason+");\n");
do_check_eq(reason, aReason);
do_test_finished();
}
});
do_test_pending();
// Cancel immediately
if (!pendingStatement.cancel()) {
// It is possible that we finished before we canceled
reason = Ci.mozIStorageStatementCallback.REASON_FINISHED;
}
// And cancel again - expect an exception
try {
pendingStatement.cancel();
do_throw("function call should have thrown!");
}
catch (e) {
do_check_eq(Cr.NS_ERROR_UNEXPECTED, e.result);
}
stmt.finalize();
}
function test_double_execute()
{
dump("test_double_execute()\n");
var stmt = getOpenedDatabase().createStatement(
"SELECT * FROM test"
);
var listener = {
handleResult: function(aResultSet)
{
dump("handleResult("+aResultSet+");\n");
},
handleError: function(aError)
{
dump("handleError("+aError+");\n");
do_throw("unexpected error!");
},
handleCompletion: function(aReason)
{
dump("handleCompletion("+aReason+");\n");
do_check_eq(Ci.mozIStorageStatementCallback.REASON_FINISHED, aReason);
do_test_finished();
}
}
do_test_pending();
stmt.executeAsync(listener);
do_test_pending();
stmt.executeAsync(listener);
stmt.finalize();
}
function test_finalized_statement_does_not_crash()
{
dump("test_finalized_statement_does_not_crash()\n");
var stmt = getOpenedDatabase().createStatement(
"SELECT * FROM TEST"
);
stmt.finalize();
// we are concerned about a crash here; an error is fine.
try {
stmt.executeAsync();
}
catch (ex) {}
}
var tests =
[
test_add_data,
test_get_data,
test_tuple_out_of_bounds,
test_no_listener_works_on_success,
test_no_listener_works_on_results,
test_no_listener_works_on_error,
test_partial_listener_works,
test_immediate_cancellation,
test_double_cancellation,
test_double_execute,
test_finalized_statement_does_not_crash,
];
function run_test()
{
cleanup();
// This test has to run first and run to completion. When it is done, it will
// run the rest of the tests.
test_create_table();
}