Bug 634734 - Fennec ASSERTION: mFUnitsConvFactor not valid: mFUnitsConvFactor > 0...
[mozilla-central.git] / storage / src / mozStorageStatement.cpp
blob12d583de00a4beb2d595f18f0c6820f118d3e9eb
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
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
14 * License.
16 * The Original Code is Oracle Corporation code.
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.
23 * Contributor(s):
24 * Vladimir Vukicevic <vladimir.vukicevic@oracle.com>
25 * Shawn Wilsher <me@shawnwilsher.com>
26 * John Zhang <jzhang@aptana.com>
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.
40 * ***** END LICENSE BLOCK ***** */
42 #include <limits.h>
43 #include <stdio.h>
45 #include "nsError.h"
46 #include "nsMemory.h"
47 #include "nsThreadUtils.h"
48 #include "nsIClassInfoImpl.h"
49 #include "nsIProgrammingLanguage.h"
50 #include "Variant.h"
52 #include "mozIStorageError.h"
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"
62 #include "prlog.h"
64 #include "mozilla/FunctionTimer.h"
66 #ifdef PR_LOGGING
67 extern PRLogModuleInfo* gStorageLog;
68 #endif
70 namespace mozilla {
71 namespace storage {
73 ////////////////////////////////////////////////////////////////////////////////
74 //// nsIClassInfo
76 NS_IMPL_CI_INTERFACE_GETTER5(
77 Statement,
78 mozIStorageStatement,
79 mozIStorageBaseStatement,
80 mozIStorageBindingParams,
81 mozIStorageValueArray,
82 mozilla::storage::StorageBaseStatementInternal
85 class StatementClassInfo : public nsIClassInfo
87 public:
88 NS_DECL_ISUPPORTS
90 NS_IMETHODIMP
91 GetInterfaces(PRUint32 *_count, nsIID ***_array)
93 return NS_CI_INTERFACE_GETTER_NAME(Statement)(_count, _array);
96 NS_IMETHODIMP
97 GetHelperForLanguage(PRUint32 aLanguage, nsISupports **_helper)
99 if (aLanguage == nsIProgrammingLanguage::JAVASCRIPT) {
100 static StatementJSHelper sJSHelper;
101 *_helper = &sJSHelper;
102 return NS_OK;
105 *_helper = nsnull;
106 return NS_OK;
109 NS_IMETHODIMP
110 GetContractID(char **_contractID)
112 *_contractID = nsnull;
113 return NS_OK;
116 NS_IMETHODIMP
117 GetClassDescription(char **_desc)
119 *_desc = nsnull;
120 return NS_OK;
123 NS_IMETHODIMP
124 GetClassID(nsCID **_id)
126 *_id = nsnull;
127 return NS_OK;
130 NS_IMETHODIMP
131 GetImplementationLanguage(PRUint32 *_language)
133 *_language = nsIProgrammingLanguage::CPLUSPLUS;
134 return NS_OK;
137 NS_IMETHODIMP
138 GetFlags(PRUint32 *_flags)
140 *_flags = nsnull;
141 return NS_OK;
144 NS_IMETHODIMP
145 GetClassIDNoAlloc(nsCID *_cid)
147 return NS_ERROR_NOT_AVAILABLE;
151 NS_IMETHODIMP_(nsrefcnt) StatementClassInfo::AddRef() { return 2; }
152 NS_IMETHODIMP_(nsrefcnt) StatementClassInfo::Release() { return 1; }
153 NS_IMPL_QUERY_INTERFACE1(StatementClassInfo, nsIClassInfo)
155 static StatementClassInfo sStatementClassInfo;
157 ////////////////////////////////////////////////////////////////////////////////
158 //// Statement
160 Statement::Statement()
161 : StorageBaseStatementInternal()
162 , mDBStatement(NULL)
163 , mColumnNames()
164 , mExecuting(false)
168 nsresult
169 Statement::initialize(Connection *aDBConnection,
170 const nsACString &aSQLStatement)
172 NS_ASSERTION(aDBConnection, "No database connection given!");
173 NS_ASSERTION(!mDBStatement, "Statement already initialized!");
175 sqlite3 *db = aDBConnection->GetNativeConnection();
176 NS_ASSERTION(db, "We should never be called with a null sqlite3 database!");
178 int srv = prepareStmt(db, PromiseFlatCString(aSQLStatement), &mDBStatement);
179 if (srv != SQLITE_OK) {
180 #ifdef PR_LOGGING
181 PR_LOG(gStorageLog, PR_LOG_ERROR,
182 ("Sqlite statement prepare error: %d '%s'", srv,
183 ::sqlite3_errmsg(db)));
184 PR_LOG(gStorageLog, PR_LOG_ERROR,
185 ("Statement was: '%s'", PromiseFlatCString(aSQLStatement).get()));
186 #endif
187 return NS_ERROR_FAILURE;
190 #ifdef PR_LOGGING
191 PR_LOG(gStorageLog, PR_LOG_NOTICE, ("Initialized statement '%s' (0x%p)",
192 PromiseFlatCString(aSQLStatement).get(),
193 mDBStatement));
194 #endif
196 mDBConnection = aDBConnection;
197 mParamCount = ::sqlite3_bind_parameter_count(mDBStatement);
198 mResultColumnCount = ::sqlite3_column_count(mDBStatement);
199 mColumnNames.Clear();
201 for (PRUint32 i = 0; i < mResultColumnCount; i++) {
202 const char *name = ::sqlite3_column_name(mDBStatement, i);
203 (void)mColumnNames.AppendElement(nsDependentCString(name));
206 #ifdef DEBUG
207 // We want to try and test for LIKE and that consumers are using
208 // escapeStringForLIKE instead of just trusting user input. The idea to
209 // check to see if they are binding a parameter after like instead of just
210 // using a string. We only do this in debug builds because it's expensive!
211 const nsCaseInsensitiveCStringComparator c;
212 nsACString::const_iterator start, end, e;
213 aSQLStatement.BeginReading(start);
214 aSQLStatement.EndReading(end);
215 e = end;
216 while (::FindInReadable(NS_LITERAL_CSTRING(" LIKE"), start, e, c)) {
217 // We have a LIKE in here, so we perform our tests
218 // FindInReadable moves the iterator, so we have to get a new one for
219 // each test we perform.
220 nsACString::const_iterator s1, s2, s3;
221 s1 = s2 = s3 = start;
223 if (!(::FindInReadable(NS_LITERAL_CSTRING(" LIKE ?"), s1, end, c) ||
224 ::FindInReadable(NS_LITERAL_CSTRING(" LIKE :"), s2, end, c) ||
225 ::FindInReadable(NS_LITERAL_CSTRING(" LIKE @"), s3, end, c))) {
226 // At this point, we didn't find a LIKE statement followed by ?, :,
227 // or @, all of which are valid characters for binding a parameter.
228 // We will warn the consumer that they may not be safely using LIKE.
229 NS_WARNING("Unsafe use of LIKE detected! Please ensure that you "
230 "are using mozIStorageStatement::escapeStringForLIKE "
231 "and that you are binding that result to the statement "
232 "to prevent SQL injection attacks.");
235 // resetting start and e
236 start = e;
237 e = end;
239 #endif
241 return NS_OK;
244 mozIStorageBindingParams *
245 Statement::getParams()
247 nsresult rv;
249 // If we do not have an array object yet, make it.
250 if (!mParamsArray) {
251 nsCOMPtr<mozIStorageBindingParamsArray> array;
252 rv = NewBindingParamsArray(getter_AddRefs(array));
253 NS_ENSURE_SUCCESS(rv, nsnull);
255 mParamsArray = static_cast<BindingParamsArray *>(array.get());
258 // If there isn't already any rows added, we'll have to add one to use.
259 if (mParamsArray->length() == 0) {
260 nsRefPtr<BindingParams> params(new BindingParams(mParamsArray, this));
261 NS_ENSURE_TRUE(params, nsnull);
263 rv = mParamsArray->AddParams(params);
264 NS_ENSURE_SUCCESS(rv, nsnull);
266 // We have to unlock our params because AddParams locks them. This is safe
267 // because no reference to the params object was, or ever will be given out.
268 params->unlock(this);
270 // We also want to lock our array at this point - we don't want anything to
271 // be added to it. Nothing has, or will ever get a reference to it, but we
272 // will get additional safety checks via assertions by doing this.
273 mParamsArray->lock();
276 return *mParamsArray->begin();
279 Statement::~Statement()
281 (void)internalFinalize(true);
284 ////////////////////////////////////////////////////////////////////////////////
285 //// nsISupports
287 NS_IMPL_THREADSAFE_ADDREF(Statement)
288 NS_IMPL_THREADSAFE_RELEASE(Statement)
290 NS_INTERFACE_MAP_BEGIN(Statement)
291 NS_INTERFACE_MAP_ENTRY(mozIStorageStatement)
292 NS_INTERFACE_MAP_ENTRY(mozIStorageBaseStatement)
293 NS_INTERFACE_MAP_ENTRY(mozIStorageBindingParams)
294 NS_INTERFACE_MAP_ENTRY(mozIStorageValueArray)
295 NS_INTERFACE_MAP_ENTRY(mozilla::storage::StorageBaseStatementInternal)
296 if (aIID.Equals(NS_GET_IID(nsIClassInfo))) {
297 foundInterface = static_cast<nsIClassInfo *>(&sStatementClassInfo);
299 else
300 NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, mozIStorageStatement)
301 NS_INTERFACE_MAP_END
304 ////////////////////////////////////////////////////////////////////////////////
305 //// StorageBaseStatementInternal
307 Connection *
308 Statement::getOwner()
310 return mDBConnection;
314 Statement::getAsyncStatement(sqlite3_stmt **_stmt)
316 // If we have no statement, we shouldn't be calling this method!
317 NS_ASSERTION(mDBStatement != NULL, "We have no statement to clone!");
319 // If we do not yet have a cached async statement, clone our statement now.
320 if (!mAsyncStatement) {
321 nsDependentCString sql(::sqlite3_sql(mDBStatement));
322 int rc = prepareStmt(mDBConnection->GetNativeConnection(), sql,
323 &mAsyncStatement);
324 if (rc != SQLITE_OK) {
325 *_stmt = nsnull;
326 return rc;
329 #ifdef PR_LOGGING
330 PR_LOG(gStorageLog, PR_LOG_NOTICE,
331 ("Cloned statement 0x%p to 0x%p", mDBStatement, mAsyncStatement));
332 #endif
335 *_stmt = mAsyncStatement;
336 return SQLITE_OK;
339 nsresult
340 Statement::getAsynchronousStatementData(StatementData &_data)
342 if (!mDBStatement)
343 return NS_ERROR_UNEXPECTED;
345 sqlite3_stmt *stmt;
346 int rc = getAsyncStatement(&stmt);
347 if (rc != SQLITE_OK)
348 return convertResultCode(rc);
350 _data = StatementData(stmt, bindingParamsArray(), this);
352 return NS_OK;
355 already_AddRefed<mozIStorageBindingParams>
356 Statement::newBindingParams(mozIStorageBindingParamsArray *aOwner)
358 nsCOMPtr<mozIStorageBindingParams> params = new BindingParams(aOwner, this);
359 return params.forget();
363 ////////////////////////////////////////////////////////////////////////////////
364 //// mozIStorageStatement
366 // proxy to StorageBaseStatementInternal using its define helper.
367 MIXIN_IMPL_STORAGEBASESTATEMENTINTERNAL(Statement, (void)0;)
369 NS_IMETHODIMP
370 Statement::Clone(mozIStorageStatement **_statement)
372 nsRefPtr<Statement> statement(new Statement());
373 NS_ENSURE_TRUE(statement, NS_ERROR_OUT_OF_MEMORY);
375 nsCAutoString sql(::sqlite3_sql(mDBStatement));
376 nsresult rv = statement->initialize(mDBConnection, sql);
377 NS_ENSURE_SUCCESS(rv, rv);
379 statement.forget(_statement);
380 return NS_OK;
383 NS_IMETHODIMP
384 Statement::Finalize()
386 return internalFinalize(false);
389 nsresult
390 Statement::internalFinalize(bool aDestructing)
392 if (!mDBStatement)
393 return NS_OK;
395 #ifdef PR_LOGGING
396 PR_LOG(gStorageLog, PR_LOG_NOTICE, ("Finalizing statement '%s'",
397 ::sqlite3_sql(mDBStatement)));
398 #endif
400 int srv = ::sqlite3_finalize(mDBStatement);
401 mDBStatement = NULL;
403 if (mAsyncStatement) {
404 // If the destructor called us, there are no pending async statements (they
405 // hold a reference to us) and we can/must just kill the statement directly.
406 if (aDestructing)
407 destructorAsyncFinalize();
408 else
409 asyncFinalize();
412 // We are considered dead at this point, so any wrappers for row or params
413 // need to lose their reference to us.
414 if (mStatementParamsHolder) {
415 nsCOMPtr<nsIXPConnectWrappedNative> wrapper =
416 do_QueryInterface(mStatementParamsHolder);
417 nsCOMPtr<mozIStorageStatementParams> iParams =
418 do_QueryWrappedNative(wrapper);
419 StatementParams *params = static_cast<StatementParams *>(iParams.get());
420 params->mStatement = nsnull;
421 mStatementParamsHolder = nsnull;
424 if (mStatementRowHolder) {
425 nsCOMPtr<nsIXPConnectWrappedNative> wrapper =
426 do_QueryInterface(mStatementRowHolder);
427 nsCOMPtr<mozIStorageStatementRow> iRow =
428 do_QueryWrappedNative(wrapper);
429 StatementRow *row = static_cast<StatementRow *>(iRow.get());
430 row->mStatement = nsnull;
431 mStatementRowHolder = nsnull;
434 return convertResultCode(srv);
437 NS_IMETHODIMP
438 Statement::GetParameterCount(PRUint32 *_parameterCount)
440 if (!mDBStatement)
441 return NS_ERROR_NOT_INITIALIZED;
443 *_parameterCount = mParamCount;
444 return NS_OK;
447 NS_IMETHODIMP
448 Statement::GetParameterName(PRUint32 aParamIndex,
449 nsACString &_name)
451 if (!mDBStatement)
452 return NS_ERROR_NOT_INITIALIZED;
453 ENSURE_INDEX_VALUE(aParamIndex, mParamCount);
455 const char *name = ::sqlite3_bind_parameter_name(mDBStatement,
456 aParamIndex + 1);
457 if (name == NULL) {
458 // this thing had no name, so fake one
459 nsCAutoString name(":");
460 name.AppendInt(aParamIndex);
461 _name.Assign(name);
463 else {
464 _name.Assign(nsDependentCString(name));
467 return NS_OK;
470 NS_IMETHODIMP
471 Statement::GetParameterIndex(const nsACString &aName,
472 PRUint32 *_index)
474 if (!mDBStatement)
475 return NS_ERROR_NOT_INITIALIZED;
477 // We do not accept any forms of names other than ":name", but we need to add
478 // the colon for SQLite.
479 nsCAutoString name(":");
480 name.Append(aName);
481 int ind = ::sqlite3_bind_parameter_index(mDBStatement,
482 PromiseFlatCString(name).get());
483 if (ind == 0) // Named parameter not found.
484 return NS_ERROR_INVALID_ARG;
486 *_index = ind - 1; // SQLite indexes are 1-based, we are 0-based.
488 return NS_OK;
491 NS_IMETHODIMP
492 Statement::GetColumnCount(PRUint32 *_columnCount)
494 if (!mDBStatement)
495 return NS_ERROR_NOT_INITIALIZED;
497 *_columnCount = mResultColumnCount;
498 return NS_OK;
501 NS_IMETHODIMP
502 Statement::GetColumnName(PRUint32 aColumnIndex,
503 nsACString &_name)
505 if (!mDBStatement)
506 return NS_ERROR_NOT_INITIALIZED;
507 ENSURE_INDEX_VALUE(aColumnIndex, mResultColumnCount);
509 const char *cname = ::sqlite3_column_name(mDBStatement, aColumnIndex);
510 _name.Assign(nsDependentCString(cname));
512 return NS_OK;
515 NS_IMETHODIMP
516 Statement::GetColumnIndex(const nsACString &aName,
517 PRUint32 *_index)
519 if (!mDBStatement)
520 return NS_ERROR_NOT_INITIALIZED;
522 // Surprisingly enough, SQLite doesn't provide an API for this. We have to
523 // determine it ourselves sadly.
524 for (PRUint32 i = 0; i < mResultColumnCount; i++) {
525 if (mColumnNames[i].Equals(aName)) {
526 *_index = i;
527 return NS_OK;
531 return NS_ERROR_INVALID_ARG;
534 NS_IMETHODIMP
535 Statement::Reset()
537 if (!mDBStatement)
538 return NS_ERROR_NOT_INITIALIZED;
540 #ifdef DEBUG
541 PR_LOG(gStorageLog, PR_LOG_DEBUG, ("Resetting statement: '%s'",
542 ::sqlite3_sql(mDBStatement)));
544 checkAndLogStatementPerformance(mDBStatement);
545 #endif
547 mParamsArray = nsnull;
548 (void)sqlite3_reset(mDBStatement);
549 (void)sqlite3_clear_bindings(mDBStatement);
551 mExecuting = false;
553 return NS_OK;
556 NS_IMETHODIMP
557 Statement::BindParameters(mozIStorageBindingParamsArray *aParameters)
559 if (!mDBStatement)
560 return NS_ERROR_NOT_INITIALIZED;
562 BindingParamsArray *array = static_cast<BindingParamsArray *>(aParameters);
563 if (array->getOwner() != this)
564 return NS_ERROR_UNEXPECTED;
566 if (array->length() == 0)
567 return NS_ERROR_UNEXPECTED;
569 mParamsArray = array;
570 mParamsArray->lock();
572 return NS_OK;
575 NS_IMETHODIMP
576 Statement::Execute()
578 if (!mDBStatement)
579 return NS_ERROR_NOT_INITIALIZED;
581 PRBool ret;
582 nsresult rv = ExecuteStep(&ret);
583 nsresult rv2 = Reset();
585 return NS_FAILED(rv) ? rv : rv2;
588 NS_IMETHODIMP
589 Statement::ExecuteStep(PRBool *_moreResults)
591 if (!mDBStatement)
592 return NS_ERROR_NOT_INITIALIZED;
594 NS_TIME_FUNCTION_MIN_FMT(5, "mozIStorageStatement::ExecuteStep(%s) (0x%p)",
595 mDBConnection->getFilename().get(), mDBStatement);
597 // Bind any parameters first before executing.
598 if (mParamsArray) {
599 // If we have more than one row of parameters to bind, they shouldn't be
600 // calling this method (and instead use executeAsync).
601 if (mParamsArray->length() != 1)
602 return NS_ERROR_UNEXPECTED;
604 BindingParamsArray::iterator row = mParamsArray->begin();
605 nsCOMPtr<IStorageBindingParamsInternal> bindingInternal =
606 do_QueryInterface(*row);
607 nsCOMPtr<mozIStorageError> error = bindingInternal->bind(mDBStatement);
608 if (error) {
609 PRInt32 srv;
610 (void)error->GetResult(&srv);
611 return convertResultCode(srv);
614 // We have bound, so now we can clear our array.
615 mParamsArray = nsnull;
617 int srv = stepStmt(mDBStatement);
619 #ifdef PR_LOGGING
620 if (srv != SQLITE_ROW && srv != SQLITE_DONE) {
621 nsCAutoString errStr;
622 (void)mDBConnection->GetLastErrorString(errStr);
623 PR_LOG(gStorageLog, PR_LOG_DEBUG,
624 ("Statement::ExecuteStep error: %s", errStr.get()));
626 #endif
628 // SQLITE_ROW and SQLITE_DONE are non-errors
629 if (srv == SQLITE_ROW) {
630 // we got a row back
631 mExecuting = true;
632 *_moreResults = PR_TRUE;
633 return NS_OK;
635 else if (srv == SQLITE_DONE) {
636 // statement is done (no row returned)
637 mExecuting = false;
638 *_moreResults = PR_FALSE;
639 return NS_OK;
641 else if (srv == SQLITE_BUSY || srv == SQLITE_MISUSE) {
642 mExecuting = PR_FALSE;
644 else if (mExecuting) {
645 #ifdef PR_LOGGING
646 PR_LOG(gStorageLog, PR_LOG_ERROR,
647 ("SQLite error after mExecuting was true!"));
648 #endif
649 mExecuting = PR_FALSE;
652 return convertResultCode(srv);
655 NS_IMETHODIMP
656 Statement::GetState(PRInt32 *_state)
658 if (!mDBStatement)
659 *_state = MOZ_STORAGE_STATEMENT_INVALID;
660 else if (mExecuting)
661 *_state = MOZ_STORAGE_STATEMENT_EXECUTING;
662 else
663 *_state = MOZ_STORAGE_STATEMENT_READY;
665 return NS_OK;
668 NS_IMETHODIMP
669 Statement::GetColumnDecltype(PRUint32 aParamIndex,
670 nsACString &_declType)
672 if (!mDBStatement)
673 return NS_ERROR_NOT_INITIALIZED;
675 ENSURE_INDEX_VALUE(aParamIndex, mResultColumnCount);
677 _declType.Assign(::sqlite3_column_decltype(mDBStatement, aParamIndex));
678 return NS_OK;
681 ////////////////////////////////////////////////////////////////////////////////
682 //// mozIStorageValueArray (now part of mozIStorageStatement too)
684 NS_IMETHODIMP
685 Statement::GetNumEntries(PRUint32 *_length)
687 *_length = mResultColumnCount;
688 return NS_OK;
691 NS_IMETHODIMP
692 Statement::GetTypeOfIndex(PRUint32 aIndex,
693 PRInt32 *_type)
695 if (!mDBStatement)
696 return NS_ERROR_NOT_INITIALIZED;
698 ENSURE_INDEX_VALUE(aIndex, mResultColumnCount);
700 if (!mExecuting)
701 return NS_ERROR_UNEXPECTED;
703 int t = ::sqlite3_column_type(mDBStatement, aIndex);
704 switch (t) {
705 case SQLITE_INTEGER:
706 *_type = mozIStorageStatement::VALUE_TYPE_INTEGER;
707 break;
708 case SQLITE_FLOAT:
709 *_type = mozIStorageStatement::VALUE_TYPE_FLOAT;
710 break;
711 case SQLITE_TEXT:
712 *_type = mozIStorageStatement::VALUE_TYPE_TEXT;
713 break;
714 case SQLITE_BLOB:
715 *_type = mozIStorageStatement::VALUE_TYPE_BLOB;
716 break;
717 case SQLITE_NULL:
718 *_type = mozIStorageStatement::VALUE_TYPE_NULL;
719 break;
720 default:
721 return NS_ERROR_FAILURE;
724 return NS_OK;
727 NS_IMETHODIMP
728 Statement::GetInt32(PRUint32 aIndex,
729 PRInt32 *_value)
731 if (!mDBStatement)
732 return NS_ERROR_NOT_INITIALIZED;
734 ENSURE_INDEX_VALUE(aIndex, mResultColumnCount);
736 if (!mExecuting)
737 return NS_ERROR_UNEXPECTED;
739 *_value = ::sqlite3_column_int(mDBStatement, aIndex);
740 return NS_OK;
743 NS_IMETHODIMP
744 Statement::GetInt64(PRUint32 aIndex,
745 PRInt64 *_value)
747 if (!mDBStatement)
748 return NS_ERROR_NOT_INITIALIZED;
750 ENSURE_INDEX_VALUE(aIndex, mResultColumnCount);
752 if (!mExecuting)
753 return NS_ERROR_UNEXPECTED;
755 *_value = ::sqlite3_column_int64(mDBStatement, aIndex);
757 return NS_OK;
760 NS_IMETHODIMP
761 Statement::GetDouble(PRUint32 aIndex,
762 double *_value)
764 if (!mDBStatement)
765 return NS_ERROR_NOT_INITIALIZED;
767 ENSURE_INDEX_VALUE(aIndex, mResultColumnCount);
769 if (!mExecuting)
770 return NS_ERROR_UNEXPECTED;
772 *_value = ::sqlite3_column_double(mDBStatement, aIndex);
774 return NS_OK;
777 NS_IMETHODIMP
778 Statement::GetUTF8String(PRUint32 aIndex,
779 nsACString &_value)
781 // Get type of Index will check aIndex for us, so we don't have to.
782 PRInt32 type;
783 nsresult rv = GetTypeOfIndex(aIndex, &type);
784 NS_ENSURE_SUCCESS(rv, rv);
785 if (type == mozIStorageStatement::VALUE_TYPE_NULL) {
786 // NULL columns should have IsVoid set to distinguish them from the empty
787 // string.
788 _value.Truncate(0);
789 _value.SetIsVoid(PR_TRUE);
791 else {
792 const char *value =
793 reinterpret_cast<const char *>(::sqlite3_column_text(mDBStatement,
794 aIndex));
795 _value.Assign(value, ::sqlite3_column_bytes(mDBStatement, aIndex));
797 return NS_OK;
800 NS_IMETHODIMP
801 Statement::GetString(PRUint32 aIndex,
802 nsAString &_value)
804 // Get type of Index will check aIndex for us, so we don't have to.
805 PRInt32 type;
806 nsresult rv = GetTypeOfIndex(aIndex, &type);
807 NS_ENSURE_SUCCESS(rv, rv);
808 if (type == mozIStorageStatement::VALUE_TYPE_NULL) {
809 // NULL columns should have IsVoid set to distinguish them from the empty
810 // string.
811 _value.Truncate(0);
812 _value.SetIsVoid(PR_TRUE);
813 } else {
814 const PRUnichar *value =
815 static_cast<const PRUnichar *>(::sqlite3_column_text16(mDBStatement,
816 aIndex));
817 _value.Assign(value, ::sqlite3_column_bytes16(mDBStatement, aIndex) / 2);
819 return NS_OK;
822 NS_IMETHODIMP
823 Statement::GetBlob(PRUint32 aIndex,
824 PRUint32 *_size,
825 PRUint8 **_blob)
827 if (!mDBStatement)
828 return NS_ERROR_NOT_INITIALIZED;
830 ENSURE_INDEX_VALUE(aIndex, mResultColumnCount);
832 if (!mExecuting)
833 return NS_ERROR_UNEXPECTED;
835 int size = ::sqlite3_column_bytes(mDBStatement, aIndex);
836 void *blob = nsnull;
837 if (size) {
838 blob = nsMemory::Clone(::sqlite3_column_blob(mDBStatement, aIndex), size);
839 NS_ENSURE_TRUE(blob, NS_ERROR_OUT_OF_MEMORY);
842 *_blob = static_cast<PRUint8 *>(blob);
843 *_size = size;
844 return NS_OK;
847 NS_IMETHODIMP
848 Statement::GetSharedUTF8String(PRUint32 aIndex,
849 PRUint32 *_length,
850 const char **_value)
852 if (_length)
853 *_length = ::sqlite3_column_bytes(mDBStatement, aIndex);
855 *_value = reinterpret_cast<const char *>(::sqlite3_column_text(mDBStatement,
856 aIndex));
857 return NS_OK;
860 NS_IMETHODIMP
861 Statement::GetSharedString(PRUint32 aIndex,
862 PRUint32 *_length,
863 const PRUnichar **_value)
865 if (_length)
866 *_length = ::sqlite3_column_bytes16(mDBStatement, aIndex);
868 *_value = static_cast<const PRUnichar *>(::sqlite3_column_text16(mDBStatement,
869 aIndex));
870 return NS_OK;
873 NS_IMETHODIMP
874 Statement::GetSharedBlob(PRUint32 aIndex,
875 PRUint32 *_size,
876 const PRUint8 **_blob)
878 *_size = ::sqlite3_column_bytes(mDBStatement, aIndex);
879 *_blob = static_cast<const PRUint8 *>(::sqlite3_column_blob(mDBStatement,
880 aIndex));
881 return NS_OK;
884 NS_IMETHODIMP
885 Statement::GetIsNull(PRUint32 aIndex,
886 PRBool *_isNull)
888 // Get type of Index will check aIndex for us, so we don't have to.
889 PRInt32 type;
890 nsresult rv = GetTypeOfIndex(aIndex, &type);
891 NS_ENSURE_SUCCESS(rv, rv);
892 *_isNull = (type == mozIStorageStatement::VALUE_TYPE_NULL);
893 return NS_OK;
896 ////////////////////////////////////////////////////////////////////////////////
897 //// mozIStorageBindingParams
899 BOILERPLATE_BIND_PROXIES(
900 Statement,
901 if (!mDBStatement) return NS_ERROR_NOT_INITIALIZED;
904 } // namespace storage
905 } // namespace mozilla