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() {}
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 : StorageBaseStatementInternal(),
103 mDBStatement(nullptr),
105 mResultColumnCount(0),
108 mQueryStatusRecorded(false),
109 mHasExecuted(false) {}
111 nsresult
Statement::initialize(Connection
* aDBConnection
,
112 sqlite3
* aNativeConnection
,
113 const nsACString
& aSQLStatement
) {
114 MOZ_ASSERT(aDBConnection
, "No database connection given!");
115 MOZ_ASSERT(aDBConnection
->isConnectionReadyOnThisThread(),
116 "Database connection should be valid");
117 MOZ_ASSERT(!mDBStatement
, "Statement already initialized!");
118 MOZ_ASSERT(aNativeConnection
, "No native connection given!");
120 int srv
= aDBConnection
->prepareStatement(
121 aNativeConnection
, PromiseFlatCString(aSQLStatement
), &mDBStatement
);
122 if (srv
!= SQLITE_OK
) {
123 MOZ_LOG(gStorageLog
, LogLevel::Error
,
124 ("Sqlite statement prepare error: %d '%s'", srv
,
125 ::sqlite3_errmsg(aNativeConnection
)));
126 MOZ_LOG(gStorageLog
, LogLevel::Error
,
127 ("Statement was: '%s'", PromiseFlatCString(aSQLStatement
).get()));
129 aDBConnection
->RecordQueryStatus(srv
);
130 mQueryStatusRecorded
= true;
131 return convertResultCode(srv
);
134 MOZ_LOG(gStorageLog
, LogLevel::Debug
,
135 ("Initialized statement '%s' (0x%p)",
136 PromiseFlatCString(aSQLStatement
).get(), mDBStatement
));
138 mDBConnection
= aDBConnection
;
139 mNativeConnection
= aNativeConnection
;
140 mParamCount
= ::sqlite3_bind_parameter_count(mDBStatement
);
141 mResultColumnCount
= ::sqlite3_column_count(mDBStatement
);
142 mColumnNames
.Clear();
144 nsCString
* columnNames
= mColumnNames
.AppendElements(mResultColumnCount
);
145 for (uint32_t i
= 0; i
< mResultColumnCount
; i
++) {
146 const char* name
= ::sqlite3_column_name(mDBStatement
, i
);
147 columnNames
[i
].Assign(name
);
151 // We want to try and test for LIKE and that consumers are using
152 // escapeStringForLIKE instead of just trusting user input. The idea to
153 // check to see if they are binding a parameter after like instead of just
154 // using a string. We only do this in debug builds because it's expensive!
155 auto c
= nsCaseInsensitiveCStringComparator
;
156 nsACString::const_iterator start
, end
, e
;
157 aSQLStatement
.BeginReading(start
);
158 aSQLStatement
.EndReading(end
);
160 while (::FindInReadable(" LIKE"_ns
, start
, e
, c
)) {
161 // We have a LIKE in here, so we perform our tests
162 // FindInReadable moves the iterator, so we have to get a new one for
163 // each test we perform.
164 nsACString::const_iterator s1
, s2
, s3
;
165 s1
= s2
= s3
= start
;
167 if (!(::FindInReadable(" LIKE ?"_ns
, s1
, end
, c
) ||
168 ::FindInReadable(" LIKE :"_ns
, s2
, end
, c
) ||
169 ::FindInReadable(" LIKE @"_ns
, s3
, end
, c
))) {
170 // At this point, we didn't find a LIKE statement followed by ?, :,
171 // or @, all of which are valid characters for binding a parameter.
172 // We will warn the consumer that they may not be safely using LIKE.
174 "Unsafe use of LIKE detected! Please ensure that you "
175 "are using mozIStorageStatement::escapeStringForLIKE "
176 "and that you are binding that result to the statement "
177 "to prevent SQL injection attacks.");
180 // resetting start and e
189 mozIStorageBindingParams
* Statement::getParams() {
192 // If we do not have an array object yet, make it.
194 nsCOMPtr
<mozIStorageBindingParamsArray
> array
;
195 rv
= NewBindingParamsArray(getter_AddRefs(array
));
196 NS_ENSURE_SUCCESS(rv
, nullptr);
198 mParamsArray
= static_cast<BindingParamsArray
*>(array
.get());
201 // If there isn't already any rows added, we'll have to add one to use.
202 if (mParamsArray
->length() == 0) {
203 RefPtr
<BindingParams
> params(new BindingParams(mParamsArray
, this));
204 NS_ENSURE_TRUE(params
, nullptr);
206 rv
= mParamsArray
->AddParams(params
);
207 NS_ENSURE_SUCCESS(rv
, nullptr);
209 // We have to unlock our params because AddParams locks them. This is safe
210 // because no reference to the params object was, or ever will be given out.
211 params
->unlock(this);
213 // We also want to lock our array at this point - we don't want anything to
214 // be added to it. Nothing has, or will ever get a reference to it, but we
215 // will get additional safety checks via assertions by doing this.
216 mParamsArray
->lock();
219 return *mParamsArray
->begin();
222 void Statement::MaybeRecordQueryStatus(int srv
, bool isResetting
) {
223 // If the statement hasn't been executed synchronously since it was last reset
224 // or created then there is no need to record anything. Asynchronous
225 // statements have their status tracked and recorded by StatementData.
230 if (!isResetting
&& !isErrorCode(srv
)) {
231 // Non-errors will be recorded when finalizing.
235 // We only record a status if no status has been recorded previously.
236 if (!mQueryStatusRecorded
&& mDBConnection
) {
237 mDBConnection
->RecordQueryStatus(srv
);
240 // Allow another status to be recorded if we are resetting this statement.
241 mQueryStatusRecorded
= !isResetting
;
244 Statement::~Statement() { (void)internalFinalize(true); }
246 ////////////////////////////////////////////////////////////////////////////////
249 NS_IMPL_ADDREF(Statement
)
250 NS_IMPL_RELEASE(Statement
)
252 NS_INTERFACE_MAP_BEGIN(Statement
)
253 NS_INTERFACE_MAP_ENTRY(mozIStorageStatement
)
254 NS_INTERFACE_MAP_ENTRY(mozIStorageBaseStatement
)
255 NS_INTERFACE_MAP_ENTRY(mozIStorageBindingParams
)
256 NS_INTERFACE_MAP_ENTRY(mozIStorageValueArray
)
257 NS_INTERFACE_MAP_ENTRY(mozilla::storage::StorageBaseStatementInternal
)
258 if (aIID
.Equals(NS_GET_IID(nsIClassInfo
))) {
259 foundInterface
= static_cast<nsIClassInfo
*>(&sStatementClassInfo
);
261 NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports
, mozIStorageStatement
)
264 ////////////////////////////////////////////////////////////////////////////////
265 //// StorageBaseStatementInternal
267 Connection
* Statement::getOwner() { return mDBConnection
; }
269 int Statement::getAsyncStatement(sqlite3_stmt
** _stmt
) {
270 // If we have no statement, we shouldn't be calling this method!
271 NS_ASSERTION(mDBStatement
!= nullptr, "We have no statement to clone!");
273 // If we do not yet have a cached async statement, clone our statement now.
274 if (!mAsyncStatement
) {
275 nsDependentCString
sql(::sqlite3_sql(mDBStatement
));
276 int rc
= mDBConnection
->prepareStatement(mNativeConnection
, sql
,
278 if (rc
!= SQLITE_OK
) {
279 mDBConnection
->RecordQueryStatus(rc
);
284 MOZ_LOG(gStorageLog
, LogLevel::Debug
,
285 ("Cloned statement 0x%p to 0x%p", mDBStatement
, mAsyncStatement
));
288 *_stmt
= mAsyncStatement
;
292 nsresult
Statement::getAsynchronousStatementData(StatementData
& _data
) {
293 if (!mDBStatement
) return NS_ERROR_UNEXPECTED
;
296 int rc
= getAsyncStatement(&stmt
);
297 if (rc
!= SQLITE_OK
) return convertResultCode(rc
);
299 _data
= StatementData(stmt
, bindingParamsArray(), this);
304 already_AddRefed
<mozIStorageBindingParams
> Statement::newBindingParams(
305 mozIStorageBindingParamsArray
* aOwner
) {
306 nsCOMPtr
<mozIStorageBindingParams
> params
= new BindingParams(aOwner
, this);
307 return params
.forget();
310 ////////////////////////////////////////////////////////////////////////////////
311 //// mozIStorageStatement
313 // proxy to StorageBaseStatementInternal using its define helper.
314 MIXIN_IMPL_STORAGEBASESTATEMENTINTERNAL(Statement
, (void)0;)
317 Statement::Clone(mozIStorageStatement
** _statement
) {
318 RefPtr
<Statement
> statement(new Statement());
319 NS_ENSURE_TRUE(statement
, NS_ERROR_OUT_OF_MEMORY
);
321 nsAutoCString
sql(::sqlite3_sql(mDBStatement
));
322 nsresult rv
= statement
->initialize(mDBConnection
, mNativeConnection
, sql
);
323 NS_ENSURE_SUCCESS(rv
, rv
);
325 statement
.forget(_statement
);
330 Statement::Finalize() { return internalFinalize(false); }
332 nsresult
Statement::internalFinalize(bool aDestructing
) {
333 if (!mDBStatement
) return NS_OK
;
338 // If the statement ends up being finalized twice, the second finalization
339 // would apply to a dangling pointer and may cause unexpected consequences.
340 // Thus we must be sure that the connection state won't change during this
341 // operation, to avoid racing with finalizations made by the closing
342 // connection. See Connection::internalClose().
343 MutexAutoLock
lockedScope(mDBConnection
->sharedAsyncExecutionMutex
);
344 if (!mDBConnection
->isClosed(lockedScope
)) {
345 MOZ_LOG(gStorageLog
, LogLevel::Debug
,
346 ("Finalizing statement '%s' during garbage-collection",
347 ::sqlite3_sql(mDBStatement
)));
348 srv
= ::sqlite3_finalize(mDBStatement
);
352 // The database connection is closed. The sqlite
353 // statement has either been finalized already by the connection
354 // or is about to be finalized by the connection.
356 // Finalizing it here would be useless and segfaultish.
358 // Note that we can't display the statement itself, as the data structure
359 // is not valid anymore. However, the address shown here should help
360 // developers correlate with the more complete debug message triggered
363 SmprintfPointer msg
= ::mozilla::Smprintf(
364 "SQL statement (%p) should have been finalized"
365 " before garbage-collection. For more details on this statement, set"
366 " NSPR_LOG_MESSAGES=mozStorage:5 .",
368 NS_WARNING(msg
.get());
370 // Use %s so we aren't exposing random strings to printf interpolation.
371 MOZ_LOG(gStorageLog
, LogLevel::Warning
, ("%s", msg
.get()));
376 // This will be a no-op if the status has already been recorded or if this
377 // statement has not been executed. Async statements have their status
378 // tracked and recorded in StatementData.
379 MaybeRecordQueryStatus(srv
, true);
381 mDBStatement
= nullptr;
383 if (mAsyncStatement
) {
384 // If the destructor called us, there are no pending async statements (they
385 // hold a reference to us) and we can/must just kill the statement directly.
387 destructorAsyncFinalize();
392 // Release the holders, so they can release the reference to us.
393 mStatementParamsHolder
= nullptr;
394 mStatementRowHolder
= nullptr;
396 return convertResultCode(srv
);
400 Statement::GetParameterCount(uint32_t* _parameterCount
) {
401 if (!mDBStatement
) return NS_ERROR_NOT_INITIALIZED
;
403 *_parameterCount
= mParamCount
;
408 Statement::GetParameterName(uint32_t aParamIndex
, nsACString
& _name
) {
409 if (!mDBStatement
) return NS_ERROR_NOT_INITIALIZED
;
410 ENSURE_INDEX_VALUE(aParamIndex
, mParamCount
);
413 ::sqlite3_bind_parameter_name(mDBStatement
, aParamIndex
+ 1);
414 if (name
== nullptr) {
415 // this thing had no name, so fake one
416 nsAutoCString
fakeName(":");
417 fakeName
.AppendInt(aParamIndex
);
418 _name
.Assign(fakeName
);
420 _name
.Assign(nsDependentCString(name
));
427 Statement::GetParameterIndex(const nsACString
& aName
, uint32_t* _index
) {
428 if (!mDBStatement
) return NS_ERROR_NOT_INITIALIZED
;
430 // We do not accept any forms of names other than ":name", but we need to add
431 // the colon for SQLite.
432 nsAutoCString
name(":");
434 int ind
= ::sqlite3_bind_parameter_index(mDBStatement
, name
.get());
435 if (ind
== 0) // Named parameter not found.
436 return NS_ERROR_INVALID_ARG
;
438 *_index
= ind
- 1; // SQLite indexes are 1-based, we are 0-based.
444 Statement::GetColumnCount(uint32_t* _columnCount
) {
445 if (!mDBStatement
) return NS_ERROR_NOT_INITIALIZED
;
447 *_columnCount
= mResultColumnCount
;
452 Statement::GetColumnName(uint32_t aColumnIndex
, nsACString
& _name
) {
453 if (!mDBStatement
) return NS_ERROR_NOT_INITIALIZED
;
454 ENSURE_INDEX_VALUE(aColumnIndex
, mResultColumnCount
);
456 const char* cname
= ::sqlite3_column_name(mDBStatement
, aColumnIndex
);
457 _name
.Assign(nsDependentCString(cname
));
463 Statement::GetColumnIndex(const nsACString
& aName
, uint32_t* _index
) {
464 if (!mDBStatement
) return NS_ERROR_NOT_INITIALIZED
;
466 // Surprisingly enough, SQLite doesn't provide an API for this. We have to
467 // determine it ourselves sadly.
468 for (uint32_t i
= 0; i
< mResultColumnCount
; i
++) {
469 if (mColumnNames
[i
].Equals(aName
)) {
475 return NS_ERROR_INVALID_ARG
;
480 if (!mDBStatement
) return NS_ERROR_NOT_INITIALIZED
;
483 MOZ_LOG(gStorageLog
, LogLevel::Debug
,
484 ("Resetting statement: '%s'", ::sqlite3_sql(mDBStatement
)));
486 checkAndLogStatementPerformance(mDBStatement
);
489 mParamsArray
= nullptr;
490 (void)sqlite3_reset(mDBStatement
);
491 (void)sqlite3_clear_bindings(mDBStatement
);
495 // This will be a no-op if the status has already been recorded or if this
496 // statement has not been executed. Async statements have their status
497 // tracked and recorded in StatementData.
498 MaybeRecordQueryStatus(SQLITE_OK
, true);
499 mHasExecuted
= false;
505 Statement::BindParameters(mozIStorageBindingParamsArray
* aParameters
) {
506 NS_ENSURE_ARG_POINTER(aParameters
);
508 if (!mDBStatement
) return NS_ERROR_NOT_INITIALIZED
;
510 BindingParamsArray
* array
= static_cast<BindingParamsArray
*>(aParameters
);
511 if (array
->getOwner() != this) return NS_ERROR_UNEXPECTED
;
513 if (array
->length() == 0) return NS_ERROR_UNEXPECTED
;
515 mParamsArray
= array
;
516 mParamsArray
->lock();
522 Statement::Execute() {
523 if (!mDBStatement
) return NS_ERROR_NOT_INITIALIZED
;
526 nsresult rv
= ExecuteStep(&ret
);
527 nsresult rv2
= Reset();
529 return NS_FAILED(rv
) ? rv
: rv2
;
533 Statement::ExecuteStep(bool* _moreResults
) {
534 AUTO_PROFILER_LABEL("Statement::ExecuteStep", OTHER
);
536 if (!mDBStatement
) return NS_ERROR_NOT_INITIALIZED
;
538 // Bind any parameters first before executing.
540 // If we have more than one row of parameters to bind, they shouldn't be
541 // calling this method (and instead use executeAsync).
542 if (mParamsArray
->length() != 1) return NS_ERROR_UNEXPECTED
;
544 BindingParamsArray::iterator row
= mParamsArray
->begin();
545 nsCOMPtr
<IStorageBindingParamsInternal
> bindingInternal
=
546 do_QueryInterface(*row
);
547 nsCOMPtr
<mozIStorageError
> error
= bindingInternal
->bind(mDBStatement
);
550 (void)error
->GetResult(&srv
);
551 return convertResultCode(srv
);
554 // We have bound, so now we can clear our array.
555 mParamsArray
= nullptr;
557 int srv
= mDBConnection
->stepStatement(mNativeConnection
, mDBStatement
);
559 MaybeRecordQueryStatus(srv
);
561 if (srv
!= SQLITE_ROW
&& srv
!= SQLITE_DONE
&&
562 MOZ_LOG_TEST(gStorageLog
, LogLevel::Debug
)) {
563 nsAutoCString errStr
;
564 (void)mDBConnection
->GetLastErrorString(errStr
);
565 MOZ_LOG(gStorageLog
, LogLevel::Debug
,
566 ("Statement::ExecuteStep error: %s", errStr
.get()));
569 // SQLITE_ROW and SQLITE_DONE are non-errors
570 if (srv
== SQLITE_ROW
) {
573 *_moreResults
= true;
575 } else if (srv
== SQLITE_DONE
) {
576 // statement is done (no row returned)
578 *_moreResults
= false;
580 } else if (srv
== SQLITE_BUSY
|| srv
== SQLITE_MISUSE
) {
582 } else if (mExecuting
) {
583 MOZ_LOG(gStorageLog
, LogLevel::Error
,
584 ("SQLite error after mExecuting was true!"));
588 return convertResultCode(srv
);
592 Statement::GetState(int32_t* _state
) {
594 *_state
= MOZ_STORAGE_STATEMENT_INVALID
;
596 *_state
= MOZ_STORAGE_STATEMENT_EXECUTING
;
598 *_state
= MOZ_STORAGE_STATEMENT_READY
;
603 ////////////////////////////////////////////////////////////////////////////////
604 //// mozIStorageValueArray (now part of mozIStorageStatement too)
607 Statement::GetNumEntries(uint32_t* _length
) {
608 *_length
= mResultColumnCount
;
613 Statement::GetTypeOfIndex(uint32_t aIndex
, int32_t* _type
) {
614 if (!mDBStatement
) return NS_ERROR_NOT_INITIALIZED
;
616 ENSURE_INDEX_VALUE(aIndex
, mResultColumnCount
);
618 if (!mExecuting
) return NS_ERROR_UNEXPECTED
;
620 int t
= ::sqlite3_column_type(mDBStatement
, aIndex
);
623 *_type
= mozIStorageStatement::VALUE_TYPE_INTEGER
;
626 *_type
= mozIStorageStatement::VALUE_TYPE_FLOAT
;
629 *_type
= mozIStorageStatement::VALUE_TYPE_TEXT
;
632 *_type
= mozIStorageStatement::VALUE_TYPE_BLOB
;
635 *_type
= mozIStorageStatement::VALUE_TYPE_NULL
;
638 return NS_ERROR_FAILURE
;
645 Statement::GetInt32(uint32_t aIndex
, int32_t* _value
) {
646 if (!mDBStatement
) return NS_ERROR_NOT_INITIALIZED
;
648 ENSURE_INDEX_VALUE(aIndex
, mResultColumnCount
);
650 if (!mExecuting
) return NS_ERROR_UNEXPECTED
;
652 *_value
= ::sqlite3_column_int(mDBStatement
, aIndex
);
657 Statement::GetInt64(uint32_t aIndex
, int64_t* _value
) {
658 if (!mDBStatement
) return NS_ERROR_NOT_INITIALIZED
;
660 ENSURE_INDEX_VALUE(aIndex
, mResultColumnCount
);
662 if (!mExecuting
) return NS_ERROR_UNEXPECTED
;
664 *_value
= ::sqlite3_column_int64(mDBStatement
, aIndex
);
670 Statement::GetDouble(uint32_t aIndex
, double* _value
) {
671 if (!mDBStatement
) return NS_ERROR_NOT_INITIALIZED
;
673 ENSURE_INDEX_VALUE(aIndex
, mResultColumnCount
);
675 if (!mExecuting
) return NS_ERROR_UNEXPECTED
;
677 *_value
= ::sqlite3_column_double(mDBStatement
, aIndex
);
683 Statement::GetUTF8String(uint32_t aIndex
, nsACString
& _value
) {
684 // Get type of Index will check aIndex for us, so we don't have to.
686 nsresult rv
= GetTypeOfIndex(aIndex
, &type
);
687 NS_ENSURE_SUCCESS(rv
, rv
);
688 if (type
== mozIStorageStatement::VALUE_TYPE_NULL
) {
689 // NULL columns should have IsVoid set to distinguish them from the empty
691 _value
.SetIsVoid(true);
693 const char* value
= reinterpret_cast<const char*>(
694 ::sqlite3_column_text(mDBStatement
, aIndex
));
695 _value
.Assign(value
, ::sqlite3_column_bytes(mDBStatement
, aIndex
));
701 Statement::GetString(uint32_t aIndex
, nsAString
& _value
) {
702 // Get type of Index will check aIndex for us, so we don't have to.
704 nsresult rv
= GetTypeOfIndex(aIndex
, &type
);
705 NS_ENSURE_SUCCESS(rv
, rv
);
706 if (type
== mozIStorageStatement::VALUE_TYPE_NULL
) {
707 // NULL columns should have IsVoid set to distinguish them from the empty
709 _value
.SetIsVoid(true);
711 const char16_t
* value
= static_cast<const char16_t
*>(
712 ::sqlite3_column_text16(mDBStatement
, aIndex
));
713 _value
.Assign(value
, ::sqlite3_column_bytes16(mDBStatement
, aIndex
) /
720 Statement::GetVariant(uint32_t aIndex
, nsIVariant
** _value
) {
722 return NS_ERROR_NOT_INITIALIZED
;
725 ENSURE_INDEX_VALUE(aIndex
, mResultColumnCount
);
728 return NS_ERROR_UNEXPECTED
;
731 nsCOMPtr
<nsIVariant
> variant
;
732 int type
= ::sqlite3_column_type(mDBStatement
, aIndex
);
736 new IntegerVariant(::sqlite3_column_int64(mDBStatement
, aIndex
));
739 variant
= new FloatVariant(::sqlite3_column_double(mDBStatement
, aIndex
));
742 const char16_t
* value
= static_cast<const char16_t
*>(
743 ::sqlite3_column_text16(mDBStatement
, aIndex
));
744 nsDependentString
str(
746 ::sqlite3_column_bytes16(mDBStatement
, aIndex
) / sizeof(char16_t
));
747 variant
= new TextVariant(str
);
751 variant
= new NullVariant();
754 int size
= ::sqlite3_column_bytes(mDBStatement
, aIndex
);
755 const void* data
= ::sqlite3_column_blob(mDBStatement
, aIndex
);
756 variant
= new BlobVariant(std::pair
<const void*, int>(data
, size
));
760 NS_ENSURE_TRUE(variant
, NS_ERROR_UNEXPECTED
);
762 variant
.forget(_value
);
767 Statement::GetBlob(uint32_t aIndex
, uint32_t* _size
, uint8_t** _blob
) {
768 if (!mDBStatement
) return NS_ERROR_NOT_INITIALIZED
;
770 ENSURE_INDEX_VALUE(aIndex
, mResultColumnCount
);
772 if (!mExecuting
) return NS_ERROR_UNEXPECTED
;
774 int size
= ::sqlite3_column_bytes(mDBStatement
, aIndex
);
775 void* blob
= nullptr;
777 blob
= moz_xmemdup(::sqlite3_column_blob(mDBStatement
, aIndex
), size
);
780 *_blob
= static_cast<uint8_t*>(blob
);
786 Statement::GetBlobAsString(uint32_t aIndex
, nsAString
& aValue
) {
787 return DoGetBlobAsString(this, aIndex
, aValue
);
791 Statement::GetBlobAsUTF8String(uint32_t aIndex
, nsACString
& aValue
) {
792 return DoGetBlobAsString(this, aIndex
, aValue
);
796 Statement::GetSharedUTF8String(uint32_t aIndex
, uint32_t* _byteLength
,
797 const char** _value
) {
798 *_value
= reinterpret_cast<const char*>(
799 ::sqlite3_column_text(mDBStatement
, aIndex
));
801 *_byteLength
= ::sqlite3_column_bytes(mDBStatement
, aIndex
);
807 Statement::GetSharedString(uint32_t aIndex
, uint32_t* _byteLength
,
808 const char16_t
** _value
) {
809 *_value
= static_cast<const char16_t
*>(
810 ::sqlite3_column_text16(mDBStatement
, aIndex
));
812 *_byteLength
= ::sqlite3_column_bytes16(mDBStatement
, aIndex
);
818 Statement::GetSharedBlob(uint32_t aIndex
, uint32_t* _byteLength
,
819 const uint8_t** _blob
) {
821 static_cast<const uint8_t*>(::sqlite3_column_blob(mDBStatement
, aIndex
));
823 *_byteLength
= ::sqlite3_column_bytes(mDBStatement
, aIndex
);
829 Statement::GetIsNull(uint32_t aIndex
, bool* _isNull
) {
830 // Get type of Index will check aIndex for us, so we don't have to.
832 nsresult rv
= GetTypeOfIndex(aIndex
, &type
);
833 NS_ENSURE_SUCCESS(rv
, rv
);
834 *_isNull
= (type
== mozIStorageStatement::VALUE_TYPE_NULL
);
838 ////////////////////////////////////////////////////////////////////////////////
839 //// mozIStorageBindingParams
841 BOILERPLATE_BIND_PROXIES(Statement
,
842 if (!mDBStatement
) return NS_ERROR_NOT_INITIALIZED
;)
844 } // namespace storage
845 } // namespace mozilla