Bug 1318565 - Allow extensions with permission to read from tainted Canvas r=bz
[gecko.git] / storage / mozStorageStatement.cpp
blobf68ed155058176642826d8365b9347937e8f96c5
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 * This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #include <limits.h>
8 #include <stdio.h>
10 #include "nsError.h"
11 #include "nsMemory.h"
12 #include "nsThreadUtils.h"
13 #include "nsIClassInfoImpl.h"
14 #include "Variant.h"
16 #include "mozIStorageError.h"
18 #include "mozStorageBindingParams.h"
19 #include "mozStorageConnection.h"
20 #include "mozStorageStatementJSHelper.h"
21 #include "mozStoragePrivateHelpers.h"
22 #include "mozStorageStatementParams.h"
23 #include "mozStorageStatementRow.h"
24 #include "mozStorageStatement.h"
25 #include "GeckoProfiler.h"
26 #include "nsDOMClassInfo.h"
28 #include "mozilla/Logging.h"
29 #include "mozilla/Printf.h"
32 extern mozilla::LazyLogModule gStorageLog;
34 namespace mozilla {
35 namespace storage {
37 ////////////////////////////////////////////////////////////////////////////////
38 //// nsIClassInfo
40 NS_IMPL_CI_INTERFACE_GETTER(Statement,
41 mozIStorageStatement,
42 mozIStorageBaseStatement,
43 mozIStorageBindingParams,
44 mozIStorageValueArray,
45 mozilla::storage::StorageBaseStatementInternal)
47 class StatementClassInfo : public nsIClassInfo
49 public:
50 constexpr StatementClassInfo() {}
52 NS_DECL_ISUPPORTS_INHERITED
54 NS_IMETHOD
55 GetInterfaces(uint32_t *_count, nsIID ***_array) override
57 return NS_CI_INTERFACE_GETTER_NAME(Statement)(_count, _array);
60 NS_IMETHOD
61 GetScriptableHelper(nsIXPCScriptable **_helper) override
63 static StatementJSHelper sJSHelper;
64 *_helper = &sJSHelper;
65 return NS_OK;
68 NS_IMETHOD
69 GetContractID(char **_contractID) override
71 *_contractID = nullptr;
72 return NS_OK;
75 NS_IMETHOD
76 GetClassDescription(char **_desc) override
78 *_desc = nullptr;
79 return NS_OK;
82 NS_IMETHOD
83 GetClassID(nsCID **_id) override
85 *_id = nullptr;
86 return NS_OK;
89 NS_IMETHOD
90 GetFlags(uint32_t *_flags) override
92 *_flags = 0;
93 return NS_OK;
96 NS_IMETHOD
97 GetClassIDNoAlloc(nsCID *_cid) override
99 return NS_ERROR_NOT_AVAILABLE;
103 NS_IMETHODIMP_(MozExternalRefCountType) StatementClassInfo::AddRef() { return 2; }
104 NS_IMETHODIMP_(MozExternalRefCountType) StatementClassInfo::Release() { return 1; }
105 NS_IMPL_QUERY_INTERFACE(StatementClassInfo, nsIClassInfo)
107 static StatementClassInfo sStatementClassInfo;
109 ////////////////////////////////////////////////////////////////////////////////
110 //// Statement
112 Statement::Statement()
113 : StorageBaseStatementInternal()
114 , mDBStatement(nullptr)
115 , mColumnNames()
116 , mExecuting(false)
120 nsresult
121 Statement::initialize(Connection *aDBConnection,
122 sqlite3 *aNativeConnection,
123 const nsACString &aSQLStatement)
125 MOZ_ASSERT(aDBConnection, "No database connection given!");
126 MOZ_ASSERT(!aDBConnection->isClosed(), "Database connection should be valid");
127 MOZ_ASSERT(!mDBStatement, "Statement already initialized!");
128 MOZ_ASSERT(aNativeConnection, "No native connection given!");
130 int srv = aDBConnection->prepareStatement(aNativeConnection,
131 PromiseFlatCString(aSQLStatement),
132 &mDBStatement);
133 if (srv != SQLITE_OK) {
134 MOZ_LOG(gStorageLog, LogLevel::Error,
135 ("Sqlite statement prepare error: %d '%s'", srv,
136 ::sqlite3_errmsg(aNativeConnection)));
137 MOZ_LOG(gStorageLog, LogLevel::Error,
138 ("Statement was: '%s'", PromiseFlatCString(aSQLStatement).get()));
139 return NS_ERROR_FAILURE;
142 MOZ_LOG(gStorageLog, LogLevel::Debug, ("Initialized statement '%s' (0x%p)",
143 PromiseFlatCString(aSQLStatement).get(),
144 mDBStatement));
146 mDBConnection = aDBConnection;
147 mNativeConnection = aNativeConnection;
148 mParamCount = ::sqlite3_bind_parameter_count(mDBStatement);
149 mResultColumnCount = ::sqlite3_column_count(mDBStatement);
150 mColumnNames.Clear();
152 nsCString* columnNames = mColumnNames.AppendElements(mResultColumnCount);
153 for (uint32_t i = 0; i < mResultColumnCount; i++) {
154 const char *name = ::sqlite3_column_name(mDBStatement, i);
155 columnNames[i].Assign(name);
158 #ifdef DEBUG
159 // We want to try and test for LIKE and that consumers are using
160 // escapeStringForLIKE instead of just trusting user input. The idea to
161 // check to see if they are binding a parameter after like instead of just
162 // using a string. We only do this in debug builds because it's expensive!
163 const nsCaseInsensitiveCStringComparator c;
164 nsACString::const_iterator start, end, e;
165 aSQLStatement.BeginReading(start);
166 aSQLStatement.EndReading(end);
167 e = end;
168 while (::FindInReadable(NS_LITERAL_CSTRING(" LIKE"), start, e, c)) {
169 // We have a LIKE in here, so we perform our tests
170 // FindInReadable moves the iterator, so we have to get a new one for
171 // each test we perform.
172 nsACString::const_iterator s1, s2, s3;
173 s1 = s2 = s3 = start;
175 if (!(::FindInReadable(NS_LITERAL_CSTRING(" LIKE ?"), s1, end, c) ||
176 ::FindInReadable(NS_LITERAL_CSTRING(" LIKE :"), s2, end, c) ||
177 ::FindInReadable(NS_LITERAL_CSTRING(" LIKE @"), s3, end, c))) {
178 // At this point, we didn't find a LIKE statement followed by ?, :,
179 // or @, all of which are valid characters for binding a parameter.
180 // We will warn the consumer that they may not be safely using LIKE.
181 NS_WARNING("Unsafe use of LIKE detected! Please ensure that you "
182 "are using mozIStorageStatement::escapeStringForLIKE "
183 "and that you are binding that result to the statement "
184 "to prevent SQL injection attacks.");
187 // resetting start and e
188 start = e;
189 e = end;
191 #endif
193 return NS_OK;
196 mozIStorageBindingParams *
197 Statement::getParams()
199 nsresult rv;
201 // If we do not have an array object yet, make it.
202 if (!mParamsArray) {
203 nsCOMPtr<mozIStorageBindingParamsArray> array;
204 rv = NewBindingParamsArray(getter_AddRefs(array));
205 NS_ENSURE_SUCCESS(rv, nullptr);
207 mParamsArray = static_cast<BindingParamsArray *>(array.get());
210 // If there isn't already any rows added, we'll have to add one to use.
211 if (mParamsArray->length() == 0) {
212 RefPtr<BindingParams> params(new BindingParams(mParamsArray, this));
213 NS_ENSURE_TRUE(params, nullptr);
215 rv = mParamsArray->AddParams(params);
216 NS_ENSURE_SUCCESS(rv, nullptr);
218 // We have to unlock our params because AddParams locks them. This is safe
219 // because no reference to the params object was, or ever will be given out.
220 params->unlock(this);
222 // We also want to lock our array at this point - we don't want anything to
223 // be added to it. Nothing has, or will ever get a reference to it, but we
224 // will get additional safety checks via assertions by doing this.
225 mParamsArray->lock();
228 return *mParamsArray->begin();
231 Statement::~Statement()
233 (void)internalFinalize(true);
236 ////////////////////////////////////////////////////////////////////////////////
237 //// nsISupports
239 NS_IMPL_ADDREF(Statement)
240 NS_IMPL_RELEASE(Statement)
242 NS_INTERFACE_MAP_BEGIN(Statement)
243 NS_INTERFACE_MAP_ENTRY(mozIStorageStatement)
244 NS_INTERFACE_MAP_ENTRY(mozIStorageBaseStatement)
245 NS_INTERFACE_MAP_ENTRY(mozIStorageBindingParams)
246 NS_INTERFACE_MAP_ENTRY(mozIStorageValueArray)
247 NS_INTERFACE_MAP_ENTRY(mozilla::storage::StorageBaseStatementInternal)
248 if (aIID.Equals(NS_GET_IID(nsIClassInfo))) {
249 foundInterface = static_cast<nsIClassInfo *>(&sStatementClassInfo);
251 else
252 NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, mozIStorageStatement)
253 NS_INTERFACE_MAP_END
256 ////////////////////////////////////////////////////////////////////////////////
257 //// StorageBaseStatementInternal
259 Connection *
260 Statement::getOwner()
262 return mDBConnection;
266 Statement::getAsyncStatement(sqlite3_stmt **_stmt)
268 // If we have no statement, we shouldn't be calling this method!
269 NS_ASSERTION(mDBStatement != nullptr, "We have no statement to clone!");
271 // If we do not yet have a cached async statement, clone our statement now.
272 if (!mAsyncStatement) {
273 nsDependentCString sql(::sqlite3_sql(mDBStatement));
274 int rc = mDBConnection->prepareStatement(mNativeConnection, sql,
275 &mAsyncStatement);
276 if (rc != SQLITE_OK) {
277 *_stmt = nullptr;
278 return rc;
281 MOZ_LOG(gStorageLog, LogLevel::Debug,
282 ("Cloned statement 0x%p to 0x%p", mDBStatement, mAsyncStatement));
285 *_stmt = mAsyncStatement;
286 return SQLITE_OK;
289 nsresult
290 Statement::getAsynchronousStatementData(StatementData &_data)
292 if (!mDBStatement)
293 return NS_ERROR_UNEXPECTED;
295 sqlite3_stmt *stmt;
296 int rc = getAsyncStatement(&stmt);
297 if (rc != SQLITE_OK)
298 return convertResultCode(rc);
300 _data = StatementData(stmt, bindingParamsArray(), this);
302 return NS_OK;
305 already_AddRefed<mozIStorageBindingParams>
306 Statement::newBindingParams(mozIStorageBindingParamsArray *aOwner)
308 nsCOMPtr<mozIStorageBindingParams> params = new BindingParams(aOwner, this);
309 return params.forget();
313 ////////////////////////////////////////////////////////////////////////////////
314 //// mozIStorageStatement
316 // proxy to StorageBaseStatementInternal using its define helper.
317 MIXIN_IMPL_STORAGEBASESTATEMENTINTERNAL(Statement, (void)0;)
319 NS_IMETHODIMP
320 Statement::Clone(mozIStorageStatement **_statement)
322 RefPtr<Statement> statement(new Statement());
323 NS_ENSURE_TRUE(statement, NS_ERROR_OUT_OF_MEMORY);
325 nsAutoCString sql(::sqlite3_sql(mDBStatement));
326 nsresult rv = statement->initialize(mDBConnection, mNativeConnection, sql);
327 NS_ENSURE_SUCCESS(rv, rv);
329 statement.forget(_statement);
330 return NS_OK;
333 NS_IMETHODIMP
334 Statement::Finalize()
336 return internalFinalize(false);
339 nsresult
340 Statement::internalFinalize(bool aDestructing)
342 if (!mDBStatement)
343 return NS_OK;
345 int srv = SQLITE_OK;
347 if (!mDBConnection->isClosed()) {
349 // The connection is still open. While statement finalization and
350 // closing may, in some cases, take place in two distinct threads,
351 // we have a guarantee that the connection will remain open until
352 // this method terminates:
354 // a. The connection will be closed synchronously. In this case,
355 // there is no race condition, as everything takes place on the
356 // same thread.
358 // b. The connection is closed asynchronously and this code is
359 // executed on the opener thread. In this case, asyncClose() has
360 // not been called yet and will not be called before we return
361 // from this function.
363 // c. The connection is closed asynchronously and this code is
364 // executed on the async execution thread. In this case,
365 // AsyncCloseConnection::Run() has not been called yet and will
366 // not be called before we return from this function.
368 // In either case, the connection is still valid, hence closing
369 // here is safe.
371 MOZ_LOG(gStorageLog, LogLevel::Debug, ("Finalizing statement '%s' during garbage-collection",
372 ::sqlite3_sql(mDBStatement)));
373 srv = ::sqlite3_finalize(mDBStatement);
375 #ifdef DEBUG
376 else {
378 // The database connection is either closed or closing. The sqlite
379 // statement has either been finalized already by the connection
380 // or is about to be finalized by the connection.
382 // Finalizing it here would be useless and segfaultish.
385 char *msg = ::mozilla::Smprintf("SQL statement (%p) should have been finalized"
386 " before garbage-collection. For more details on this statement, set"
387 " NSPR_LOG_MESSAGES=mozStorage:5 .",
388 mDBStatement);
391 // Note that we can't display the statement itself, as the data structure
392 // is not valid anymore. However, the address shown here should help
393 // developers correlate with the more complete debug message triggered
394 // by AsyncClose().
397 #if 0
398 // Deactivate the warning until we have fixed the exising culprit
399 // (see bug 914070).
400 NS_WARNING(msg);
401 #endif // 0
403 // Use %s so we aren't exposing random strings to printf interpolation.
404 MOZ_LOG(gStorageLog, LogLevel::Warning, ("%s", msg));
406 ::mozilla::SmprintfFree(msg);
409 #endif
411 mDBStatement = nullptr;
413 if (mAsyncStatement) {
414 // If the destructor called us, there are no pending async statements (they
415 // hold a reference to us) and we can/must just kill the statement directly.
416 if (aDestructing)
417 destructorAsyncFinalize();
418 else
419 asyncFinalize();
422 // Release the holders, so they can release the reference to us.
423 mStatementParamsHolder = nullptr;
424 mStatementRowHolder = nullptr;
426 return convertResultCode(srv);
429 NS_IMETHODIMP
430 Statement::GetParameterCount(uint32_t *_parameterCount)
432 if (!mDBStatement)
433 return NS_ERROR_NOT_INITIALIZED;
435 *_parameterCount = mParamCount;
436 return NS_OK;
439 NS_IMETHODIMP
440 Statement::GetParameterName(uint32_t aParamIndex,
441 nsACString &_name)
443 if (!mDBStatement)
444 return NS_ERROR_NOT_INITIALIZED;
445 ENSURE_INDEX_VALUE(aParamIndex, mParamCount);
447 const char *name = ::sqlite3_bind_parameter_name(mDBStatement,
448 aParamIndex + 1);
449 if (name == nullptr) {
450 // this thing had no name, so fake one
451 nsAutoCString fakeName(":");
452 fakeName.AppendInt(aParamIndex);
453 _name.Assign(fakeName);
455 else {
456 _name.Assign(nsDependentCString(name));
459 return NS_OK;
462 NS_IMETHODIMP
463 Statement::GetParameterIndex(const nsACString &aName,
464 uint32_t *_index)
466 if (!mDBStatement)
467 return NS_ERROR_NOT_INITIALIZED;
469 // We do not accept any forms of names other than ":name", but we need to add
470 // the colon for SQLite.
471 nsAutoCString name(":");
472 name.Append(aName);
473 int ind = ::sqlite3_bind_parameter_index(mDBStatement, name.get());
474 if (ind == 0) // Named parameter not found.
475 return NS_ERROR_INVALID_ARG;
477 *_index = ind - 1; // SQLite indexes are 1-based, we are 0-based.
479 return NS_OK;
482 NS_IMETHODIMP
483 Statement::GetColumnCount(uint32_t *_columnCount)
485 if (!mDBStatement)
486 return NS_ERROR_NOT_INITIALIZED;
488 *_columnCount = mResultColumnCount;
489 return NS_OK;
492 NS_IMETHODIMP
493 Statement::GetColumnName(uint32_t aColumnIndex,
494 nsACString &_name)
496 if (!mDBStatement)
497 return NS_ERROR_NOT_INITIALIZED;
498 ENSURE_INDEX_VALUE(aColumnIndex, mResultColumnCount);
500 const char *cname = ::sqlite3_column_name(mDBStatement, aColumnIndex);
501 _name.Assign(nsDependentCString(cname));
503 return NS_OK;
506 NS_IMETHODIMP
507 Statement::GetColumnIndex(const nsACString &aName,
508 uint32_t *_index)
510 if (!mDBStatement)
511 return NS_ERROR_NOT_INITIALIZED;
513 // Surprisingly enough, SQLite doesn't provide an API for this. We have to
514 // determine it ourselves sadly.
515 for (uint32_t i = 0; i < mResultColumnCount; i++) {
516 if (mColumnNames[i].Equals(aName)) {
517 *_index = i;
518 return NS_OK;
522 return NS_ERROR_INVALID_ARG;
525 NS_IMETHODIMP
526 Statement::Reset()
528 if (!mDBStatement)
529 return NS_ERROR_NOT_INITIALIZED;
531 #ifdef DEBUG
532 MOZ_LOG(gStorageLog, LogLevel::Debug, ("Resetting statement: '%s'",
533 ::sqlite3_sql(mDBStatement)));
535 checkAndLogStatementPerformance(mDBStatement);
536 #endif
538 mParamsArray = nullptr;
539 (void)sqlite3_reset(mDBStatement);
540 (void)sqlite3_clear_bindings(mDBStatement);
542 mExecuting = false;
544 return NS_OK;
547 NS_IMETHODIMP
548 Statement::BindParameters(mozIStorageBindingParamsArray *aParameters)
550 NS_ENSURE_ARG_POINTER(aParameters);
552 if (!mDBStatement)
553 return NS_ERROR_NOT_INITIALIZED;
555 BindingParamsArray *array = static_cast<BindingParamsArray *>(aParameters);
556 if (array->getOwner() != this)
557 return NS_ERROR_UNEXPECTED;
559 if (array->length() == 0)
560 return NS_ERROR_UNEXPECTED;
562 mParamsArray = array;
563 mParamsArray->lock();
565 return NS_OK;
568 NS_IMETHODIMP
569 Statement::Execute()
571 if (!mDBStatement)
572 return NS_ERROR_NOT_INITIALIZED;
574 bool ret;
575 nsresult rv = ExecuteStep(&ret);
576 nsresult rv2 = Reset();
578 return NS_FAILED(rv) ? rv : rv2;
581 NS_IMETHODIMP
582 Statement::ExecuteStep(bool *_moreResults)
584 PROFILER_LABEL("Statement", "ExecuteStep",
585 js::ProfileEntry::Category::STORAGE);
587 if (!mDBStatement)
588 return NS_ERROR_NOT_INITIALIZED;
590 // Bind any parameters first before executing.
591 if (mParamsArray) {
592 // If we have more than one row of parameters to bind, they shouldn't be
593 // calling this method (and instead use executeAsync).
594 if (mParamsArray->length() != 1)
595 return NS_ERROR_UNEXPECTED;
597 BindingParamsArray::iterator row = mParamsArray->begin();
598 nsCOMPtr<IStorageBindingParamsInternal> bindingInternal =
599 do_QueryInterface(*row);
600 nsCOMPtr<mozIStorageError> error = bindingInternal->bind(mDBStatement);
601 if (error) {
602 int32_t srv;
603 (void)error->GetResult(&srv);
604 return convertResultCode(srv);
607 // We have bound, so now we can clear our array.
608 mParamsArray = nullptr;
610 int srv = mDBConnection->stepStatement(mNativeConnection, mDBStatement);
612 if (srv != SQLITE_ROW && srv != SQLITE_DONE && MOZ_LOG_TEST(gStorageLog, LogLevel::Debug)) {
613 nsAutoCString errStr;
614 (void)mDBConnection->GetLastErrorString(errStr);
615 MOZ_LOG(gStorageLog, LogLevel::Debug,
616 ("Statement::ExecuteStep error: %s", errStr.get()));
619 // SQLITE_ROW and SQLITE_DONE are non-errors
620 if (srv == SQLITE_ROW) {
621 // we got a row back
622 mExecuting = true;
623 *_moreResults = true;
624 return NS_OK;
626 else if (srv == SQLITE_DONE) {
627 // statement is done (no row returned)
628 mExecuting = false;
629 *_moreResults = false;
630 return NS_OK;
632 else if (srv == SQLITE_BUSY || srv == SQLITE_MISUSE) {
633 mExecuting = false;
635 else if (mExecuting) {
636 MOZ_LOG(gStorageLog, LogLevel::Error,
637 ("SQLite error after mExecuting was true!"));
638 mExecuting = false;
641 return convertResultCode(srv);
644 NS_IMETHODIMP
645 Statement::GetState(int32_t *_state)
647 if (!mDBStatement)
648 *_state = MOZ_STORAGE_STATEMENT_INVALID;
649 else if (mExecuting)
650 *_state = MOZ_STORAGE_STATEMENT_EXECUTING;
651 else
652 *_state = MOZ_STORAGE_STATEMENT_READY;
654 return NS_OK;
657 ////////////////////////////////////////////////////////////////////////////////
658 //// mozIStorageValueArray (now part of mozIStorageStatement too)
660 NS_IMETHODIMP
661 Statement::GetNumEntries(uint32_t *_length)
663 *_length = mResultColumnCount;
664 return NS_OK;
667 NS_IMETHODIMP
668 Statement::GetTypeOfIndex(uint32_t aIndex,
669 int32_t *_type)
671 if (!mDBStatement)
672 return NS_ERROR_NOT_INITIALIZED;
674 ENSURE_INDEX_VALUE(aIndex, mResultColumnCount);
676 if (!mExecuting)
677 return NS_ERROR_UNEXPECTED;
679 int t = ::sqlite3_column_type(mDBStatement, aIndex);
680 switch (t) {
681 case SQLITE_INTEGER:
682 *_type = mozIStorageStatement::VALUE_TYPE_INTEGER;
683 break;
684 case SQLITE_FLOAT:
685 *_type = mozIStorageStatement::VALUE_TYPE_FLOAT;
686 break;
687 case SQLITE_TEXT:
688 *_type = mozIStorageStatement::VALUE_TYPE_TEXT;
689 break;
690 case SQLITE_BLOB:
691 *_type = mozIStorageStatement::VALUE_TYPE_BLOB;
692 break;
693 case SQLITE_NULL:
694 *_type = mozIStorageStatement::VALUE_TYPE_NULL;
695 break;
696 default:
697 return NS_ERROR_FAILURE;
700 return NS_OK;
703 NS_IMETHODIMP
704 Statement::GetInt32(uint32_t aIndex,
705 int32_t *_value)
707 if (!mDBStatement)
708 return NS_ERROR_NOT_INITIALIZED;
710 ENSURE_INDEX_VALUE(aIndex, mResultColumnCount);
712 if (!mExecuting)
713 return NS_ERROR_UNEXPECTED;
715 *_value = ::sqlite3_column_int(mDBStatement, aIndex);
716 return NS_OK;
719 NS_IMETHODIMP
720 Statement::GetInt64(uint32_t aIndex,
721 int64_t *_value)
723 if (!mDBStatement)
724 return NS_ERROR_NOT_INITIALIZED;
726 ENSURE_INDEX_VALUE(aIndex, mResultColumnCount);
728 if (!mExecuting)
729 return NS_ERROR_UNEXPECTED;
731 *_value = ::sqlite3_column_int64(mDBStatement, aIndex);
733 return NS_OK;
736 NS_IMETHODIMP
737 Statement::GetDouble(uint32_t aIndex,
738 double *_value)
740 if (!mDBStatement)
741 return NS_ERROR_NOT_INITIALIZED;
743 ENSURE_INDEX_VALUE(aIndex, mResultColumnCount);
745 if (!mExecuting)
746 return NS_ERROR_UNEXPECTED;
748 *_value = ::sqlite3_column_double(mDBStatement, aIndex);
750 return NS_OK;
753 NS_IMETHODIMP
754 Statement::GetUTF8String(uint32_t aIndex,
755 nsACString &_value)
757 // Get type of Index will check aIndex for us, so we don't have to.
758 int32_t type;
759 nsresult rv = GetTypeOfIndex(aIndex, &type);
760 NS_ENSURE_SUCCESS(rv, rv);
761 if (type == mozIStorageStatement::VALUE_TYPE_NULL) {
762 // NULL columns should have IsVoid set to distinguish them from the empty
763 // string.
764 _value.SetIsVoid(true);
766 else {
767 const char *value =
768 reinterpret_cast<const char *>(::sqlite3_column_text(mDBStatement,
769 aIndex));
770 _value.Assign(value, ::sqlite3_column_bytes(mDBStatement, aIndex));
772 return NS_OK;
775 NS_IMETHODIMP
776 Statement::GetString(uint32_t aIndex,
777 nsAString &_value)
779 // Get type of Index will check aIndex for us, so we don't have to.
780 int32_t type;
781 nsresult rv = GetTypeOfIndex(aIndex, &type);
782 NS_ENSURE_SUCCESS(rv, rv);
783 if (type == mozIStorageStatement::VALUE_TYPE_NULL) {
784 // NULL columns should have IsVoid set to distinguish them from the empty
785 // string.
786 _value.SetIsVoid(true);
787 } else {
788 const char16_t *value =
789 static_cast<const char16_t *>(::sqlite3_column_text16(mDBStatement,
790 aIndex));
791 _value.Assign(value, ::sqlite3_column_bytes16(mDBStatement, aIndex) / 2);
793 return NS_OK;
796 NS_IMETHODIMP
797 Statement::GetBlob(uint32_t aIndex,
798 uint32_t *_size,
799 uint8_t **_blob)
801 if (!mDBStatement)
802 return NS_ERROR_NOT_INITIALIZED;
804 ENSURE_INDEX_VALUE(aIndex, mResultColumnCount);
806 if (!mExecuting)
807 return NS_ERROR_UNEXPECTED;
809 int size = ::sqlite3_column_bytes(mDBStatement, aIndex);
810 void *blob = nullptr;
811 if (size) {
812 blob = nsMemory::Clone(::sqlite3_column_blob(mDBStatement, aIndex), size);
813 NS_ENSURE_TRUE(blob, NS_ERROR_OUT_OF_MEMORY);
816 *_blob = static_cast<uint8_t *>(blob);
817 *_size = size;
818 return NS_OK;
821 NS_IMETHODIMP
822 Statement::GetBlobAsString(uint32_t aIndex, nsAString& aValue)
824 return DoGetBlobAsString(this, aIndex, aValue);
827 NS_IMETHODIMP
828 Statement::GetBlobAsUTF8String(uint32_t aIndex, nsACString& aValue)
830 return DoGetBlobAsString(this, aIndex, aValue);
833 NS_IMETHODIMP
834 Statement::GetSharedUTF8String(uint32_t aIndex,
835 uint32_t *_length,
836 const char **_value)
838 if (_length)
839 *_length = ::sqlite3_column_bytes(mDBStatement, aIndex);
841 *_value = reinterpret_cast<const char *>(::sqlite3_column_text(mDBStatement,
842 aIndex));
843 return NS_OK;
846 NS_IMETHODIMP
847 Statement::GetSharedString(uint32_t aIndex,
848 uint32_t *_length,
849 const char16_t **_value)
851 if (_length)
852 *_length = ::sqlite3_column_bytes16(mDBStatement, aIndex);
854 *_value = static_cast<const char16_t *>(::sqlite3_column_text16(mDBStatement,
855 aIndex));
856 return NS_OK;
859 NS_IMETHODIMP
860 Statement::GetSharedBlob(uint32_t aIndex,
861 uint32_t *_size,
862 const uint8_t **_blob)
864 *_size = ::sqlite3_column_bytes(mDBStatement, aIndex);
865 *_blob = static_cast<const uint8_t *>(::sqlite3_column_blob(mDBStatement,
866 aIndex));
867 return NS_OK;
870 NS_IMETHODIMP
871 Statement::GetIsNull(uint32_t aIndex,
872 bool *_isNull)
874 // Get type of Index will check aIndex for us, so we don't have to.
875 int32_t type;
876 nsresult rv = GetTypeOfIndex(aIndex, &type);
877 NS_ENSURE_SUCCESS(rv, rv);
878 *_isNull = (type == mozIStorageStatement::VALUE_TYPE_NULL);
879 return NS_OK;
882 ////////////////////////////////////////////////////////////////////////////////
883 //// mozIStorageBindingParams
885 BOILERPLATE_BIND_PROXIES(
886 Statement,
887 if (!mDBStatement) return NS_ERROR_NOT_INITIALIZED;
890 } // namespace storage
891 } // namespace mozilla