LCOV - code coverage report
Current view: directory - storage/src - StorageBaseStatementInternal.cpp (source / functions) Found Hit Coverage
Test: app.info Lines: 65 63 96.9 %
Date: 2012-06-02 Functions: 14 14 100.0 %

       1                 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
       2                 :  * vim: sw=2 ts=2 sts=2 expandtab
       3                 :  * ***** BEGIN LICENSE BLOCK *****
       4                 :  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
       5                 :  *
       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/
      10                 :  *
      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
      14                 :  * License.
      15                 :  *
      16                 :  * The Original Code is mozilla.org code.
      17                 :  *
      18                 :  * The Initial Developer of the Original Code is the Mozilla Foundation.
      19                 :  * Portions created by the Initial Developer are Copyright (C) 2010
      20                 :  * the Initial Developer. All Rights Reserved.
      21                 :  *
      22                 :  * Contributor(s):
      23                 :  *   Andrew Sutherland <asutherland@asutherland.org>
      24                 :  *
      25                 :  * Alternatively, the contents of this file may be used under the terms of
      26                 :  * either the GNU General Public License Version 2 or later (the "GPL"), or
      27                 :  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
      28                 :  * in which case the provisions of the GPL or the LGPL are applicable instead
      29                 :  * of those above. If you wish to allow use of your version of this file only
      30                 :  * under the terms of either the GPL or the LGPL, and not to allow others to
      31                 :  * use your version of this file under the terms of the MPL, indicate your
      32                 :  * decision by deleting the provisions above and replace them with the notice
      33                 :  * and other provisions required by the GPL or the LGPL. If you do not delete
      34                 :  * the provisions above, a recipient may use your version of this file under
      35                 :  * the terms of any one of the MPL, the GPL or the LGPL.
      36                 :  *
      37                 :  * ***** END LICENSE BLOCK ***** */
      38                 : 
      39                 : #include "StorageBaseStatementInternal.h"
      40                 : 
      41                 : #include "nsProxyRelease.h"
      42                 : 
      43                 : #include "mozStorageBindingParamsArray.h"
      44                 : #include "mozStorageStatementData.h"
      45                 : #include "mozStorageAsyncStatementExecution.h"
      46                 : 
      47                 : namespace mozilla {
      48                 : namespace storage {
      49                 : 
      50                 : ////////////////////////////////////////////////////////////////////////////////
      51                 : //// Local Classes
      52                 : 
      53                 : /**
      54                 :  * Used to finalize an asynchronous statement on the background thread.
      55                 :  */
      56                 : class AsyncStatementFinalizer : public nsRunnable
      57           35084 : {
      58                 : public:
      59                 :   /**
      60                 :    * Constructor for the event.
      61                 :    *
      62                 :    * @param aStatement
      63                 :    *        We need the AsyncStatement to be able to get at the sqlite3_stmt;
      64                 :    *        we only access/create it on the async thread.
      65                 :    * @param aConnection
      66                 :    *        We need the connection to know what thread to release the statement
      67                 :    *        on.  We release the statement on that thread since releasing the
      68                 :    *        statement might end up releasing the connection too.
      69                 :    */
      70            8771 :   AsyncStatementFinalizer(StorageBaseStatementInternal *aStatement,
      71                 :                           Connection *aConnection)
      72                 :   : mStatement(aStatement)
      73            8771 :   , mConnection(aConnection)
      74                 :   {
      75            8771 :   }
      76                 : 
      77            8771 :   NS_IMETHOD Run()
      78                 :   {
      79            8771 :     if (mStatement->mAsyncStatement) {
      80            8758 :       (void)::sqlite3_finalize(mStatement->mAsyncStatement);
      81            8758 :       mStatement->mAsyncStatement = nsnull;
      82                 :     }
      83            8771 :     (void)::NS_ProxyRelease(mConnection->threadOpenedOn, mStatement);
      84            8771 :     return NS_OK;
      85                 :   }
      86                 : private:
      87                 :   nsRefPtr<StorageBaseStatementInternal> mStatement;
      88                 :   nsRefPtr<Connection> mConnection;
      89                 : };
      90                 : 
      91                 : /**
      92                 :  * Finalize a sqlite3_stmt on the background thread for a statement whose
      93                 :  * destructor was invoked and the statement was non-null.
      94                 :  */
      95                 : class LastDitchSqliteStatementFinalizer : public nsRunnable
      96            4332 : {
      97                 : public:
      98                 :   /**
      99                 :    * Event constructor.
     100                 :    *
     101                 :    * @param aConnection
     102                 :    *        Used to keep the connection alive.  If we failed to do this, it
     103                 :    *        is possible that the statement going out of scope invoking us
     104                 :    *        might have the last reference to the connection and so trigger
     105                 :    *        an attempt to close the connection which is doomed to fail
     106                 :    *        (because the asynchronous execution thread must exist which will
     107                 :    *        trigger the failure case).
     108                 :    * @param aStatement
     109                 :    *        The sqlite3_stmt to finalize.  This object takes ownership /
     110                 :    *        responsibility for the instance and all other references to it
     111                 :    *        should be forgotten.
     112                 :    */
     113            1083 :   LastDitchSqliteStatementFinalizer(nsRefPtr<Connection> &aConnection,
     114                 :                                     sqlite3_stmt *aStatement)
     115                 :   : mConnection(aConnection)
     116            1083 :   , mAsyncStatement(aStatement)
     117                 :   {
     118            1083 :     NS_PRECONDITION(aConnection, "You must provide a Connection");
     119            1083 :   }
     120                 : 
     121            1083 :   NS_IMETHOD Run()
     122                 :   {
     123            1083 :     (void)::sqlite3_finalize(mAsyncStatement);
     124            1083 :     mAsyncStatement = nsnull;
     125                 : 
     126                 :     // Because of our ambiguous nsISupports we cannot use the NS_ProxyRelease
     127                 :     // template helpers.
     128            1083 :     Connection *rawConnection = nsnull;
     129            1083 :     mConnection.swap(rawConnection);
     130                 :     (void)::NS_ProxyRelease(
     131                 :       rawConnection->threadOpenedOn,
     132            1083 :       NS_ISUPPORTS_CAST(mozIStorageConnection *, rawConnection));
     133            1083 :     return NS_OK;
     134                 :   }
     135                 : private:
     136                 :   nsRefPtr<Connection> mConnection;
     137                 :   sqlite3_stmt *mAsyncStatement;
     138                 : };
     139                 : 
     140                 : ////////////////////////////////////////////////////////////////////////////////
     141                 : //// StorageBaseStatementInternal
     142                 : 
     143           42729 : StorageBaseStatementInternal::StorageBaseStatementInternal()
     144           42729 : : mAsyncStatement(NULL)
     145                 : {
     146           42729 : }
     147                 : 
     148                 : void
     149            8771 : StorageBaseStatementInternal::asyncFinalize()
     150                 : {
     151            8771 :   nsIEventTarget *target = mDBConnection->getAsyncExecutionTarget();
     152            8771 :   if (!target) {
     153                 :     // If we cannot get the background thread, we have to assume it has been
     154                 :     // shutdown (or is in the process of doing so).  As a result, we should
     155                 :     // just finalize it here and now.
     156               0 :     destructorAsyncFinalize();
     157                 :   }
     158                 :   else {
     159                 :     nsCOMPtr<nsIRunnable> event =
     160           26313 :       new AsyncStatementFinalizer(this, mDBConnection);
     161                 : 
     162                 :     // If the dispatching did not go as planned, finalize now.
     163            8771 :     if (NS_FAILED(target->Dispatch(event, NS_DISPATCH_NORMAL))) {
     164               0 :       destructorAsyncFinalize();
     165                 :     }
     166                 :   }
     167            8771 : }
     168                 : 
     169                 : void
     170            5918 : StorageBaseStatementInternal::destructorAsyncFinalize()
     171                 : {
     172            5918 :   if (!mAsyncStatement)
     173            4729 :     return;
     174                 : 
     175            1189 :   nsIEventTarget *target = mDBConnection->getAsyncExecutionTarget();
     176            1189 :   if (target) {
     177                 :     nsCOMPtr<nsIRunnable> event =
     178            2166 :       new LastDitchSqliteStatementFinalizer(mDBConnection, mAsyncStatement);
     179            1083 :     if (NS_SUCCEEDED(target->Dispatch(event, NS_DISPATCH_NORMAL))) {
     180            1083 :       mAsyncStatement = nsnull;
     181                 :       return;
     182                 :     }
     183                 :   }
     184                 :   // (no async thread remains or we could not dispatch to it)
     185             106 :   (void)::sqlite3_finalize(mAsyncStatement);
     186             106 :   mAsyncStatement = nsnull;
     187                 : }
     188                 : 
     189                 : NS_IMETHODIMP
     190          121768 : StorageBaseStatementInternal::NewBindingParamsArray(
     191                 :   mozIStorageBindingParamsArray **_array
     192                 : )
     193                 : {
     194          243536 :   nsCOMPtr<mozIStorageBindingParamsArray> array = new BindingParamsArray(this);
     195          121768 :   NS_ENSURE_TRUE(array, NS_ERROR_OUT_OF_MEMORY);
     196                 : 
     197          121768 :   array.forget(_array);
     198          121768 :   return NS_OK;
     199                 : }
     200                 : 
     201                 : NS_IMETHODIMP
     202           37300 : StorageBaseStatementInternal::ExecuteAsync(
     203                 :   mozIStorageStatementCallback *aCallback,
     204                 :   mozIStoragePendingStatement **_stmt
     205                 : )
     206                 : {
     207                 :   // We used to call Connection::ExecuteAsync but it takes a
     208                 :   // mozIStorageBaseStatement signature because it is also a public API.  Since
     209                 :   // our 'this' has no static concept of mozIStorageBaseStatement and Connection
     210                 :   // would just QI it back across to a StorageBaseStatementInternal and the
     211                 :   // actual logic is very simple, we now roll our own.
     212           74600 :   nsTArray<StatementData> stmts(1);
     213           74600 :   StatementData data;
     214           37300 :   nsresult rv = getAsynchronousStatementData(data);
     215           37300 :   NS_ENSURE_SUCCESS(rv, rv);
     216           37299 :   NS_ENSURE_TRUE(stmts.AppendElement(data), NS_ERROR_OUT_OF_MEMORY);
     217                 : 
     218                 :   // Dispatch to the background
     219                 :   return AsyncExecuteStatements::execute(stmts, mDBConnection, aCallback,
     220           37299 :                                          _stmt);
     221                 : }
     222                 : 
     223                 : NS_IMETHODIMP
     224             100 : StorageBaseStatementInternal::EscapeStringForLIKE(
     225                 :   const nsAString &aValue,
     226                 :   const PRUnichar aEscapeChar,
     227                 :   nsAString &_escapedString
     228                 : )
     229                 : {
     230             100 :   const PRUnichar MATCH_ALL('%');
     231             100 :   const PRUnichar MATCH_ONE('_');
     232                 : 
     233             100 :   _escapedString.Truncate(0);
     234                 : 
     235            1186 :   for (PRUint32 i = 0; i < aValue.Length(); i++) {
     236            2168 :     if (aValue[i] == aEscapeChar || aValue[i] == MATCH_ALL ||
     237            1082 :         aValue[i] == MATCH_ONE) {
     238               6 :       _escapedString += aEscapeChar;
     239                 :     }
     240            1086 :     _escapedString += aValue[i];
     241                 :   }
     242             100 :   return NS_OK;
     243                 : }
     244                 : 
     245                 : } // namespace storage
     246                 : } // namespace mozilla

Generated by: LCOV version 1.7