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/. */
12 #include "nsThreadUtils.h"
13 #include "nsIClassInfoImpl.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"
26 #include "mozilla/Logging.h"
27 #include "mozilla/Printf.h"
28 #include "mozilla/ProfilerLabels.h"
30 extern mozilla::LazyLogModule gStorageLog
;
35 ////////////////////////////////////////////////////////////////////////////////
38 NS_IMPL_CI_INTERFACE_GETTER(Statement
, mozIStorageStatement
,
39 mozIStorageBaseStatement
, mozIStorageBindingParams
,
40 mozIStorageValueArray
,
41 mozilla::storage::StorageBaseStatementInternal
)
43 class StatementClassInfo
: public nsIClassInfo
{
45 constexpr StatementClassInfo() {}
47 NS_DECL_ISUPPORTS_INHERITED
50 GetInterfaces(nsTArray
<nsIID
>& _array
) override
{
51 return NS_CI_INTERFACE_GETTER_NAME(Statement
)(_array
);
55 GetScriptableHelper(nsIXPCScriptable
** _helper
) override
{
56 static StatementJSHelper sJSHelper
;
57 *_helper
= &sJSHelper
;
62 GetContractID(nsACString
& aContractID
) override
{
63 aContractID
.SetIsVoid(true);
68 GetClassDescription(nsACString
& aDesc
) override
{
69 aDesc
.SetIsVoid(true);
74 GetClassID(nsCID
** _id
) override
{
80 GetFlags(uint32_t* _flags
) override
{
86 GetClassIDNoAlloc(nsCID
* _cid
) override
{ return NS_ERROR_NOT_AVAILABLE
; }
89 NS_IMETHODIMP_(MozExternalRefCountType
) StatementClassInfo::AddRef() {
92 NS_IMETHODIMP_(MozExternalRefCountType
) StatementClassInfo::Release() {
95 NS_IMPL_QUERY_INTERFACE(StatementClassInfo
, nsIClassInfo
)
97 static StatementClassInfo sStatementClassInfo
;
99 ////////////////////////////////////////////////////////////////////////////////
102 Statement::Statement()
103 : StorageBaseStatementInternal(),
104 mDBStatement(nullptr),
106 mResultColumnCount(0),
109 mQueryStatusRecorded(false),
110 mHasExecuted(false) {}
112 nsresult
Statement::initialize(Connection
* aDBConnection
,
113 sqlite3
* aNativeConnection
,
114 const nsACString
& aSQLStatement
) {
115 MOZ_ASSERT(aDBConnection
, "No database connection given!");
116 MOZ_ASSERT(aDBConnection
->isConnectionReadyOnThisThread(),
117 "Database connection should be valid");
118 MOZ_ASSERT(!mDBStatement
, "Statement already initialized!");
119 MOZ_ASSERT(aNativeConnection
, "No native connection given!");
121 int srv
= aDBConnection
->prepareStatement(
122 aNativeConnection
, PromiseFlatCString(aSQLStatement
), &mDBStatement
);
123 if (srv
!= SQLITE_OK
) {
124 MOZ_LOG(gStorageLog
, LogLevel::Error
,
125 ("Sqlite statement prepare error: %d '%s'", srv
,
126 ::sqlite3_errmsg(aNativeConnection
)));
127 MOZ_LOG(gStorageLog
, LogLevel::Error
,
128 ("Statement was: '%s'", PromiseFlatCString(aSQLStatement
).get()));
130 aDBConnection
->RecordQueryStatus(srv
);
131 mQueryStatusRecorded
= true;
132 return NS_ERROR_FAILURE
;
135 MOZ_LOG(gStorageLog
, LogLevel::Debug
,
136 ("Initialized statement '%s' (0x%p)",
137 PromiseFlatCString(aSQLStatement
).get(), mDBStatement
));
139 mDBConnection
= aDBConnection
;
140 mNativeConnection
= aNativeConnection
;
141 mParamCount
= ::sqlite3_bind_parameter_count(mDBStatement
);
142 mResultColumnCount
= ::sqlite3_column_count(mDBStatement
);
143 mColumnNames
.Clear();
145 nsCString
* columnNames
= mColumnNames
.AppendElements(mResultColumnCount
);
146 for (uint32_t i
= 0; i
< mResultColumnCount
; i
++) {
147 const char* name
= ::sqlite3_column_name(mDBStatement
, i
);
148 columnNames
[i
].Assign(name
);
152 // We want to try and test for LIKE and that consumers are using
153 // escapeStringForLIKE instead of just trusting user input. The idea to
154 // check to see if they are binding a parameter after like instead of just
155 // using a string. We only do this in debug builds because it's expensive!
156 auto c
= nsCaseInsensitiveCStringComparator
;
157 nsACString::const_iterator start
, end
, e
;
158 aSQLStatement
.BeginReading(start
);
159 aSQLStatement
.EndReading(end
);
161 while (::FindInReadable(" LIKE"_ns
, start
, e
, c
)) {
162 // We have a LIKE in here, so we perform our tests
163 // FindInReadable moves the iterator, so we have to get a new one for
164 // each test we perform.
165 nsACString::const_iterator s1
, s2
, s3
;
166 s1
= s2
= s3
= start
;
168 if (!(::FindInReadable(" LIKE ?"_ns
, s1
, end
, c
) ||
169 ::FindInReadable(" LIKE :"_ns
, s2
, end
, c
) ||
170 ::FindInReadable(" LIKE @"_ns
, s3
, end
, c
))) {
171 // At this point, we didn't find a LIKE statement followed by ?, :,
172 // or @, all of which are valid characters for binding a parameter.
173 // We will warn the consumer that they may not be safely using LIKE.
175 "Unsafe use of LIKE detected! Please ensure that you "
176 "are using mozIStorageStatement::escapeStringForLIKE "
177 "and that you are binding that result to the statement "
178 "to prevent SQL injection attacks.");
181 // resetting start and e
190 mozIStorageBindingParams
* Statement::getParams() {
193 // If we do not have an array object yet, make it.
195 nsCOMPtr
<mozIStorageBindingParamsArray
> array
;
196 rv
= NewBindingParamsArray(getter_AddRefs(array
));
197 NS_ENSURE_SUCCESS(rv
, nullptr);
199 mParamsArray
= static_cast<BindingParamsArray
*>(array
.get());
202 // If there isn't already any rows added, we'll have to add one to use.
203 if (mParamsArray
->length() == 0) {
204 RefPtr
<BindingParams
> params(new BindingParams(mParamsArray
, this));
205 NS_ENSURE_TRUE(params
, nullptr);
207 rv
= mParamsArray
->AddParams(params
);
208 NS_ENSURE_SUCCESS(rv
, nullptr);
210 // We have to unlock our params because AddParams locks them. This is safe
211 // because no reference to the params object was, or ever will be given out.
212 params
->unlock(this);
214 // We also want to lock our array at this point - we don't want anything to
215 // be added to it. Nothing has, or will ever get a reference to it, but we
216 // will get additional safety checks via assertions by doing this.
217 mParamsArray
->lock();
220 return *mParamsArray
->begin();
223 void Statement::MaybeRecordQueryStatus(int srv
, bool isResetting
) {
224 // If the statement hasn't been executed synchronously since it was last reset
225 // or created then there is no need to record anything. Asynchronous
226 // statements have their status tracked and recorded by StatementData.
231 if (!isResetting
&& !isErrorCode(srv
)) {
232 // Non-errors will be recorded when finalizing.
236 // We only record a status if no status has been recorded previously.
237 if (!mQueryStatusRecorded
&& mDBConnection
) {
238 mDBConnection
->RecordQueryStatus(srv
);
241 // Allow another status to be recorded if we are resetting this statement.
242 mQueryStatusRecorded
= !isResetting
;
245 Statement::~Statement() { (void)internalFinalize(true); }
247 ////////////////////////////////////////////////////////////////////////////////
250 NS_IMPL_ADDREF(Statement
)
251 NS_IMPL_RELEASE(Statement
)
253 NS_INTERFACE_MAP_BEGIN(Statement
)
254 NS_INTERFACE_MAP_ENTRY(mozIStorageStatement
)
255 NS_INTERFACE_MAP_ENTRY(mozIStorageBaseStatement
)
256 NS_INTERFACE_MAP_ENTRY(mozIStorageBindingParams
)
257 NS_INTERFACE_MAP_ENTRY(mozIStorageValueArray
)
258 NS_INTERFACE_MAP_ENTRY(mozilla::storage::StorageBaseStatementInternal
)
259 if (aIID
.Equals(NS_GET_IID(nsIClassInfo
))) {
260 foundInterface
= static_cast<nsIClassInfo
*>(&sStatementClassInfo
);
262 NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports
, mozIStorageStatement
)
265 ////////////////////////////////////////////////////////////////////////////////
266 //// StorageBaseStatementInternal
268 Connection
* Statement::getOwner() { return mDBConnection
; }
270 int Statement::getAsyncStatement(sqlite3_stmt
** _stmt
) {
271 // If we have no statement, we shouldn't be calling this method!
272 NS_ASSERTION(mDBStatement
!= nullptr, "We have no statement to clone!");
274 // If we do not yet have a cached async statement, clone our statement now.
275 if (!mAsyncStatement
) {
276 nsDependentCString
sql(::sqlite3_sql(mDBStatement
));
277 int rc
= mDBConnection
->prepareStatement(mNativeConnection
, sql
,
279 if (rc
!= SQLITE_OK
) {
280 mDBConnection
->RecordQueryStatus(rc
);
285 MOZ_LOG(gStorageLog
, LogLevel::Debug
,
286 ("Cloned statement 0x%p to 0x%p", mDBStatement
, mAsyncStatement
));
289 *_stmt
= mAsyncStatement
;
293 nsresult
Statement::getAsynchronousStatementData(StatementData
& _data
) {
294 if (!mDBStatement
) return NS_ERROR_UNEXPECTED
;
297 int rc
= getAsyncStatement(&stmt
);
298 if (rc
!= SQLITE_OK
) return convertResultCode(rc
);
300 _data
= StatementData(stmt
, bindingParamsArray(), this);
305 already_AddRefed
<mozIStorageBindingParams
> Statement::newBindingParams(
306 mozIStorageBindingParamsArray
* aOwner
) {
307 nsCOMPtr
<mozIStorageBindingParams
> params
= new BindingParams(aOwner
, this);
308 return params
.forget();
311 ////////////////////////////////////////////////////////////////////////////////
312 //// mozIStorageStatement
314 // proxy to StorageBaseStatementInternal using its define helper.
315 MIXIN_IMPL_STORAGEBASESTATEMENTINTERNAL(Statement
, (void)0;)
318 Statement::Clone(mozIStorageStatement
** _statement
) {
319 RefPtr
<Statement
> statement(new Statement());
320 NS_ENSURE_TRUE(statement
, NS_ERROR_OUT_OF_MEMORY
);
322 nsAutoCString
sql(::sqlite3_sql(mDBStatement
));
323 nsresult rv
= statement
->initialize(mDBConnection
, mNativeConnection
, sql
);
324 NS_ENSURE_SUCCESS(rv
, rv
);
326 statement
.forget(_statement
);
331 Statement::Finalize() { return internalFinalize(false); }
333 nsresult
Statement::internalFinalize(bool aDestructing
) {
334 if (!mDBStatement
) return NS_OK
;
339 // If the statement ends up being finalized twice, the second finalization
340 // would apply to a dangling pointer and may cause unexpected consequences.
341 // Thus we must be sure that the connection state won't change during this
342 // operation, to avoid racing with finalizations made by the closing
343 // connection. See Connection::internalClose().
344 MutexAutoLock
lockedScope(mDBConnection
->sharedAsyncExecutionMutex
);
345 if (!mDBConnection
->isClosed(lockedScope
)) {
346 MOZ_LOG(gStorageLog
, LogLevel::Debug
,
347 ("Finalizing statement '%s' during garbage-collection",
348 ::sqlite3_sql(mDBStatement
)));
349 srv
= ::sqlite3_finalize(mDBStatement
);
353 // The database connection is closed. The sqlite
354 // statement has either been finalized already by the connection
355 // or is about to be finalized by the connection.
357 // Finalizing it here would be useless and segfaultish.
359 // Note that we can't display the statement itself, as the data structure
360 // is not valid anymore. However, the address shown here should help
361 // developers correlate with the more complete debug message triggered
364 SmprintfPointer msg
= ::mozilla::Smprintf(
365 "SQL statement (%p) should have been finalized"
366 " before garbage-collection. For more details on this statement, set"
367 " NSPR_LOG_MESSAGES=mozStorage:5 .",
369 NS_WARNING(msg
.get());
371 // Use %s so we aren't exposing random strings to printf interpolation.
372 MOZ_LOG(gStorageLog
, LogLevel::Warning
, ("%s", msg
.get()));
377 // This will be a no-op if the status has already been recorded or if this
378 // statement has not been executed. Async statements have their status
379 // tracked and recorded in StatementData.
380 MaybeRecordQueryStatus(srv
, true);
382 mDBStatement
= nullptr;
384 if (mAsyncStatement
) {
385 // If the destructor called us, there are no pending async statements (they
386 // hold a reference to us) and we can/must just kill the statement directly.
388 destructorAsyncFinalize();
393 // Release the holders, so they can release the reference to us.
394 mStatementParamsHolder
= nullptr;
395 mStatementRowHolder
= nullptr;
397 return convertResultCode(srv
);
401 Statement::GetParameterCount(uint32_t* _parameterCount
) {
402 if (!mDBStatement
) return NS_ERROR_NOT_INITIALIZED
;
404 *_parameterCount
= mParamCount
;
409 Statement::GetParameterName(uint32_t aParamIndex
, nsACString
& _name
) {
410 if (!mDBStatement
) return NS_ERROR_NOT_INITIALIZED
;
411 ENSURE_INDEX_VALUE(aParamIndex
, mParamCount
);
414 ::sqlite3_bind_parameter_name(mDBStatement
, aParamIndex
+ 1);
415 if (name
== nullptr) {
416 // this thing had no name, so fake one
417 nsAutoCString
fakeName(":");
418 fakeName
.AppendInt(aParamIndex
);
419 _name
.Assign(fakeName
);
421 _name
.Assign(nsDependentCString(name
));
428 Statement::GetParameterIndex(const nsACString
& aName
, uint32_t* _index
) {
429 if (!mDBStatement
) return NS_ERROR_NOT_INITIALIZED
;
431 // We do not accept any forms of names other than ":name", but we need to add
432 // the colon for SQLite.
433 nsAutoCString
name(":");
435 int ind
= ::sqlite3_bind_parameter_index(mDBStatement
, name
.get());
436 if (ind
== 0) // Named parameter not found.
437 return NS_ERROR_INVALID_ARG
;
439 *_index
= ind
- 1; // SQLite indexes are 1-based, we are 0-based.
445 Statement::GetColumnCount(uint32_t* _columnCount
) {
446 if (!mDBStatement
) return NS_ERROR_NOT_INITIALIZED
;
448 *_columnCount
= mResultColumnCount
;
453 Statement::GetColumnName(uint32_t aColumnIndex
, nsACString
& _name
) {
454 if (!mDBStatement
) return NS_ERROR_NOT_INITIALIZED
;
455 ENSURE_INDEX_VALUE(aColumnIndex
, mResultColumnCount
);
457 const char* cname
= ::sqlite3_column_name(mDBStatement
, aColumnIndex
);
458 _name
.Assign(nsDependentCString(cname
));
464 Statement::GetColumnIndex(const nsACString
& aName
, uint32_t* _index
) {
465 if (!mDBStatement
) return NS_ERROR_NOT_INITIALIZED
;
467 // Surprisingly enough, SQLite doesn't provide an API for this. We have to
468 // determine it ourselves sadly.
469 for (uint32_t i
= 0; i
< mResultColumnCount
; i
++) {
470 if (mColumnNames
[i
].Equals(aName
)) {
476 return NS_ERROR_INVALID_ARG
;
481 if (!mDBStatement
) return NS_ERROR_NOT_INITIALIZED
;
484 MOZ_LOG(gStorageLog
, LogLevel::Debug
,
485 ("Resetting statement: '%s'", ::sqlite3_sql(mDBStatement
)));
487 checkAndLogStatementPerformance(mDBStatement
);
490 mParamsArray
= nullptr;
491 (void)sqlite3_reset(mDBStatement
);
492 (void)sqlite3_clear_bindings(mDBStatement
);
496 // This will be a no-op if the status has already been recorded or if this
497 // statement has not been executed. Async statements have their status
498 // tracked and recorded in StatementData.
499 MaybeRecordQueryStatus(SQLITE_OK
, true);
500 mHasExecuted
= false;
506 Statement::BindParameters(mozIStorageBindingParamsArray
* aParameters
) {
507 NS_ENSURE_ARG_POINTER(aParameters
);
509 if (!mDBStatement
) return NS_ERROR_NOT_INITIALIZED
;
511 BindingParamsArray
* array
= static_cast<BindingParamsArray
*>(aParameters
);
512 if (array
->getOwner() != this) return NS_ERROR_UNEXPECTED
;
514 if (array
->length() == 0) return NS_ERROR_UNEXPECTED
;
516 mParamsArray
= array
;
517 mParamsArray
->lock();
523 Statement::Execute() {
524 if (!mDBStatement
) return NS_ERROR_NOT_INITIALIZED
;
527 nsresult rv
= ExecuteStep(&ret
);
528 nsresult rv2
= Reset();
530 return NS_FAILED(rv
) ? rv
: rv2
;
534 Statement::ExecuteStep(bool* _moreResults
) {
535 AUTO_PROFILER_LABEL("Statement::ExecuteStep", OTHER
);
537 if (!mDBStatement
) return NS_ERROR_NOT_INITIALIZED
;
539 // Bind any parameters first before executing.
541 // If we have more than one row of parameters to bind, they shouldn't be
542 // calling this method (and instead use executeAsync).
543 if (mParamsArray
->length() != 1) return NS_ERROR_UNEXPECTED
;
545 BindingParamsArray::iterator row
= mParamsArray
->begin();
546 nsCOMPtr
<IStorageBindingParamsInternal
> bindingInternal
=
547 do_QueryInterface(*row
);
548 nsCOMPtr
<mozIStorageError
> error
= bindingInternal
->bind(mDBStatement
);
551 (void)error
->GetResult(&srv
);
552 return convertResultCode(srv
);
555 // We have bound, so now we can clear our array.
556 mParamsArray
= nullptr;
558 int srv
= mDBConnection
->stepStatement(mNativeConnection
, mDBStatement
);
560 MaybeRecordQueryStatus(srv
);
562 if (srv
!= SQLITE_ROW
&& srv
!= SQLITE_DONE
&&
563 MOZ_LOG_TEST(gStorageLog
, LogLevel::Debug
)) {
564 nsAutoCString errStr
;
565 (void)mDBConnection
->GetLastErrorString(errStr
);
566 MOZ_LOG(gStorageLog
, LogLevel::Debug
,
567 ("Statement::ExecuteStep error: %s", errStr
.get()));
570 // SQLITE_ROW and SQLITE_DONE are non-errors
571 if (srv
== SQLITE_ROW
) {
574 *_moreResults
= true;
576 } else if (srv
== SQLITE_DONE
) {
577 // statement is done (no row returned)
579 *_moreResults
= false;
581 } else if (srv
== SQLITE_BUSY
|| srv
== SQLITE_MISUSE
) {
583 } else if (mExecuting
) {
584 MOZ_LOG(gStorageLog
, LogLevel::Error
,
585 ("SQLite error after mExecuting was true!"));
589 return convertResultCode(srv
);
593 Statement::GetState(int32_t* _state
) {
595 *_state
= MOZ_STORAGE_STATEMENT_INVALID
;
597 *_state
= MOZ_STORAGE_STATEMENT_EXECUTING
;
599 *_state
= MOZ_STORAGE_STATEMENT_READY
;
604 ////////////////////////////////////////////////////////////////////////////////
605 //// mozIStorageValueArray (now part of mozIStorageStatement too)
608 Statement::GetNumEntries(uint32_t* _length
) {
609 *_length
= mResultColumnCount
;
614 Statement::GetTypeOfIndex(uint32_t aIndex
, int32_t* _type
) {
615 if (!mDBStatement
) return NS_ERROR_NOT_INITIALIZED
;
617 ENSURE_INDEX_VALUE(aIndex
, mResultColumnCount
);
619 if (!mExecuting
) return NS_ERROR_UNEXPECTED
;
621 int t
= ::sqlite3_column_type(mDBStatement
, aIndex
);
624 *_type
= mozIStorageStatement::VALUE_TYPE_INTEGER
;
627 *_type
= mozIStorageStatement::VALUE_TYPE_FLOAT
;
630 *_type
= mozIStorageStatement::VALUE_TYPE_TEXT
;
633 *_type
= mozIStorageStatement::VALUE_TYPE_BLOB
;
636 *_type
= mozIStorageStatement::VALUE_TYPE_NULL
;
639 return NS_ERROR_FAILURE
;
646 Statement::GetInt32(uint32_t aIndex
, int32_t* _value
) {
647 if (!mDBStatement
) return NS_ERROR_NOT_INITIALIZED
;
649 ENSURE_INDEX_VALUE(aIndex
, mResultColumnCount
);
651 if (!mExecuting
) return NS_ERROR_UNEXPECTED
;
653 *_value
= ::sqlite3_column_int(mDBStatement
, aIndex
);
658 Statement::GetInt64(uint32_t aIndex
, int64_t* _value
) {
659 if (!mDBStatement
) return NS_ERROR_NOT_INITIALIZED
;
661 ENSURE_INDEX_VALUE(aIndex
, mResultColumnCount
);
663 if (!mExecuting
) return NS_ERROR_UNEXPECTED
;
665 *_value
= ::sqlite3_column_int64(mDBStatement
, aIndex
);
671 Statement::GetDouble(uint32_t aIndex
, double* _value
) {
672 if (!mDBStatement
) return NS_ERROR_NOT_INITIALIZED
;
674 ENSURE_INDEX_VALUE(aIndex
, mResultColumnCount
);
676 if (!mExecuting
) return NS_ERROR_UNEXPECTED
;
678 *_value
= ::sqlite3_column_double(mDBStatement
, aIndex
);
684 Statement::GetUTF8String(uint32_t aIndex
, nsACString
& _value
) {
685 // Get type of Index will check aIndex for us, so we don't have to.
687 nsresult rv
= GetTypeOfIndex(aIndex
, &type
);
688 NS_ENSURE_SUCCESS(rv
, rv
);
689 if (type
== mozIStorageStatement::VALUE_TYPE_NULL
) {
690 // NULL columns should have IsVoid set to distinguish them from the empty
692 _value
.SetIsVoid(true);
694 const char* value
= reinterpret_cast<const char*>(
695 ::sqlite3_column_text(mDBStatement
, aIndex
));
696 _value
.Assign(value
, ::sqlite3_column_bytes(mDBStatement
, aIndex
));
702 Statement::GetString(uint32_t aIndex
, nsAString
& _value
) {
703 // Get type of Index will check aIndex for us, so we don't have to.
705 nsresult rv
= GetTypeOfIndex(aIndex
, &type
);
706 NS_ENSURE_SUCCESS(rv
, rv
);
707 if (type
== mozIStorageStatement::VALUE_TYPE_NULL
) {
708 // NULL columns should have IsVoid set to distinguish them from the empty
710 _value
.SetIsVoid(true);
712 const char16_t
* value
= static_cast<const char16_t
*>(
713 ::sqlite3_column_text16(mDBStatement
, aIndex
));
714 _value
.Assign(value
, ::sqlite3_column_bytes16(mDBStatement
, aIndex
) /
721 Statement::GetVariant(uint32_t aIndex
, nsIVariant
** _value
) {
723 return NS_ERROR_NOT_INITIALIZED
;
726 ENSURE_INDEX_VALUE(aIndex
, mResultColumnCount
);
729 return NS_ERROR_UNEXPECTED
;
732 nsCOMPtr
<nsIVariant
> variant
;
733 int type
= ::sqlite3_column_type(mDBStatement
, aIndex
);
737 new IntegerVariant(::sqlite3_column_int64(mDBStatement
, aIndex
));
740 variant
= new FloatVariant(::sqlite3_column_double(mDBStatement
, aIndex
));
743 const char16_t
* value
= static_cast<const char16_t
*>(
744 ::sqlite3_column_text16(mDBStatement
, aIndex
));
745 nsDependentString
str(
747 ::sqlite3_column_bytes16(mDBStatement
, aIndex
) / sizeof(char16_t
));
748 variant
= new TextVariant(str
);
752 variant
= new NullVariant();
755 int size
= ::sqlite3_column_bytes(mDBStatement
, aIndex
);
756 const void* data
= ::sqlite3_column_blob(mDBStatement
, aIndex
);
757 variant
= new BlobVariant(std::pair
<const void*, int>(data
, size
));
761 NS_ENSURE_TRUE(variant
, NS_ERROR_UNEXPECTED
);
763 variant
.forget(_value
);
768 Statement::GetBlob(uint32_t aIndex
, uint32_t* _size
, uint8_t** _blob
) {
769 if (!mDBStatement
) return NS_ERROR_NOT_INITIALIZED
;
771 ENSURE_INDEX_VALUE(aIndex
, mResultColumnCount
);
773 if (!mExecuting
) return NS_ERROR_UNEXPECTED
;
775 int size
= ::sqlite3_column_bytes(mDBStatement
, aIndex
);
776 void* blob
= nullptr;
778 blob
= moz_xmemdup(::sqlite3_column_blob(mDBStatement
, aIndex
), size
);
781 *_blob
= static_cast<uint8_t*>(blob
);
787 Statement::GetBlobAsString(uint32_t aIndex
, nsAString
& aValue
) {
788 return DoGetBlobAsString(this, aIndex
, aValue
);
792 Statement::GetBlobAsUTF8String(uint32_t aIndex
, nsACString
& aValue
) {
793 return DoGetBlobAsString(this, aIndex
, aValue
);
797 Statement::GetSharedUTF8String(uint32_t aIndex
, uint32_t* _byteLength
,
798 const char** _value
) {
799 *_value
= reinterpret_cast<const char*>(
800 ::sqlite3_column_text(mDBStatement
, aIndex
));
802 *_byteLength
= ::sqlite3_column_bytes(mDBStatement
, aIndex
);
808 Statement::GetSharedString(uint32_t aIndex
, uint32_t* _byteLength
,
809 const char16_t
** _value
) {
810 *_value
= static_cast<const char16_t
*>(
811 ::sqlite3_column_text16(mDBStatement
, aIndex
));
813 *_byteLength
= ::sqlite3_column_bytes16(mDBStatement
, aIndex
);
819 Statement::GetSharedBlob(uint32_t aIndex
, uint32_t* _byteLength
,
820 const uint8_t** _blob
) {
822 static_cast<const uint8_t*>(::sqlite3_column_blob(mDBStatement
, aIndex
));
824 *_byteLength
= ::sqlite3_column_bytes(mDBStatement
, aIndex
);
830 Statement::GetIsNull(uint32_t aIndex
, bool* _isNull
) {
831 // Get type of Index will check aIndex for us, so we don't have to.
833 nsresult rv
= GetTypeOfIndex(aIndex
, &type
);
834 NS_ENSURE_SUCCESS(rv
, rv
);
835 *_isNull
= (type
== mozIStorageStatement::VALUE_TYPE_NULL
);
839 ////////////////////////////////////////////////////////////////////////////////
840 //// mozIStorageBindingParams
842 BOILERPLATE_BIND_PROXIES(Statement
,
843 if (!mDBStatement
) return NS_ERROR_NOT_INITIALIZED
;)
845 } // namespace storage
846 } // namespace mozilla