1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
3 * ***** BEGIN LICENSE BLOCK *****
4 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
6 * The contents of this file are subject to the Mozilla Public License Version
7 * 1.1 (the "License"); you may not use this file except in compliance with
8 * the License. You may obtain a copy of the License at
9 * http://www.mozilla.org/MPL/
11 * Software distributed under the License is distributed on an "AS IS" basis,
12 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
13 * for the specific language governing rights and limitations under the
16 * The Original Code is Oracle Corporation code.
18 * The Initial Developer of the Original Code is
20 * Portions created by the Initial Developer are Copyright (C) 2004
21 * the Initial Developer. All Rights Reserved.
24 * Vladimir Vukicevic <vladimir.vukicevic@oracle.com>
25 * Brett Wilson <brettw@gmail.com>
26 * Shawn Wilsher <me@shawnwilsher.com>
27 * Lev Serebryakov <lev@serebryakov.spb.ru>
29 * Alternatively, the contents of this file may be used under the terms of
30 * either the GNU General Public License Version 2 or later (the "GPL"), or
31 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
32 * in which case the provisions of the GPL or the LGPL are applicable instead
33 * of those above. If you wish to allow use of your version of this file only
34 * under the terms of either the GPL or the LGPL, and not to allow others to
35 * use your version of this file under the terms of the MPL, indicate your
36 * decision by deleting the provisions above and replace them with the notice
37 * and other provisions required by the GPL or the LGPL. If you do not delete
38 * the provisions above, a recipient may use your version of this file under
39 * the terms of any one of the MPL, the GPL or the LGPL.
41 * ***** END LICENSE BLOCK ***** */
46 #include "nsIMutableArray.h"
47 #include "nsHashSets.h"
48 #include "nsAutoPtr.h"
50 #include "nsIVariant.h"
51 #include "nsIPrefService.h"
52 #include "nsIPrefBranch.h"
53 #include "nsThreadUtils.h"
55 #include "mozIStorageAggregateFunction.h"
56 #include "mozIStorageFunction.h"
58 #include "mozStorageEvents.h"
59 #include "mozStorageUnicodeFunctions.h"
60 #include "mozStorageConnection.h"
61 #include "mozStorageService.h"
62 #include "mozStorageStatement.h"
63 #include "mozStorageValueArray.h"
64 #include "mozStoragePrivateHelpers.h"
70 PRLogModuleInfo
* gStorageLog
= nsnull
;
73 #define PREF_TS_SYNCHRONOUS "toolkit.storage.synchronous"
75 NS_IMPL_THREADSAFE_ISUPPORTS1(mozStorageConnection
, mozIStorageConnection
)
77 mozStorageConnection::mozStorageConnection(mozIStorageService
* aService
) :
79 , mAsyncExecutionMutex(nsAutoLock::NewLock("AsyncExecutionMutex"))
80 , mAsyncExecutionThreadShuttingDown(PR_FALSE
)
81 , mTransactionMutex(nsAutoLock::NewLock("TransactionMutex"))
82 , mTransactionInProgress(PR_FALSE
)
83 , mFunctionsMutex(nsAutoLock::NewLock("FunctionsMutex"))
84 , mProgressHandlerMutex(nsAutoLock::NewLock("ProgressHandlerMutex"))
85 , mProgressHandler(nsnull
)
86 , mStorageService(aService
)
91 mozStorageConnection::~mozStorageConnection()
94 nsAutoLock::DestroyLock(mAsyncExecutionMutex
);
95 nsAutoLock::DestroyLock(mTransactionMutex
);
96 nsAutoLock::DestroyLock(mFunctionsMutex
);
97 nsAutoLock::DestroyLock(mProgressHandlerMutex
);
101 void tracefunc (void *closure
, const char *stmt
)
103 PR_LOG(gStorageLog
, PR_LOG_DEBUG
, ("sqlite3_trace on %p for '%s'", closure
,
109 * Actually creates the connection from the DB. Called by mozStorageService.
110 * You can pass a NULL database file in to get an sqlite in-memory database.
113 mozStorageConnection::Initialize(nsIFile
*aDatabaseFile
)
115 NS_ASSERTION (!mDBConn
, "Initialize called on already opened database!");
116 NS_ENSURE_TRUE(mAsyncExecutionMutex
, NS_ERROR_OUT_OF_MEMORY
);
117 NS_ENSURE_TRUE(mTransactionMutex
, NS_ERROR_OUT_OF_MEMORY
);
118 NS_ENSURE_TRUE(mFunctionsMutex
, NS_ERROR_OUT_OF_MEMORY
);
119 NS_ENSURE_TRUE(mProgressHandlerMutex
, NS_ERROR_OUT_OF_MEMORY
);
124 mDatabaseFile
= aDatabaseFile
;
128 rv
= aDatabaseFile
->GetPath(path
);
129 NS_ENSURE_SUCCESS(rv
, rv
);
131 srv
= sqlite3_open (NS_ConvertUTF16toUTF8(path
).get(), &mDBConn
);
133 // in memory database requested, sqlite uses a magic file name
134 srv
= sqlite3_open (":memory:", &mDBConn
);
136 if (srv
!= SQLITE_OK
) {
138 return ConvertResultCode(srv
);
143 gStorageLog
= PR_NewLogModule("mozStorage");
145 sqlite3_trace (mDBConn
, tracefunc
, this);
147 nsCAutoString
leafName(":memory");
149 (void)aDatabaseFile
->GetNativeLeafName(leafName
);
150 PR_LOG(gStorageLog
, PR_LOG_NOTICE
, ("Opening connection to '%s' (%p)",
151 leafName
.get(), this));
154 // Hook up i18n functions
155 srv
= StorageUnicodeFunctions::RegisterFunctions(mDBConn
);
156 if (srv
!= SQLITE_OK
) {
158 return ConvertResultCode(srv
);
161 /* Execute a dummy statement to force the db open, and to verify
162 * whether it's valid or not
164 sqlite3_stmt
*stmt
= nsnull
;
165 srv
= sqlite3_prepare_v2(mDBConn
, "SELECT * FROM sqlite_master", -1, &stmt
,
168 if (srv
== SQLITE_OK
) {
169 srv
= sqlite3_step(stmt
);
171 if (srv
== SQLITE_DONE
|| srv
== SQLITE_ROW
)
178 sqlite3_finalize (stmt
);
180 if (srv
!= SQLITE_OK
) {
181 sqlite3_close (mDBConn
);
184 return ConvertResultCode(srv
);
187 // Set the synchronous PRAGMA, according to the pref
188 nsCOMPtr
<nsIPrefBranch
> pref(do_GetService(NS_PREFSERVICE_CONTRACTID
));
189 PRInt32 synchronous
= 1; // Default to NORMAL if pref not set
191 (void)pref
->GetIntPref(PREF_TS_SYNCHRONOUS
, &synchronous
);
193 switch (synchronous
) {
195 (void)ExecuteSimpleSQL(NS_LITERAL_CSTRING(
196 "PRAGMA synchronous = FULL;"));
199 (void)ExecuteSimpleSQL(NS_LITERAL_CSTRING(
200 "PRAGMA synchronous = OFF;"));
204 (void)ExecuteSimpleSQL(NS_LITERAL_CSTRING(
205 "PRAGMA synchronous = NORMAL;"));
212 /*****************************************************************************
213 ** mozIStorageConnection interface
214 *****************************************************************************/
217 ** Core status/initialization
221 mozStorageConnection::Close()
224 return NS_ERROR_NOT_INITIALIZED
;
227 nsCAutoString
leafName(":memory");
229 (void)mDatabaseFile
->GetNativeLeafName(leafName
);
230 PR_LOG(gStorageLog
, PR_LOG_NOTICE
, ("Opening connection to '%s'",
234 // Flag that we are shutting down the async thread, so that
235 // getAsyncExecutionTarget knows not to expose/create the async thread.
237 nsAutoLock
mutex(mAsyncExecutionMutex
);
238 mAsyncExecutionThreadShuttingDown
= PR_TRUE
;
240 // Shutdown the async thread if it exists. (Because we just set the flag,
241 // we are the only code that is going to be touching this variable from here
243 if (mAsyncExecutionThread
) {
244 mAsyncExecutionThread
->Shutdown();
245 mAsyncExecutionThread
= nsnull
;
249 // Notify about any non-finalized statements.
250 sqlite3_stmt
*stmt
= NULL
;
251 while (stmt
= sqlite3_next_stmt(mDBConn
, stmt
)) {
252 char *msg
= PR_smprintf("SQL statement '%s' was not finalized",
255 PR_smprintf_free(msg
);
260 nsAutoLock
mutex(mProgressHandlerMutex
);
261 if (mProgressHandler
)
262 sqlite3_progress_handler(mDBConn
, 0, NULL
, NULL
);
265 int srv
= sqlite3_close(mDBConn
);
266 if (srv
!= SQLITE_OK
)
267 NS_WARNING("sqlite3_close failed. There are probably outstanding statements that are listed above!");
270 return ConvertResultCode(srv
);
274 mozStorageConnection::GetConnectionReady(PRBool
*aConnectionReady
)
276 *aConnectionReady
= (mDBConn
!= nsnull
);
281 mozStorageConnection::GetDatabaseFile(nsIFile
**aFile
)
283 if (!mDBConn
) return NS_ERROR_NOT_INITIALIZED
;
285 NS_IF_ADDREF(*aFile
= mDatabaseFile
);
291 mozStorageConnection::GetLastInsertRowID(PRInt64
*aLastInsertRowID
)
293 if (!mDBConn
) return NS_ERROR_NOT_INITIALIZED
;
295 sqlite_int64 id
= sqlite3_last_insert_rowid(mDBConn
);
296 *aLastInsertRowID
= id
;
302 mozStorageConnection::GetLastError(PRInt32
*aLastError
)
304 if (!mDBConn
) return NS_ERROR_NOT_INITIALIZED
;
306 *aLastError
= sqlite3_errcode(mDBConn
);
312 mozStorageConnection::GetLastErrorString(nsACString
& aLastErrorString
)
314 if (!mDBConn
) return NS_ERROR_NOT_INITIALIZED
;
316 const char *serr
= sqlite3_errmsg(mDBConn
);
317 aLastErrorString
.Assign(serr
);
323 mozStorageConnection::GetSchemaVersion(PRInt32
*version
)
325 if (!mDBConn
) return NS_ERROR_NOT_INITIALIZED
;
327 nsCOMPtr
<mozIStorageStatement
> stmt
;
328 nsresult rv
= CreateStatement(NS_LITERAL_CSTRING(
329 "PRAGMA user_version"), getter_AddRefs(stmt
));
330 if (NS_FAILED(rv
)) return rv
;
334 if (NS_SUCCEEDED(stmt
->ExecuteStep(&hasResult
)) && hasResult
)
335 *version
= stmt
->AsInt32(0);
341 mozStorageConnection::SetSchemaVersion(PRInt32 aVersion
)
343 if (!mDBConn
) return NS_ERROR_NOT_INITIALIZED
;
345 nsCAutoString
stmt(NS_LITERAL_CSTRING("PRAGMA user_version = "));
346 stmt
.AppendInt(aVersion
);
348 return ExecuteSimpleSQL(stmt
);
352 ** Statements & Queries
356 mozStorageConnection::CreateStatement(const nsACString
& aSQLStatement
,
357 mozIStorageStatement
**_retval
)
359 NS_ENSURE_ARG_POINTER(_retval
);
360 if (!mDBConn
) return NS_ERROR_NOT_INITIALIZED
;
362 mozStorageStatement
*statement
= new mozStorageStatement();
364 return NS_ERROR_OUT_OF_MEMORY
;
365 NS_ADDREF(statement
);
367 nsresult rv
= statement
->Initialize (this, aSQLStatement
);
369 NS_RELEASE(statement
);
373 *_retval
= statement
;
378 mozStorageConnection::ExecuteSimpleSQL(const nsACString
& aSQLStatement
)
380 if (!mDBConn
) return NS_ERROR_NOT_INITIALIZED
;
382 int srv
= sqlite3_exec (mDBConn
, PromiseFlatCString(aSQLStatement
).get(),
384 if (srv
!= SQLITE_OK
) {
385 HandleSqliteError(nsPromiseFlatCString(aSQLStatement
).get());
386 return ConvertResultCode(srv
);
393 mozStorageConnection::ExecuteAsync(mozIStorageStatement
** aStatements
,
394 PRUint32 aNumStatements
,
395 mozIStorageStatementCallback
*aCallback
,
396 mozIStoragePendingStatement
**_stmt
)
399 nsTArray
<sqlite3_stmt
*> stmts(aNumStatements
);
400 for (PRUint32 i
= 0; i
< aNumStatements
&& rc
== SQLITE_OK
; i
++) {
401 sqlite3_stmt
*old_stmt
= aStatements
[i
]->GetNativeStatementPointer();
402 NS_ASSERTION(sqlite3_db_handle(old_stmt
) == mDBConn
,
403 "Statement must be from this database connection!");
405 // Clone this statement. We only need a sqlite3_stmt object, so we can
406 // avoid all the extra work that making a new mozStorageStatement would
407 // normally involve and use the SQLite API.
408 sqlite3_stmt
*new_stmt
;
409 rc
= sqlite3_prepare_v2(mDBConn
, sqlite3_sql(old_stmt
), -1, &new_stmt
,
414 // Transfer the bindings
415 rc
= sqlite3_transfer_bindings(old_stmt
, new_stmt
);
419 if (!stmts
.AppendElement(new_stmt
)) {
425 // Dispatch to the background
428 rv
= NS_executeAsync(stmts
, this, aCallback
, _stmt
);
430 // We had a failure, so we need to clean up...
431 if (rc
!= SQLITE_OK
|| NS_FAILED(rv
)) {
432 for (PRUint32 i
= 0; i
< stmts
.Length(); i
++)
433 (void)sqlite3_finalize(stmts
[i
]);
436 rv
= ConvertResultCode(rc
);
439 // Always reset all the statements
440 for (PRUint32 i
= 0; i
< aNumStatements
; i
++)
441 (void)aStatements
[i
]->Reset();
447 mozStorageConnection::TableExists(const nsACString
& aSQLStatement
, PRBool
*_retval
)
449 if (!mDBConn
) return NS_ERROR_NOT_INITIALIZED
;
451 nsCString
query("SELECT name FROM sqlite_master WHERE type = 'table' AND name ='");
452 query
.Append(aSQLStatement
);
453 query
.AppendLiteral("'");
455 sqlite3_stmt
*stmt
= nsnull
;
456 int srv
= sqlite3_prepare_v2(mDBConn
, query
.get(), -1, &stmt
, NULL
);
457 if (srv
!= SQLITE_OK
) {
458 HandleSqliteError(query
.get());
459 return ConvertResultCode(srv
);
462 PRBool exists
= PR_FALSE
;
464 srv
= sqlite3_step(stmt
);
465 // we just care about the return value from step
466 sqlite3_finalize(stmt
);
468 if (srv
== SQLITE_ROW
) {
470 } else if (srv
== SQLITE_DONE
) {
473 HandleSqliteError("TableExists finalize");
474 return ConvertResultCode(srv
);
482 mozStorageConnection::IndexExists(const nsACString
& aIndexName
, PRBool
* _retval
)
484 if (!mDBConn
) return NS_ERROR_NOT_INITIALIZED
;
486 nsCString
query("SELECT name FROM sqlite_master WHERE type = 'index' AND name ='");
487 query
.Append(aIndexName
);
488 query
.AppendLiteral("'");
490 sqlite3_stmt
*stmt
= nsnull
;
491 int srv
= sqlite3_prepare_v2(mDBConn
, query
.get(), -1, &stmt
, NULL
);
492 if (srv
!= SQLITE_OK
) {
493 HandleSqliteError(query
.get());
494 return ConvertResultCode(srv
);
499 srv
= sqlite3_step(stmt
);
500 (void)sqlite3_finalize(stmt
);
502 if (srv
== SQLITE_ROW
) {
506 return ConvertResultCode(srv
);
515 mozStorageConnection::GetTransactionInProgress(PRBool
*_retval
)
517 nsAutoLock
mutex(mTransactionMutex
);
518 *_retval
= mTransactionInProgress
;
522 // XXX do we want to just store compiled statements for these?
524 mozStorageConnection::BeginTransaction()
526 return BeginTransactionAs(mozIStorageConnection::TRANSACTION_DEFERRED
);
530 mozStorageConnection::BeginTransactionAs(PRInt32 aTransactionType
)
532 nsAutoLock
mutex(mTransactionMutex
);
533 if (mTransactionInProgress
)
534 return NS_ERROR_FAILURE
;
536 switch(aTransactionType
) {
537 case TRANSACTION_DEFERRED
:
538 rv
= ExecuteSimpleSQL(NS_LITERAL_CSTRING("BEGIN DEFERRED"));
540 case TRANSACTION_IMMEDIATE
:
541 rv
= ExecuteSimpleSQL(NS_LITERAL_CSTRING("BEGIN IMMEDIATE"));
543 case TRANSACTION_EXCLUSIVE
:
544 rv
= ExecuteSimpleSQL(NS_LITERAL_CSTRING("BEGIN EXCLUSIVE"));
547 return NS_ERROR_ILLEGAL_VALUE
;
549 if (NS_SUCCEEDED(rv
))
550 mTransactionInProgress
= PR_TRUE
;
555 mozStorageConnection::CommitTransaction()
557 nsAutoLock
mutex(mTransactionMutex
);
558 if (!mTransactionInProgress
)
559 return NS_ERROR_FAILURE
;
560 nsresult rv
= ExecuteSimpleSQL(NS_LITERAL_CSTRING("COMMIT TRANSACTION"));
561 if (NS_SUCCEEDED(rv
))
562 mTransactionInProgress
= PR_FALSE
;
567 mozStorageConnection::RollbackTransaction()
569 nsAutoLock
mutex(mTransactionMutex
);
570 if (!mTransactionInProgress
)
571 return NS_ERROR_FAILURE
;
572 nsresult rv
= ExecuteSimpleSQL(NS_LITERAL_CSTRING("ROLLBACK TRANSACTION"));
573 if (NS_SUCCEEDED(rv
))
574 mTransactionInProgress
= PR_FALSE
;
583 mozStorageConnection::CreateTable(/*const nsID& aID,*/
584 const char *aTableName
,
585 const char *aTableSchema
)
587 if (!mDBConn
) return NS_ERROR_NOT_INITIALIZED
;
591 buf
= PR_smprintf("CREATE TABLE %s (%s)", aTableName
, aTableSchema
);
593 return NS_ERROR_OUT_OF_MEMORY
;
595 srv
= sqlite3_exec (mDBConn
, buf
,
598 PR_smprintf_free(buf
);
600 return ConvertResultCode(srv
);
608 mozStorageConnection::s_FindFuncEnum(const nsACString
&aKey
,
612 FindFuncEnumArgs
*args
= static_cast<FindFuncEnumArgs
*>(userArg
);
613 if ((void*)aData
== args
->mTarget
) {
614 args
->mFound
= PR_TRUE
;
615 return PL_DHASH_STOP
;
617 return PL_DHASH_NEXT
;
621 mozStorageConnection::FindFunctionByInstance(nsISupports
*aInstance
)
623 // The lock should already be held by calling functions
624 FindFuncEnumArgs args
= { aInstance
, PR_FALSE
};
625 mFunctions
.EnumerateRead(s_FindFuncEnum
, &args
);
630 mozStorageVariantToSQLite3Result(sqlite3_context
*ctx
,
635 // Allow to return NULL not wrapped to
636 // nsIVariant for speed
638 sqlite3_result_null (ctx
);
641 (void)var
->GetDataType( &dt
);
643 case nsIDataType::VTYPE_INT8
:
644 case nsIDataType::VTYPE_INT16
:
645 case nsIDataType::VTYPE_INT32
:
646 case nsIDataType::VTYPE_UINT8
:
647 case nsIDataType::VTYPE_UINT16
:
650 rv
= var
->GetAsInt32 (&v
);
651 if (NS_FAILED(rv
)) return rv
;
652 sqlite3_result_int (ctx
, v
);
655 case nsIDataType::VTYPE_UINT32
: // Try to preserve full range
656 case nsIDataType::VTYPE_INT64
:
657 // Data loss possible, but there is no unsigned types in SQLite
658 case nsIDataType::VTYPE_UINT64
:
661 rv
= var
->GetAsInt64 (&v
);
662 if (NS_FAILED(rv
)) return rv
;
663 sqlite3_result_int64 (ctx
, v
);
666 case nsIDataType::VTYPE_FLOAT
:
667 case nsIDataType::VTYPE_DOUBLE
:
670 rv
= var
->GetAsDouble (&v
);
671 if (NS_FAILED(rv
)) return rv
;
672 sqlite3_result_double (ctx
, v
);
675 case nsIDataType::VTYPE_BOOL
:
678 rv
= var
->GetAsBool(&v
);
679 if (NS_FAILED(rv
)) return rv
;
680 sqlite3_result_int (ctx
, v
? 1 : 0);
683 case nsIDataType::VTYPE_CHAR
:
684 case nsIDataType::VTYPE_WCHAR
:
685 case nsIDataType::VTYPE_DOMSTRING
:
686 case nsIDataType::VTYPE_CHAR_STR
:
687 case nsIDataType::VTYPE_WCHAR_STR
:
688 case nsIDataType::VTYPE_STRING_SIZE_IS
:
689 case nsIDataType::VTYPE_WSTRING_SIZE_IS
:
690 case nsIDataType::VTYPE_UTF8STRING
:
691 case nsIDataType::VTYPE_CSTRING
:
692 case nsIDataType::VTYPE_ASTRING
:
695 // GetAsAString does proper conversion to UCS2
696 // from all string-like types. It can be used
697 // universally without problems.
698 rv
= var
->GetAsAString (v
);
699 if (NS_FAILED(rv
)) return rv
;
700 sqlite3_result_text16 (ctx
,
701 nsPromiseFlatString(v
).get(),
706 case nsIDataType::VTYPE_VOID
:
707 case nsIDataType::VTYPE_EMPTY
:
708 sqlite3_result_null (ctx
);
710 // Maybe, it'll be possible to convert these
712 case nsIDataType::VTYPE_ID
:
713 case nsIDataType::VTYPE_INTERFACE
:
714 case nsIDataType::VTYPE_INTERFACE_IS
:
715 case nsIDataType::VTYPE_ARRAY
:
716 case nsIDataType::VTYPE_EMPTY_ARRAY
:
718 return NS_ERROR_CANNOT_CONVERT_DATA
;
724 mozStorageSqlFuncHelper (sqlite3_context
*ctx
,
726 sqlite3_value
**argv
)
728 void *userData
= sqlite3_user_data (ctx
);
729 // We don't want to QI here, because this will be called a -lot-
730 mozIStorageFunction
*userFunction
=
731 static_cast<mozIStorageFunction
*>(userData
);
733 nsRefPtr
<mozStorageArgvValueArray
> ava
= new mozStorageArgvValueArray (argc
, argv
);
736 nsCOMPtr
<nsIVariant
> retval
;
737 nsresult rv
= userFunction
->OnFunctionCall (ava
, getter_AddRefs(retval
));
739 NS_WARNING("mozIStorageConnection: User function returned error code!\n");
740 sqlite3_result_error(ctx
,
741 "User function returned error code",
745 rv
= mozStorageVariantToSQLite3Result(ctx
,retval
);
747 NS_WARNING("mozIStorageConnection: User function returned invalid data type!\n");
748 sqlite3_result_error(ctx
,
749 "User function returned invalid data type",
755 mozStorageConnection::CreateFunction(const nsACString
&aFunctionName
,
756 PRInt32 aNumArguments
,
757 mozIStorageFunction
*aFunction
)
759 if (!mDBConn
) return NS_ERROR_NOT_INITIALIZED
;
761 // do we already have this function defined?
762 // Check for name only because simple function can
763 // be defined multiple times with different names (aliases).
764 nsAutoLock
mutex(mFunctionsMutex
);
765 NS_ENSURE_FALSE(mFunctions
.Get (aFunctionName
, NULL
), NS_ERROR_FAILURE
);
767 int srv
= sqlite3_create_function (mDBConn
,
768 nsPromiseFlatCString(aFunctionName
).get(),
772 mozStorageSqlFuncHelper
,
775 if (srv
!= SQLITE_OK
) {
776 HandleSqliteError(nsnull
);
777 return ConvertResultCode(srv
);
780 if (mFunctions
.Put (aFunctionName
, aFunction
)) {
783 return NS_ERROR_OUT_OF_MEMORY
;
787 mozStorageSqlAggrFuncStepHelper (sqlite3_context
*ctx
,
789 sqlite3_value
**argv
)
791 void *userData
= sqlite3_user_data (ctx
);
792 // We don't want to QI here, because this will be called a -lot-
793 mozIStorageAggregateFunction
*userFunction
=
794 static_cast<mozIStorageAggregateFunction
*>(userData
);
796 nsRefPtr
<mozStorageArgvValueArray
> ava
=
797 new mozStorageArgvValueArray (argc
, argv
);
800 nsresult rv
= userFunction
->OnStep(ava
);
802 NS_WARNING("mozIStorageConnection: User aggregate step function returned error code!\n");
806 mozStorageSqlAggrFuncFinalHelper (sqlite3_context
*ctx
)
808 void *userData
= sqlite3_user_data (ctx
);
809 // We don't want to QI here, because this will be called a -lot-
810 mozIStorageAggregateFunction
*userFunction
=
811 static_cast<mozIStorageAggregateFunction
*>(userData
);
813 nsRefPtr
<nsIVariant
> retval
;
814 nsresult rv
= userFunction
->OnFinal (getter_AddRefs(retval
));
816 NS_WARNING("mozIStorageConnection: User aggregate final function returned error code!\n");
817 sqlite3_result_error(ctx
,
818 "User aggregate final function returned error code",
822 rv
= mozStorageVariantToSQLite3Result(ctx
,retval
);
824 NS_WARNING("mozIStorageConnection: User aggregate final function returned invalid data type!\n");
825 sqlite3_result_error(ctx
,
826 "User aggregate final function returned invalid data type",
832 mozStorageConnection::CreateAggregateFunction(const nsACString
&aFunctionName
,
833 PRInt32 aNumArguments
,
834 mozIStorageAggregateFunction
*aFunction
)
836 if (!mDBConn
) return NS_ERROR_NOT_INITIALIZED
;
838 // do we already have this function defined?
840 nsAutoLock
mutex(mFunctionsMutex
);
841 NS_ENSURE_FALSE(mFunctions
.Get (aFunctionName
, NULL
), NS_ERROR_FAILURE
);
843 // Aggregate functions are stateful, so we cannot have
845 // Enumerate all functions and determine if this one is already
847 NS_ENSURE_FALSE(FindFunctionByInstance (aFunction
), NS_ERROR_FAILURE
);
849 int srv
= sqlite3_create_function (mDBConn
,
850 nsPromiseFlatCString(aFunctionName
).get(),
855 mozStorageSqlAggrFuncStepHelper
,
856 mozStorageSqlAggrFuncFinalHelper
);
857 if (srv
!= SQLITE_OK
) {
858 HandleSqliteError(nsnull
);
859 return ConvertResultCode(srv
);
862 if (mFunctions
.Put (aFunctionName
, aFunction
)) {
865 return NS_ERROR_OUT_OF_MEMORY
;
869 mozStorageConnection::RemoveFunction(const nsACString
&aFunctionName
)
871 if (!mDBConn
) return NS_ERROR_NOT_INITIALIZED
;
873 nsAutoLock
mutex(mFunctionsMutex
);
874 NS_ENSURE_TRUE(mFunctions
.Get (aFunctionName
, NULL
), NS_ERROR_FAILURE
);
876 int srv
= sqlite3_create_function (mDBConn
,
877 nsPromiseFlatCString(aFunctionName
).get(),
884 if (srv
!= SQLITE_OK
) {
885 HandleSqliteError(nsnull
);
886 return ConvertResultCode(srv
);
889 mFunctions
.Remove (aFunctionName
);
895 mozStorageConnection::s_ProgressHelper(void *arg
)
897 mozStorageConnection
*_this
= static_cast<mozStorageConnection
*>(arg
);
898 return _this
->ProgressHandler();
902 mozStorageConnection::SetProgressHandler(PRInt32 aGranularity
,
903 mozIStorageProgressHandler
*aHandler
,
904 mozIStorageProgressHandler
**aOldHandler
)
906 if (!mDBConn
) return NS_ERROR_NOT_INITIALIZED
;
908 // Return previous one
909 nsAutoLock
mutex(mProgressHandlerMutex
);
910 NS_IF_ADDREF(*aOldHandler
= mProgressHandler
);
912 if (!aHandler
|| aGranularity
<= 0) {
916 mProgressHandler
= aHandler
;
917 sqlite3_progress_handler (mDBConn
, aGranularity
, s_ProgressHelper
, this);
923 mozStorageConnection::RemoveProgressHandler(mozIStorageProgressHandler
**aOldHandler
)
925 if (!mDBConn
) return NS_ERROR_NOT_INITIALIZED
;
927 // Return previous one
928 nsAutoLock
mutex(mProgressHandlerMutex
);
929 NS_IF_ADDREF(*aOldHandler
= mProgressHandler
);
931 mProgressHandler
= nsnull
;
932 sqlite3_progress_handler (mDBConn
, 0, NULL
, NULL
);
938 mozStorageConnection::ProgressHandler()
940 nsAutoLock
mutex(mProgressHandlerMutex
);
941 if (mProgressHandler
) {
943 nsresult rv
= mProgressHandler
->OnProgress(this, &res
);
944 if (NS_FAILED(rv
)) return 0; // Don't break request
954 already_AddRefed
<nsIEventTarget
>
955 mozStorageConnection::getAsyncExecutionTarget()
957 nsAutoLock
mutex(mAsyncExecutionMutex
);
959 // If we are shutting down the asynchronous thread, don't hand out any more
960 // references to the thread.
961 if (mAsyncExecutionThreadShuttingDown
)
964 if (!mAsyncExecutionThread
) {
965 nsresult rv
= NS_NewThread(getter_AddRefs(mAsyncExecutionThread
));
967 NS_WARNING("Failed to create async thread.");
972 nsIEventTarget
*eventTarget
;
973 NS_ADDREF(eventTarget
= mAsyncExecutionThread
);
978 mozStorageConnection::HandleSqliteError(const char *aSqlStatement
)
980 // an error just occured!
982 PR_LOG(gStorageLog
, PR_LOG_DEBUG
, ("Sqlite error: %d '%s'", sqlite3_errcode(mDBConn
), sqlite3_errmsg(mDBConn
)));
984 PR_LOG(gStorageLog
, PR_LOG_DEBUG
, ("Statement was: %s", aSqlStatement
));