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/. */
11 #include "nsThreadUtils.h"
12 #include "nsIClassInfoImpl.h"
15 #include "mozIStorageError.h"
17 #include "mozStorageBindingParams.h"
18 #include "mozStorageConnection.h"
19 #include "mozStorageStatementJSHelper.h"
20 #include "mozStoragePrivateHelpers.h"
21 #include "mozStorageStatementParams.h"
22 #include "mozStorageStatementRow.h"
23 #include "mozStorageStatement.h"
25 #include "mozilla/Logging.h"
26 #include "mozilla/Printf.h"
27 #include "mozilla/ProfilerLabels.h"
29 extern mozilla::LazyLogModule gStorageLog
;
34 ////////////////////////////////////////////////////////////////////////////////
37 NS_IMPL_CI_INTERFACE_GETTER(Statement
, mozIStorageStatement
,
38 mozIStorageBaseStatement
, mozIStorageBindingParams
,
39 mozIStorageValueArray
,
40 mozilla::storage::StorageBaseStatementInternal
)
42 class StatementClassInfo
: public nsIClassInfo
{
44 constexpr StatementClassInfo() = default;
46 NS_DECL_ISUPPORTS_INHERITED
49 GetInterfaces(nsTArray
<nsIID
>& _array
) override
{
50 return NS_CI_INTERFACE_GETTER_NAME(Statement
)(_array
);
54 GetScriptableHelper(nsIXPCScriptable
** _helper
) override
{
55 static StatementJSHelper sJSHelper
;
56 *_helper
= &sJSHelper
;
61 GetContractID(nsACString
& aContractID
) override
{
62 aContractID
.SetIsVoid(true);
67 GetClassDescription(nsACString
& aDesc
) override
{
68 aDesc
.SetIsVoid(true);
73 GetClassID(nsCID
** _id
) override
{
79 GetFlags(uint32_t* _flags
) override
{
85 GetClassIDNoAlloc(nsCID
* _cid
) override
{ return NS_ERROR_NOT_AVAILABLE
; }
88 NS_IMETHODIMP_(MozExternalRefCountType
) StatementClassInfo::AddRef() {
91 NS_IMETHODIMP_(MozExternalRefCountType
) StatementClassInfo::Release() {
94 NS_IMPL_QUERY_INTERFACE(StatementClassInfo
, nsIClassInfo
)
96 static StatementClassInfo sStatementClassInfo
;
98 ////////////////////////////////////////////////////////////////////////////////
101 Statement::Statement()
102 : mDBStatement(nullptr),
104 mResultColumnCount(0),
106 mQueryStatusRecorded(false),
107 mHasExecuted(false) {}
109 nsresult
Statement::initialize(Connection
* aDBConnection
,
110 sqlite3
* aNativeConnection
,
111 const nsACString
& aSQLStatement
) {
112 MOZ_ASSERT(aDBConnection
, "No database connection given!");
113 MOZ_ASSERT(aDBConnection
->isConnectionReadyOnThisThread(),
114 "Database connection should be valid");
115 MOZ_ASSERT(!mDBStatement
, "Statement already initialized!");
116 MOZ_ASSERT(aNativeConnection
, "No native connection given!");
118 int srv
= aDBConnection
->prepareStatement(
119 aNativeConnection
, PromiseFlatCString(aSQLStatement
), &mDBStatement
);
120 if (srv
!= SQLITE_OK
) {
121 MOZ_LOG(gStorageLog
, LogLevel::Error
,
122 ("Sqlite statement prepare error: %d '%s'", srv
,
123 ::sqlite3_errmsg(aNativeConnection
)));
124 MOZ_LOG(gStorageLog
, LogLevel::Error
,
125 ("Statement was: '%s'", PromiseFlatCString(aSQLStatement
).get()));
127 aDBConnection
->RecordQueryStatus(srv
);
128 mQueryStatusRecorded
= true;
129 return convertResultCode(srv
);
132 MOZ_LOG(gStorageLog
, LogLevel::Debug
,
133 ("Initialized statement '%s' (0x%p)",
134 PromiseFlatCString(aSQLStatement
).get(), mDBStatement
));
136 mDBConnection
= aDBConnection
;
137 mNativeConnection
= aNativeConnection
;
138 mParamCount
= ::sqlite3_bind_parameter_count(mDBStatement
);
139 mResultColumnCount
= ::sqlite3_column_count(mDBStatement
);
140 mColumnNames
.Clear();
142 nsCString
* columnNames
= mColumnNames
.AppendElements(mResultColumnCount
);
143 for (uint32_t i
= 0; i
< mResultColumnCount
; i
++) {
144 const char* name
= ::sqlite3_column_name(mDBStatement
, i
);
145 columnNames
[i
].Assign(name
);
149 // We want to try and test for LIKE and that consumers are using
150 // escapeStringForLIKE instead of just trusting user input. The idea to
151 // check to see if they are binding a parameter after like instead of just
152 // using a string. We only do this in debug builds because it's expensive!
153 auto c
= nsCaseInsensitiveCStringComparator
;
154 nsACString::const_iterator start
, end
, e
;
155 aSQLStatement
.BeginReading(start
);
156 aSQLStatement
.EndReading(end
);
158 while (::FindInReadable(" LIKE"_ns
, start
, e
, c
)) {
159 // We have a LIKE in here, so we perform our tests
160 // FindInReadable moves the iterator, so we have to get a new one for
161 // each test we perform.
162 nsACString::const_iterator s1
, s2
, s3
;
163 s1
= s2
= s3
= start
;
165 if (!(::FindInReadable(" LIKE ?"_ns
, s1
, end
, c
) ||
166 ::FindInReadable(" LIKE :"_ns
, s2
, end
, c
) ||
167 ::FindInReadable(" LIKE @"_ns
, s3
, end
, c
))) {
168 // At this point, we didn't find a LIKE statement followed by ?, :,
169 // or @, all of which are valid characters for binding a parameter.
170 // We will warn the consumer that they may not be safely using LIKE.
172 "Unsafe use of LIKE detected! Please ensure that you "
173 "are using mozIStorageStatement::escapeStringForLIKE "
174 "and that you are binding that result to the statement "
175 "to prevent SQL injection attacks.");
178 // resetting start and e
187 mozIStorageBindingParams
* Statement::getParams() {
190 // If we do not have an array object yet, make it.
192 nsCOMPtr
<mozIStorageBindingParamsArray
> array
;
193 rv
= NewBindingParamsArray(getter_AddRefs(array
));
194 NS_ENSURE_SUCCESS(rv
, nullptr);
196 mParamsArray
= static_cast<BindingParamsArray
*>(array
.get());
199 // If there isn't already any rows added, we'll have to add one to use.
200 if (mParamsArray
->length() == 0) {
201 RefPtr
<BindingParams
> params(new BindingParams(mParamsArray
, this));
202 NS_ENSURE_TRUE(params
, nullptr);
204 rv
= mParamsArray
->AddParams(params
);
205 NS_ENSURE_SUCCESS(rv
, nullptr);
207 // We have to unlock our params because AddParams locks them. This is safe
208 // because no reference to the params object was, or ever will be given out.
209 params
->unlock(this);
211 // We also want to lock our array at this point - we don't want anything to
212 // be added to it. Nothing has, or will ever get a reference to it, but we
213 // will get additional safety checks via assertions by doing this.
214 mParamsArray
->lock();
217 return *mParamsArray
->begin();
220 void Statement::MaybeRecordQueryStatus(int srv
, bool isResetting
) {
221 // If the statement hasn't been executed synchronously since it was last reset
222 // or created then there is no need to record anything. Asynchronous
223 // statements have their status tracked and recorded by StatementData.
228 if (!isResetting
&& !isErrorCode(srv
)) {
229 // Non-errors will be recorded when finalizing.
233 // We only record a status if no status has been recorded previously.
234 if (!mQueryStatusRecorded
&& mDBConnection
) {
235 mDBConnection
->RecordQueryStatus(srv
);
238 // Allow another status to be recorded if we are resetting this statement.
239 mQueryStatusRecorded
= !isResetting
;
242 Statement::~Statement() { (void)internalFinalize(true); }
244 ////////////////////////////////////////////////////////////////////////////////
247 NS_IMPL_ADDREF(Statement
)
248 NS_IMPL_RELEASE(Statement
)
250 NS_INTERFACE_MAP_BEGIN(Statement
)
251 NS_INTERFACE_MAP_ENTRY(mozIStorageStatement
)
252 NS_INTERFACE_MAP_ENTRY(mozIStorageBaseStatement
)
253 NS_INTERFACE_MAP_ENTRY(mozIStorageBindingParams
)
254 NS_INTERFACE_MAP_ENTRY(mozIStorageValueArray
)
255 NS_INTERFACE_MAP_ENTRY(mozilla::storage::StorageBaseStatementInternal
)
256 if (aIID
.Equals(NS_GET_IID(nsIClassInfo
))) {
257 foundInterface
= static_cast<nsIClassInfo
*>(&sStatementClassInfo
);
259 NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports
, mozIStorageStatement
)
262 ////////////////////////////////////////////////////////////////////////////////
263 //// StorageBaseStatementInternal
265 Connection
* Statement::getOwner() { return mDBConnection
; }
267 int 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
,
276 if (rc
!= SQLITE_OK
) {
277 mDBConnection
->RecordQueryStatus(rc
);
282 MOZ_LOG(gStorageLog
, LogLevel::Debug
,
283 ("Cloned statement 0x%p to 0x%p", mDBStatement
, mAsyncStatement
));
286 *_stmt
= mAsyncStatement
;
290 nsresult
Statement::getAsynchronousStatementData(StatementData
& _data
) {
291 if (!mDBStatement
) return NS_ERROR_UNEXPECTED
;
294 int rc
= getAsyncStatement(&stmt
);
295 if (rc
!= SQLITE_OK
) return convertResultCode(rc
);
297 _data
= StatementData(stmt
, bindingParamsArray(), this);
302 already_AddRefed
<mozIStorageBindingParams
> Statement::newBindingParams(
303 mozIStorageBindingParamsArray
* aOwner
) {
304 nsCOMPtr
<mozIStorageBindingParams
> params
= new BindingParams(aOwner
, this);
305 return params
.forget();
308 ////////////////////////////////////////////////////////////////////////////////
309 //// mozIStorageStatement
311 // proxy to StorageBaseStatementInternal using its define helper.
312 MIXIN_IMPL_STORAGEBASESTATEMENTINTERNAL(Statement
, (void)0;)
315 Statement::Clone(mozIStorageStatement
** _statement
) {
316 RefPtr
<Statement
> statement(new Statement());
317 NS_ENSURE_TRUE(statement
, NS_ERROR_OUT_OF_MEMORY
);
319 nsAutoCString
sql(::sqlite3_sql(mDBStatement
));
320 nsresult rv
= statement
->initialize(mDBConnection
, mNativeConnection
, sql
);
321 NS_ENSURE_SUCCESS(rv
, rv
);
323 statement
.forget(_statement
);
328 Statement::Finalize() { return internalFinalize(false); }
330 nsresult
Statement::internalFinalize(bool aDestructing
) {
331 if (!mDBStatement
) return NS_OK
;
336 // If the statement ends up being finalized twice, the second finalization
337 // would apply to a dangling pointer and may cause unexpected consequences.
338 // Thus we must be sure that the connection state won't change during this
339 // operation, to avoid racing with finalizations made by the closing
340 // connection. See Connection::internalClose().
341 MutexAutoLock
lockedScope(mDBConnection
->sharedAsyncExecutionMutex
);
342 if (!mDBConnection
->isClosed(lockedScope
)) {
343 MOZ_LOG(gStorageLog
, LogLevel::Debug
,
344 ("Finalizing statement '%s' during garbage-collection",
345 ::sqlite3_sql(mDBStatement
)));
346 srv
= ::sqlite3_finalize(mDBStatement
);
350 // The database connection is closed. The sqlite
351 // statement has either been finalized already by the connection
352 // or is about to be finalized by the connection.
354 // Finalizing it here would be useless and segfaultish.
356 // Note that we can't display the statement itself, as the data structure
357 // is not valid anymore. However, the address shown here should help
358 // developers correlate with the more complete debug message triggered
361 SmprintfPointer msg
= ::mozilla::Smprintf(
362 "SQL statement (%p) should have been finalized"
363 " before garbage-collection. For more details on this statement, set"
364 " NSPR_LOG_MESSAGES=mozStorage:5 .",
366 NS_WARNING(msg
.get());
368 // Use %s so we aren't exposing random strings to printf interpolation.
369 MOZ_LOG(gStorageLog
, LogLevel::Warning
, ("%s", msg
.get()));
374 // This will be a no-op if the status has already been recorded or if this
375 // statement has not been executed. Async statements have their status
376 // tracked and recorded in StatementData.
377 MaybeRecordQueryStatus(srv
, true);
379 mDBStatement
= nullptr;
381 if (mAsyncStatement
) {
382 // If the destructor called us, there are no pending async statements (they
383 // hold a reference to us) and we can/must just kill the statement directly.
385 destructorAsyncFinalize();
390 // Release the holders, so they can release the reference to us.
391 mStatementParamsHolder
= nullptr;
392 mStatementRowHolder
= nullptr;
394 return convertResultCode(srv
);
398 Statement::GetParameterCount(uint32_t* _parameterCount
) {
399 if (!mDBStatement
) return NS_ERROR_NOT_INITIALIZED
;
401 *_parameterCount
= mParamCount
;
406 Statement::GetParameterName(uint32_t aParamIndex
, nsACString
& _name
) {
407 if (!mDBStatement
) return NS_ERROR_NOT_INITIALIZED
;
408 ENSURE_INDEX_VALUE(aParamIndex
, mParamCount
);
411 ::sqlite3_bind_parameter_name(mDBStatement
, aParamIndex
+ 1);
412 if (name
== nullptr) {
413 // this thing had no name, so fake one
414 nsAutoCString
fakeName(":");
415 fakeName
.AppendInt(aParamIndex
);
416 _name
.Assign(fakeName
);
418 _name
.Assign(nsDependentCString(name
));
425 Statement::GetParameterIndex(const nsACString
& aName
, uint32_t* _index
) {
426 if (!mDBStatement
) return NS_ERROR_NOT_INITIALIZED
;
428 // We do not accept any forms of names other than ":name", but we need to add
429 // the colon for SQLite.
430 nsAutoCString
name(":");
432 int ind
= ::sqlite3_bind_parameter_index(mDBStatement
, name
.get());
433 if (ind
== 0) // Named parameter not found.
434 return NS_ERROR_INVALID_ARG
;
436 *_index
= ind
- 1; // SQLite indexes are 1-based, we are 0-based.
442 Statement::GetColumnCount(uint32_t* _columnCount
) {
443 if (!mDBStatement
) return NS_ERROR_NOT_INITIALIZED
;
445 *_columnCount
= mResultColumnCount
;
450 Statement::GetColumnName(uint32_t aColumnIndex
, nsACString
& _name
) {
451 if (!mDBStatement
) return NS_ERROR_NOT_INITIALIZED
;
452 ENSURE_INDEX_VALUE(aColumnIndex
, mResultColumnCount
);
454 const char* cname
= ::sqlite3_column_name(mDBStatement
, aColumnIndex
);
455 _name
.Assign(nsDependentCString(cname
));
461 Statement::GetColumnIndex(const nsACString
& aName
, uint32_t* _index
) {
462 if (!mDBStatement
) return NS_ERROR_NOT_INITIALIZED
;
464 // Surprisingly enough, SQLite doesn't provide an API for this. We have to
465 // determine it ourselves sadly.
466 for (uint32_t i
= 0; i
< mResultColumnCount
; i
++) {
467 if (mColumnNames
[i
].Equals(aName
)) {
473 return NS_ERROR_INVALID_ARG
;
478 if (!mDBStatement
) return NS_ERROR_NOT_INITIALIZED
;
481 MOZ_LOG(gStorageLog
, LogLevel::Debug
,
482 ("Resetting statement: '%s'", ::sqlite3_sql(mDBStatement
)));
484 checkAndLogStatementPerformance(mDBStatement
);
487 mParamsArray
= nullptr;
488 (void)sqlite3_reset(mDBStatement
);
489 (void)sqlite3_clear_bindings(mDBStatement
);
493 // This will be a no-op if the status has already been recorded or if this
494 // statement has not been executed. Async statements have their status
495 // tracked and recorded in StatementData.
496 MaybeRecordQueryStatus(SQLITE_OK
, true);
497 mHasExecuted
= false;
503 Statement::BindParameters(mozIStorageBindingParamsArray
* aParameters
) {
504 NS_ENSURE_ARG_POINTER(aParameters
);
506 if (!mDBStatement
) return NS_ERROR_NOT_INITIALIZED
;
508 BindingParamsArray
* array
= static_cast<BindingParamsArray
*>(aParameters
);
509 if (array
->getOwner() != this) return NS_ERROR_UNEXPECTED
;
511 if (array
->length() == 0) return NS_ERROR_UNEXPECTED
;
513 mParamsArray
= array
;
514 mParamsArray
->lock();
520 Statement::Execute() {
521 if (!mDBStatement
) return NS_ERROR_NOT_INITIALIZED
;
524 nsresult rv
= ExecuteStep(&ret
);
525 nsresult rv2
= Reset();
527 return NS_FAILED(rv
) ? rv
: rv2
;
531 Statement::ExecuteStep(bool* _moreResults
) {
532 AUTO_PROFILER_LABEL("Statement::ExecuteStep", OTHER
);
534 if (!mDBStatement
) return NS_ERROR_NOT_INITIALIZED
;
536 // Bind any parameters first before executing.
538 // If we have more than one row of parameters to bind, they shouldn't be
539 // calling this method (and instead use executeAsync).
540 if (mParamsArray
->length() != 1) return NS_ERROR_UNEXPECTED
;
542 BindingParamsArray::iterator row
= mParamsArray
->begin();
543 nsCOMPtr
<IStorageBindingParamsInternal
> bindingInternal
=
544 do_QueryInterface(*row
);
545 nsCOMPtr
<mozIStorageError
> error
= bindingInternal
->bind(mDBStatement
);
548 (void)error
->GetResult(&srv
);
549 return convertResultCode(srv
);
552 // We have bound, so now we can clear our array.
553 mParamsArray
= nullptr;
555 int srv
= mDBConnection
->stepStatement(mNativeConnection
, mDBStatement
);
557 MaybeRecordQueryStatus(srv
);
559 if (srv
!= SQLITE_ROW
&& srv
!= SQLITE_DONE
&&
560 MOZ_LOG_TEST(gStorageLog
, LogLevel::Debug
)) {
561 nsAutoCString errStr
;
562 (void)mDBConnection
->GetLastErrorString(errStr
);
563 MOZ_LOG(gStorageLog
, LogLevel::Debug
,
564 ("Statement::ExecuteStep error: %s", errStr
.get()));
567 // SQLITE_ROW and SQLITE_DONE are non-errors
568 if (srv
== SQLITE_ROW
) {
571 *_moreResults
= true;
573 } else if (srv
== SQLITE_DONE
) {
574 // statement is done (no row returned)
576 *_moreResults
= false;
578 } else if (srv
== SQLITE_BUSY
|| srv
== SQLITE_MISUSE
) {
580 } else if (mExecuting
) {
581 MOZ_LOG(gStorageLog
, LogLevel::Error
,
582 ("SQLite error after mExecuting was true!"));
586 return convertResultCode(srv
);
590 Statement::GetState(int32_t* _state
) {
592 *_state
= MOZ_STORAGE_STATEMENT_INVALID
;
594 *_state
= MOZ_STORAGE_STATEMENT_EXECUTING
;
596 *_state
= MOZ_STORAGE_STATEMENT_READY
;
601 ////////////////////////////////////////////////////////////////////////////////
602 //// mozIStorageValueArray (now part of mozIStorageStatement too)
605 Statement::GetNumEntries(uint32_t* _length
) {
606 *_length
= mResultColumnCount
;
611 Statement::GetTypeOfIndex(uint32_t aIndex
, int32_t* _type
) {
612 if (!mDBStatement
) return NS_ERROR_NOT_INITIALIZED
;
614 ENSURE_INDEX_VALUE(aIndex
, mResultColumnCount
);
616 if (!mExecuting
) return NS_ERROR_UNEXPECTED
;
618 int t
= ::sqlite3_column_type(mDBStatement
, aIndex
);
621 *_type
= mozIStorageStatement::VALUE_TYPE_INTEGER
;
624 *_type
= mozIStorageStatement::VALUE_TYPE_FLOAT
;
627 *_type
= mozIStorageStatement::VALUE_TYPE_TEXT
;
630 *_type
= mozIStorageStatement::VALUE_TYPE_BLOB
;
633 *_type
= mozIStorageStatement::VALUE_TYPE_NULL
;
636 return NS_ERROR_FAILURE
;
643 Statement::GetInt32(uint32_t aIndex
, int32_t* _value
) {
644 if (!mDBStatement
) return NS_ERROR_NOT_INITIALIZED
;
646 ENSURE_INDEX_VALUE(aIndex
, mResultColumnCount
);
648 if (!mExecuting
) return NS_ERROR_UNEXPECTED
;
650 *_value
= ::sqlite3_column_int(mDBStatement
, aIndex
);
655 Statement::GetInt64(uint32_t aIndex
, int64_t* _value
) {
656 if (!mDBStatement
) return NS_ERROR_NOT_INITIALIZED
;
658 ENSURE_INDEX_VALUE(aIndex
, mResultColumnCount
);
660 if (!mExecuting
) return NS_ERROR_UNEXPECTED
;
662 *_value
= ::sqlite3_column_int64(mDBStatement
, aIndex
);
668 Statement::GetDouble(uint32_t aIndex
, double* _value
) {
669 if (!mDBStatement
) return NS_ERROR_NOT_INITIALIZED
;
671 ENSURE_INDEX_VALUE(aIndex
, mResultColumnCount
);
673 if (!mExecuting
) return NS_ERROR_UNEXPECTED
;
675 *_value
= ::sqlite3_column_double(mDBStatement
, aIndex
);
681 Statement::GetUTF8String(uint32_t aIndex
, nsACString
& _value
) {
682 // Get type of Index will check aIndex for us, so we don't have to.
684 nsresult rv
= GetTypeOfIndex(aIndex
, &type
);
685 NS_ENSURE_SUCCESS(rv
, rv
);
686 if (type
== mozIStorageStatement::VALUE_TYPE_NULL
) {
687 // NULL columns should have IsVoid set to distinguish them from the empty
689 _value
.SetIsVoid(true);
691 const char* value
= reinterpret_cast<const char*>(
692 ::sqlite3_column_text(mDBStatement
, aIndex
));
693 _value
.Assign(value
, ::sqlite3_column_bytes(mDBStatement
, aIndex
));
699 Statement::GetString(uint32_t aIndex
, nsAString
& _value
) {
700 // Get type of Index will check aIndex for us, so we don't have to.
702 nsresult rv
= GetTypeOfIndex(aIndex
, &type
);
703 NS_ENSURE_SUCCESS(rv
, rv
);
704 if (type
== mozIStorageStatement::VALUE_TYPE_NULL
) {
705 // NULL columns should have IsVoid set to distinguish them from the empty
707 _value
.SetIsVoid(true);
709 const char16_t
* value
= static_cast<const char16_t
*>(
710 ::sqlite3_column_text16(mDBStatement
, aIndex
));
711 _value
.Assign(value
, ::sqlite3_column_bytes16(mDBStatement
, aIndex
) /
718 Statement::GetVariant(uint32_t aIndex
, nsIVariant
** _value
) {
720 return NS_ERROR_NOT_INITIALIZED
;
723 ENSURE_INDEX_VALUE(aIndex
, mResultColumnCount
);
726 return NS_ERROR_UNEXPECTED
;
729 nsCOMPtr
<nsIVariant
> variant
;
730 int type
= ::sqlite3_column_type(mDBStatement
, aIndex
);
734 new IntegerVariant(::sqlite3_column_int64(mDBStatement
, aIndex
));
737 variant
= new FloatVariant(::sqlite3_column_double(mDBStatement
, aIndex
));
740 const char16_t
* value
= static_cast<const char16_t
*>(
741 ::sqlite3_column_text16(mDBStatement
, aIndex
));
742 nsDependentString
str(
744 ::sqlite3_column_bytes16(mDBStatement
, aIndex
) / sizeof(char16_t
));
745 variant
= new TextVariant(str
);
749 variant
= new NullVariant();
752 int size
= ::sqlite3_column_bytes(mDBStatement
, aIndex
);
753 const void* data
= ::sqlite3_column_blob(mDBStatement
, aIndex
);
754 variant
= new BlobVariant(std::pair
<const void*, int>(data
, size
));
758 NS_ENSURE_TRUE(variant
, NS_ERROR_UNEXPECTED
);
760 variant
.forget(_value
);
765 Statement::GetBlob(uint32_t aIndex
, uint32_t* _size
, uint8_t** _blob
) {
766 if (!mDBStatement
) return NS_ERROR_NOT_INITIALIZED
;
768 ENSURE_INDEX_VALUE(aIndex
, mResultColumnCount
);
770 if (!mExecuting
) return NS_ERROR_UNEXPECTED
;
772 int size
= ::sqlite3_column_bytes(mDBStatement
, aIndex
);
773 void* blob
= nullptr;
775 blob
= moz_xmemdup(::sqlite3_column_blob(mDBStatement
, aIndex
), size
);
778 *_blob
= static_cast<uint8_t*>(blob
);
784 Statement::GetBlobAsString(uint32_t aIndex
, nsAString
& aValue
) {
785 return DoGetBlobAsString(this, aIndex
, aValue
);
789 Statement::GetBlobAsUTF8String(uint32_t aIndex
, nsACString
& aValue
) {
790 return DoGetBlobAsString(this, aIndex
, aValue
);
794 Statement::GetSharedUTF8String(uint32_t aIndex
, uint32_t* _byteLength
,
795 const char** _value
) {
796 *_value
= reinterpret_cast<const char*>(
797 ::sqlite3_column_text(mDBStatement
, aIndex
));
799 *_byteLength
= ::sqlite3_column_bytes(mDBStatement
, aIndex
);
805 Statement::GetSharedString(uint32_t aIndex
, uint32_t* _byteLength
,
806 const char16_t
** _value
) {
807 *_value
= static_cast<const char16_t
*>(
808 ::sqlite3_column_text16(mDBStatement
, aIndex
));
810 *_byteLength
= ::sqlite3_column_bytes16(mDBStatement
, aIndex
);
816 Statement::GetSharedBlob(uint32_t aIndex
, uint32_t* _byteLength
,
817 const uint8_t** _blob
) {
819 static_cast<const uint8_t*>(::sqlite3_column_blob(mDBStatement
, aIndex
));
821 *_byteLength
= ::sqlite3_column_bytes(mDBStatement
, aIndex
);
827 Statement::GetIsNull(uint32_t aIndex
, bool* _isNull
) {
828 // Get type of Index will check aIndex for us, so we don't have to.
830 nsresult rv
= GetTypeOfIndex(aIndex
, &type
);
831 NS_ENSURE_SUCCESS(rv
, rv
);
832 *_isNull
= (type
== mozIStorageStatement::VALUE_TYPE_NULL
);
836 ////////////////////////////////////////////////////////////////////////////////
837 //// mozIStorageBindingParams
839 BOILERPLATE_BIND_PROXIES(Statement
,
840 if (!mDBStatement
) return NS_ERROR_NOT_INITIALIZED
;)
842 } // namespace storage
843 } // namespace mozilla