Bug 658135 - Use sqlite3_stmt_readonly to check if multiple async statements need a transaction.

r=sdwilsh
This commit is contained in:
Marco Bonardo 2011-05-24 00:15:01 +02:00
Родитель 1e67f54266
Коммит 50b71d031b
11 изменённых файлов: 599 добавлений и 86 удалений

Просмотреть файл

@ -155,6 +155,7 @@ EXPORTS
sqlite3_sql
sqlite3_status
sqlite3_step
sqlite3_stmt_readonly
sqlite3_stmt_status
sqlite3_thread_cleanup
sqlite3_total_changes

Просмотреть файл

@ -534,6 +534,21 @@ NS_IMPL_THREADSAFE_ISUPPORTS2(
mozIStoragePendingStatement
)
bool
AsyncExecuteStatements::statementsNeedTransaction()
{
// If there is more than one write statement, run in a transaction.
// Additionally, if we have only one statement but it needs a transaction, due
// to multiple BindingParams, we will wrap it in one.
for (PRUint32 i = 0, transactionsCount = 0; i < mStatements.Length(); ++i) {
transactionsCount += mStatements[i].needsTransaction();
if (transactionsCount > 1) {
return true;
}
}
return false;
}
////////////////////////////////////////////////////////////////////////////////
//// mozIStoragePendingStatement
@ -575,13 +590,7 @@ AsyncExecuteStatements::Run()
if (mState == CANCELED)
return notifyComplete();
// 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 needs a transaction, we
// will wrap it in one.
if (mStatements.Length() > 1 || mStatements[0].needsTransaction()) {
// We don't error if this failed because it's not terrible if it does.
if (statementsNeedTransaction()) {
mTransactionManager = new mozStorageTransaction(mConnection, PR_FALSE,
mozIStorageConnection::TRANSACTION_IMMEDIATE);
}

Просмотреть файл

@ -201,6 +201,14 @@ private:
*/
nsresult notifyResults();
/**
* Tests whether the current statements should be wrapped in an explicit
* transaction.
*
* @return true if an explicit transaction is needed, false otherwise.
*/
bool statementsNeedTransaction();
StatementDataArray mStatements;
nsRefPtr<Connection> mConnection;
mozStorageTransaction *mTransactionManager;

Просмотреть файл

@ -46,7 +46,6 @@
#include "mozilla/Mutex.h"
#include "nsIInterfaceRequestor.h"
#include "nsString.h"
#include "nsDataHashtable.h"
#include "mozIStorageProgressHandler.h"
#include "SQLiteMutex.h"

Просмотреть файл

@ -45,6 +45,8 @@
#include "nsAutoPtr.h"
#include "nsTArray.h"
#include "nsIEventTarget.h"
#include "mozilla/Util.h"
#include "nsThreadUtils.h"
#include "mozStorageBindingParamsArray.h"
#include "mozIStorageBaseStatement.h"
@ -143,13 +145,27 @@ public:
*/
inline bool hasParametersToBeBound() const { return !!mParamsArray; }
/**
* Indicates if this statement needs a transaction for execution.
* Indicates the number of implicit statements generated by this statement
* requiring a transaction for execution. For example a single statement
* with N BindingParams will execute N implicit staments.
*
* @return true if the statement needs a transaction, false otherwise.
* @return number of statements requiring a transaction for execution.
*
* @note In the case of AsyncStatements this may actually create the
* statement.
*/
inline bool needsTransaction() const
inline PRUint32 needsTransaction()
{
return mParamsArray != nsnull && mParamsArray->length() > 1;
MOZ_ASSERT(!NS_IsMainThread());
// Be sure to use the getSqliteStatement helper, since sqlite3_stmt_readonly
// can only analyze prepared statements and AsyncStatements are prepared
// lazily.
sqlite3_stmt *stmt;
int rc = getSqliteStatement(&stmt);
if (SQLITE_OK != rc || ::sqlite3_stmt_readonly(stmt)) {
return 0;
}
return mParamsArray ? mParamsArray->length() : 1;
}
private:

Просмотреть файл

@ -61,6 +61,7 @@ CPP_UNIT_TESTS = \
test_StatementCache.cpp \
test_async_callbacks_with_spun_event_loops.cpp \
test_file_perms.cpp \
test_asyncStatementExecution_transaction.cpp \
$(NULL)
ifdef MOZ_DEBUG

Просмотреть файл

@ -50,6 +50,7 @@
#include "mozIStorageAsyncStatement.h"
#include "mozIStorageStatement.h"
#include "mozIStoragePendingStatement.h"
#include "mozIStorageError.h"
#include "nsThreadUtils.h"
static int gTotalTests = 0;
@ -176,6 +177,20 @@ AsyncStatementSpinner::HandleResult(mozIStorageResultSet *aResultSet)
NS_IMETHODIMP
AsyncStatementSpinner::HandleError(mozIStorageError *aError)
{
PRInt32 result;
nsresult rv = aError->GetResult(&result);
NS_ENSURE_SUCCESS(rv, rv);
nsCAutoString message;
rv = aError->GetMessage(message);
NS_ENSURE_SUCCESS(rv, rv);
nsCAutoString warnMsg;
warnMsg.Append("An error occurred while executing an async statement: ");
warnMsg.AppendInt(result);
warnMsg.Append(" ");
warnMsg.Append(message);
NS_WARNING(warnMsg.get());
return NS_OK;
}
@ -206,3 +221,33 @@ void AsyncStatementSpinner::SpinUntilCompleted()
#define NS_DECL_ASYNCSTATEMENTSPINNER \
NS_IMETHOD HandleResult(mozIStorageResultSet *aResultSet);
////////////////////////////////////////////////////////////////////////////////
//// Async Helpers
/**
* Execute an async statement, blocking the main thread until we get the
* callback completion notification.
*/
void
blocking_async_execute(mozIStorageBaseStatement *stmt)
{
nsRefPtr<AsyncStatementSpinner> spinner(new AsyncStatementSpinner());
nsCOMPtr<mozIStoragePendingStatement> pendy;
(void)stmt->ExecuteAsync(spinner, getter_AddRefs(pendy));
spinner->SpinUntilCompleted();
}
/**
* Invoke AsyncClose on the given connection, blocking the main thread until we
* get the completion notification.
*/
void
blocking_async_close(mozIStorageConnection *db)
{
nsRefPtr<AsyncStatementSpinner> spinner(new AsyncStatementSpinner());
db->AsyncClose(spinner);
spinner->SpinUntilCompleted();
}

Просмотреть файл

@ -0,0 +1,508 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
#include "storage_test_harness.h"
#include "nsIEventTarget.h"
#include "mozStorageConnection.h"
#include "sqlite3.h"
using namespace mozilla::storage;
////////////////////////////////////////////////////////////////////////////////
//// Helpers
/**
* Commit hook to detect transactions.
*
* @param aArg
* An integer pointer that will be incremented for each commit.
*/
int commit_hook(void *aArg)
{
int *arg = static_cast<int *>(aArg);
(*arg)++;
return 0;
}
/**
* Executes the passed-in statements and checks if a transaction is created.
* When done statements are finalized and database connection is closed.
*
* @param aDB
* The database connection.
* @param aStmts
* Vector of statements.
* @param aStmtsLen
* Number of statements.
* @param aTransactionExpected
* Whether a transaction is expected or not.
*/
void
check_transaction(mozIStorageConnection *aDB,
mozIStorageBaseStatement **aStmts,
PRUint32 aStmtsLen,
bool aTransactionExpected)
{
// -- install a transaction commit hook.
int commit = 0;
::sqlite3_commit_hook(*static_cast<Connection *>(aDB), commit_hook, &commit);
nsRefPtr<AsyncStatementSpinner> asyncSpin(new AsyncStatementSpinner());
nsCOMPtr<mozIStoragePendingStatement> asyncPend;
do_check_success(aDB->ExecuteAsync(aStmts, aStmtsLen, asyncSpin,
getter_AddRefs(asyncPend)));
do_check_true(asyncPend);
// -- complete the execution
asyncSpin->SpinUntilCompleted();
// -- uninstall the transaction commit hook.
::sqlite3_commit_hook(*static_cast<Connection *>(aDB), NULL, NULL);
// -- check transaction
do_check_eq(aTransactionExpected, !!commit);
// -- check that only one transaction was created.
if (aTransactionExpected) {
do_check_eq(1, commit);
}
// -- cleanup
for (PRUint32 i = 0; i < aStmtsLen; ++i) {
aStmts[i]->Finalize();
}
blocking_async_close(aDB);
}
////////////////////////////////////////////////////////////////////////////////
//// Tests
/**
* Test that executing multiple readonly AsyncStatements doesn't create a
* transaction.
*/
void
test_MultipleAsyncReadStatements()
{
nsCOMPtr<mozIStorageConnection> db(getMemoryDatabase());
// -- create statements and execute them
nsCOMPtr<mozIStorageAsyncStatement> stmt1;
db->CreateAsyncStatement(NS_LITERAL_CSTRING(
"SELECT * FROM sqlite_master"
), getter_AddRefs(stmt1));
nsCOMPtr<mozIStorageAsyncStatement> stmt2;
db->CreateAsyncStatement(NS_LITERAL_CSTRING(
"SELECT * FROM sqlite_master"
), getter_AddRefs(stmt2));
mozIStorageBaseStatement *stmts[] = {
stmt1,
stmt2,
};
check_transaction(db, stmts, NS_ARRAY_LENGTH(stmts), false);
}
/**
* Test that executing multiple readonly Statements doesn't create a
* transaction.
*/
void
test_MultipleReadStatements()
{
nsCOMPtr<mozIStorageConnection> db(getMemoryDatabase());
// -- create statements and execute them
nsCOMPtr<mozIStorageStatement> stmt1;
db->CreateStatement(NS_LITERAL_CSTRING(
"SELECT * FROM sqlite_master"
), getter_AddRefs(stmt1));
nsCOMPtr<mozIStorageStatement> stmt2;
db->CreateStatement(NS_LITERAL_CSTRING(
"SELECT * FROM sqlite_master"
), getter_AddRefs(stmt2));
mozIStorageBaseStatement *stmts[] = {
stmt1,
stmt2,
};
check_transaction(db, stmts, NS_ARRAY_LENGTH(stmts), false);
}
/**
* Test that executing multiple AsyncStatements causing writes creates a
* transaction.
*/
void
test_MultipleAsyncReadWriteStatements()
{
nsCOMPtr<mozIStorageConnection> db(getMemoryDatabase());
// -- create statements and execute them
nsCOMPtr<mozIStorageAsyncStatement> stmt1;
db->CreateAsyncStatement(NS_LITERAL_CSTRING(
"SELECT * FROM sqlite_master"
), getter_AddRefs(stmt1));
nsCOMPtr<mozIStorageAsyncStatement> stmt2;
db->CreateAsyncStatement(NS_LITERAL_CSTRING(
"CREATE TABLE test (id INTEGER PRIMARY KEY)"
), getter_AddRefs(stmt2));
mozIStorageBaseStatement *stmts[] = {
stmt1,
stmt2,
};
check_transaction(db, stmts, NS_ARRAY_LENGTH(stmts), true);
}
/**
* Test that executing multiple Statements causing writes creates a transaction.
*/
void
test_MultipleReadWriteStatements()
{
nsCOMPtr<mozIStorageConnection> db(getMemoryDatabase());
// -- create statements and execute them
nsCOMPtr<mozIStorageStatement> stmt1;
db->CreateStatement(NS_LITERAL_CSTRING(
"SELECT * FROM sqlite_master"
), getter_AddRefs(stmt1));
nsCOMPtr<mozIStorageStatement> stmt2;
db->CreateStatement(NS_LITERAL_CSTRING(
"CREATE TABLE test (id INTEGER PRIMARY KEY)"
), getter_AddRefs(stmt2));
mozIStorageBaseStatement *stmts[] = {
stmt1,
stmt2,
};
check_transaction(db, stmts, NS_ARRAY_LENGTH(stmts), true);
}
/**
* Test that executing multiple AsyncStatements causing writes creates a
* single transaction.
*/
void
test_MultipleAsyncWriteStatements()
{
nsCOMPtr<mozIStorageConnection> db(getMemoryDatabase());
// -- create statements and execute them
nsCOMPtr<mozIStorageAsyncStatement> stmt1;
db->CreateAsyncStatement(NS_LITERAL_CSTRING(
"CREATE TABLE test1 (id INTEGER PRIMARY KEY)"
), getter_AddRefs(stmt1));
nsCOMPtr<mozIStorageAsyncStatement> stmt2;
db->CreateAsyncStatement(NS_LITERAL_CSTRING(
"CREATE TABLE test2 (id INTEGER PRIMARY KEY)"
), getter_AddRefs(stmt2));
mozIStorageBaseStatement *stmts[] = {
stmt1,
stmt2,
};
check_transaction(db, stmts, NS_ARRAY_LENGTH(stmts), true);
}
/**
* Test that executing multiple Statements causing writes creates a
* single transaction.
*/
void
test_MultipleWriteStatements()
{
nsCOMPtr<mozIStorageConnection> db(getMemoryDatabase());
// -- create statements and execute them
nsCOMPtr<mozIStorageStatement> stmt1;
db->CreateStatement(NS_LITERAL_CSTRING(
"CREATE TABLE test1 (id INTEGER PRIMARY KEY)"
), getter_AddRefs(stmt1));
nsCOMPtr<mozIStorageStatement> stmt2;
db->CreateStatement(NS_LITERAL_CSTRING(
"CREATE TABLE test2 (id INTEGER PRIMARY KEY)"
), getter_AddRefs(stmt2));
mozIStorageBaseStatement *stmts[] = {
stmt1,
stmt2,
};
check_transaction(db, stmts, NS_ARRAY_LENGTH(stmts), true);
}
/**
* Test that executing a single read-only AsyncStatement doesn't create a
* transaction.
*/
void
test_SingleAsyncReadStatement()
{
nsCOMPtr<mozIStorageConnection> db(getMemoryDatabase());
// -- create statements and execute them
nsCOMPtr<mozIStorageAsyncStatement> stmt;
db->CreateAsyncStatement(NS_LITERAL_CSTRING(
"SELECT * FROM sqlite_master"
), getter_AddRefs(stmt));
mozIStorageBaseStatement *stmts[] = {
stmt,
};
check_transaction(db, stmts, NS_ARRAY_LENGTH(stmts), false);
}
/**
* Test that executing a single read-only Statement doesn't create a
* transaction.
*/
void
test_SingleReadStatement()
{
nsCOMPtr<mozIStorageConnection> db(getMemoryDatabase());
// -- create statements and execute them
nsCOMPtr<mozIStorageStatement> stmt;
db->CreateStatement(NS_LITERAL_CSTRING(
"SELECT * FROM sqlite_master"
), getter_AddRefs(stmt));
mozIStorageBaseStatement *stmts[] = {
stmt,
};
check_transaction(db, stmts, NS_ARRAY_LENGTH(stmts), false);
}
/**
* Test that executing a single AsyncStatement causing writes creates a
* transaction.
*/
void
test_SingleAsyncWriteStatement()
{
nsCOMPtr<mozIStorageConnection> db(getMemoryDatabase());
// -- create statements and execute them
nsCOMPtr<mozIStorageAsyncStatement> stmt;
db->CreateAsyncStatement(NS_LITERAL_CSTRING(
"CREATE TABLE test (id INTEGER PRIMARY KEY)"
), getter_AddRefs(stmt));
mozIStorageBaseStatement *stmts[] = {
stmt,
};
check_transaction(db, stmts, NS_ARRAY_LENGTH(stmts), true);
}
/**
* Test that executing a single Statement causing writes creates a transaction.
*/
void
test_SingleWriteStatement()
{
nsCOMPtr<mozIStorageConnection> db(getMemoryDatabase());
// -- create statements and execute them
nsCOMPtr<mozIStorageStatement> stmt;
db->CreateStatement(NS_LITERAL_CSTRING(
"CREATE TABLE test (id INTEGER PRIMARY KEY)"
), getter_AddRefs(stmt));
mozIStorageBaseStatement *stmts[] = {
stmt,
};
check_transaction(db, stmts, NS_ARRAY_LENGTH(stmts), true);
}
/**
* Test that executing a single read-only AsyncStatement with multiple params
* doesn't create a transaction.
*/
void
test_MultipleParamsAsyncReadStatement()
{
nsCOMPtr<mozIStorageConnection> db(getMemoryDatabase());
// -- create statements and execute them
nsCOMPtr<mozIStorageAsyncStatement> stmt;
db->CreateAsyncStatement(NS_LITERAL_CSTRING(
"SELECT :param FROM sqlite_master"
), getter_AddRefs(stmt));
// -- bind multiple BindingParams
nsCOMPtr<mozIStorageBindingParamsArray> paramsArray;
stmt->NewBindingParamsArray(getter_AddRefs(paramsArray));
for (PRInt32 i = 0; i < 2; i++) {
nsCOMPtr<mozIStorageBindingParams> params;
paramsArray->NewBindingParams(getter_AddRefs(params));
params->BindInt32ByName(NS_LITERAL_CSTRING("param"), 1);
paramsArray->AddParams(params);
}
stmt->BindParameters(paramsArray);
paramsArray = nsnull;
mozIStorageBaseStatement *stmts[] = {
stmt,
};
check_transaction(db, stmts, NS_ARRAY_LENGTH(stmts), false);
}
/**
* Test that executing a single read-only Statement with multiple params
* doesn't create a transaction.
*/
void
test_MultipleParamsReadStatement()
{
nsCOMPtr<mozIStorageConnection> db(getMemoryDatabase());
// -- create statements and execute them
nsCOMPtr<mozIStorageStatement> stmt;
db->CreateStatement(NS_LITERAL_CSTRING(
"SELECT :param FROM sqlite_master"
), getter_AddRefs(stmt));
// -- bind multiple BindingParams
nsCOMPtr<mozIStorageBindingParamsArray> paramsArray;
stmt->NewBindingParamsArray(getter_AddRefs(paramsArray));
for (PRInt32 i = 0; i < 2; i++) {
nsCOMPtr<mozIStorageBindingParams> params;
paramsArray->NewBindingParams(getter_AddRefs(params));
params->BindInt32ByName(NS_LITERAL_CSTRING("param"), 1);
paramsArray->AddParams(params);
}
stmt->BindParameters(paramsArray);
paramsArray = nsnull;
mozIStorageBaseStatement *stmts[] = {
stmt,
};
check_transaction(db, stmts, NS_ARRAY_LENGTH(stmts), false);
}
/**
* Test that executing a single write AsyncStatement with multiple params
* creates a transaction.
*/
void
test_MultipleParamsAsyncWriteStatement()
{
nsCOMPtr<mozIStorageConnection> db(getMemoryDatabase());
// -- create a table for writes
nsCOMPtr<mozIStorageStatement> tableStmt;
db->CreateStatement(NS_LITERAL_CSTRING(
"CREATE TABLE test (id INTEGER PRIMARY KEY)"
), getter_AddRefs(tableStmt));
tableStmt->Execute();
tableStmt->Finalize();
// -- create statements and execute them
nsCOMPtr<mozIStorageAsyncStatement> stmt;
db->CreateAsyncStatement(NS_LITERAL_CSTRING(
"DELETE FROM test WHERE id = :param"
), getter_AddRefs(stmt));
// -- bind multiple BindingParams
nsCOMPtr<mozIStorageBindingParamsArray> paramsArray;
stmt->NewBindingParamsArray(getter_AddRefs(paramsArray));
for (PRInt32 i = 0; i < 2; i++) {
nsCOMPtr<mozIStorageBindingParams> params;
paramsArray->NewBindingParams(getter_AddRefs(params));
params->BindInt32ByName(NS_LITERAL_CSTRING("param"), 1);
paramsArray->AddParams(params);
}
stmt->BindParameters(paramsArray);
paramsArray = nsnull;
mozIStorageBaseStatement *stmts[] = {
stmt,
};
check_transaction(db, stmts, NS_ARRAY_LENGTH(stmts), true);
}
/**
* Test that executing a single write Statement with multiple params
* creates a transaction.
*/
void
test_MultipleParamsWriteStatement()
{
nsCOMPtr<mozIStorageConnection> db(getMemoryDatabase());
// -- create a table for writes
nsCOMPtr<mozIStorageStatement> tableStmt;
db->CreateStatement(NS_LITERAL_CSTRING(
"CREATE TABLE test (id INTEGER PRIMARY KEY)"
), getter_AddRefs(tableStmt));
tableStmt->Execute();
tableStmt->Finalize();
// -- create statements and execute them
nsCOMPtr<mozIStorageStatement> stmt;
db->CreateStatement(NS_LITERAL_CSTRING(
"DELETE FROM test WHERE id = :param"
), getter_AddRefs(stmt));
// -- bind multiple BindingParams
nsCOMPtr<mozIStorageBindingParamsArray> paramsArray;
stmt->NewBindingParamsArray(getter_AddRefs(paramsArray));
for (PRInt32 i = 0; i < 2; i++) {
nsCOMPtr<mozIStorageBindingParams> params;
paramsArray->NewBindingParams(getter_AddRefs(params));
params->BindInt32ByName(NS_LITERAL_CSTRING("param"), 1);
paramsArray->AddParams(params);
}
stmt->BindParameters(paramsArray);
paramsArray = nsnull;
mozIStorageBaseStatement *stmts[] = {
stmt,
};
check_transaction(db, stmts, NS_ARRAY_LENGTH(stmts), true);
}
void (*gTests[])(void) = {
test_MultipleAsyncReadStatements,
test_MultipleReadStatements,
test_MultipleAsyncReadWriteStatements,
test_MultipleReadWriteStatements,
test_MultipleAsyncWriteStatements,
test_MultipleWriteStatements,
test_SingleAsyncReadStatement,
test_SingleReadStatement,
test_SingleAsyncWriteStatement,
test_SingleWriteStatement,
test_MultipleParamsAsyncReadStatement,
test_MultipleParamsReadStatement,
test_MultipleParamsAsyncWriteStatement,
test_MultipleParamsWriteStatement,
};
const char *file = __FILE__;
#define TEST_NAME "async statement execution transaction"
#define TEST_FILE file
#include "storage_test_harness_tail.h"

Просмотреть файл

@ -11,19 +11,6 @@
////////////////////////////////////////////////////////////////////////////////
//// Async Helpers
/**
* Invoke AsyncClose on the given connection, blocking the main thread until we
* get the completion notification.
*/
void
blocking_async_close(mozIStorageConnection *db)
{
nsRefPtr<AsyncStatementSpinner> spinner(new AsyncStatementSpinner());
db->AsyncClose(spinner);
spinner->SpinUntilCompleted();
}
/**
* Spins the events loop for current thread until aCondition is true.
*/

Просмотреть файл

@ -171,33 +171,6 @@ private:
////////////////////////////////////////////////////////////////////////////////
//// Async Helpers
/**
* Execute an async statement, blocking the main thread until we get the
* callback completion notification.
*/
void
blocking_async_execute(mozIStorageBaseStatement *stmt)
{
nsRefPtr<AsyncStatementSpinner> spinner(new AsyncStatementSpinner());
nsCOMPtr<mozIStoragePendingStatement> pendy;
(void)stmt->ExecuteAsync(spinner, getter_AddRefs(pendy));
spinner->SpinUntilCompleted();
}
/**
* Invoke AsyncClose on the given connection, blocking the main thread until we
* get the completion notification.
*/
void
blocking_async_close(mozIStorageConnection *db)
{
nsRefPtr<AsyncStatementSpinner> spinner(new AsyncStatementSpinner());
db->AsyncClose(spinner);
spinner->SpinUntilCompleted();
}
/**
* A horrible hack to figure out what the connection's async thread is. By
* creating a statement and async dispatching we can tell from the mutex who

Просмотреть файл

@ -131,39 +131,6 @@ function test_create_and_add()
stmts[1].finalize();
}
function test_transaction_created()
{
let stmts = [];
stmts[0] = getOpenedDatabase().createAsyncStatement(
"BEGIN"
);
stmts[1] = getOpenedDatabase().createStatement(
"SELECT * FROM test"
);
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);
// Run the next test.
run_next_test();
}
});
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
@ -309,7 +276,6 @@ function test_double_asyncClose_throws()
[
test_create_and_add,
test_transaction_created,
test_multiple_bindings_on_statements,
test_asyncClose_does_not_complete_before_statements,
test_asyncClose_does_not_throw_no_callback,