Bug 491196 don't implement static functions in headers
[mozilla-central.git] / storage / src / mozStorageStatement.cpp
blob971eb4fbfa298e2faf8f01c12b97822584dd1599
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 * ***** 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
14 * License.
16 * The Original Code is Oracle Corporation code.
18 * The Initial Developer of the Original Code is
19 * Oracle Corporation
20 * Portions created by the Initial Developer are Copyright (C) 2004
21 * the Initial Developer. All Rights Reserved.
23 * Contributor(s):
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 ***** */
42 #include <stdio.h>
44 #include "nsError.h"
45 #include "nsMemory.h"
46 #include "nsIClassInfoImpl.h"
47 #include "nsIProgrammingLanguage.h"
49 #include "mozStorageConnection.h"
50 #include "mozStorageStatementJSHelper.h"
51 #include "mozStoragePrivateHelpers.h"
52 #include "mozStorageStatementParams.h"
53 #include "mozStorageStatementRow.h"
54 #include "mozStorageStatement.h"
56 #include "prlog.h"
58 #ifdef PR_LOGGING
59 extern PRLogModuleInfo* gStorageLog;
60 #endif
62 namespace mozilla {
63 namespace storage {
65 ////////////////////////////////////////////////////////////////////////////////
66 //// nsIClassInfo
68 NS_IMPL_CI_INTERFACE_GETTER2(
69 Statement,
70 mozIStorageStatement,
71 mozIStorageValueArray
74 class StatementClassInfo : public nsIClassInfo
76 public:
77 NS_DECL_ISUPPORTS
79 NS_IMETHODIMP
80 GetInterfaces(PRUint32 *_count, nsIID ***_array)
82 return NS_CI_INTERFACE_GETTER_NAME(Statement)(_count, _array);
85 NS_IMETHODIMP
86 GetHelperForLanguage(PRUint32 aLanguage, nsISupports **_helper)
88 if (aLanguage == nsIProgrammingLanguage::JAVASCRIPT) {
89 static StatementJSHelper sJSHelper;
90 *_helper = &sJSHelper;
91 return NS_OK;
94 *_helper = nsnull;
95 return NS_OK;
98 NS_IMETHODIMP
99 GetContractID(char **_contractID)
101 *_contractID = nsnull;
102 return NS_OK;
105 NS_IMETHODIMP
106 GetClassDescription(char **_desc)
108 *_desc = nsnull;
109 return NS_OK;
112 NS_IMETHODIMP
113 GetClassID(nsCID **_id)
115 *_id = nsnull;
116 return NS_OK;
119 NS_IMETHODIMP
120 GetImplementationLanguage(PRUint32 *_language)
122 *_language = nsIProgrammingLanguage::CPLUSPLUS;
123 return NS_OK;
126 NS_IMETHODIMP
127 GetFlags(PRUint32 *_flags)
129 *_flags = nsnull;
130 return NS_OK;
133 NS_IMETHODIMP
134 GetClassIDNoAlloc(nsCID *_cid)
136 return NS_ERROR_NOT_AVAILABLE;
140 NS_IMETHODIMP_(nsrefcnt) StatementClassInfo::AddRef() { return 2; }
141 NS_IMETHODIMP_(nsrefcnt) StatementClassInfo::Release() { return 1; }
142 NS_IMPL_QUERY_INTERFACE1(StatementClassInfo, nsIClassInfo)
144 static StatementClassInfo sStatementClassInfo;
146 ////////////////////////////////////////////////////////////////////////////////
147 //// Statement
149 Statement::Statement()
150 : mDBConnection(nsnull)
151 , mDBStatement(NULL)
152 , mColumnNames()
153 , mExecuting(false)
157 nsresult
158 Statement::initialize(Connection *aDBConnection,
159 const nsACString &aSQLStatement)
161 NS_ASSERTION(aDBConnection, "No database connection given!");
162 NS_ASSERTION(!mDBStatement, "Statement already initialized!");
164 sqlite3 *db = aDBConnection->GetNativeConnection();
165 NS_ASSERTION(db, "We should never be called with a null sqlite3 database!");
167 int srv = ::sqlite3_prepare_v2(db, PromiseFlatCString(aSQLStatement).get(),
168 -1, &mDBStatement, NULL);
169 if (srv != SQLITE_OK) {
170 #ifdef PR_LOGGING
171 PR_LOG(gStorageLog, PR_LOG_ERROR,
172 ("Sqlite statement prepare error: %d '%s'", srv,
173 ::sqlite3_errmsg(db)));
174 PR_LOG(gStorageLog, PR_LOG_ERROR,
175 ("Statement was: '%s'", PromiseFlatCString(aSQLStatement).get()));
176 #endif
177 return NS_ERROR_FAILURE;
180 #ifdef PR_LOGGING
181 PR_LOG(gStorageLog, PR_LOG_NOTICE, ("Initialized statement '%s' (0x%p)",
182 PromiseFlatCString(aSQLStatement).get(),
183 mDBStatement));
184 #endif
186 mDBConnection = aDBConnection;
187 mParamCount = ::sqlite3_bind_parameter_count(mDBStatement);
188 mResultColumnCount = ::sqlite3_column_count(mDBStatement);
189 mColumnNames.Clear();
191 for (PRUint32 i = 0; i < mResultColumnCount; i++) {
192 const char *name = ::sqlite3_column_name(mDBStatement, i);
193 (void)mColumnNames.AppendElement(nsDependentCString(name));
196 #ifdef DEBUG
197 // We want to try and test for LIKE and that consumers are using
198 // escapeStringForLIKE instead of just trusting user input. The idea to
199 // check to see if they are binding a parameter after like instead of just
200 // using a string. We only do this in debug builds because it's expensive!
201 const nsCaseInsensitiveCStringComparator c;
202 nsACString::const_iterator start, end, e;
203 aSQLStatement.BeginReading(start);
204 aSQLStatement.EndReading(end);
205 e = end;
206 while (::FindInReadable(NS_LITERAL_CSTRING(" LIKE"), start, e, c)) {
207 // We have a LIKE in here, so we perform our tests
208 // FindInReadable moves the iterator, so we have to get a new one for
209 // each test we perform.
210 nsACString::const_iterator s1, s2, s3;
211 s1 = s2 = s3 = start;
213 if (!(::FindInReadable(NS_LITERAL_CSTRING(" LIKE ?"), s1, end, c) ||
214 ::FindInReadable(NS_LITERAL_CSTRING(" LIKE :"), s2, end, c) ||
215 ::FindInReadable(NS_LITERAL_CSTRING(" LIKE @"), s3, end, c))) {
216 // At this point, we didn't find a LIKE statement followed by ?, :,
217 // or @, all of which are valid characters for binding a parameter.
218 // We will warn the consumer that they may not be safely using LIKE.
219 NS_WARNING("Unsafe use of LIKE detected! Please ensure that you "
220 "are using mozIStorageConnection::escapeStringForLIKE "
221 "and that you are binding that result to the statement "
222 "to prevent SQL injection attacks.");
225 // resetting start and e
226 start = e;
227 e = end;
229 #endif
231 return NS_OK;
234 Statement::~Statement()
236 (void)Finalize();
239 NS_IMPL_THREADSAFE_ADDREF(Statement)
240 NS_IMPL_THREADSAFE_RELEASE(Statement)
242 NS_INTERFACE_MAP_BEGIN(Statement)
243 NS_INTERFACE_MAP_ENTRY(mozIStorageStatement)
244 NS_INTERFACE_MAP_ENTRY(mozIStorageValueArray)
245 if (aIID.Equals(NS_GET_IID(nsIClassInfo))) {
246 foundInterface = static_cast<nsIClassInfo *>(&sStatementClassInfo);
248 else
249 NS_INTERFACE_MAP_ENTRY(nsISupports)
250 NS_INTERFACE_MAP_END
252 ////////////////////////////////////////////////////////////////////////////////
253 //// mozIStorageStatement
255 NS_IMETHODIMP
256 Statement::Clone(mozIStorageStatement **_statement)
258 nsRefPtr<Statement> statement(new Statement());
259 NS_ENSURE_TRUE(statement, NS_ERROR_OUT_OF_MEMORY);
261 nsCAutoString sql(::sqlite3_sql(mDBStatement));
262 nsresult rv = statement->initialize(mDBConnection, sql);
263 NS_ENSURE_SUCCESS(rv, rv);
265 statement.forget(_statement);
266 return NS_OK;
269 NS_IMETHODIMP
270 Statement::Finalize()
272 if (!mDBStatement)
273 return NS_OK;
275 #ifdef PR_LOGGING
276 PR_LOG(gStorageLog, PR_LOG_NOTICE, ("Finalizing statement '%s'",
277 ::sqlite3_sql(mDBStatement)));
278 #endif
280 int srv = ::sqlite3_finalize(mDBStatement);
281 mDBStatement = NULL;
283 // We are considered dead at this point, so any wrappers for row or params
284 // need to lose their reference to us.
285 if (mStatementParamsHolder) {
286 nsCOMPtr<nsIXPConnectWrappedNative> wrapper =
287 do_QueryInterface(mStatementParamsHolder);
288 nsCOMPtr<mozIStorageStatementParams> iParams =
289 do_QueryWrappedNative(wrapper);
290 StatementParams *params = static_cast<StatementParams *>(iParams.get());
291 params->mStatement = nsnull;
292 mStatementParamsHolder = nsnull;
295 if (mStatementRowHolder) {
296 nsCOMPtr<nsIXPConnectWrappedNative> wrapper =
297 do_QueryInterface(mStatementRowHolder);
298 nsCOMPtr<mozIStorageStatementRow> iRow =
299 do_QueryWrappedNative(wrapper);
300 StatementRow *row = static_cast<StatementRow *>(iRow.get());
301 row->mStatement = nsnull;
302 mStatementRowHolder = nsnull;
305 return convertResultCode(srv);
308 NS_IMETHODIMP
309 Statement::GetParameterCount(PRUint32 *_parameterCount)
311 if (!mDBStatement)
312 return NS_ERROR_NOT_INITIALIZED;
314 *_parameterCount = mParamCount;
315 return NS_OK;
318 NS_IMETHODIMP
319 Statement::GetParameterName(PRUint32 aParamIndex,
320 nsACString &_name)
322 if (!mDBStatement)
323 return NS_ERROR_NOT_INITIALIZED;
324 ENSURE_INDEX_VALUE(aParamIndex, mParamCount);
326 const char *name = ::sqlite3_bind_parameter_name(mDBStatement,
327 aParamIndex + 1);
328 if (name == NULL) {
329 // this thing had no name, so fake one
330 nsCAutoString name(":");
331 name.AppendInt(aParamIndex);
332 _name.Assign(name);
334 else {
335 _name.Assign(nsDependentCString(name));
338 return NS_OK;
341 NS_IMETHODIMP
342 Statement::GetParameterIndex(const nsACString &aName,
343 PRUint32 *_index)
345 if (!mDBStatement)
346 return NS_ERROR_NOT_INITIALIZED;
348 // We do not accept any forms of names other than ":name", but we need to add
349 // the colon for SQLite.
350 nsCAutoString name(":");
351 name.Append(aName);
352 int ind = ::sqlite3_bind_parameter_index(mDBStatement,
353 PromiseFlatCString(name).get());
354 if (ind == 0) // Named parameter not found.
355 return NS_ERROR_INVALID_ARG;
357 *_index = ind - 1; // SQLite indexes are 1-based, we are 0-based.
359 return NS_OK;
362 NS_IMETHODIMP
363 Statement::GetColumnCount(PRUint32 *_columnCount)
365 if (!mDBStatement)
366 return NS_ERROR_NOT_INITIALIZED;
368 *_columnCount = mResultColumnCount;
369 return NS_OK;
372 NS_IMETHODIMP
373 Statement::GetColumnName(PRUint32 aColumnIndex,
374 nsACString &_name)
376 if (!mDBStatement)
377 return NS_ERROR_NOT_INITIALIZED;
378 ENSURE_INDEX_VALUE(aColumnIndex, mResultColumnCount);
380 const char *cname = ::sqlite3_column_name(mDBStatement, aColumnIndex);
381 _name.Assign(nsDependentCString(cname));
383 return NS_OK;
386 NS_IMETHODIMP
387 Statement::GetColumnIndex(const nsACString &aName,
388 PRUint32 *_index)
390 if (!mDBStatement)
391 return NS_ERROR_NOT_INITIALIZED;
393 // Surprisingly enough, SQLite doesn't provide an API for this. We have to
394 // determine it ourselves sadly.
395 for (PRUint32 i = 0; i < mResultColumnCount; i++) {
396 if (mColumnNames[i].Equals(aName)) {
397 *_index = i;
398 return NS_OK;
402 return NS_ERROR_INVALID_ARG;
405 NS_IMETHODIMP
406 Statement::Reset()
408 if (!mDBStatement)
409 return NS_ERROR_NOT_INITIALIZED;
411 #ifdef DEBUG
412 PR_LOG(gStorageLog, PR_LOG_DEBUG, ("Resetting statement: '%s'",
413 ::sqlite3_sql(mDBStatement)));
415 checkAndLogStatementPerformance(mDBStatement);
416 #endif
418 (void)sqlite3_reset(mDBStatement);
419 (void)sqlite3_clear_bindings(mDBStatement);
421 mExecuting = false;
423 return NS_OK;
426 NS_IMETHODIMP
427 Statement::BindUTF8StringParameter(PRUint32 aParamIndex,
428 const nsACString &aValue)
430 if (!mDBStatement)
431 return NS_ERROR_NOT_INITIALIZED;
433 int srv = ::sqlite3_bind_text(mDBStatement, aParamIndex + 1,
434 PromiseFlatCString(aValue).get(),
435 aValue.Length(), SQLITE_TRANSIENT);
436 return convertResultCode(srv);
439 NS_IMETHODIMP
440 Statement::BindStringParameter(PRUint32 aParamIndex,
441 const nsAString &aValue)
443 if (!mDBStatement)
444 return NS_ERROR_NOT_INITIALIZED;
446 int srv = ::sqlite3_bind_text16(mDBStatement, aParamIndex + 1,
447 PromiseFlatString(aValue).get(),
448 aValue.Length() * 2, SQLITE_TRANSIENT);
449 return convertResultCode(srv);
452 NS_IMETHODIMP
453 Statement::BindDoubleParameter(PRUint32 aParamIndex,
454 double aValue)
456 if (!mDBStatement)
457 return NS_ERROR_NOT_INITIALIZED;
459 int srv = ::sqlite3_bind_double(mDBStatement, aParamIndex + 1, aValue);
460 return convertResultCode(srv);
463 NS_IMETHODIMP
464 Statement::BindInt32Parameter(PRUint32 aParamIndex,
465 PRInt32 aValue)
467 if (!mDBStatement)
468 return NS_ERROR_NOT_INITIALIZED;
470 int srv = ::sqlite3_bind_int(mDBStatement, aParamIndex + 1, aValue);
471 return convertResultCode(srv);
474 NS_IMETHODIMP
475 Statement::BindInt64Parameter(PRUint32 aParamIndex,
476 PRInt64 aValue)
478 if (!mDBStatement)
479 return NS_ERROR_NOT_INITIALIZED;
481 int srv = ::sqlite3_bind_int64(mDBStatement, aParamIndex + 1, aValue);
482 return convertResultCode(srv);
485 NS_IMETHODIMP
486 Statement::BindNullParameter(PRUint32 aParamIndex)
488 if (!mDBStatement)
489 return NS_ERROR_NOT_INITIALIZED;
491 int srv = ::sqlite3_bind_null(mDBStatement, aParamIndex + 1);
492 return convertResultCode(srv);
495 NS_IMETHODIMP
496 Statement::BindBlobParameter(PRUint32 aParamIndex,
497 const PRUint8 *aValue,
498 PRUint32 aValueSize)
500 if (!mDBStatement)
501 return NS_ERROR_NOT_INITIALIZED;
503 int srv = ::sqlite3_bind_blob(mDBStatement, aParamIndex + 1, aValue,
504 aValueSize, SQLITE_TRANSIENT);
505 return convertResultCode(srv);
508 NS_IMETHODIMP
509 Statement::BindParameters(mozIStorageBindingParamsArray *aParameters)
511 if (!mDBStatement)
512 return NS_ERROR_NOT_INITIALIZED;
514 BindingParamsArray *array = static_cast<BindingParamsArray *>(aParameters);
515 if (array->getOwner() != this)
516 return NS_ERROR_UNEXPECTED;
518 mParamsArray = array;
519 mParamsArray->lock();
521 return NS_OK;
524 NS_IMETHODIMP
525 Statement::NewBindingParamsArray(mozIStorageBindingParamsArray **_array)
527 nsCOMPtr<mozIStorageBindingParamsArray> array =
528 new BindingParamsArray(this);
529 NS_ENSURE_TRUE(array, NS_ERROR_OUT_OF_MEMORY);
531 array.forget(_array);
532 return NS_OK;
535 NS_IMETHODIMP
536 Statement::Execute()
538 if (!mDBStatement)
539 return NS_ERROR_NOT_INITIALIZED;
541 PRBool ret;
542 nsresult rv = ExecuteStep(&ret);
543 NS_ENSURE_SUCCESS(rv, rv);
545 return Reset();
548 NS_IMETHODIMP
549 Statement::ExecuteStep(PRBool *_moreResults)
551 if (!mDBStatement)
552 return NS_ERROR_NOT_INITIALIZED;
554 int srv = ::sqlite3_step(mDBStatement);
556 #ifdef PR_LOGGING
557 if (srv != SQLITE_ROW && srv != SQLITE_DONE) {
558 nsCAutoString errStr;
559 (void)mDBConnection->GetLastErrorString(errStr);
560 PR_LOG(gStorageLog, PR_LOG_DEBUG,
561 ("Statement::ExecuteStep error: %s", errStr.get()));
563 #endif
565 // SQLITE_ROW and SQLITE_DONE are non-errors
566 if (srv == SQLITE_ROW) {
567 // we got a row back
568 mExecuting = true;
569 *_moreResults = PR_TRUE;
570 return NS_OK;
572 else if (srv == SQLITE_DONE) {
573 // statement is done (no row returned)
574 mExecuting = false;
575 *_moreResults = PR_FALSE;
576 return NS_OK;
578 else if (srv == SQLITE_BUSY || srv == SQLITE_MISUSE) {
579 mExecuting = PR_FALSE;
581 else if (mExecuting) {
582 #ifdef PR_LOGGING
583 PR_LOG(gStorageLog, PR_LOG_ERROR,
584 ("SQLite error after mExecuting was true!"));
585 #endif
586 mExecuting = PR_FALSE;
589 return convertResultCode(srv);
592 nsresult
593 Statement::ExecuteAsync(mozIStorageStatementCallback *aCallback,
594 mozIStoragePendingStatement **_stmt)
596 mozIStorageStatement *stmts[1] = {this};
597 return mDBConnection->ExecuteAsync(stmts, 1, aCallback, _stmt);
600 NS_IMETHODIMP
601 Statement::GetState(PRInt32 *_state)
603 if (!mDBStatement)
604 *_state = MOZ_STORAGE_STATEMENT_INVALID;
605 else if (mExecuting)
606 *_state = MOZ_STORAGE_STATEMENT_EXECUTING;
607 else
608 *_state = MOZ_STORAGE_STATEMENT_READY;
610 return NS_OK;
613 NS_IMETHODIMP
614 Statement::EscapeStringForLIKE(const nsAString &aValue,
615 const PRUnichar aEscapeChar,
616 nsAString &_escapedString)
618 const PRUnichar MATCH_ALL('%');
619 const PRUnichar MATCH_ONE('_');
621 _escapedString.Truncate(0);
623 for (PRUint32 i = 0; i < aValue.Length(); i++) {
624 if (aValue[i] == aEscapeChar || aValue[i] == MATCH_ALL ||
625 aValue[i] == MATCH_ONE)
626 _escapedString += aEscapeChar;
627 _escapedString += aValue[i];
629 return NS_OK;
632 NS_IMETHODIMP
633 Statement::GetColumnDecltype(PRUint32 aParamIndex,
634 nsACString &_declType)
636 if (!mDBStatement)
637 return NS_ERROR_NOT_INITIALIZED;
639 ENSURE_INDEX_VALUE(aParamIndex, mResultColumnCount);
641 _declType.Assign(::sqlite3_column_decltype(mDBStatement, aParamIndex));
642 return NS_OK;
645 ////////////////////////////////////////////////////////////////////////////////
646 //// mozIStorageValueArray
648 NS_IMETHODIMP
649 Statement::GetNumEntries(PRUint32 *_length)
651 *_length = mResultColumnCount;
652 return NS_OK;
655 NS_IMETHODIMP
656 Statement::GetTypeOfIndex(PRUint32 aIndex,
657 PRInt32 *_type)
659 if (!mDBStatement)
660 return NS_ERROR_NOT_INITIALIZED;
662 ENSURE_INDEX_VALUE(aIndex, mResultColumnCount);
664 if (!mExecuting)
665 return NS_ERROR_UNEXPECTED;
667 int t = ::sqlite3_column_type(mDBStatement, aIndex);
668 switch (t) {
669 case SQLITE_INTEGER:
670 *_type = VALUE_TYPE_INTEGER;
671 break;
672 case SQLITE_FLOAT:
673 *_type = VALUE_TYPE_FLOAT;
674 break;
675 case SQLITE_TEXT:
676 *_type = VALUE_TYPE_TEXT;
677 break;
678 case SQLITE_BLOB:
679 *_type = VALUE_TYPE_BLOB;
680 break;
681 case SQLITE_NULL:
682 *_type = VALUE_TYPE_NULL;
683 break;
684 default:
685 return NS_ERROR_FAILURE;
688 return NS_OK;
691 NS_IMETHODIMP
692 Statement::GetInt32(PRUint32 aIndex,
693 PRInt32 *_value)
695 if (!mDBStatement)
696 return NS_ERROR_NOT_INITIALIZED;
698 ENSURE_INDEX_VALUE(aIndex, mResultColumnCount);
700 if (!mExecuting)
701 return NS_ERROR_UNEXPECTED;
703 *_value = ::sqlite3_column_int(mDBStatement, aIndex);
704 return NS_OK;
707 NS_IMETHODIMP
708 Statement::GetInt64(PRUint32 aIndex,
709 PRInt64 *_value)
711 if (!mDBStatement)
712 return NS_ERROR_NOT_INITIALIZED;
714 ENSURE_INDEX_VALUE(aIndex, mResultColumnCount);
716 if (!mExecuting)
717 return NS_ERROR_UNEXPECTED;
719 *_value = ::sqlite3_column_int64(mDBStatement, aIndex);
721 return NS_OK;
724 NS_IMETHODIMP
725 Statement::GetDouble(PRUint32 aIndex,
726 double *_value)
728 if (!mDBStatement)
729 return NS_ERROR_NOT_INITIALIZED;
731 ENSURE_INDEX_VALUE(aIndex, mResultColumnCount);
733 if (!mExecuting)
734 return NS_ERROR_UNEXPECTED;
736 *_value = ::sqlite3_column_double(mDBStatement, aIndex);
738 return NS_OK;
741 NS_IMETHODIMP
742 Statement::GetUTF8String(PRUint32 aIndex,
743 nsACString &_value)
745 // Get type of Index will check aIndex for us, so we don't have to.
746 PRInt32 type;
747 nsresult rv = GetTypeOfIndex(aIndex, &type);
748 NS_ENSURE_SUCCESS(rv, rv);
749 if (type == VALUE_TYPE_NULL) {
750 // NULL columns should have IsVod set to distinguis them from an empty
751 // string.
752 _value.Truncate(0);
753 _value.SetIsVoid(PR_TRUE);
755 else {
756 const char *value =
757 reinterpret_cast<const char *>(::sqlite3_column_text(mDBStatement,
758 aIndex));
759 _value.Assign(value, ::sqlite3_column_bytes(mDBStatement, aIndex));
761 return NS_OK;
764 NS_IMETHODIMP
765 Statement::GetString(PRUint32 aIndex,
766 nsAString &_value)
768 // Get type of Index will check aIndex for us, so we don't have to.
769 PRInt32 type;
770 nsresult rv = GetTypeOfIndex(aIndex, &type);
771 NS_ENSURE_SUCCESS(rv, rv);
772 if (type == VALUE_TYPE_NULL) {
773 // NULL columns should have IsVod set to distinguis them from an empty
774 // string.
775 _value.Truncate(0);
776 _value.SetIsVoid(PR_TRUE);
777 } else {
778 const PRUnichar *value =
779 static_cast<const PRUnichar *>(::sqlite3_column_text16(mDBStatement,
780 aIndex));
781 _value.Assign(value, ::sqlite3_column_bytes16(mDBStatement, aIndex) / 2);
783 return NS_OK;
786 NS_IMETHODIMP
787 Statement::GetBlob(PRUint32 aIndex,
788 PRUint32 *_size,
789 PRUint8 **_blob)
791 if (!mDBStatement)
792 return NS_ERROR_NOT_INITIALIZED;
794 ENSURE_INDEX_VALUE(aIndex, mResultColumnCount);
796 if (!mExecuting)
797 return NS_ERROR_UNEXPECTED;
799 int size = ::sqlite3_column_bytes(mDBStatement, aIndex);
800 void *blob = nsnull;
801 if (size) {
802 blob = nsMemory::Clone(::sqlite3_column_blob(mDBStatement, aIndex), size);
803 NS_ENSURE_TRUE(blob, NS_ERROR_OUT_OF_MEMORY);
806 *_blob = static_cast<PRUint8 *>(blob);
807 *_size = size;
808 return NS_OK;
811 NS_IMETHODIMP
812 Statement::GetSharedUTF8String(PRUint32 aIndex,
813 PRUint32 *_length,
814 const char **_value)
816 if (_length)
817 *_length = ::sqlite3_column_bytes(mDBStatement, aIndex);
819 *_value = reinterpret_cast<const char *>(::sqlite3_column_text(mDBStatement,
820 aIndex));
821 return NS_OK;
824 NS_IMETHODIMP
825 Statement::GetSharedString(PRUint32 aIndex,
826 PRUint32 *_length,
827 const PRUnichar **_value)
829 if (_length)
830 *_length = ::sqlite3_column_bytes16(mDBStatement, aIndex);
832 *_value = static_cast<const PRUnichar *>(::sqlite3_column_text16(mDBStatement,
833 aIndex));
834 return NS_OK;
837 NS_IMETHODIMP
838 Statement::GetSharedBlob(PRUint32 aIndex,
839 PRUint32 *_size,
840 const PRUint8 **_blob)
842 *_size = ::sqlite3_column_bytes(mDBStatement, aIndex);
843 *_blob = static_cast<const PRUint8 *>(::sqlite3_column_blob(mDBStatement,
844 aIndex));
845 return NS_OK;
848 NS_IMETHODIMP
849 Statement::GetIsNull(PRUint32 aIndex,
850 PRBool *_isNull)
852 // Get type of Index will check aIndex for us, so we don't have to.
853 PRInt32 type;
854 nsresult rv = GetTypeOfIndex(aIndex, &type);
855 NS_ENSURE_SUCCESS(rv, rv);
856 *_isNull = (type == VALUE_TYPE_NULL);
857 return NS_OK;
860 } // namespace storage
861 } // namespace mozilla