LCOV - code coverage report
Current view: directory - storage/src - mozStorageStatement.cpp (source / functions) Found Hit Coverage
Test: app.info Lines: 376 317 84.3 %
Date: 2012-06-02 Functions: 80 64 80.0 %

       1                 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
       2                 :  * vim: sw=2 ts=2 et lcs=trail\:.,tab\:>~ :
       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 Oracle Corporation code.
      17                 :  *
      18                 :  * The Initial Developer of the Original Code is
      19                 :  *  Oracle Corporation
      20                 :  * Portions created by the Initial Developer are Copyright (C) 2004
      21                 :  * the Initial Developer. All Rights Reserved.
      22                 :  *
      23                 :  * Contributor(s):
      24                 :  *   Vladimir Vukicevic <vladimir.vukicevic@oracle.com>
      25                 :  *   Shawn Wilsher <me@shawnwilsher.com>
      26                 :  *   John Zhang <jzhang@aptana.com>
      27                 :  *
      28                 :  * Alternatively, the contents of this file may be used under the terms of
      29                 :  * either the GNU General Public License Version 2 or later (the "GPL"), or
      30                 :  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
      31                 :  * in which case the provisions of the GPL or the LGPL are applicable instead
      32                 :  * of those above. If you wish to allow use of your version of this file only
      33                 :  * under the terms of either the GPL or the LGPL, and not to allow others to
      34                 :  * use your version of this file under the terms of the MPL, indicate your
      35                 :  * decision by deleting the provisions above and replace them with the notice
      36                 :  * and other provisions required by the GPL or the LGPL. If you do not delete
      37                 :  * the provisions above, a recipient may use your version of this file under
      38                 :  * the terms of any one of the MPL, the GPL or the LGPL.
      39                 :  *
      40                 :  * ***** END LICENSE BLOCK ***** */
      41                 : 
      42                 : #include <limits.h>
      43                 : #include <stdio.h>
      44                 : 
      45                 : #include "nsError.h"
      46                 : #include "nsMemory.h"
      47                 : #include "nsThreadUtils.h"
      48                 : #include "nsIClassInfoImpl.h"
      49                 : #include "nsIProgrammingLanguage.h"
      50                 : #include "Variant.h"
      51                 : 
      52                 : #include "mozIStorageError.h"
      53                 : 
      54                 : #include "mozStorageBindingParams.h"
      55                 : #include "mozStorageConnection.h"
      56                 : #include "mozStorageStatementJSHelper.h"
      57                 : #include "mozStoragePrivateHelpers.h"
      58                 : #include "mozStorageStatementParams.h"
      59                 : #include "mozStorageStatementRow.h"
      60                 : #include "mozStorageStatement.h"
      61                 : #include "sampler.h"
      62                 : 
      63                 : #include "prlog.h"
      64                 : 
      65                 : #include "mozilla/FunctionTimer.h"
      66                 : 
      67                 : #ifdef PR_LOGGING
      68                 : extern PRLogModuleInfo* gStorageLog;
      69                 : #endif
      70                 : 
      71                 : namespace mozilla {
      72                 : namespace storage {
      73                 : 
      74                 : ////////////////////////////////////////////////////////////////////////////////
      75                 : //// nsIClassInfo
      76                 : 
      77             396 : NS_IMPL_CI_INTERFACE_GETTER5(
      78                 :   Statement,
      79                 :   mozIStorageStatement,
      80                 :   mozIStorageBaseStatement,
      81                 :   mozIStorageBindingParams,
      82                 :   mozIStorageValueArray,
      83                 :   mozilla::storage::StorageBaseStatementInternal
      84             396 : )
      85                 : 
      86                 : class StatementClassInfo : public nsIClassInfo
      87            1464 : {
      88                 : public:
      89                 :   NS_DECL_ISUPPORTS
      90                 : 
      91                 :   NS_IMETHODIMP
      92             396 :   GetInterfaces(PRUint32 *_count, nsIID ***_array)
      93                 :   {
      94             396 :     return NS_CI_INTERFACE_GETTER_NAME(Statement)(_count, _array);
      95                 :   }
      96                 : 
      97                 :   NS_IMETHODIMP
      98           16934 :   GetHelperForLanguage(PRUint32 aLanguage, nsISupports **_helper)
      99                 :   {
     100           16934 :     if (aLanguage == nsIProgrammingLanguage::JAVASCRIPT) {
     101           16934 :       static StatementJSHelper sJSHelper;
     102           16934 :       *_helper = &sJSHelper;
     103           16934 :       return NS_OK;
     104                 :     }
     105                 : 
     106               0 :     *_helper = nsnull;
     107               0 :     return NS_OK;
     108                 :   }
     109                 : 
     110                 :   NS_IMETHODIMP
     111               0 :   GetContractID(char **_contractID)
     112                 :   {
     113               0 :     *_contractID = nsnull;
     114               0 :     return NS_OK;
     115                 :   }
     116                 : 
     117                 :   NS_IMETHODIMP
     118               0 :   GetClassDescription(char **_desc)
     119                 :   {
     120               0 :     *_desc = nsnull;
     121               0 :     return NS_OK;
     122                 :   }
     123                 : 
     124                 :   NS_IMETHODIMP
     125               0 :   GetClassID(nsCID **_id)
     126                 :   {
     127               0 :     *_id = nsnull;
     128               0 :     return NS_OK;
     129                 :   }
     130                 : 
     131                 :   NS_IMETHODIMP
     132               0 :   GetImplementationLanguage(PRUint32 *_language)
     133                 :   {
     134               0 :     *_language = nsIProgrammingLanguage::CPLUSPLUS;
     135               0 :     return NS_OK;
     136                 :   }
     137                 : 
     138                 :   NS_IMETHODIMP
     139           30602 :   GetFlags(PRUint32 *_flags)
     140                 :   {
     141           30602 :     *_flags = nsnull;
     142           30602 :     return NS_OK;
     143                 :   }
     144                 : 
     145                 :   NS_IMETHODIMP
     146               0 :   GetClassIDNoAlloc(nsCID *_cid)
     147                 :   {
     148               0 :     return NS_ERROR_NOT_AVAILABLE;
     149                 :   }
     150                 : };
     151                 : 
     152           17794 : NS_IMETHODIMP_(nsrefcnt) StatementClassInfo::AddRef() { return 2; }
     153           17794 : NS_IMETHODIMP_(nsrefcnt) StatementClassInfo::Release() { return 1; }
     154           17364 : NS_IMPL_QUERY_INTERFACE1(StatementClassInfo, nsIClassInfo)
     155                 : 
     156            1464 : static StatementClassInfo sStatementClassInfo;
     157                 : 
     158                 : ////////////////////////////////////////////////////////////////////////////////
     159                 : //// Statement
     160                 : 
     161           36811 : Statement::Statement()
     162                 : : StorageBaseStatementInternal()
     163                 : , mDBStatement(NULL)
     164                 : , mColumnNames()
     165           36811 : , mExecuting(false)
     166                 : {
     167           36811 : }
     168                 : 
     169                 : nsresult
     170           36811 : Statement::initialize(Connection *aDBConnection,
     171                 :                       const nsACString &aSQLStatement)
     172                 : {
     173           36811 :   NS_ASSERTION(aDBConnection, "No database connection given!");
     174           36811 :   NS_ASSERTION(!mDBStatement, "Statement already initialized!");
     175                 : 
     176           36811 :   sqlite3 *db = aDBConnection->GetNativeConnection();
     177           36811 :   NS_ASSERTION(db, "We should never be called with a null sqlite3 database!");
     178                 : 
     179           36811 :   int srv = aDBConnection->prepareStatement(PromiseFlatCString(aSQLStatement),
     180           36811 :                                             &mDBStatement);
     181           36811 :   if (srv != SQLITE_OK) {
     182                 : #ifdef PR_LOGGING
     183              49 :       PR_LOG(gStorageLog, PR_LOG_ERROR,
     184                 :              ("Sqlite statement prepare error: %d '%s'", srv,
     185                 :               ::sqlite3_errmsg(db)));
     186              49 :       PR_LOG(gStorageLog, PR_LOG_ERROR,
     187                 :              ("Statement was: '%s'", PromiseFlatCString(aSQLStatement).get()));
     188                 : #endif
     189              49 :       return NS_ERROR_FAILURE;
     190                 :     }
     191                 : 
     192                 : #ifdef PR_LOGGING
     193           36762 :   PR_LOG(gStorageLog, PR_LOG_NOTICE, ("Initialized statement '%s' (0x%p)",
     194                 :                                       PromiseFlatCString(aSQLStatement).get(),
     195                 :                                       mDBStatement));
     196                 : #endif
     197                 : 
     198           36762 :   mDBConnection = aDBConnection;
     199           36762 :   mParamCount = ::sqlite3_bind_parameter_count(mDBStatement);
     200           36762 :   mResultColumnCount = ::sqlite3_column_count(mDBStatement);
     201           36762 :   mColumnNames.Clear();
     202                 : 
     203          196705 :   for (PRUint32 i = 0; i < mResultColumnCount; i++) {
     204          159943 :       const char *name = ::sqlite3_column_name(mDBStatement, i);
     205          159943 :       (void)mColumnNames.AppendElement(nsDependentCString(name));
     206                 :   }
     207                 : 
     208                 : #ifdef DEBUG
     209                 :   // We want to try and test for LIKE and that consumers are using
     210                 :   // escapeStringForLIKE instead of just trusting user input.  The idea to
     211                 :   // check to see if they are binding a parameter after like instead of just
     212                 :   // using a string.  We only do this in debug builds because it's expensive!
     213           36762 :   const nsCaseInsensitiveCStringComparator c;
     214           36762 :   nsACString::const_iterator start, end, e;
     215           36762 :   aSQLStatement.BeginReading(start);
     216           36762 :   aSQLStatement.EndReading(end);
     217           36762 :   e = end;
     218           73634 :   while (::FindInReadable(NS_LITERAL_CSTRING(" LIKE"), start, e, c)) {
     219                 :     // We have a LIKE in here, so we perform our tests
     220                 :     // FindInReadable moves the iterator, so we have to get a new one for
     221                 :     // each test we perform.
     222             110 :     nsACString::const_iterator s1, s2, s3;
     223             110 :     s1 = s2 = s3 = start;
     224                 : 
     225             221 :     if (!(::FindInReadable(NS_LITERAL_CSTRING(" LIKE ?"), s1, end, c) ||
     226             114 :           ::FindInReadable(NS_LITERAL_CSTRING(" LIKE :"), s2, end, c) ||
     227             114 :           ::FindInReadable(NS_LITERAL_CSTRING(" LIKE @"), s3, end, c))) {
     228                 :       // At this point, we didn't find a LIKE statement followed by ?, :,
     229                 :       // or @, all of which are valid characters for binding a parameter.
     230                 :       // We will warn the consumer that they may not be safely using LIKE.
     231                 :       NS_WARNING("Unsafe use of LIKE detected!  Please ensure that you "
     232                 :                  "are using mozIStorageStatement::escapeStringForLIKE "
     233                 :                  "and that you are binding that result to the statement "
     234               1 :                  "to prevent SQL injection attacks.");
     235                 :     }
     236                 : 
     237                 :     // resetting start and e
     238             110 :     start = e;
     239             110 :     e = end;
     240                 :   }
     241                 : #endif
     242                 : 
     243           36762 :   return NS_OK;
     244                 : }
     245                 : 
     246                 : mozIStorageBindingParams *
     247          237392 : Statement::getParams()
     248                 : {
     249                 :   nsresult rv;
     250                 : 
     251                 :   // If we do not have an array object yet, make it.
     252          237392 :   if (!mParamsArray) {
     253          177378 :     nsCOMPtr<mozIStorageBindingParamsArray> array;
     254           88689 :     rv = NewBindingParamsArray(getter_AddRefs(array));
     255           88689 :     NS_ENSURE_SUCCESS(rv, nsnull);
     256                 : 
     257          177378 :     mParamsArray = static_cast<BindingParamsArray *>(array.get());
     258                 :   }
     259                 : 
     260                 :   // If there isn't already any rows added, we'll have to add one to use.
     261          237392 :   if (mParamsArray->length() == 0) {
     262          266067 :     nsRefPtr<BindingParams> params(new BindingParams(mParamsArray, this));
     263           88689 :     NS_ENSURE_TRUE(params, nsnull);
     264                 : 
     265           88689 :     rv = mParamsArray->AddParams(params);
     266           88689 :     NS_ENSURE_SUCCESS(rv, nsnull);
     267                 : 
     268                 :     // We have to unlock our params because AddParams locks them.  This is safe
     269                 :     // because no reference to the params object was, or ever will be given out.
     270           88689 :     params->unlock(this);
     271                 : 
     272                 :     // We also want to lock our array at this point - we don't want anything to
     273                 :     // be added to it.  Nothing has, or will ever get a reference to it, but we
     274                 :     // will get additional safety checks via assertions by doing this.
     275          177378 :     mParamsArray->lock();
     276                 :   }
     277                 : 
     278          237392 :   return *mParamsArray->begin();
     279                 : }
     280                 : 
     281           73594 : Statement::~Statement()
     282                 : {
     283           36797 :   (void)internalFinalize(true);
     284           36797 : }
     285                 : 
     286                 : ////////////////////////////////////////////////////////////////////////////////
     287                 : //// nsISupports
     288                 : 
     289          757368 : NS_IMPL_THREADSAFE_ADDREF(Statement)
     290          794150 : NS_IMPL_THREADSAFE_RELEASE(Statement)
     291                 : 
     292          567887 : NS_INTERFACE_MAP_BEGIN(Statement)
     293          567887 :   NS_INTERFACE_MAP_ENTRY(mozIStorageStatement)
     294          244077 :   NS_INTERFACE_MAP_ENTRY(mozIStorageBaseStatement)
     295          244074 :   NS_INTERFACE_MAP_ENTRY(mozIStorageBindingParams)
     296          244074 :   NS_INTERFACE_MAP_ENTRY(mozIStorageValueArray)
     297          242293 :   NS_INTERFACE_MAP_ENTRY(mozilla::storage::StorageBaseStatementInternal)
     298          137333 :   if (aIID.Equals(NS_GET_IID(nsIClassInfo))) {
     299           16934 :     foundInterface = static_cast<nsIClassInfo *>(&sStatementClassInfo);
     300                 :   }
     301                 :   else
     302          120399 :   NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, mozIStorageStatement)
     303          101347 : NS_INTERFACE_MAP_END
     304                 : 
     305                 : 
     306                 : ////////////////////////////////////////////////////////////////////////////////
     307                 : //// StorageBaseStatementInternal
     308                 : 
     309                 : Connection *
     310               0 : Statement::getOwner()
     311                 : {
     312               0 :   return mDBConnection;
     313                 : }
     314                 : 
     315                 : int
     316           16240 : Statement::getAsyncStatement(sqlite3_stmt **_stmt)
     317                 : {
     318                 :   // If we have no statement, we shouldn't be calling this method!
     319           16240 :   NS_ASSERTION(mDBStatement != NULL, "We have no statement to clone!");
     320                 : 
     321                 :   // If we do not yet have a cached async statement, clone our statement now.
     322           16240 :   if (!mAsyncStatement) {
     323            9524 :     nsDependentCString sql(::sqlite3_sql(mDBStatement));
     324            4762 :     int rc = mDBConnection->prepareStatement(sql, &mAsyncStatement);
     325            4762 :     if (rc != SQLITE_OK) {
     326               0 :       *_stmt = nsnull;
     327               0 :       return rc;
     328                 :     }
     329                 : 
     330                 : #ifdef PR_LOGGING
     331            4762 :     PR_LOG(gStorageLog, PR_LOG_NOTICE,
     332                 :            ("Cloned statement 0x%p to 0x%p", mDBStatement, mAsyncStatement));
     333                 : #endif
     334                 :   }
     335                 : 
     336           16240 :   *_stmt = mAsyncStatement;
     337           16240 :   return SQLITE_OK;
     338                 : }
     339                 : 
     340                 : nsresult
     341           16241 : Statement::getAsynchronousStatementData(StatementData &_data)
     342                 : {
     343           16241 :   if (!mDBStatement)
     344               1 :     return NS_ERROR_UNEXPECTED;
     345                 : 
     346                 :   sqlite3_stmt *stmt;
     347           16240 :   int rc = getAsyncStatement(&stmt);
     348           16240 :   if (rc != SQLITE_OK)
     349               0 :     return convertResultCode(rc);
     350                 : 
     351           16240 :   _data = StatementData(stmt, bindingParamsArray(), this);
     352                 : 
     353           16240 :   return NS_OK;
     354                 : }
     355                 : 
     356                 : already_AddRefed<mozIStorageBindingParams>
     357              34 : Statement::newBindingParams(mozIStorageBindingParamsArray *aOwner)
     358                 : {
     359              68 :   nsCOMPtr<mozIStorageBindingParams> params = new BindingParams(aOwner, this);
     360              34 :   return params.forget();
     361                 : }
     362                 : 
     363                 : 
     364                 : ////////////////////////////////////////////////////////////////////////////////
     365                 : //// mozIStorageStatement
     366                 : 
     367                 : // proxy to StorageBaseStatementInternal using its define helper.
     368          105035 : MIXIN_IMPL_STORAGEBASESTATEMENTINTERNAL(Statement, (void)0;)
     369                 : 
     370                 : NS_IMETHODIMP
     371               0 : Statement::Clone(mozIStorageStatement **_statement)
     372                 : {
     373               0 :   nsRefPtr<Statement> statement(new Statement());
     374               0 :   NS_ENSURE_TRUE(statement, NS_ERROR_OUT_OF_MEMORY);
     375                 : 
     376               0 :   nsCAutoString sql(::sqlite3_sql(mDBStatement));
     377               0 :   nsresult rv = statement->initialize(mDBConnection, sql);
     378               0 :   NS_ENSURE_SUCCESS(rv, rv);
     379                 : 
     380               0 :   statement.forget(_statement);
     381               0 :   return NS_OK;
     382                 : }
     383                 : 
     384                 : NS_IMETHODIMP
     385           20461 : Statement::Finalize()
     386                 : {
     387           20461 :   return internalFinalize(false);
     388                 : }
     389                 : 
     390                 : nsresult
     391           57258 : Statement::internalFinalize(bool aDestructing)
     392                 : {
     393           57258 :   if (!mDBStatement)
     394           20496 :     return NS_OK;
     395                 : 
     396                 : #ifdef PR_LOGGING
     397           36762 :   PR_LOG(gStorageLog, PR_LOG_NOTICE, ("Finalizing statement '%s'",
     398                 :                                       ::sqlite3_sql(mDBStatement)));
     399                 : #endif
     400                 : 
     401           36762 :   int srv = ::sqlite3_finalize(mDBStatement);
     402           36762 :   mDBStatement = NULL;
     403                 : 
     404           36762 :   if (mAsyncStatement) {
     405                 :     // If the destructor called us, there are no pending async statements (they
     406                 :     // hold a reference to us) and we can/must just kill the statement directly.
     407            4762 :     if (aDestructing)
     408               0 :       destructorAsyncFinalize();
     409                 :     else
     410            4762 :       asyncFinalize();
     411                 :   }
     412                 : 
     413                 :   // We are considered dead at this point, so any wrappers for row or params
     414                 :   // need to lose their reference to us.
     415           36762 :   if (mStatementParamsHolder) {
     416                 :     nsCOMPtr<nsIXPConnectWrappedNative> wrapper =
     417           21440 :         do_QueryInterface(mStatementParamsHolder);
     418                 :     nsCOMPtr<mozIStorageStatementParams> iParams =
     419           21440 :         do_QueryWrappedNative(wrapper);
     420           10720 :     StatementParams *params = static_cast<StatementParams *>(iParams.get());
     421           10720 :     params->mStatement = nsnull;
     422           10720 :     mStatementParamsHolder = nsnull;
     423                 :   }
     424                 : 
     425           36762 :   if (mStatementRowHolder) {
     426                 :     nsCOMPtr<nsIXPConnectWrappedNative> wrapper =
     427            5270 :         do_QueryInterface(mStatementRowHolder);
     428                 :     nsCOMPtr<mozIStorageStatementRow> iRow =
     429            5270 :         do_QueryWrappedNative(wrapper);
     430            2635 :     StatementRow *row = static_cast<StatementRow *>(iRow.get());
     431            2635 :     row->mStatement = nsnull;
     432            2635 :     mStatementRowHolder = nsnull;
     433                 :   }
     434                 : 
     435           36762 :   return convertResultCode(srv);
     436                 : }
     437                 : 
     438                 : NS_IMETHODIMP
     439           99527 : Statement::GetParameterCount(PRUint32 *_parameterCount)
     440                 : {
     441           99527 :   if (!mDBStatement)
     442               0 :     return NS_ERROR_NOT_INITIALIZED;
     443                 : 
     444           99527 :   *_parameterCount = mParamCount;
     445           99527 :   return NS_OK;
     446                 : }
     447                 : 
     448                 : NS_IMETHODIMP
     449              16 : Statement::GetParameterName(PRUint32 aParamIndex,
     450                 :                             nsACString &_name)
     451                 : {
     452              16 :   if (!mDBStatement)
     453               0 :     return NS_ERROR_NOT_INITIALIZED;
     454              16 :   ENSURE_INDEX_VALUE(aParamIndex, mParamCount);
     455                 : 
     456                 :   const char *name = ::sqlite3_bind_parameter_name(mDBStatement,
     457              16 :                                                    aParamIndex + 1);
     458              16 :   if (name == NULL) {
     459                 :     // this thing had no name, so fake one
     460               0 :     nsCAutoString name(":");
     461               0 :     name.AppendInt(aParamIndex);
     462               0 :     _name.Assign(name);
     463                 :   }
     464                 :   else {
     465              16 :     _name.Assign(nsDependentCString(name));
     466                 :   }
     467                 : 
     468              16 :   return NS_OK;
     469                 : }
     470                 : 
     471                 : NS_IMETHODIMP
     472          264239 : Statement::GetParameterIndex(const nsACString &aName,
     473                 :                              PRUint32 *_index)
     474                 : {
     475          264239 :   if (!mDBStatement)
     476               0 :     return NS_ERROR_NOT_INITIALIZED;
     477                 : 
     478                 :   // We do not accept any forms of names other than ":name", but we need to add
     479                 :   // the colon for SQLite.
     480          528478 :   nsCAutoString name(":");
     481          264239 :   name.Append(aName);
     482          264239 :   int ind = ::sqlite3_bind_parameter_index(mDBStatement, name.get());
     483          264239 :   if (ind  == 0) // Named parameter not found.
     484              29 :     return NS_ERROR_INVALID_ARG;
     485                 : 
     486          264210 :   *_index = ind - 1; // SQLite indexes are 1-based, we are 0-based.
     487                 : 
     488          264210 :   return NS_OK;
     489                 : }
     490                 : 
     491                 : NS_IMETHODIMP
     492              68 : Statement::GetColumnCount(PRUint32 *_columnCount)
     493                 : {
     494              68 :   if (!mDBStatement)
     495               0 :     return NS_ERROR_NOT_INITIALIZED;
     496                 : 
     497              68 :   *_columnCount = mResultColumnCount;
     498              68 :   return NS_OK;
     499                 : }
     500                 : 
     501                 : NS_IMETHODIMP
     502               4 : Statement::GetColumnName(PRUint32 aColumnIndex,
     503                 :                          nsACString &_name)
     504                 : {
     505               4 :   if (!mDBStatement)
     506               0 :     return NS_ERROR_NOT_INITIALIZED;
     507               4 :   ENSURE_INDEX_VALUE(aColumnIndex, mResultColumnCount);
     508                 : 
     509               4 :   const char *cname = ::sqlite3_column_name(mDBStatement, aColumnIndex);
     510               4 :   _name.Assign(nsDependentCString(cname));
     511                 : 
     512               4 :   return NS_OK;
     513                 : }
     514                 : 
     515                 : NS_IMETHODIMP
     516           85158 : Statement::GetColumnIndex(const nsACString &aName,
     517                 :                           PRUint32 *_index)
     518                 : {
     519           85158 :   if (!mDBStatement)
     520               0 :       return NS_ERROR_NOT_INITIALIZED;
     521                 : 
     522                 :   // Surprisingly enough, SQLite doesn't provide an API for this.  We have to
     523                 :   // determine it ourselves sadly.
     524         1038019 :   for (PRUint32 i = 0; i < mResultColumnCount; i++) {
     525         1038014 :     if (mColumnNames[i].Equals(aName)) {
     526           85153 :       *_index = i;
     527           85153 :       return NS_OK;
     528                 :     }
     529                 :   }
     530                 : 
     531               5 :   return NS_ERROR_INVALID_ARG;
     532                 : }
     533                 : 
     534                 : NS_IMETHODIMP
     535          124402 : Statement::Reset()
     536                 : {
     537          124402 :   if (!mDBStatement)
     538               0 :     return NS_ERROR_NOT_INITIALIZED;
     539                 : 
     540                 : #ifdef DEBUG
     541          124402 :   PR_LOG(gStorageLog, PR_LOG_DEBUG, ("Resetting statement: '%s'",
     542                 :                                      ::sqlite3_sql(mDBStatement)));
     543                 : 
     544          124402 :   checkAndLogStatementPerformance(mDBStatement);
     545                 : #endif
     546                 : 
     547          124402 :   mParamsArray = nsnull;
     548          124402 :   (void)sqlite3_reset(mDBStatement);
     549          124402 :   (void)sqlite3_clear_bindings(mDBStatement);
     550                 : 
     551          124402 :   mExecuting = false;
     552                 : 
     553          124402 :   return NS_OK;
     554                 : }
     555                 : 
     556                 : NS_IMETHODIMP
     557              12 : Statement::BindParameters(mozIStorageBindingParamsArray *aParameters)
     558                 : {
     559              12 :   if (!mDBStatement)
     560               0 :     return NS_ERROR_NOT_INITIALIZED;
     561                 : 
     562              12 :   BindingParamsArray *array = static_cast<BindingParamsArray *>(aParameters);
     563              12 :   if (array->getOwner() != this)
     564               1 :     return NS_ERROR_UNEXPECTED;
     565                 : 
     566              11 :   if (array->length() == 0)
     567               1 :     return NS_ERROR_UNEXPECTED;
     568                 : 
     569              10 :   mParamsArray = array;
     570              10 :   mParamsArray->lock();
     571                 : 
     572              10 :   return NS_OK;
     573                 : }
     574                 : 
     575                 : NS_IMETHODIMP
     576           49508 : Statement::Execute()
     577                 : {
     578           49508 :   if (!mDBStatement)
     579               0 :     return NS_ERROR_NOT_INITIALIZED;
     580                 : 
     581                 :   bool ret;
     582           49508 :   nsresult rv = ExecuteStep(&ret);
     583           49508 :   nsresult rv2 = Reset();
     584                 : 
     585           49508 :   return NS_FAILED(rv) ? rv : rv2;
     586                 : }
     587                 : 
     588                 : NS_IMETHODIMP
     589          137514 : Statement::ExecuteStep(bool *_moreResults)
     590                 : {
     591          275028 :   SAMPLE_LABEL("storage", "Statement::ExecuteStep");
     592          137514 :   if (!mDBStatement)
     593               0 :     return NS_ERROR_NOT_INITIALIZED;
     594                 : 
     595                 :   NS_TIME_FUNCTION_MIN_FMT(5, "mozIStorageStatement::ExecuteStep(%s) (0x%p)",
     596                 :                            mDBConnection->getFilename().get(), mDBStatement);
     597                 : 
     598                 :   // Bind any parameters first before executing.
     599          137514 :   if (mParamsArray) {
     600                 :     // If we have more than one row of parameters to bind, they shouldn't be
     601                 :     // calling this method (and instead use executeAsync).
     602           72623 :     if (mParamsArray->length() != 1)
     603               0 :       return NS_ERROR_UNEXPECTED;
     604                 : 
     605           72623 :     BindingParamsArray::iterator row = mParamsArray->begin();
     606                 :     nsCOMPtr<IStorageBindingParamsInternal> bindingInternal = 
     607          145246 :       do_QueryInterface(*row);
     608          145246 :     nsCOMPtr<mozIStorageError> error = bindingInternal->bind(mDBStatement);
     609           72623 :     if (error) {
     610                 :       PRInt32 srv;
     611               0 :       (void)error->GetResult(&srv);
     612               0 :       return convertResultCode(srv);
     613                 :     }
     614                 : 
     615                 :     // We have bound, so now we can clear our array.
     616          145246 :     mParamsArray = nsnull;
     617                 :   }
     618          137514 :   int srv = mDBConnection->stepStatement(mDBStatement);
     619                 : 
     620                 : #ifdef PR_LOGGING
     621          137514 :   if (srv != SQLITE_ROW && srv != SQLITE_DONE) {
     622             100 :       nsCAutoString errStr;
     623              50 :       (void)mDBConnection->GetLastErrorString(errStr);
     624              50 :       PR_LOG(gStorageLog, PR_LOG_DEBUG,
     625                 :              ("Statement::ExecuteStep error: %s", errStr.get()));
     626                 :   }
     627                 : #endif
     628                 : 
     629                 :   // SQLITE_ROW and SQLITE_DONE are non-errors
     630          137514 :   if (srv == SQLITE_ROW) {
     631                 :     // we got a row back
     632           66236 :     mExecuting = true;
     633           66236 :     *_moreResults = true;
     634           66236 :     return NS_OK;
     635                 :   }
     636           71278 :   else if (srv == SQLITE_DONE) {
     637                 :     // statement is done (no row returned)
     638           71228 :     mExecuting = false;
     639           71228 :     *_moreResults = false;
     640           71228 :     return NS_OK;
     641                 :   }
     642              50 :   else if (srv == SQLITE_BUSY || srv == SQLITE_MISUSE) {
     643               0 :     mExecuting = false;
     644                 :   }
     645              50 :   else if (mExecuting) {
     646                 : #ifdef PR_LOGGING
     647               2 :     PR_LOG(gStorageLog, PR_LOG_ERROR,
     648                 :            ("SQLite error after mExecuting was true!"));
     649                 : #endif
     650               2 :     mExecuting = false;
     651                 :   }
     652                 : 
     653              50 :   return convertResultCode(srv);
     654                 : }
     655                 : 
     656                 : NS_IMETHODIMP
     657           94689 : Statement::GetState(PRInt32 *_state)
     658                 : {
     659           94689 :   if (!mDBStatement)
     660               3 :     *_state = MOZ_STORAGE_STATEMENT_INVALID;
     661           94686 :   else if (mExecuting)
     662           21543 :     *_state = MOZ_STORAGE_STATEMENT_EXECUTING;
     663                 :   else
     664           73143 :     *_state = MOZ_STORAGE_STATEMENT_READY;
     665                 : 
     666           94689 :   return NS_OK;
     667                 : }
     668                 : 
     669                 : NS_IMETHODIMP
     670               3 : Statement::GetColumnDecltype(PRUint32 aParamIndex,
     671                 :                              nsACString &_declType)
     672                 : {
     673               3 :   if (!mDBStatement)
     674               0 :     return NS_ERROR_NOT_INITIALIZED;
     675                 : 
     676               3 :   ENSURE_INDEX_VALUE(aParamIndex, mResultColumnCount);
     677                 : 
     678               2 :   _declType.Assign(::sqlite3_column_decltype(mDBStatement, aParamIndex));
     679               2 :   return NS_OK;
     680                 : }
     681                 : 
     682                 : ////////////////////////////////////////////////////////////////////////////////
     683                 : //// mozIStorageValueArray (now part of mozIStorageStatement too)
     684                 : 
     685                 : NS_IMETHODIMP
     686              12 : Statement::GetNumEntries(PRUint32 *_length)
     687                 : {
     688              12 :   *_length = mResultColumnCount;
     689              12 :   return NS_OK;
     690                 : }
     691                 : 
     692                 : NS_IMETHODIMP
     693          169629 : Statement::GetTypeOfIndex(PRUint32 aIndex,
     694                 :                           PRInt32 *_type)
     695                 : {
     696          169629 :   if (!mDBStatement)
     697               0 :     return NS_ERROR_NOT_INITIALIZED;
     698                 : 
     699          169629 :   ENSURE_INDEX_VALUE(aIndex, mResultColumnCount);
     700                 : 
     701          169629 :   if (!mExecuting)
     702               0 :     return NS_ERROR_UNEXPECTED;
     703                 : 
     704          169629 :   int t = ::sqlite3_column_type(mDBStatement, aIndex);
     705          169629 :   switch (t) {
     706                 :     case SQLITE_INTEGER:
     707           30945 :       *_type = mozIStorageStatement::VALUE_TYPE_INTEGER;
     708           30945 :       break;
     709                 :     case SQLITE_FLOAT:
     710             407 :       *_type = mozIStorageStatement::VALUE_TYPE_FLOAT;
     711             407 :       break;
     712                 :     case SQLITE_TEXT:
     713          117364 :       *_type = mozIStorageStatement::VALUE_TYPE_TEXT;
     714          117364 :       break;
     715                 :     case SQLITE_BLOB:
     716            2005 :       *_type = mozIStorageStatement::VALUE_TYPE_BLOB;
     717            2005 :       break;
     718                 :     case SQLITE_NULL:
     719           18908 :       *_type = mozIStorageStatement::VALUE_TYPE_NULL;
     720           18908 :       break;
     721                 :     default:
     722               0 :       return NS_ERROR_FAILURE;
     723                 :   }
     724                 : 
     725          169629 :   return NS_OK;
     726                 : }
     727                 : 
     728                 : NS_IMETHODIMP
     729           86446 : Statement::GetInt32(PRUint32 aIndex,
     730                 :                     PRInt32 *_value)
     731                 : {
     732           86446 :   if (!mDBStatement)
     733               0 :     return NS_ERROR_NOT_INITIALIZED;
     734                 : 
     735           86446 :   ENSURE_INDEX_VALUE(aIndex, mResultColumnCount);
     736                 : 
     737           86446 :   if (!mExecuting)
     738               0 :     return NS_ERROR_UNEXPECTED;
     739                 : 
     740           86446 :   *_value = ::sqlite3_column_int(mDBStatement, aIndex);
     741           86446 :   return NS_OK;
     742                 : }
     743                 : 
     744                 : NS_IMETHODIMP
     745           83490 : Statement::GetInt64(PRUint32 aIndex,
     746                 :                     PRInt64 *_value)
     747                 : {
     748           83490 :   if (!mDBStatement)
     749               0 :     return NS_ERROR_NOT_INITIALIZED;
     750                 : 
     751           83490 :   ENSURE_INDEX_VALUE(aIndex, mResultColumnCount);
     752                 : 
     753           83490 :   if (!mExecuting)
     754               0 :     return NS_ERROR_UNEXPECTED;
     755                 : 
     756           83490 :   *_value = ::sqlite3_column_int64(mDBStatement, aIndex);
     757                 : 
     758           83490 :   return NS_OK;
     759                 : }
     760                 : 
     761                 : NS_IMETHODIMP
     762           29776 : Statement::GetDouble(PRUint32 aIndex,
     763                 :                      double *_value)
     764                 : {
     765           29776 :   if (!mDBStatement)
     766               0 :     return NS_ERROR_NOT_INITIALIZED;
     767                 : 
     768           29776 :   ENSURE_INDEX_VALUE(aIndex, mResultColumnCount);
     769                 : 
     770           29776 :   if (!mExecuting)
     771               0 :     return NS_ERROR_UNEXPECTED;
     772                 : 
     773           29776 :   *_value = ::sqlite3_column_double(mDBStatement, aIndex);
     774                 : 
     775           29776 :   return NS_OK;
     776                 : }
     777                 : 
     778                 : NS_IMETHODIMP
     779           93697 : Statement::GetUTF8String(PRUint32 aIndex,
     780                 :                          nsACString &_value)
     781                 : {
     782                 :   // Get type of Index will check aIndex for us, so we don't have to.
     783                 :   PRInt32 type;
     784           93697 :   nsresult rv = GetTypeOfIndex(aIndex, &type);
     785           93697 :   NS_ENSURE_SUCCESS(rv, rv);
     786           93697 :   if (type == mozIStorageStatement::VALUE_TYPE_NULL) {
     787                 :     // NULL columns should have IsVoid set to distinguish them from the empty
     788                 :     // string.
     789            4162 :     _value.Truncate(0);
     790            4162 :     _value.SetIsVoid(true);
     791                 :   }
     792                 :   else {
     793                 :     const char *value =
     794                 :       reinterpret_cast<const char *>(::sqlite3_column_text(mDBStatement,
     795           89535 :                                                            aIndex));
     796           89535 :     _value.Assign(value, ::sqlite3_column_bytes(mDBStatement, aIndex));
     797                 :   }
     798           93697 :   return NS_OK;
     799                 : }
     800                 : 
     801                 : NS_IMETHODIMP
     802            4292 : Statement::GetString(PRUint32 aIndex,
     803                 :                      nsAString &_value)
     804                 : {
     805                 :   // Get type of Index will check aIndex for us, so we don't have to.
     806                 :   PRInt32 type;
     807            4292 :   nsresult rv = GetTypeOfIndex(aIndex, &type);
     808            4292 :   NS_ENSURE_SUCCESS(rv, rv);
     809            4292 :   if (type == mozIStorageStatement::VALUE_TYPE_NULL) {
     810                 :     // NULL columns should have IsVoid set to distinguish them from the empty
     811                 :     // string.
     812            2542 :     _value.Truncate(0);
     813            2542 :     _value.SetIsVoid(true);
     814                 :   } else {
     815                 :     const PRUnichar *value =
     816                 :       static_cast<const PRUnichar *>(::sqlite3_column_text16(mDBStatement,
     817            1750 :                                                              aIndex));
     818            1750 :     _value.Assign(value, ::sqlite3_column_bytes16(mDBStatement, aIndex) / 2);
     819                 :   }
     820            4292 :   return NS_OK;
     821                 : }
     822                 : 
     823                 : NS_IMETHODIMP
     824            2570 : Statement::GetBlob(PRUint32 aIndex,
     825                 :                    PRUint32 *_size,
     826                 :                    PRUint8 **_blob)
     827                 : {
     828            2570 :   if (!mDBStatement)
     829               0 :     return NS_ERROR_NOT_INITIALIZED;
     830                 : 
     831            2570 :   ENSURE_INDEX_VALUE(aIndex, mResultColumnCount);
     832                 : 
     833            2570 :   if (!mExecuting)
     834               0 :      return NS_ERROR_UNEXPECTED;
     835                 : 
     836            2570 :   int size = ::sqlite3_column_bytes(mDBStatement, aIndex);
     837            2570 :   void *blob = nsnull;
     838            2570 :   if (size) {
     839            2569 :     blob = nsMemory::Clone(::sqlite3_column_blob(mDBStatement, aIndex), size);
     840            2569 :     NS_ENSURE_TRUE(blob, NS_ERROR_OUT_OF_MEMORY);
     841                 :   }
     842                 : 
     843            2570 :   *_blob = static_cast<PRUint8 *>(blob);
     844            2570 :   *_size = size;
     845            2570 :   return NS_OK;
     846                 : }
     847                 : 
     848                 : NS_IMETHODIMP
     849               2 : Statement::GetSharedUTF8String(PRUint32 aIndex,
     850                 :                                PRUint32 *_length,
     851                 :                                const char **_value)
     852                 : {
     853               2 :   if (_length)
     854               2 :     *_length = ::sqlite3_column_bytes(mDBStatement, aIndex);
     855                 : 
     856                 :   *_value = reinterpret_cast<const char *>(::sqlite3_column_text(mDBStatement,
     857               2 :                                                                  aIndex));
     858               2 :   return NS_OK;
     859                 : }
     860                 : 
     861                 : NS_IMETHODIMP
     862           24639 : Statement::GetSharedString(PRUint32 aIndex,
     863                 :                            PRUint32 *_length,
     864                 :                            const PRUnichar **_value)
     865                 : {
     866           24639 :   if (_length)
     867           24639 :     *_length = ::sqlite3_column_bytes16(mDBStatement, aIndex);
     868                 : 
     869                 :   *_value = static_cast<const PRUnichar *>(::sqlite3_column_text16(mDBStatement,
     870           24639 :                                                                    aIndex));
     871           24639 :   return NS_OK;
     872                 : }
     873                 : 
     874                 : NS_IMETHODIMP
     875            3093 : Statement::GetSharedBlob(PRUint32 aIndex,
     876                 :                          PRUint32 *_size,
     877                 :                          const PRUint8 **_blob)
     878                 : {
     879            3093 :   *_size = ::sqlite3_column_bytes(mDBStatement, aIndex);
     880                 :   *_blob = static_cast<const PRUint8 *>(::sqlite3_column_blob(mDBStatement,
     881            3093 :                                                               aIndex));
     882            3093 :   return NS_OK;
     883                 : }
     884                 : 
     885                 : NS_IMETHODIMP
     886            5286 : Statement::GetIsNull(PRUint32 aIndex,
     887                 :                      bool *_isNull)
     888                 : {
     889                 :   // Get type of Index will check aIndex for us, so we don't have to.
     890                 :   PRInt32 type;
     891            5286 :   nsresult rv = GetTypeOfIndex(aIndex, &type);
     892            5286 :   NS_ENSURE_SUCCESS(rv, rv);
     893            5286 :   *_isNull = (type == mozIStorageStatement::VALUE_TYPE_NULL);
     894            5286 :   return NS_OK;
     895                 : }
     896                 : 
     897                 : ////////////////////////////////////////////////////////////////////////////////
     898                 : //// mozIStorageBindingParams
     899                 : 
     900          237392 : BOILERPLATE_BIND_PROXIES(
     901                 :   Statement, 
     902                 :   if (!mDBStatement) return NS_ERROR_NOT_INITIALIZED;
     903                 : )
     904                 : 
     905                 : } // namespace storage
     906            4392 : } // namespace mozilla

Generated by: LCOV version 1.7