Back to index

lightning-sunbird  0.9+nobinonly
mozStorageStatement.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
00002 /* ***** BEGIN LICENSE BLOCK *****
00003  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00004  *
00005  * The contents of this file are subject to the Mozilla Public License Version
00006  * 1.1 (the "License"); you may not use this file except in compliance with
00007  * the License. You may obtain a copy of the License at
00008  * http://www.mozilla.org/MPL/
00009  *
00010  * Software distributed under the License is distributed on an "AS IS" basis,
00011  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00012  * for the specific language governing rights and limitations under the
00013  * License.
00014  *
00015  * The Original Code is Oracle Corporation code.
00016  *
00017  * The Initial Developer of the Original Code is
00018  *  Oracle Corporation
00019  * Portions created by the Initial Developer are Copyright (C) 2004
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *   Vladimir Vukicevic <vladimir.vukicevic@oracle.com>
00024  *
00025  * Alternatively, the contents of this file may be used under the terms of
00026  * either the GNU General Public License Version 2 or later (the "GPL"), or
00027  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00028  * in which case the provisions of the GPL or the LGPL are applicable instead
00029  * of those above. If you wish to allow use of your version of this file only
00030  * under the terms of either the GPL or the LGPL, and not to allow others to
00031  * use your version of this file under the terms of the MPL, indicate your
00032  * decision by deleting the provisions above and replace them with the notice
00033  * and other provisions required by the GPL or the LGPL. If you do not delete
00034  * the provisions above, a recipient may use your version of this file under
00035  * the terms of any one of the MPL, the GPL or the LGPL.
00036  *
00037  * ***** END LICENSE BLOCK ***** */
00038 
00039 #include <stdio.h>
00040 
00041 #include "nsError.h"
00042 #include "nsISimpleEnumerator.h"
00043 #include "nsMemory.h"
00044 
00045 #include "mozStorageConnection.h"
00046 #include "mozStorageStatement.h"
00047 #include "mozStorageValueArray.h"
00048 
00049 #include "prlog.h"
00050 
00051 #ifdef PR_LOGGING
00052 extern PRLogModuleInfo* gStorageLog;
00053 #endif
00054 
00058 class mozStorageStatementRowEnumerator : public nsISimpleEnumerator {
00059 public:
00060     // this expects a statement that has NOT had step called on it yet
00061     mozStorageStatementRowEnumerator (sqlite3_stmt *aDBStatement);
00062 
00063     // nsISupports interface
00064     NS_DECL_ISUPPORTS
00065 
00066     // nsISimpleEnumerator interface
00067     NS_DECL_NSISIMPLEENUMERATOR
00068 
00069 private:
00070     ~mozStorageStatementRowEnumerator ();
00071 protected:
00072     sqlite3_stmt *mDBStatement;
00073     PRBool mHasMore;
00074     PRBool mDidStep;
00075 
00076     void DoRealStep();
00077 };
00078 
00079 
00084 NS_IMPL_ISUPPORTS2(mozStorageStatement, mozIStorageStatement, mozIStorageValueArray)
00085 
00086 mozStorageStatement::mozStorageStatement()
00087     : mDBConnection (nsnull), mDBStatement(nsnull), mColumnNames(nsnull), mExecuting(PR_FALSE)
00088 {
00089 }
00090 
00091 NS_IMETHODIMP
00092 mozStorageStatement::Initialize(mozIStorageConnection *aDBConnection, const nsACString & aSQLStatement)
00093 {
00094     int srv;
00095 
00096     // we can't do this if we're mid-execute
00097     if (mExecuting) {
00098         return NS_ERROR_FAILURE;
00099     }
00100 
00101     sqlite3 *db = nsnull;
00102     // XXX - need to implement a private iid to QI for here, to make sure
00103     // we have a real mozStorageConnection
00104     mozStorageConnection *msc = NS_STATIC_CAST(mozStorageConnection*, aDBConnection);
00105     db = msc->GetNativeConnection();
00106     NS_ENSURE_TRUE(db != nsnull, NS_ERROR_NULL_POINTER);
00107 
00108     // clean up old goop
00109     if (mDBStatement) {
00110         sqlite3_finalize(mDBStatement);
00111         mDBStatement = nsnull;
00112     }
00113 
00114     int nRetries = 0;
00115 
00116     while (nRetries < 2) {
00117         srv = sqlite3_prepare (db, nsPromiseFlatCString(aSQLStatement).get(), aSQLStatement.Length(), &mDBStatement, NULL);
00118         if ((srv == SQLITE_SCHEMA && nRetries != 0) ||
00119             (srv != SQLITE_SCHEMA && srv != SQLITE_OK))
00120         {
00121 #ifdef PR_LOGGING
00122             PR_LOG(gStorageLog, PR_LOG_ERROR, ("Sqlite statement prepare error: %d '%s'", srv, sqlite3_errmsg(db)));
00123             PR_LOG(gStorageLog, PR_LOG_ERROR, ("Statement was: '%s'", nsPromiseFlatCString(aSQLStatement).get()));
00124 #endif
00125             return NS_ERROR_FAILURE;
00126         }
00127 
00128         if (srv == SQLITE_OK)
00129             break;
00130 
00131         nRetries++;
00132     }
00133 
00134     mDBConnection = aDBConnection;
00135     mStatementString.Assign (aSQLStatement);
00136     mParamCount = sqlite3_bind_parameter_count (mDBStatement);
00137     mResultColumnCount = sqlite3_column_count (mDBStatement);
00138     mColumnNames.Clear();
00139 
00140     for (unsigned int i = 0; i < mResultColumnCount; i++) {
00141         const void *name = sqlite3_column_name16 (mDBStatement, i);
00142         if (name != nsnull)
00143             mColumnNames.AppendString(nsDependentString(NS_STATIC_CAST(const PRUnichar*, name)));
00144         else
00145             mColumnNames.AppendString(EmptyString());
00146     }
00147 
00148     // doing a sqlite3_prepare sets up the execution engine
00149     // for that statement; doing a create_function after that
00150     // results in badness, because there's a selected statement.
00151     // use this hack to clear it out -- this may be a bug.
00152     sqlite3_exec (db, "", 0, 0, 0);
00153 
00154     return NS_OK;
00155 }
00156 
00157 mozStorageStatement::~mozStorageStatement()
00158 {
00159     if (mDBStatement)
00160         sqlite3_finalize (mDBStatement);
00161 }
00162 
00163 /* mozIStorageStatement clone (); */
00164 NS_IMETHODIMP
00165 mozStorageStatement::Clone(mozIStorageStatement **_retval)
00166 {
00167     mozStorageStatement *mss = new mozStorageStatement();
00168     NS_ADDREF(mss);
00169 
00170     nsresult rv = mss->Initialize (mDBConnection, mStatementString);
00171     if (NS_FAILED(rv)) {
00172         NS_RELEASE(mss);
00173         return NS_ERROR_FAILURE; // XXX error code
00174     }
00175 
00176     *_retval = mss;
00177     return NS_OK;
00178 }
00179 
00180 /* readonly attribute unsigned long parameterCount; */
00181 NS_IMETHODIMP
00182 mozStorageStatement::GetParameterCount(PRUint32 *aParameterCount)
00183 {
00184     NS_ASSERTION (mDBConnection && mDBStatement, "statement not initialized");
00185     NS_ENSURE_ARG_POINTER(aParameterCount);
00186 
00187     *aParameterCount = mParamCount;
00188     return NS_OK;
00189 }
00190 
00191 /* AUTF8String getParameterName(in unsigned long aParamIndex); */
00192 NS_IMETHODIMP
00193 mozStorageStatement::GetParameterName(PRUint32 aParamIndex, nsACString & _retval)
00194 {
00195     NS_ASSERTION (mDBConnection && mDBStatement, "statement not initialized");
00196     if (aParamIndex < 0 || aParamIndex >= mParamCount)
00197         return NS_ERROR_FAILURE; // XXXerror
00198 
00199     const char *pname = sqlite3_bind_parameter_name(mDBStatement, aParamIndex + 1);
00200     if (pname == NULL) {
00201         // this thing had no name, so fake one
00202         nsCAutoString pname(":");
00203         pname.AppendInt(aParamIndex);
00204         _retval.Assign(pname);
00205     } else {
00206         _retval.Assign(nsDependentCString(pname));
00207     }
00208 
00209     return NS_OK;
00210 }
00211 
00212 /* void getParameterIndexes(in AUTF8String aParameterName, out unsigned long aCount, [array,size_is(aCount),retval] out unsigned long aIndexes); */
00213 NS_IMETHODIMP
00214 mozStorageStatement::GetParameterIndexes(const nsACString &aParameterName, PRUint32 *aCount, PRUint32 **aIndexes)
00215 {
00216     NS_ASSERTION (mDBConnection && mDBStatement, "statement not initialized");
00217     NS_ENSURE_ARG_POINTER(aCount);
00218     NS_ENSURE_ARG_POINTER(aIndexes);
00219 
00220     int *indexes, count;
00221     count = sqlite3_bind_parameter_indexes(mDBStatement, nsPromiseFlatCString(aParameterName).get(), &indexes);
00222     if (count) {
00223         *aIndexes = (PRUint32*) nsMemory::Alloc(sizeof(PRUint32) * count);
00224         for (int i = 0; i < count; i++)
00225             (*aIndexes)[i] = indexes[i];
00226         sqlite3_free_parameter_indexes(indexes);
00227         *aCount = count;
00228     } else {
00229         *aCount = 0;
00230         *aIndexes = nsnull;
00231     }
00232     return NS_OK;
00233 }
00234 
00235 /* readonly attribute unsigned long columnCount; */
00236 NS_IMETHODIMP
00237 mozStorageStatement::GetColumnCount(PRUint32 *aColumnCount)
00238 {
00239     NS_ASSERTION (mDBConnection && mDBStatement, "statement not initialized");
00240     NS_ENSURE_ARG_POINTER(aColumnCount);
00241 
00242     *aColumnCount = mResultColumnCount;
00243     return NS_OK;
00244 }
00245 
00246 /* AUTF8String getColumnName(in unsigned long aColumnIndex); */
00247 NS_IMETHODIMP
00248 mozStorageStatement::GetColumnName(PRUint32 aColumnIndex, nsACString & _retval)
00249 {
00250     NS_ASSERTION (mDBConnection && mDBStatement, "statement not initialized");
00251     if (aColumnIndex < 0 || aColumnIndex >= mResultColumnCount)
00252         return NS_ERROR_FAILURE; // XXXerror
00253 
00254     const char *cname = sqlite3_column_name(mDBStatement, aColumnIndex);
00255     _retval.Assign(nsDependentCString(cname));
00256 
00257     return NS_OK;
00258 }
00259 
00260 /* void reset (); */
00261 NS_IMETHODIMP
00262 mozStorageStatement::Reset()
00263 {
00264     NS_ASSERTION (mDBConnection && mDBStatement, "statement not initialized");
00265 
00266     PR_LOG(gStorageLog, PR_LOG_DEBUG, ("Resetting statement: '%s'", nsPromiseFlatCString(mStatementString).get()));
00267 
00268     sqlite3_reset(mDBStatement);
00269     sqlite3_clear_bindings(mDBStatement);
00270 
00271     mExecuting = PR_FALSE;
00272 
00273     return NS_OK;
00274 }
00275 
00276 /* void bindUTF8StringParameter (in unsigned long aParamIndex, in AUTF8String aValue); */
00277 NS_IMETHODIMP
00278 mozStorageStatement::BindUTF8StringParameter(PRUint32 aParamIndex, const nsACString & aValue)
00279 {
00280     NS_ASSERTION (mDBConnection && mDBStatement, "statement not initialized");
00281     if (aParamIndex < 0 || aParamIndex >= mParamCount)
00282         return NS_ERROR_FAILURE; // XXXerror
00283 
00284     sqlite3_bind_text (mDBStatement, aParamIndex + 1,
00285                        nsPromiseFlatCString(aValue).get(), aValue.Length(),
00286                        SQLITE_TRANSIENT);
00287     // XXX check return value for errors?
00288 
00289     return NS_OK;
00290 }
00291 
00292 /* void bindStringParameter (in unsigned long aParamIndex, in AString aValue); */
00293 NS_IMETHODIMP
00294 mozStorageStatement::BindStringParameter(PRUint32 aParamIndex, const nsAString & aValue)
00295 {
00296     NS_ASSERTION (mDBConnection && mDBStatement, "statement not initialized");
00297     if (aParamIndex < 0 || aParamIndex >= mParamCount)
00298         return NS_ERROR_FAILURE; // XXXerror
00299 
00300     sqlite3_bind_text16 (mDBStatement, aParamIndex + 1,
00301                          nsPromiseFlatString(aValue).get(), aValue.Length() * 2,
00302                          SQLITE_TRANSIENT);
00303     // XXX check return value for errors?
00304 
00305     return NS_OK;
00306 }
00307 
00308 /* void bindDoubleParameter (in unsigned long aParamIndex, in double aValue); */
00309 NS_IMETHODIMP
00310 mozStorageStatement::BindDoubleParameter(PRUint32 aParamIndex, double aValue)
00311 {
00312     NS_ASSERTION (mDBConnection && mDBStatement, "statement not initialized");
00313     if (aParamIndex < 0 || aParamIndex >= mParamCount)
00314         return NS_ERROR_FAILURE; // XXXerror
00315 
00316     sqlite3_bind_double (mDBStatement, aParamIndex + 1, aValue);
00317     // XXX check return value for errors?
00318 
00319     return NS_OK;
00320 }
00321 
00322 /* void bindInt32Parameter (in unsigned long aParamIndex, in long aValue); */
00323 NS_IMETHODIMP
00324 mozStorageStatement::BindInt32Parameter(PRUint32 aParamIndex, PRInt32 aValue)
00325 {
00326     NS_ASSERTION (mDBConnection && mDBStatement, "statement not initialized");
00327     if (aParamIndex < 0 || aParamIndex >= mParamCount)
00328         return NS_ERROR_FAILURE; // XXXerror
00329 
00330     sqlite3_bind_int (mDBStatement, aParamIndex + 1, aValue);
00331     // XXX check return value for errors?
00332 
00333     return NS_OK;
00334 }
00335 
00336 /* void bindInt64Parameter (in unsigned long aParamIndex, in long long aValue); */
00337 NS_IMETHODIMP
00338 mozStorageStatement::BindInt64Parameter(PRUint32 aParamIndex, PRInt64 aValue)
00339 {
00340     NS_ASSERTION (mDBConnection && mDBStatement, "statement not initialized");
00341     if (aParamIndex < 0 || aParamIndex >= mParamCount)
00342         return NS_ERROR_FAILURE; // XXXerror
00343 
00344     sqlite3_bind_int64 (mDBStatement, aParamIndex + 1, aValue);
00345     // XXX check return value for errors?
00346 
00347     return NS_OK;
00348 }
00349 
00350 /* void bindNullParameter (in unsigned long aParamIndex); */
00351 NS_IMETHODIMP
00352 mozStorageStatement::BindNullParameter(PRUint32 aParamIndex)
00353 {
00354     NS_ASSERTION (mDBConnection && mDBStatement, "statement not initialized");
00355     if (aParamIndex < 0 || aParamIndex >= mParamCount)
00356         return NS_ERROR_FAILURE; // XXXerror
00357 
00358     sqlite3_bind_null (mDBStatement, aParamIndex + 1);
00359     // XXX check return value for errors?
00360 
00361     return NS_OK;
00362 }
00363 
00364 /* void bindBlobParameter (in unsigned long aParamIndex, [array, const, size_is (aValueSize)] in octet aValue, in unsigned long aValueSize); */
00365 NS_IMETHODIMP
00366 mozStorageStatement::BindBlobParameter(PRUint32 aParamIndex, const PRUint8 *aValue, PRUint32 aValueSize)
00367 {
00368     NS_ASSERTION (mDBConnection && mDBStatement, "statement not initialized");
00369     if (aParamIndex < 0 || aParamIndex >= mParamCount)
00370         return NS_ERROR_FAILURE; // XXXerror
00371 
00372     sqlite3_bind_blob (mDBStatement, aParamIndex + 1, aValue, aValueSize, SQLITE_TRANSIENT);
00373     // XXX check return value for errors?
00374 
00375     return NS_OK;
00376 }
00377 
00378 /* void execute (); */
00379 NS_IMETHODIMP
00380 mozStorageStatement::Execute()
00381 {
00382     NS_ASSERTION (mDBConnection && mDBStatement, "statement not initialized");
00383 
00384     PRBool ret = PR_FALSE;
00385     nsresult rv = ExecuteStep(&ret);
00386     if (NS_FAILED(rv))
00387         return rv;
00388     return Reset();
00389 }
00390 
00391 /* boolean executeStep (); */
00392 NS_IMETHODIMP
00393 mozStorageStatement::ExecuteStep(PRBool *_retval)
00394 {
00395     NS_ASSERTION (mDBConnection && mDBStatement, "statement not initialized");
00396     nsresult rv;
00397 
00398     if (mExecuting == PR_FALSE) {
00399         // check if we need to recreate this statement before executing
00400         if (sqlite3_expired(mDBStatement)) {
00401             PR_LOG(gStorageLog, PR_LOG_DEBUG, ("Statement expired, recreating before step"));
00402             rv = Recreate();
00403             NS_ENSURE_SUCCESS(rv, rv);
00404         }
00405     }
00406 
00407     int nRetries = 0;
00408 
00409     while (nRetries < 2) {
00410         int srv = sqlite3_step (mDBStatement);
00411 
00412 #ifdef PR_LOGGING
00413         if (srv != SQLITE_ROW && srv != SQLITE_DONE)
00414         {
00415             nsCAutoString errStr;
00416             mDBConnection->GetLastErrorString(errStr);
00417             PR_LOG(gStorageLog, PR_LOG_DEBUG, ("mozStorageStatement::ExecuteStep error: %s", errStr.get()));
00418         }
00419 #endif
00420 
00421         // SQLITE_ROW and SQLITE_DONE are non-errors
00422         if (srv == SQLITE_ROW) {
00423             // we got a row back
00424             mExecuting = PR_TRUE;
00425             *_retval = PR_TRUE;
00426             return NS_OK;
00427         } else if (srv == SQLITE_DONE) {
00428             // statement is done (no row returned)
00429             mExecuting = PR_FALSE;
00430             *_retval = PR_FALSE;
00431             return NS_OK;
00432         } else if (srv == SQLITE_BUSY ||
00433                    srv == SQLITE_MISUSE)
00434         {
00435             mExecuting = PR_FALSE;
00436             return NS_ERROR_FAILURE;
00437         } else if (srv == SQLITE_SCHEMA) {
00438             // step should never return SQLITE_SCHEMA
00439             NS_NOTREACHED("sqlite3_step returned SQLITE_SCHEMA!");
00440             return NS_ERROR_FAILURE;
00441         } else if (srv == SQLITE_ERROR) {
00442             // so we may end up with a SQLITE_ERROR/SQLITE_SCHEMA only after
00443             // we reset, because SQLite's error reporting story
00444             // sucks.
00445             if (mExecuting == PR_TRUE) {
00446                 PR_LOG(gStorageLog, PR_LOG_ERROR, ("SQLITE_ERROR after mExecuting was true!"));
00447 
00448                 mExecuting = PR_FALSE;
00449                 return NS_ERROR_FAILURE;
00450             }
00451 
00452             srv = sqlite3_reset(mDBStatement);
00453             if (srv == SQLITE_SCHEMA) {
00454                 rv = Recreate();
00455                 NS_ENSURE_SUCCESS(rv, rv);
00456 
00457                 nRetries++;
00458             } else {
00459                 return NS_ERROR_FAILURE;
00460             }
00461         } else {
00462             // something that shouldn't happen happened
00463             NS_ERROR ("sqlite3_step returned an error code we don't know about!");
00464         }
00465     }
00466 
00467     // shouldn't get here
00468     return NS_ERROR_FAILURE;
00469 }
00470 
00471 /* [noscript,notxpcom] sqlite3stmtptr getNativeStatementPointer(); */
00472 sqlite3_stmt*
00473 mozStorageStatement::GetNativeStatementPointer()
00474 {
00475     return mDBStatement;
00476 }
00477 
00478 /* readonly attribute long state; */
00479 NS_IMETHODIMP
00480 mozStorageStatement::GetState(PRInt32 *_retval)
00481 {
00482     if (!mDBConnection || !mDBStatement) {
00483         *_retval = MOZ_STORAGE_STATEMENT_INVALID;
00484     } else if (mExecuting) {
00485         *_retval = MOZ_STORAGE_STATEMENT_EXECUTING;
00486     } else {
00487         *_retval = MOZ_STORAGE_STATEMENT_READY;
00488     }
00489 
00490     return NS_OK;
00491 }
00492 
00493 nsresult
00494 mozStorageStatement::Recreate()
00495 {
00496     nsresult rv;
00497     int srv;
00498     sqlite3_stmt *savedStmt = mDBStatement;
00499     mDBStatement = nsnull;
00500     rv = Initialize(mDBConnection, mStatementString);
00501     NS_ENSURE_SUCCESS(rv, rv);
00502 
00503     // copy over the param bindings
00504     srv = sqlite3_transfer_bindings(savedStmt, mDBStatement);
00505 
00506     // we're always going to finalize this, so no need to
00507     // error check
00508     sqlite3_finalize(savedStmt);
00509 
00510     if (srv != SQLITE_OK) {
00511         PR_LOG(gStorageLog, PR_LOG_ERROR, ("sqlite3_transfer_bindings returned: %d", srv));
00512         return NS_ERROR_FAILURE;
00513     }
00514 
00515     return NS_OK;
00516 }
00517 
00518 /***
00519  *** mozIStorageValueArray
00520  ***/
00521 
00522 /* readonly attribute unsigned long numEntries; */
00523 NS_IMETHODIMP
00524 mozStorageStatement::GetNumEntries(PRUint32 *aLength)
00525 {
00526     *aLength = mResultColumnCount;
00527     return NS_OK;
00528 }
00529 
00530 /* long getTypeOfIndex (in unsigned long aIndex); */
00531 NS_IMETHODIMP
00532 mozStorageStatement::GetTypeOfIndex(PRUint32 aIndex, PRInt32 *_retval)
00533 {
00534     NS_ASSERTION (aIndex < mResultColumnCount, "aIndex out of range");
00535 
00536     int t = sqlite3_column_type (mDBStatement, aIndex);
00537     switch (t) {
00538         case SQLITE_INTEGER:
00539             *_retval = VALUE_TYPE_INTEGER;
00540             break;
00541         case SQLITE_FLOAT:
00542             *_retval = VALUE_TYPE_FLOAT;
00543             break;
00544         case SQLITE_TEXT:
00545             *_retval = VALUE_TYPE_TEXT;
00546             break;
00547         case SQLITE_BLOB:
00548             *_retval = VALUE_TYPE_BLOB;
00549             break;
00550         case SQLITE_NULL:
00551             *_retval = VALUE_TYPE_NULL;
00552             break;
00553         default:
00554             // ???
00555             return NS_ERROR_FAILURE;
00556     }
00557 
00558     return NS_OK;
00559 }
00560 
00561 /* long getInt32 (in unsigned long aIndex); */
00562 NS_IMETHODIMP
00563 mozStorageStatement::GetInt32(PRUint32 aIndex, PRInt32 *_retval)
00564 {
00565     NS_ASSERTION (aIndex < mResultColumnCount, "aIndex out of range");
00566     if (!mExecuting)
00567         return NS_ERROR_FAILURE;
00568 
00569     *_retval = sqlite3_column_int (mDBStatement, aIndex);
00570 
00571     return NS_OK;
00572 }
00573 
00574 /* long long getInt64 (in unsigned long aIndex); */
00575 NS_IMETHODIMP
00576 mozStorageStatement::GetInt64(PRUint32 aIndex, PRInt64 *_retval)
00577 {
00578     NS_ASSERTION (aIndex < mResultColumnCount, "aIndex out of range");
00579     if (!mExecuting)
00580         return NS_ERROR_FAILURE;
00581 
00582     *_retval = sqlite3_column_int64 (mDBStatement, aIndex);
00583 
00584     return NS_OK;
00585 }
00586 
00587 /* double getDouble (in unsigned long aIndex); */
00588 NS_IMETHODIMP
00589 mozStorageStatement::GetDouble(PRUint32 aIndex, double *_retval)
00590 {
00591     NS_ASSERTION (aIndex < mResultColumnCount, "aIndex out of range");
00592     if (!mExecuting)
00593         return NS_ERROR_FAILURE;
00594 
00595     *_retval = sqlite3_column_double (mDBStatement, aIndex);
00596 
00597     return NS_OK;
00598 }
00599 
00600 /* AUTF8String getUTF8String (in unsigned long aIndex); */
00601 NS_IMETHODIMP
00602 mozStorageStatement::GetUTF8String(PRUint32 aIndex, nsACString & _retval)
00603 {
00604     NS_ASSERTION (aIndex < mResultColumnCount, "aIndex out of range");
00605     if (!mExecuting)
00606         return NS_ERROR_FAILURE;
00607 
00608     PRInt32 t;
00609     nsresult rv = GetTypeOfIndex (aIndex, &t);
00610     NS_ENSURE_SUCCESS(rv, rv);
00611     if (t == VALUE_TYPE_NULL) {
00612         // null columns get IsVoid set to distinguish them from empty strings
00613         _retval.Truncate(0);
00614         _retval.SetIsVoid(PR_TRUE);
00615     } else {
00616         int slen = sqlite3_column_bytes (mDBStatement, aIndex);
00617         const unsigned char *cstr = sqlite3_column_text (mDBStatement, aIndex);
00618         _retval.Assign ((char *) cstr, slen);
00619     }
00620     return NS_OK;
00621 }
00622 
00623 /* AString getString (in unsigned long aIndex); */
00624 NS_IMETHODIMP
00625 mozStorageStatement::GetString(PRUint32 aIndex, nsAString & _retval)
00626 {
00627     NS_ASSERTION (aIndex < mResultColumnCount, "aIndex out of range");
00628     if (!mExecuting)
00629         return NS_ERROR_FAILURE;
00630 
00631     PRInt32 t;
00632     nsresult rv = GetTypeOfIndex (aIndex, &t);
00633     NS_ENSURE_SUCCESS(rv, rv);
00634     if (t == VALUE_TYPE_NULL) {
00635         // null columns get IsVoid set to distinguish them from empty strings
00636         _retval.Truncate(0);
00637         _retval.SetIsVoid(PR_TRUE);
00638     } else {
00639         int slen = sqlite3_column_bytes16 (mDBStatement, aIndex);
00640         const void *text = sqlite3_column_text16 (mDBStatement, aIndex);
00641         const PRUnichar *wstr = NS_STATIC_CAST(const PRUnichar *, text);
00642         _retval.Assign (wstr, slen/2);
00643     }
00644     return NS_OK;
00645 }
00646 
00647 /* void getBlob (in unsigned long aIndex, out unsigned long aDataSize, [array, size_is (aDataSize)] out octet aData); */
00648 NS_IMETHODIMP
00649 mozStorageStatement::GetBlob(PRUint32 aIndex, PRUint32 *aDataSize, PRUint8 **aData)
00650 {
00651     NS_ASSERTION (aIndex < mResultColumnCount, "aIndex out of range");
00652     if (!mExecuting)
00653         return NS_ERROR_FAILURE;
00654 
00655     int blobsize = sqlite3_column_bytes (mDBStatement, aIndex);
00656     if (blobsize == 0) {
00657       // empty column
00658       *aData = nsnull;
00659       *aDataSize = 0;
00660       return NS_OK;
00661     }
00662     const void *blob = sqlite3_column_blob (mDBStatement, aIndex);
00663 
00664     void *blobcopy = nsMemory::Clone(blob, blobsize);
00665     if (blobcopy == NULL)
00666         return NS_ERROR_OUT_OF_MEMORY;
00667 
00668     *aData = (PRUint8*) blobcopy;
00669     *aDataSize = blobsize;
00670 
00671     return NS_OK;
00672 }
00673 
00674 /* [noscript] void getSharedUTF8String(in unsigned long aIndex, out unsigned long aLength, [shared,retval] out string aResult); */
00675 NS_IMETHODIMP
00676 mozStorageStatement::GetSharedUTF8String(PRUint32 aIndex, PRUint32 *aLength, const char **_retval)
00677 {
00678     if (aLength) {
00679         int slen = sqlite3_column_bytes (mDBStatement, aIndex);
00680         *aLength = slen;
00681     }
00682 
00683     *_retval = (const char *) sqlite3_column_text (mDBStatement, aIndex);
00684     return NS_OK;
00685 }
00686 
00687 /* [noscript] void getSharedString(in unsigned long aIndex, out unsigned long aLength, [shared,retval] out wstring aResult); */
00688 NS_IMETHODIMP
00689 mozStorageStatement::GetSharedString(PRUint32 aIndex, PRUint32 *aLength, const PRUnichar **_retval)
00690 {
00691     if (aLength) {
00692         int slen = sqlite3_column_bytes16 (mDBStatement, aIndex);
00693         *aLength = slen;
00694     }
00695 
00696     *_retval = (const PRUnichar *) sqlite3_column_text16 (mDBStatement, aIndex);
00697     return NS_OK;
00698 }
00699 
00700 /* [noscript] void getSharedBlob(in unsigned long aIndex, out unsigned long aLength, [shared,retval] out octetPtr aResult); */
00701 NS_IMETHODIMP
00702 mozStorageStatement::GetSharedBlob(PRUint32 aIndex, PRUint32 *aDataSize, const PRUint8 **aData)
00703 {
00704     *aDataSize = sqlite3_column_bytes (mDBStatement, aIndex);
00705     *aData = (const PRUint8*) sqlite3_column_blob (mDBStatement, aIndex);
00706 
00707     return NS_OK;
00708 }
00709 
00710 /* boolean getIsNull (in unsigned long aIndex); */
00711 NS_IMETHODIMP
00712 mozStorageStatement::GetIsNull(PRUint32 aIndex, PRBool *_retval)
00713 {
00714     PRInt32 t;
00715     nsresult rv = GetTypeOfIndex (aIndex, &t);
00716     if (NS_FAILED(rv)) return rv;
00717 
00718     if (t == VALUE_TYPE_NULL)
00719         *_retval = PR_TRUE;
00720     else
00721         *_retval = PR_FALSE;
00722 
00723     return NS_OK;
00724 }