1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2 * vim: sw=4 ts=4 sts=4 expandtab
3 * ***** BEGIN LICENSE BLOCK *****
4 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
6 * The contents of this file are subject to the Mozilla Public License Version
7 * 1.1 (the "License"); you may not use this file except in compliance with
8 * the License. You may obtain a copy of the License at
9 * http://www.mozilla.org/MPL/
11 * Software distributed under the License is distributed on an "AS IS" basis,
12 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
13 * for the specific language governing rights and limitations under the
16 * The Original Code is Oracle Corporation code.
18 * The Initial Developer of the Original Code is
20 * Portions created by the Initial Developer are Copyright (C) 2004
21 * the Initial Developer. All Rights Reserved.
24 * Vladimir Vukicevic <vladimir.vukicevic@oracle.com>
25 * Shawn Wilsher <me@shawnwilsher.com>
26 * John Zhang <jzhang@aptana.com>
28 * Alternatively, the contents of this file may be used under the terms of
29 * either the GNU General Public License Version 2 or later (the "GPL"), or
30 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
31 * in which case the provisions of the GPL or the LGPL are applicable instead
32 * of those above. If you wish to allow use of your version of this file only
33 * under the terms of either the GPL or the LGPL, and not to allow others to
34 * use your version of this file under the terms of the MPL, indicate your
35 * decision by deleting the provisions above and replace them with the notice
36 * and other provisions required by the GPL or the LGPL. If you do not delete
37 * the provisions above, a recipient may use your version of this file under
38 * the terms of any one of the MPL, the GPL or the LGPL.
40 * ***** END LICENSE BLOCK ***** */
44 #include "nsAutoLock.h"
46 #include "nsISimpleEnumerator.h"
48 #include "nsIClassInfoImpl.h"
49 #include "nsIProgrammingLanguage.h"
51 #include "mozStorageConnection.h"
52 #include "mozStorageStatement.h"
53 #include "mozStorageStatementJSHelper.h"
54 #include "mozStorageValueArray.h"
55 #include "mozStoragePrivateHelpers.h"
56 #include "mozStorageEvents.h"
57 #include "mozStorageStatementParams.h"
58 #include "mozStorageStatementRow.h"
63 extern PRLogModuleInfo
* gStorageLog
;
66 ////////////////////////////////////////////////////////////////////////////////
69 NS_IMPL_CI_INTERFACE_GETTER2(
71 , mozIStorageStatement
72 , mozIStorageValueArray
75 class mozStorageStatementClassInfo
: public nsIClassInfo
81 GetInterfaces(PRUint32
*_count
, nsIID
***_array
)
83 return NS_CI_INTERFACE_GETTER_NAME(mozStorageStatement
)(_count
, _array
);
87 GetHelperForLanguage(PRUint32 aLanguage
, nsISupports
**_helper
)
89 if (aLanguage
== nsIProgrammingLanguage::JAVASCRIPT
) {
90 static mozStorageStatementJSHelper sJSHelper
;
91 *_helper
= &sJSHelper
;
100 GetContractID(char **_contractID
)
102 *_contractID
= nsnull
;
107 GetClassDescription(char **_desc
)
114 GetClassID(nsCID
**_id
)
121 GetImplementationLanguage(PRUint32
*_language
)
123 *_language
= nsIProgrammingLanguage::CPLUSPLUS
;
128 GetFlags(PRUint32
*_flags
)
135 GetClassIDNoAlloc(nsCID
*_cid
)
137 return NS_ERROR_NOT_AVAILABLE
;
141 NS_IMETHODIMP_(nsrefcnt
) mozStorageStatementClassInfo::AddRef() { return 2; }
142 NS_IMETHODIMP_(nsrefcnt
) mozStorageStatementClassInfo::Release() { return 1; }
143 NS_IMPL_QUERY_INTERFACE1(mozStorageStatementClassInfo
, nsIClassInfo
)
145 static mozStorageStatementClassInfo sStatementClassInfo
;
148 ** mozStorageStatementRowEnumerator
150 class mozStorageStatementRowEnumerator
: public nsISimpleEnumerator
{
152 // this expects a statement that has NOT had step called on it yet
153 mozStorageStatementRowEnumerator (sqlite3_stmt
*aDBStatement
);
155 // nsISupports interface
158 // nsISimpleEnumerator interface
159 NS_DECL_NSISIMPLEENUMERATOR
162 ~mozStorageStatementRowEnumerator ();
164 sqlite3_stmt
*mDBStatement
;
173 ** mozStorageStatement
176 NS_IMPL_THREADSAFE_ADDREF(mozStorageStatement
)
177 NS_IMPL_THREADSAFE_RELEASE(mozStorageStatement
)
179 NS_INTERFACE_MAP_BEGIN(mozStorageStatement
)
180 NS_INTERFACE_MAP_ENTRY(mozIStorageStatement
)
181 NS_INTERFACE_MAP_ENTRY(mozIStorageValueArray
)
182 if (aIID
.Equals(NS_GET_IID(nsIClassInfo
))) {
183 foundInterface
= static_cast<nsIClassInfo
*>(&sStatementClassInfo
);
185 NS_INTERFACE_MAP_ENTRY(nsISupports
)
188 mozStorageStatement::mozStorageStatement()
189 : mDBConnection (nsnull
), mDBStatement(nsnull
), mColumnNames(nsnull
), mExecuting(PR_FALSE
)
194 mozStorageStatement::Initialize(mozStorageConnection
*aDBConnection
,
195 const nsACString
& aSQLStatement
)
197 NS_ASSERTION(aDBConnection
, "No database connection given!");
198 NS_ASSERTION(!mDBStatement
, "Calling Initialize on an already initialized statement!");
201 PR_LOG(gStorageLog
, PR_LOG_NOTICE
, ("Initializing statement '%s'",
202 nsPromiseFlatCString(aSQLStatement
).get()));
205 sqlite3
*db
= aDBConnection
->GetNativeConnection();
206 NS_ENSURE_TRUE(db
!= nsnull
, NS_ERROR_NULL_POINTER
);
208 int srv
= sqlite3_prepare_v2(db
, PromiseFlatCString(aSQLStatement
).get(),
209 -1, &mDBStatement
, NULL
);
210 if (srv
!= SQLITE_OK
) {
212 PR_LOG(gStorageLog
, PR_LOG_ERROR
, ("Sqlite statement prepare error: %d '%s'", srv
, sqlite3_errmsg(db
)));
213 PR_LOG(gStorageLog
, PR_LOG_ERROR
, ("Statement was: '%s'", nsPromiseFlatCString(aSQLStatement
).get()));
215 return NS_ERROR_FAILURE
;
218 mDBConnection
= aDBConnection
;
219 mParamCount
= sqlite3_bind_parameter_count (mDBStatement
);
220 mResultColumnCount
= sqlite3_column_count (mDBStatement
);
221 mColumnNames
.Clear();
223 for (PRUint32 i
= 0; i
< mResultColumnCount
; i
++) {
224 const char *name
= sqlite3_column_name(mDBStatement
, i
);
225 mColumnNames
.AppendElement(nsDependentCString(name
));
229 // We want to try and test for LIKE and that consumers are using
230 // escapeStringForLIKE instead of just trusting user input. The idea to
231 // check to see if they are binding a parameter after like instead of just
232 // using a string. We only do this in debug builds because it's expensive!
233 const nsCaseInsensitiveCStringComparator c
;
234 nsACString::const_iterator start
, end
, e
;
235 aSQLStatement
.BeginReading(start
);
236 aSQLStatement
.EndReading(end
);
238 while (FindInReadable(NS_LITERAL_CSTRING(" LIKE"), start
, e
, c
)) {
239 // We have a LIKE in here, so we perform our tests
240 // FindInReadable moves the iterator, so we have to get a new one for
241 // each test we perform.
242 nsACString::const_iterator s1
, s2
, s3
;
243 s1
= s2
= s3
= start
;
245 if (!(FindInReadable(NS_LITERAL_CSTRING(" LIKE ?"), s1
, end
, c
) ||
246 FindInReadable(NS_LITERAL_CSTRING(" LIKE :"), s2
, end
, c
) ||
247 FindInReadable(NS_LITERAL_CSTRING(" LIKE @"), s3
, end
, c
))) {
248 // At this point, we didn't find a LIKE statement followed by ?, :,
249 // or @, all of which are valid characters for binding a parameter.
250 // We will warn the consumer that they may not be safely using LIKE.
251 NS_WARNING("Unsafe use of LIKE detected! Please ensure that you "
252 "are using mozIStorageConnection::escapeStringForLIKE "
253 "and that you are binding that result to the statement "
254 "to prevent SQL injection attacks.");
257 // resetting start and e
266 mozStorageStatement::~mozStorageStatement()
271 ////////////////////////////////////////////////////////////////////////////////
272 //// mozIStorageStatement
274 /* mozIStorageStatement clone (); */
276 mozStorageStatement::Clone(mozIStorageStatement
**_retval
)
278 mozStorageStatement
*mss
= new mozStorageStatement();
280 return NS_ERROR_OUT_OF_MEMORY
;
282 nsCAutoString
sql(sqlite3_sql(mDBStatement
));
283 nsresult rv
= mss
->Initialize (mDBConnection
, sql
);
284 NS_ENSURE_SUCCESS(rv
, rv
);
286 NS_ADDREF(*_retval
= mss
);
290 /* void finalize(); */
292 mozStorageStatement::Finalize()
298 PR_LOG(gStorageLog
, PR_LOG_NOTICE
, ("Finalizing statement '%s'",
299 sqlite3_sql(mDBStatement
)));
302 int srv
= sqlite3_finalize(mDBStatement
);
305 // We are considered dead at this point, so any wrappers for row or params
306 // need to lose their reference to us.
307 if (mStatementParamsHolder
) {
308 nsCOMPtr
<nsIXPConnectWrappedNative
> wrapper
=
309 do_QueryInterface(mStatementParamsHolder
);
310 nsCOMPtr
<mozIStorageStatementParams
> iParams
=
311 do_QueryWrappedNative(wrapper
);
312 mozStorageStatementParams
*params
=
313 static_cast<mozStorageStatementParams
*>(iParams
.get());
314 params
->mStatement
= nsnull
;
315 mStatementParamsHolder
= nsnull
;
318 if (mStatementRowHolder
) {
319 nsCOMPtr
<nsIXPConnectWrappedNative
> wrapper
=
320 do_QueryInterface(mStatementRowHolder
);
321 nsCOMPtr
<mozIStorageStatementRow
> iRow
=
322 do_QueryWrappedNative(wrapper
);
323 mozStorageStatementRow
*row
=
324 static_cast<mozStorageStatementRow
*>(iRow
.get());
325 row
->mStatement
= nsnull
;
326 mStatementRowHolder
= nsnull
;
329 return ConvertResultCode(srv
);
332 /* readonly attribute unsigned long parameterCount; */
334 mozStorageStatement::GetParameterCount(PRUint32
*aParameterCount
)
336 NS_ENSURE_ARG_POINTER(aParameterCount
);
338 if (!mDBConnection
|| !mDBStatement
)
339 return NS_ERROR_NOT_INITIALIZED
;
341 *aParameterCount
= mParamCount
;
345 /* AUTF8String getParameterName(in unsigned long aParamIndex); */
347 mozStorageStatement::GetParameterName(PRUint32 aParamIndex
, nsACString
& _retval
)
349 if (!mDBConnection
|| !mDBStatement
)
350 return NS_ERROR_NOT_INITIALIZED
;
352 // We have to check this index because sqlite3_bind_parameter_name returns
353 // NULL if an error occurs, or if a column is unnamed. Since we handle
354 // unnamed columns, we won't be able to tell if it is an error not without
355 // checking ourselves.
356 if (aParamIndex
< 0 || aParamIndex
>= mParamCount
)
357 return NS_ERROR_ILLEGAL_VALUE
;
359 const char *pname
= sqlite3_bind_parameter_name(mDBStatement
, aParamIndex
+ 1);
361 // this thing had no name, so fake one
362 nsCAutoString
pname(":");
363 pname
.AppendInt(aParamIndex
);
364 _retval
.Assign(pname
);
366 _retval
.Assign(nsDependentCString(pname
));
372 /* unsigned long getParameterIndex(in AUTF8String aParameterName); */
374 mozStorageStatement::GetParameterIndex(const nsACString
&aName
,
377 if (!mDBConnection
|| !mDBStatement
)
378 return NS_ERROR_NOT_INITIALIZED
;
380 int ind
= sqlite3_bind_parameter_index(mDBStatement
,
381 nsPromiseFlatCString(aName
).get());
382 if (ind
== 0) // Named parameter not found
383 return NS_ERROR_INVALID_ARG
;
385 *_retval
= ind
- 1; // SQLite indexes are 1-based, we are 0-based
390 /* readonly attribute unsigned long columnCount; */
392 mozStorageStatement::GetColumnCount(PRUint32
*aColumnCount
)
394 NS_ENSURE_ARG_POINTER(aColumnCount
);
396 if (!mDBConnection
|| !mDBStatement
)
397 return NS_ERROR_NOT_INITIALIZED
;
399 *aColumnCount
= mResultColumnCount
;
403 /* AUTF8String getColumnName(in unsigned long aColumnIndex); */
405 mozStorageStatement::GetColumnName(PRUint32 aColumnIndex
, nsACString
& _retval
)
407 if (!mDBConnection
|| !mDBStatement
)
408 return NS_ERROR_NOT_INITIALIZED
;
410 // We have to check this index because sqlite3_column_name returns
411 // NULL if an error occurs, or if a column is unnamed.
412 if (aColumnIndex
< 0 || aColumnIndex
>= mResultColumnCount
)
413 return NS_ERROR_ILLEGAL_VALUE
;
415 const char *cname
= sqlite3_column_name(mDBStatement
, aColumnIndex
);
416 _retval
.Assign(nsDependentCString(cname
));
421 /* unsigned long getColumnIndex(in AUTF8String aName); */
423 mozStorageStatement::GetColumnIndex(const nsACString
&aName
, PRUint32
*_retval
)
425 if (!mDBConnection
|| !mDBStatement
)
426 return NS_ERROR_NOT_INITIALIZED
;
428 // Surprisingly enough, SQLite doesn't provide an API for this. We have to
429 // determine it ourselves sadly.
430 for (PRUint32 i
= 0; i
< mResultColumnCount
; i
++) {
431 if (mColumnNames
[i
].Equals(aName
)) {
437 return NS_ERROR_INVALID_ARG
;
442 mozStorageStatement::Reset()
444 if (!mDBConnection
|| !mDBStatement
)
445 return NS_ERROR_NOT_INITIALIZED
;
447 PR_LOG(gStorageLog
, PR_LOG_DEBUG
, ("Resetting statement: '%s'",
448 sqlite3_sql(mDBStatement
)));
450 sqlite3_reset(mDBStatement
);
451 sqlite3_clear_bindings(mDBStatement
);
453 mExecuting
= PR_FALSE
;
458 /* void bindUTF8StringParameter (in unsigned long aParamIndex, in AUTF8String aValue); */
460 mozStorageStatement::BindUTF8StringParameter(PRUint32 aParamIndex
, const nsACString
& aValue
)
462 if (!mDBConnection
|| !mDBStatement
)
463 return NS_ERROR_NOT_INITIALIZED
;
465 int srv
= sqlite3_bind_text (mDBStatement
, aParamIndex
+ 1,
466 nsPromiseFlatCString(aValue
).get(),
467 aValue
.Length(), SQLITE_TRANSIENT
);
469 return ConvertResultCode(srv
);
472 /* void bindStringParameter (in unsigned long aParamIndex, in AString aValue); */
474 mozStorageStatement::BindStringParameter(PRUint32 aParamIndex
, const nsAString
& aValue
)
476 if (!mDBConnection
|| !mDBStatement
)
477 return NS_ERROR_NOT_INITIALIZED
;
479 int srv
= sqlite3_bind_text16 (mDBStatement
, aParamIndex
+ 1,
480 nsPromiseFlatString(aValue
).get(),
481 aValue
.Length() * 2, SQLITE_TRANSIENT
);
483 return ConvertResultCode(srv
);
486 /* void bindDoubleParameter (in unsigned long aParamIndex, in double aValue); */
488 mozStorageStatement::BindDoubleParameter(PRUint32 aParamIndex
, double aValue
)
490 if (!mDBConnection
|| !mDBStatement
)
491 return NS_ERROR_NOT_INITIALIZED
;
493 int srv
= sqlite3_bind_double (mDBStatement
, aParamIndex
+ 1, aValue
);
495 return ConvertResultCode(srv
);
498 /* void bindInt32Parameter (in unsigned long aParamIndex, in long aValue); */
500 mozStorageStatement::BindInt32Parameter(PRUint32 aParamIndex
, PRInt32 aValue
)
502 if (!mDBConnection
|| !mDBStatement
)
503 return NS_ERROR_NOT_INITIALIZED
;
505 int srv
= sqlite3_bind_int (mDBStatement
, aParamIndex
+ 1, aValue
);
507 return ConvertResultCode(srv
);
510 /* void bindInt64Parameter (in unsigned long aParamIndex, in long long aValue); */
512 mozStorageStatement::BindInt64Parameter(PRUint32 aParamIndex
, PRInt64 aValue
)
514 if (!mDBConnection
|| !mDBStatement
)
515 return NS_ERROR_NOT_INITIALIZED
;
517 int srv
= sqlite3_bind_int64 (mDBStatement
, aParamIndex
+ 1, aValue
);
519 return ConvertResultCode(srv
);
522 /* void bindNullParameter (in unsigned long aParamIndex); */
524 mozStorageStatement::BindNullParameter(PRUint32 aParamIndex
)
526 if (!mDBConnection
|| !mDBStatement
)
527 return NS_ERROR_NOT_INITIALIZED
;
529 int srv
= sqlite3_bind_null (mDBStatement
, aParamIndex
+ 1);
531 return ConvertResultCode(srv
);
534 /* void bindBlobParameter (in unsigned long aParamIndex, [array, const, size_is (aValueSize)] in octet aValue, in unsigned long aValueSize); */
536 mozStorageStatement::BindBlobParameter(PRUint32 aParamIndex
, const PRUint8
*aValue
, PRUint32 aValueSize
)
538 if (!mDBConnection
|| !mDBStatement
)
539 return NS_ERROR_NOT_INITIALIZED
;
541 int srv
= sqlite3_bind_blob (mDBStatement
, aParamIndex
+ 1, aValue
,
542 aValueSize
, SQLITE_TRANSIENT
);
544 return ConvertResultCode(srv
);
547 /* void execute (); */
549 mozStorageStatement::Execute()
551 if (!mDBConnection
|| !mDBStatement
)
552 return NS_ERROR_NOT_INITIALIZED
;
555 nsresult rv
= ExecuteStep(&ret
);
556 NS_ENSURE_SUCCESS(rv
, rv
);
561 /* boolean executeStep (); */
563 mozStorageStatement::ExecuteStep(PRBool
*_retval
)
565 if (!mDBConnection
|| !mDBStatement
)
566 return NS_ERROR_NOT_INITIALIZED
;
568 int srv
= sqlite3_step (mDBStatement
);
571 if (srv
!= SQLITE_ROW
&& srv
!= SQLITE_DONE
)
573 nsCAutoString errStr
;
574 mDBConnection
->GetLastErrorString(errStr
);
575 PR_LOG(gStorageLog
, PR_LOG_DEBUG
, ("mozStorageStatement::ExecuteStep error: %s", errStr
.get()));
579 // SQLITE_ROW and SQLITE_DONE are non-errors
580 if (srv
== SQLITE_ROW
) {
582 mExecuting
= PR_TRUE
;
585 } else if (srv
== SQLITE_DONE
) {
586 // statement is done (no row returned)
587 mExecuting
= PR_FALSE
;
590 } else if (srv
== SQLITE_BUSY
|| srv
== SQLITE_MISUSE
) {
591 mExecuting
= PR_FALSE
;
592 } else if (mExecuting
== PR_TRUE
) {
594 PR_LOG(gStorageLog
, PR_LOG_ERROR
, ("SQLite error after mExecuting was true!"));
596 mExecuting
= PR_FALSE
;
599 return ConvertResultCode(srv
);
602 /* nsICancelable executeAsync([optional] in storageIStatementCallback aCallback); */
604 mozStorageStatement::ExecuteAsync(mozIStorageStatementCallback
*aCallback
,
605 mozIStoragePendingStatement
**_stmt
)
607 mozIStorageStatement
* stmts
[1] = {this};
608 return mDBConnection
->ExecuteAsync(stmts
, 1, aCallback
, _stmt
);
611 /* [noscript,notxpcom] sqlite3stmtptr getNativeStatementPointer(); */
613 mozStorageStatement::GetNativeStatementPointer()
618 /* readonly attribute long state; */
620 mozStorageStatement::GetState(PRInt32
*_retval
)
622 if (!mDBConnection
|| !mDBStatement
) {
623 *_retval
= MOZ_STORAGE_STATEMENT_INVALID
;
624 } else if (mExecuting
) {
625 *_retval
= MOZ_STORAGE_STATEMENT_EXECUTING
;
627 *_retval
= MOZ_STORAGE_STATEMENT_READY
;
634 *** mozIStorageValueArray
637 /* readonly attribute unsigned long numEntries; */
639 mozStorageStatement::GetNumEntries(PRUint32
*aLength
)
641 *aLength
= mResultColumnCount
;
645 /* long getTypeOfIndex (in unsigned long aIndex); */
647 mozStorageStatement::GetTypeOfIndex(PRUint32 aIndex
, PRInt32
*_retval
)
649 if (!mDBConnection
|| !mDBStatement
)
650 return NS_ERROR_NOT_INITIALIZED
;
652 if (aIndex
< 0 || aIndex
>= mResultColumnCount
)
653 return NS_ERROR_ILLEGAL_VALUE
;
656 return NS_ERROR_UNEXPECTED
;
658 int t
= sqlite3_column_type (mDBStatement
, aIndex
);
661 *_retval
= VALUE_TYPE_INTEGER
;
664 *_retval
= VALUE_TYPE_FLOAT
;
667 *_retval
= VALUE_TYPE_TEXT
;
670 *_retval
= VALUE_TYPE_BLOB
;
673 *_retval
= VALUE_TYPE_NULL
;
677 return NS_ERROR_FAILURE
;
683 /* long getInt32 (in unsigned long aIndex); */
685 mozStorageStatement::GetInt32(PRUint32 aIndex
, PRInt32
*_retval
)
687 if (!mDBConnection
|| !mDBStatement
)
688 return NS_ERROR_NOT_INITIALIZED
;
690 if (aIndex
< 0 || aIndex
>= mResultColumnCount
)
691 return NS_ERROR_ILLEGAL_VALUE
;
694 return NS_ERROR_UNEXPECTED
;
696 *_retval
= sqlite3_column_int (mDBStatement
, aIndex
);
701 /* long long getInt64 (in unsigned long aIndex); */
703 mozStorageStatement::GetInt64(PRUint32 aIndex
, PRInt64
*_retval
)
705 if (!mDBConnection
|| !mDBStatement
)
706 return NS_ERROR_NOT_INITIALIZED
;
708 if (aIndex
< 0 || aIndex
>= mResultColumnCount
)
709 return NS_ERROR_ILLEGAL_VALUE
;
712 return NS_ERROR_UNEXPECTED
;
714 *_retval
= sqlite3_column_int64 (mDBStatement
, aIndex
);
719 /* double getDouble (in unsigned long aIndex); */
721 mozStorageStatement::GetDouble(PRUint32 aIndex
, double *_retval
)
723 if (!mDBConnection
|| !mDBStatement
)
724 return NS_ERROR_NOT_INITIALIZED
;
726 if (aIndex
< 0 || aIndex
>= mResultColumnCount
)
727 return NS_ERROR_ILLEGAL_VALUE
;
730 return NS_ERROR_UNEXPECTED
;
732 *_retval
= sqlite3_column_double (mDBStatement
, aIndex
);
737 /* AUTF8String getUTF8String (in unsigned long aIndex); */
739 mozStorageStatement::GetUTF8String(PRUint32 aIndex
, nsACString
& _retval
)
741 if (!mDBConnection
|| !mDBStatement
)
742 return NS_ERROR_NOT_INITIALIZED
;
744 // Get type of Index will check aIndex for us, so we don't have to.
746 nsresult rv
= GetTypeOfIndex (aIndex
, &t
);
747 NS_ENSURE_SUCCESS(rv
, rv
);
748 if (t
== VALUE_TYPE_NULL
) {
749 // null columns get IsVoid set to distinguish them from empty strings
751 _retval
.SetIsVoid(PR_TRUE
);
753 int slen
= sqlite3_column_bytes (mDBStatement
, aIndex
);
754 const unsigned char *cstr
= sqlite3_column_text (mDBStatement
, aIndex
);
755 _retval
.Assign ((char *) cstr
, slen
);
760 /* AString getString (in unsigned long aIndex); */
762 mozStorageStatement::GetString(PRUint32 aIndex
, nsAString
& _retval
)
764 if (!mDBConnection
|| !mDBStatement
)
765 return NS_ERROR_NOT_INITIALIZED
;
767 // Get type of Index will check aIndex for us, so we don't have to.
769 nsresult rv
= GetTypeOfIndex (aIndex
, &t
);
770 NS_ENSURE_SUCCESS(rv
, rv
);
771 if (t
== VALUE_TYPE_NULL
) {
772 // null columns get IsVoid set to distinguish them from empty strings
774 _retval
.SetIsVoid(PR_TRUE
);
776 int slen
= sqlite3_column_bytes16 (mDBStatement
, aIndex
);
777 const void *text
= sqlite3_column_text16 (mDBStatement
, aIndex
);
778 const PRUnichar
*wstr
= static_cast<const PRUnichar
*>(text
);
779 _retval
.Assign (wstr
, slen
/2);
784 /* void getBlob (in unsigned long aIndex, out unsigned long aDataSize, [array, size_is (aDataSize)] out octet aData); */
786 mozStorageStatement::GetBlob(PRUint32 aIndex
, PRUint32
*aDataSize
, PRUint8
**aData
)
788 if (!mDBConnection
|| !mDBStatement
)
789 return NS_ERROR_NOT_INITIALIZED
;
791 if (aIndex
< 0 || aIndex
>= mResultColumnCount
)
792 return NS_ERROR_ILLEGAL_VALUE
;
795 return NS_ERROR_UNEXPECTED
;
797 int blobsize
= sqlite3_column_bytes (mDBStatement
, aIndex
);
804 const void *blob
= sqlite3_column_blob (mDBStatement
, aIndex
);
806 void *blobcopy
= nsMemory::Clone(blob
, blobsize
);
807 if (blobcopy
== NULL
)
808 return NS_ERROR_OUT_OF_MEMORY
;
810 *aData
= (PRUint8
*) blobcopy
;
811 *aDataSize
= blobsize
;
816 /* [noscript] void getSharedUTF8String(in unsigned long aIndex, out unsigned long aLength, [shared,retval] out string aResult); */
818 mozStorageStatement::GetSharedUTF8String(PRUint32 aIndex
, PRUint32
*aLength
, const char **_retval
)
821 int slen
= sqlite3_column_bytes (mDBStatement
, aIndex
);
825 *_retval
= (const char *) sqlite3_column_text (mDBStatement
, aIndex
);
829 /* [noscript] void getSharedString(in unsigned long aIndex, out unsigned long aLength, [shared,retval] out wstring aResult); */
831 mozStorageStatement::GetSharedString(PRUint32 aIndex
, PRUint32
*aLength
, const PRUnichar
**_retval
)
834 int slen
= sqlite3_column_bytes16 (mDBStatement
, aIndex
);
838 *_retval
= (const PRUnichar
*) sqlite3_column_text16 (mDBStatement
, aIndex
);
842 /* [noscript] void getSharedBlob(in unsigned long aIndex, out unsigned long aLength, [shared,retval] out octetPtr aResult); */
844 mozStorageStatement::GetSharedBlob(PRUint32 aIndex
, PRUint32
*aDataSize
, const PRUint8
**aData
)
846 *aDataSize
= sqlite3_column_bytes (mDBStatement
, aIndex
);
847 *aData
= (const PRUint8
*) sqlite3_column_blob (mDBStatement
, aIndex
);
852 /* boolean getIsNull (in unsigned long aIndex); */
854 mozStorageStatement::GetIsNull(PRUint32 aIndex
, PRBool
*_retval
)
856 // Get type of Index will check aIndex for us, so we don't have to.
858 nsresult rv
= GetTypeOfIndex (aIndex
, &t
);
859 NS_ENSURE_SUCCESS(rv
, rv
);
861 if (t
== VALUE_TYPE_NULL
)
869 /* AString escapeStringForLIKE(in AString aValue, in char aEscapeChar); */
871 mozStorageStatement::EscapeStringForLIKE(const nsAString
& aValue
,
872 const PRUnichar aEscapeChar
,
873 nsAString
&aEscapedString
)
875 const PRUnichar
MATCH_ALL('%');
876 const PRUnichar
MATCH_ONE('_');
878 aEscapedString
.Truncate(0);
880 for (PRInt32 i
= 0; i
< aValue
.Length(); i
++) {
881 if (aValue
[i
] == aEscapeChar
|| aValue
[i
] == MATCH_ALL
||
882 aValue
[i
] == MATCH_ONE
)
883 aEscapedString
+= aEscapeChar
;
884 aEscapedString
+= aValue
[i
];
889 /* AString getColumnDecltype(in unsigned long aParamIndex); */
891 mozStorageStatement::GetColumnDecltype(PRUint32 aParamIndex
,
892 nsACString
& aDeclType
)
894 if (!mDBConnection
|| !mDBStatement
)
895 return NS_ERROR_NOT_INITIALIZED
;
897 if (aParamIndex
< 0 || aParamIndex
>= mResultColumnCount
)
898 return NS_ERROR_ILLEGAL_VALUE
;
900 const char *declType
= sqlite3_column_decltype(mDBStatement
, aParamIndex
);
901 aDeclType
.Assign(declType
);