Bug 458811 - Allow for multiple statements to be executed at in a transaction asynchronously
This changeset allows consumers to execute a series of statements, in order, asynchronously in a transaction. r=dcamp sr=sicking
This commit is contained in:
Родитель
135aace591
Коммит
de4ea794f3
|
@ -45,6 +45,8 @@ interface mozIStorageAggregateFunction;
|
|||
interface mozIStorageFunction;
|
||||
interface mozIStorageProgressHandler;
|
||||
interface mozIStorageStatement;
|
||||
interface mozIStorageStatementCallback;
|
||||
interface mozIStoragePendingStatement;
|
||||
interface nsIFile;
|
||||
|
||||
/**
|
||||
|
@ -56,12 +58,12 @@ interface nsIFile;
|
|||
*
|
||||
* @threadsafe
|
||||
*/
|
||||
[scriptable, uuid(623f9ddb-434b-4d39-bc2d-1c617da241d0)]
|
||||
[scriptable, uuid(ac3c486c-69a1-4cbe-8f25-2ad20880eab3)]
|
||||
interface mozIStorageConnection : nsISupports {
|
||||
/*
|
||||
* Initialization and status
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* Closes a database connection. C++ callers should simply set the database
|
||||
* variable to NULL.
|
||||
|
@ -126,6 +128,31 @@ interface mozIStorageConnection : nsISupports {
|
|||
*/
|
||||
void executeSimpleSQL(in AUTF8String aSQLStatement);
|
||||
|
||||
/**
|
||||
* Execute an array of queries created with this connection asynchronously
|
||||
* using any currently bound parameters. The statements are ran wrapped in a
|
||||
* transaction. These statements can be reused immediately, and reset does
|
||||
* not need to be called.
|
||||
*
|
||||
* Note: If you have any custom defined functions, they must be re-entrant
|
||||
* since they can be called on multiple threads.
|
||||
*
|
||||
* @param aStatements
|
||||
* The array of statements to execute asynchronously, in the order they
|
||||
* are given in the array.
|
||||
* @param aNumStatements
|
||||
* The number of statements in aStatements.
|
||||
* @param aCallback [optional]
|
||||
* The callback object that will be notified of progress, errors, and
|
||||
* completion.
|
||||
* @returns an object that can be used to cancel the statements execution.
|
||||
*/
|
||||
mozIStoragePendingStatement executeAsync(
|
||||
[array, size_is(aNumStatements)] in mozIStorageStatement aStatements,
|
||||
in unsigned long aNumStatements,
|
||||
[optional] in mozIStorageStatementCallback aCallback
|
||||
);
|
||||
|
||||
/**
|
||||
* Check if the given table exists.
|
||||
*
|
||||
|
|
|
@ -40,6 +40,7 @@
|
|||
#define _MOZSTORAGEHELPER_H_
|
||||
|
||||
#include "mozIStorageConnection.h"
|
||||
#include "mozIStorageStatement.h"
|
||||
|
||||
|
||||
/**
|
||||
|
|
|
@ -54,6 +54,7 @@
|
|||
#include "mozIStorageAggregateFunction.h"
|
||||
#include "mozIStorageFunction.h"
|
||||
|
||||
#include "mozStorageEvents.h"
|
||||
#include "mozStorageUnicodeFunctions.h"
|
||||
#include "mozStorageConnection.h"
|
||||
#include "mozStorageService.h"
|
||||
|
@ -358,6 +359,60 @@ mozStorageConnection::ExecuteSimpleSQL(const nsACString& aSQLStatement)
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
mozStorageConnection::ExecuteAsync(mozIStorageStatement ** aStatements,
|
||||
PRUint32 aNumStatements,
|
||||
mozIStorageStatementCallback *aCallback,
|
||||
mozIStoragePendingStatement **_stmt)
|
||||
{
|
||||
int rc = SQLITE_OK;
|
||||
nsTArray<sqlite3_stmt *> stmts(aNumStatements);
|
||||
for (PRUint32 i = 0; i < aNumStatements && rc == SQLITE_OK; i++) {
|
||||
sqlite3_stmt *old_stmt = aStatements[i]->GetNativeStatementPointer();
|
||||
NS_ASSERTION(sqlite3_db_handle(old_stmt) == mDBConn,
|
||||
"Statement must be from this database connection!");
|
||||
|
||||
// Clone this statement. We only need a sqlite3_stmt object, so we can
|
||||
// avoid all the extra work that making a new mozStorageStatement would
|
||||
// normally involve and use the SQLite API.
|
||||
sqlite3_stmt *new_stmt;
|
||||
rc = sqlite3_prepare_v2(mDBConn, sqlite3_sql(old_stmt), -1, &new_stmt,
|
||||
NULL);
|
||||
if (rc != SQLITE_OK)
|
||||
break;
|
||||
|
||||
// Transfer the bindings
|
||||
rc = sqlite3_transfer_bindings(old_stmt, new_stmt);
|
||||
if (rc != SQLITE_OK)
|
||||
break;
|
||||
|
||||
if (!stmts.AppendElement(new_stmt)) {
|
||||
rc = SQLITE_NOMEM;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Dispatch to the background
|
||||
nsresult rv = NS_OK;
|
||||
if (rc == SQLITE_OK)
|
||||
rv = NS_executeAsync(stmts, this, aCallback, _stmt);
|
||||
|
||||
// We had a failure, so we need to clean up...
|
||||
if (rc != SQLITE_OK || NS_FAILED(rv)) {
|
||||
for (PRUint32 i = 0; i < stmts.Length(); i++)
|
||||
(void)sqlite3_finalize(stmts[i]);
|
||||
|
||||
if (rc != SQLITE_OK)
|
||||
rv = ConvertResultCode(rc);
|
||||
}
|
||||
|
||||
// Always reset all the statements
|
||||
for (PRUint32 i = 0; i < aNumStatements; i++)
|
||||
(void)aStatements[i]->Reset();
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
mozStorageConnection::TableExists(const nsACString& aSQLStatement, PRBool *_retval)
|
||||
{
|
||||
|
|
|
@ -46,6 +46,7 @@
|
|||
|
||||
#include "mozIStorageStatementCallback.h"
|
||||
#include "mozIStoragePendingStatement.h"
|
||||
#include "mozStorageHelper.h"
|
||||
#include "mozStorageResultSet.h"
|
||||
#include "mozStorageRow.h"
|
||||
#include "mozStorageBackground.h"
|
||||
|
@ -272,15 +273,19 @@ public:
|
|||
/**
|
||||
* This takes ownership of both the statement and the callback.
|
||||
*/
|
||||
AsyncExecute(sqlite3_stmt *aStatement,
|
||||
AsyncExecute(nsTArray<sqlite3_stmt *> &aStatements,
|
||||
mozIStorageConnection *aConnection,
|
||||
mozIStorageStatementCallback *aCallback) :
|
||||
mStatement(aStatement)
|
||||
mConnection(aConnection)
|
||||
, mTransactionManager(nsnull)
|
||||
, mCallback(aCallback)
|
||||
, mCallingThread(do_GetCurrentThread())
|
||||
, mState(PENDING)
|
||||
, mStateMutex(nsAutoLock::NewLock("AsyncExecute::mStateMutex"))
|
||||
, mPendingEventsMutex(nsAutoLock::NewLock("AsyncExecute::mPendingEventsMutex"))
|
||||
{
|
||||
(void)mStatements.SwapElements(aStatements);
|
||||
NS_ASSERTION(mStatements.Length(), "We weren't given any statements!");
|
||||
}
|
||||
|
||||
nsresult initialize()
|
||||
|
@ -300,94 +305,106 @@ public:
|
|||
return Complete();
|
||||
}
|
||||
|
||||
// Execute the statement, giving the callback results
|
||||
// XXX better chunking of results?
|
||||
nsresult rv = NS_OK;
|
||||
while (PR_TRUE) {
|
||||
int rc = sqlite3_step(mStatement);
|
||||
// Break out if we have no more results
|
||||
if (rc == SQLITE_DONE)
|
||||
break;
|
||||
// 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.
|
||||
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);
|
||||
}
|
||||
|
||||
// Some errors are not fatal, and we can handle them and continue.
|
||||
if (rc != SQLITE_OK && rc != SQLITE_ROW) {
|
||||
if (rc == SQLITE_BUSY) {
|
||||
// Yield, and try again
|
||||
PR_Sleep(PR_INTERVAL_NO_WAIT);
|
||||
continue;
|
||||
// Execute each statement, giving the callback results if it returns any.
|
||||
nsresult rv = NS_OK;
|
||||
for (PRUint32 i = 0; i < mStatements.Length(); i++) {
|
||||
while (PR_TRUE) {
|
||||
int rc = sqlite3_step(mStatements[i]);
|
||||
// Break out if we have no more results
|
||||
if (rc == SQLITE_DONE)
|
||||
break;
|
||||
|
||||
// Some errors are not fatal, and we can handle them and continue.
|
||||
if (rc != SQLITE_OK && rc != SQLITE_ROW) {
|
||||
if (rc == SQLITE_BUSY) {
|
||||
// Yield, and try again
|
||||
PR_Sleep(PR_INTERVAL_NO_WAIT);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Set error state
|
||||
{
|
||||
nsAutoLock mutex(mStateMutex);
|
||||
mState = ERROR;
|
||||
}
|
||||
|
||||
// Notify
|
||||
sqlite3 *db = sqlite3_db_handle(mStatements[i]);
|
||||
iCancelable *cancelable = ErrorNotifier::Dispatch(
|
||||
mCallingThread, mCallback, this, rc, sqlite3_errmsg(db)
|
||||
);
|
||||
if (cancelable) {
|
||||
nsAutoLock mutex(mPendingEventsMutex);
|
||||
(void)mPendingEvents.AppendObject(cancelable);
|
||||
}
|
||||
|
||||
// And complete
|
||||
return Complete();
|
||||
}
|
||||
|
||||
// Set error state
|
||||
// Check to see if we have been canceled
|
||||
{
|
||||
nsAutoLock mutex(mStateMutex);
|
||||
mState = ERROR;
|
||||
if (mState == CANCELED)
|
||||
return Complete();
|
||||
}
|
||||
|
||||
// Notify
|
||||
sqlite3 *db = sqlite3_db_handle(mStatement);
|
||||
iCancelable *cancelable = ErrorNotifier::Dispatch(
|
||||
mCallingThread, mCallback, this, rc, sqlite3_errmsg(db)
|
||||
);
|
||||
if (cancelable) {
|
||||
// If we do not have a callback, there's no point in executing this
|
||||
// statement anymore.
|
||||
if (!mCallback)
|
||||
break;
|
||||
|
||||
// Build result object
|
||||
// XXX bug 454740 chunk these results better
|
||||
nsRefPtr<mozStorageResultSet> results(new mozStorageResultSet());
|
||||
if (!results) {
|
||||
rv = NS_ERROR_OUT_OF_MEMORY;
|
||||
break;
|
||||
}
|
||||
|
||||
nsRefPtr<mozStorageRow> row(new mozStorageRow());
|
||||
if (!row) {
|
||||
rv = NS_ERROR_OUT_OF_MEMORY;
|
||||
break;
|
||||
}
|
||||
|
||||
rv = row->initialize(mStatements[i]);
|
||||
if (NS_FAILED(rv)) {
|
||||
rv = NS_ERROR_OUT_OF_MEMORY;
|
||||
break;
|
||||
}
|
||||
|
||||
rv = results->add(row);
|
||||
if (NS_FAILED(rv))
|
||||
break;
|
||||
|
||||
// Notify caller
|
||||
nsRefPtr<CallbackResultNotifier> notifier =
|
||||
new CallbackResultNotifier(mCallback, results, this);
|
||||
if (!notifier) {
|
||||
rv = NS_ERROR_OUT_OF_MEMORY;
|
||||
break;
|
||||
}
|
||||
|
||||
nsresult status = mCallingThread->Dispatch(notifier, NS_DISPATCH_NORMAL);
|
||||
if (NS_SUCCEEDED(status)) {
|
||||
nsAutoLock mutex(mPendingEventsMutex);
|
||||
(void)mPendingEvents.AppendObject(cancelable);
|
||||
(void)mPendingEvents.AppendObject(notifier);
|
||||
}
|
||||
|
||||
// And complete
|
||||
return Complete();
|
||||
}
|
||||
|
||||
// Check to see if we have been canceled
|
||||
{
|
||||
nsAutoLock mutex(mStateMutex);
|
||||
if (mState == CANCELED)
|
||||
return Complete();
|
||||
}
|
||||
|
||||
// If we do not have a callback, but are getting results, we should stop
|
||||
// now since all this work isn't going to accomplish anything
|
||||
if (!mCallback) {
|
||||
nsAutoLock mutex(mStateMutex);
|
||||
mState = COMPLETED;
|
||||
return Complete();
|
||||
}
|
||||
|
||||
// Build result object
|
||||
nsRefPtr<mozStorageResultSet> results(new mozStorageResultSet());
|
||||
if (!results) {
|
||||
rv = NS_ERROR_OUT_OF_MEMORY;
|
||||
break;
|
||||
}
|
||||
|
||||
nsRefPtr<mozStorageRow> row(new mozStorageRow());
|
||||
if (!row) {
|
||||
rv = NS_ERROR_OUT_OF_MEMORY;
|
||||
break;
|
||||
}
|
||||
|
||||
rv = row->initialize(mStatement);
|
||||
if (NS_FAILED(rv)) {
|
||||
rv = NS_ERROR_OUT_OF_MEMORY;
|
||||
break;
|
||||
}
|
||||
|
||||
rv = results->add(row);
|
||||
// If we have an error, we need to break out now.
|
||||
if (NS_FAILED(rv))
|
||||
break;
|
||||
|
||||
// Notify caller
|
||||
nsRefPtr<CallbackResultNotifier> notifier =
|
||||
new CallbackResultNotifier(mCallback, results, this);
|
||||
if (!notifier) {
|
||||
rv = NS_ERROR_OUT_OF_MEMORY;
|
||||
break;
|
||||
}
|
||||
|
||||
nsresult status = mCallingThread->Dispatch(notifier, NS_DISPATCH_NORMAL);
|
||||
if (NS_SUCCEEDED(status)) {
|
||||
nsAutoLock mutex(mPendingEventsMutex);
|
||||
(void)mPendingEvents.AppendObject(notifier);
|
||||
}
|
||||
}
|
||||
|
||||
// We have broken out of the loop because of an error or because we are
|
||||
|
@ -474,9 +491,33 @@ private:
|
|||
NS_ASSERTION(mState != PENDING,
|
||||
"Still in a pending state when calling Complete!");
|
||||
|
||||
// Reset the statement
|
||||
(void)sqlite3_finalize(mStatement);
|
||||
mStatement = NULL;
|
||||
// Handle our transaction, if we have one
|
||||
if (mTransactionManager) {
|
||||
if (mState == COMPLETED) {
|
||||
nsresult rv = mTransactionManager->Commit();
|
||||
if (NS_FAILED(rv)) {
|
||||
iCancelable *cancelable = ErrorNotifier::Dispatch(
|
||||
mCallingThread, mCallback, this, mozIStorageError::ERROR,
|
||||
"Transaction failed to commit"
|
||||
);
|
||||
if (cancelable) {
|
||||
nsAutoLock mutex(mPendingEventsMutex);
|
||||
(void)mPendingEvents.AppendObject(cancelable);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
(void)mTransactionManager->Rollback();
|
||||
}
|
||||
delete mTransactionManager;
|
||||
mTransactionManager = nsnull;
|
||||
}
|
||||
|
||||
// Finalize our statements
|
||||
for (PRUint32 i = 0; i < mStatements.Length(); i++) {
|
||||
(void)sqlite3_finalize(mStatements[i]);
|
||||
mStatements[i] = NULL;
|
||||
}
|
||||
|
||||
// Notify about completion iff we have a callback.
|
||||
if (mCallback) {
|
||||
|
@ -495,7 +536,9 @@ private:
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
sqlite3_stmt *mStatement;
|
||||
nsTArray<sqlite3_stmt *> mStatements;
|
||||
mozIStorageConnection *mConnection;
|
||||
mozStorageTransaction *mTransactionManager;
|
||||
mozIStorageStatementCallback *mCallback;
|
||||
nsCOMPtr<nsIThread> mCallingThread;
|
||||
|
||||
|
@ -527,12 +570,13 @@ NS_IMPL_THREADSAFE_ISUPPORTS2(
|
|||
)
|
||||
|
||||
nsresult
|
||||
NS_executeAsync(sqlite3_stmt *aStatement,
|
||||
NS_executeAsync(nsTArray<sqlite3_stmt *> &aStatements,
|
||||
mozIStorageConnection *aConnection,
|
||||
mozIStorageStatementCallback *aCallback,
|
||||
mozIStoragePendingStatement **_stmt)
|
||||
{
|
||||
// Create our event to run in the background
|
||||
nsRefPtr<AsyncExecute> event(new AsyncExecute(aStatement, aCallback));
|
||||
nsRefPtr<AsyncExecute> event(new AsyncExecute(aStatements, aConnection, aCallback));
|
||||
NS_ENSURE_TRUE(event, NS_ERROR_OUT_OF_MEMORY);
|
||||
|
||||
nsresult rv = event->initialize();
|
||||
|
|
|
@ -41,6 +41,7 @@
|
|||
#define _mozStorageEvents_h_
|
||||
|
||||
#include "nscore.h"
|
||||
#include "nsTArray.h"
|
||||
#include "mozStorageBackground.h"
|
||||
struct sqlite3_stmt;
|
||||
class mozIStorageStatementCallback;
|
||||
|
@ -50,15 +51,18 @@ class mozIStoragePendingStatement;
|
|||
* Executes a statement in the background, and passes results back to the
|
||||
* caller.
|
||||
*
|
||||
* @param aStatement
|
||||
* The SQLite statement to execute in the background.
|
||||
* @param aStatements
|
||||
* The SQLite statements to execute in the background.
|
||||
* @param aConnection
|
||||
* The connection that created the statements to execute.
|
||||
* @param aCallback
|
||||
* The callback that is notified of results, completion, and errors.
|
||||
* @param _stmt
|
||||
* The handle to control the execution of the statement.
|
||||
* The handle to control the execution of the statements.
|
||||
*/
|
||||
nsresult NS_executeAsync(
|
||||
sqlite3_stmt *aStatement,
|
||||
nsTArray<sqlite3_stmt *> &aStatements,
|
||||
mozIStorageConnection *aConnection,
|
||||
mozIStorageStatementCallback *aCallback,
|
||||
mozIStoragePendingStatement **_stmt
|
||||
);
|
||||
|
|
|
@ -578,29 +578,8 @@ nsresult
|
|||
mozStorageStatement::ExecuteAsync(mozIStorageStatementCallback *aCallback,
|
||||
mozIStoragePendingStatement **_stmt)
|
||||
{
|
||||
// Clone this statement. We only need a sqlite3_stmt object, so we can
|
||||
// avoid all the extra work that making a new mozStorageStatement would
|
||||
// normally involve and use the SQLite API.
|
||||
sqlite3 *db = mDBConnection->GetNativeConnection();
|
||||
sqlite3_stmt *stmt;
|
||||
int rc = sqlite3_prepare_v2(db, sqlite3_sql(mDBStatement), -1, &stmt, NULL);
|
||||
if (rc != SQLITE_OK)
|
||||
return ConvertResultCode(rc);
|
||||
|
||||
// Transfer the bindings
|
||||
rc = sqlite3_transfer_bindings(mDBStatement, stmt);
|
||||
if (rc != SQLITE_OK)
|
||||
return ConvertResultCode(rc);
|
||||
|
||||
// Dispatch to the background.
|
||||
nsresult rv = NS_executeAsync(stmt, aCallback, _stmt);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// Reset this statement.
|
||||
rv = Reset();
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
return NS_OK;
|
||||
mozIStorageStatement * stmts[1] = {this};
|
||||
return mDBConnection->ExecuteAsync(stmts, 1, aCallback, _stmt);
|
||||
}
|
||||
|
||||
/* [noscript,notxpcom] sqlite3stmtptr getNativeStatementPointer(); */
|
||||
|
|
|
@ -0,0 +1,180 @@
|
|||
/* ***** 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 mozIStorageConnection::executeAsync
|
||||
|
||||
const INTEGER = 1;
|
||||
const TEXT = "this is test text";
|
||||
const REAL = 3.23;
|
||||
const BLOB = [1, 2];
|
||||
|
||||
function test_create_and_add()
|
||||
{
|
||||
dump("test_create_and_add()\n");
|
||||
|
||||
getOpenedDatabase().executeSimpleSQL(
|
||||
"CREATE TABLE test (" +
|
||||
"id INTEGER PRIMARY KEY, " +
|
||||
"string TEXT, " +
|
||||
"number REAL, " +
|
||||
"nuller NULL, " +
|
||||
"blober BLOB" +
|
||||
")"
|
||||
);
|
||||
|
||||
let stmts = [];
|
||||
stmts[0] = getOpenedDatabase().createStatement(
|
||||
"INSERT INTO test (id, string, number, nuller, blober) VALUES (?, ?, ?, ?, ?)"
|
||||
);
|
||||
stmts[0].bindInt32Parameter(0, INTEGER);
|
||||
stmts[0].bindStringParameter(1, TEXT);
|
||||
stmts[0].bindDoubleParameter(2, REAL);
|
||||
stmts[0].bindNullParameter(3);
|
||||
stmts[0].bindBlobParameter(4, BLOB, BLOB.length);
|
||||
stmts[1] = getOpenedDatabase().createStatement(
|
||||
"INSERT INTO test (string, number, nuller, blober) VALUES (?, ?, ?, ?)"
|
||||
);
|
||||
stmts[1].bindStringParameter(0, TEXT);
|
||||
stmts[1].bindDoubleParameter(1, REAL);
|
||||
stmts[1].bindNullParameter(2);
|
||||
stmts[1].bindBlobParameter(3, BLOB, BLOB.length);
|
||||
|
||||
do_test_pending();
|
||||
getOpenedDatabase().executeAsync(stmts, stmts.length, {
|
||||
handleResult: function(aResultSet)
|
||||
{
|
||||
dump("handleResult("+aResultSet+")\n");
|
||||
do_throw("unexpected results obtained!");
|
||||
},
|
||||
handleError: function(aError)
|
||||
{
|
||||
dump("handleError("+aError.result+")\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
|
||||
let 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));
|
||||
let count = { value: 0 };
|
||||
let blob = { value: null };
|
||||
stmt.getBlob(3, count, blob);
|
||||
do_check_eq(BLOB.length, count.value);
|
||||
for (let i = 0; i < BLOB.length; i++)
|
||||
do_check_eq(BLOB[i], blob.value[i]);
|
||||
}
|
||||
finally {
|
||||
stmt.finalize();
|
||||
}
|
||||
|
||||
// Make sure we have two rows in the table
|
||||
stmt = getOpenedDatabase().createStatement(
|
||||
"SELECT COUNT(1) FROM test"
|
||||
);
|
||||
try {
|
||||
do_check_true(stmt.executeStep());
|
||||
do_check_eq(2, stmt.getInt32(0));
|
||||
}
|
||||
finally {
|
||||
stmt.finalize();
|
||||
}
|
||||
|
||||
do_test_finished();
|
||||
}
|
||||
});
|
||||
stmts[0].finalize();
|
||||
stmts[1].finalize();
|
||||
}
|
||||
|
||||
function test_transaction_created()
|
||||
{
|
||||
dump("test_transaction_created()\n");
|
||||
|
||||
let stmts = [];
|
||||
stmts[0] = getOpenedDatabase().createStatement(
|
||||
"BEGIN"
|
||||
);
|
||||
stmts[1] = getOpenedDatabase().createStatement(
|
||||
"SELECT * FROM test"
|
||||
);
|
||||
|
||||
do_test_pending()
|
||||
getOpenedDatabase().executeAsync(stmts, stmts.length, {
|
||||
handleResult: function(aResultSet)
|
||||
{
|
||||
dump("handleResults("+aResultSet+")\n");
|
||||
do_throw("unexpected results obtained!");
|
||||
},
|
||||
handleError: function(aError)
|
||||
{
|
||||
dump("handleError("+aError.result+")\n");
|
||||
},
|
||||
handleCompletion: function(aReason)
|
||||
{
|
||||
dump("handleCompletion("+aReason+")\n");
|
||||
do_check_eq(Ci.mozIStorageStatementCallback.REASON_ERROR, aReason);
|
||||
do_test_finished();
|
||||
}
|
||||
});
|
||||
stmts[0].finalize();
|
||||
stmts[1].finalize();
|
||||
}
|
||||
|
||||
|
||||
let tests =
|
||||
[
|
||||
test_create_and_add,
|
||||
test_transaction_created,
|
||||
];
|
||||
|
||||
function run_test()
|
||||
{
|
||||
cleanup();
|
||||
|
||||
for (let i = 0; i < tests.length; i++)
|
||||
tests[i]();
|
||||
}
|
Загрузка…
Ссылка в новой задаче