/* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0/LGPL 2.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is mozilla.org code. * * The Initial Developer of the Original Code is Jan Varga * Portions created by the Initial Developer are Copyright (C) 2003 * the Initial Developer. All Rights Reserved. * * Contributor(s): * * Alternatively, the contents of this file may be used under the terms of * either the GNU General Public License Version 2 or later (the "GPL"), or * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), * in which case the provisions of the GPL or the LGPL are applicable instead * of those above. If you wish to allow use of your version of this file only * under the terms of either the GPL or the LGPL, and not to allow others to * use your version of this file under the terms of the MPL, indicate your * decision by deleting the provisions above and replace them with the notice * and other provisions required by the GPL or the LGPL. If you do not delete * the provisions above, a recipient may use your version of this file under * the terms of any one of the MPL, the GPL or the LGPL. * * ***** END LICENSE BLOCK ***** */ #include #include "nsCRT.h" #include "nsIVariant.h" #include "nsReadableUtils.h" #include "nsUnicharUtils.h" #include "rdf.h" #include "nsIServiceManager.h" #include "nsRDFCID.h" #include "nsDateTimeFormatCID.h" #include "mozSqlResult.h" #include "mozSqlConnection.h" #include "nsITreeColumns.h" static NS_DEFINE_CID(kRDFServiceCID, NS_RDFSERVICE_CID); PRInt32 mozSqlResult::gRefCnt = 0; nsIRDFService* mozSqlResult::gRDFService; nsIDateTimeFormat* mozSqlResult::gFormat; nsIRDFResource* mozSqlResult::kSQL_ResultRoot; nsIRDFResource* mozSqlResult::kNC_Child; nsIRDFLiteral* mozSqlResult::kNullLiteral; nsIRDFLiteral* mozSqlResult::kEmptyLiteral; nsIRDFLiteral* mozSqlResult::kTrueLiteral; nsIRDFLiteral* mozSqlResult::kFalseLiteral; mozSqlResult::mozSqlResult(mozISqlConnection* aConnection, const nsAString& aQuery) : mDisplayNullAsText(PR_FALSE), mConnection(aConnection), mQuery(aQuery), mSources(nsnull, nsnull, nsnull, nsnull), mCanInsert(-1), mCanUpdate(-1), mCanDelete(-1) { } nsresult mozSqlResult::Init() { nsresult rv; if (gRefCnt++ == 0) { rv = CallGetService(kRDFServiceCID, &gRDFService); if (NS_FAILED(rv)) return rv; rv = CallCreateInstance(NS_DATETIMEFORMAT_CONTRACTID, &gFormat); if (NS_FAILED(rv)) return rv; rv = gRDFService->GetResource(NS_LITERAL_CSTRING("SQL:ResultRoot"), &kSQL_ResultRoot); if (NS_FAILED(rv)) return rv; rv = gRDFService->GetResource(NS_LITERAL_CSTRING(NC_NAMESPACE_URI "child"), &kNC_Child); if (NS_FAILED(rv)) return rv; rv = gRDFService->GetLiteral(NS_LITERAL_STRING("null").get(), &kNullLiteral); if (NS_FAILED(rv)) return rv; rv = gRDFService->GetLiteral(EmptyString().get(), &kEmptyLiteral); if (NS_FAILED(rv)) return rv; rv = gRDFService->GetLiteral(NS_LITERAL_STRING("true").get(), &kTrueLiteral); if (NS_FAILED(rv)) return rv; rv = gRDFService->GetLiteral(NS_LITERAL_STRING("false").get(), &kFalseLiteral); if (NS_FAILED(rv)) return rv; } static const size_t kBucketSizes[] = { sizeof(ColumnInfo), sizeof(Cell), sizeof(Row) }; static const PRInt32 kNumBuckets = sizeof(kBucketSizes) / sizeof(size_t); static const PRInt32 kInitialSize = 16; mAllocator.Init("mozSqlResult", kBucketSizes, kNumBuckets, kInitialSize); return Rebuild(); } nsresult mozSqlResult::Rebuild() { ClearRows(); ClearColumnInfo(); nsresult rv = BuildColumnInfo(); if (NS_FAILED(rv)) return rv; rv = BuildRows(); if (NS_FAILED(rv)) return rv; ClearNativeResult(); return NS_OK; } mozSqlResult::~mozSqlResult() { ClearRows(); ClearColumnInfo(); if (--gRefCnt == 0) { NS_IF_RELEASE(kFalseLiteral); NS_IF_RELEASE(kTrueLiteral); NS_IF_RELEASE(kEmptyLiteral); NS_IF_RELEASE(kNullLiteral); NS_IF_RELEASE(kNC_Child); NS_IF_RELEASE(kSQL_ResultRoot); NS_IF_RELEASE(gFormat); NS_IF_RELEASE(gRDFService); gRDFService = nsnull; } } NS_IMPL_THREADSAFE_ISUPPORTS5(mozSqlResult, mozISqlResult, mozISqlDataSource, nsIRDFDataSource, nsIRDFRemoteDataSource, nsITreeView) NS_IMETHODIMP mozSqlResult::GetDisplayNullAsText(PRBool* aDisplayNullAsText) { *aDisplayNullAsText = mDisplayNullAsText; return NS_OK; } NS_IMETHODIMP mozSqlResult::SetDisplayNullAsText(PRBool aDisplayNullAsText) { mDisplayNullAsText = aDisplayNullAsText; return NS_OK; } NS_IMETHODIMP mozSqlResult::GetConnection(mozISqlConnection** aConnection) { NS_ADDREF(*aConnection = mConnection); return NS_OK; } NS_IMETHODIMP mozSqlResult::GetQuery(nsAString& aQuery) { aQuery = mQuery; return NS_OK; } NS_IMETHODIMP mozSqlResult::GetTableName(nsAString& aTableName) { nsresult rv = EnsureTableName(); if (NS_FAILED(rv)) return rv; aTableName = mTableName; return NS_OK; } NS_IMETHODIMP mozSqlResult::GetRowCount(PRInt32 *aRowCount) { *aRowCount = mRows.Count(); return NS_OK; } NS_IMETHODIMP mozSqlResult::GetColumnCount(PRInt32 *aColumnCount) { *aColumnCount = mColumnInfo.Count(); return NS_OK; } NS_IMETHODIMP mozSqlResult::GetColumnName(PRInt32 aColumnIndex, nsAString& _retval) { _retval.Assign(((ColumnInfo*)mColumnInfo[aColumnIndex])->mName); return NS_OK; } NS_IMETHODIMP mozSqlResult::GetColumnIndex(const nsAString & aColumnName, PRInt32 *_retval) { *_retval = -1; for (PRInt32 i = 0; i < mColumnInfo.Count(); i++) { PRUnichar* name = ((ColumnInfo*)mColumnInfo[i])->mName; if (aColumnName.Equals(name)) { *_retval = i; break; } } return NS_OK; } NS_IMETHODIMP mozSqlResult::GetColumnType(PRInt32 aColumnIndex, PRInt32* _retval) { if (aColumnIndex < 0 || aColumnIndex >= mColumnInfo.Count()) return NS_ERROR_INVALID_ARG; *_retval = ((ColumnInfo*)mColumnInfo[aColumnIndex])->mType; return NS_OK; } NS_IMETHODIMP mozSqlResult::GetColumnTypeAsString(PRInt32 aColumnIndex, nsAString& _retval) { if (aColumnIndex < 0 || aColumnIndex >= mColumnInfo.Count()) return NS_ERROR_INVALID_ARG; PRInt32 type = ((ColumnInfo*)mColumnInfo[aColumnIndex])->mType; switch (type) { case mozISqlResult::TYPE_STRING: _retval.AssignLiteral("string"); break; case mozISqlResult::TYPE_INT: _retval.AssignLiteral("int"); break; case mozISqlResult::TYPE_FLOAT: _retval.AssignLiteral("float"); break; case mozISqlResult::TYPE_DECIMAL: _retval.AssignLiteral("decimal"); break; case mozISqlResult::TYPE_DATE: _retval.AssignLiteral("date"); break; case mozISqlResult::TYPE_TIME: _retval.AssignLiteral("time"); break; case mozISqlResult::TYPE_DATETIME: _retval.AssignLiteral("datetime"); break; case mozISqlResult::TYPE_BOOL: _retval.AssignLiteral("bool"); break; } return NS_OK; } NS_IMETHODIMP mozSqlResult::GetColumnDisplaySize(PRInt32 aColumnIndex, PRInt32* _retval) { if (aColumnIndex < 0 || aColumnIndex >= mColumnInfo.Count()) return NS_ERROR_INVALID_ARG; ColumnInfo* columnInfo = ((ColumnInfo*)mColumnInfo[aColumnIndex]); PRInt32 mod = columnInfo->mMod - 4; switch (columnInfo->mType) { case mozISqlResult::TYPE_STRING: *_retval = mod; break; case mozISqlResult::TYPE_INT: *_retval = 11; // -2147483648 to +2147483647 break; case mozISqlResult::TYPE_FLOAT: *_retval = 11; break; case mozISqlResult::TYPE_DECIMAL: *_retval = ((mod >> 16) & 0xffff) + 1 + (mod & 0xffff); break; case mozISqlResult::TYPE_DATE: *_retval = 14; // "01/01/4713 BC" - "31/12/32767 AD" break; case mozISqlResult::TYPE_TIME: *_retval = 8; // 00:00:00-23:59:59 break; case mozISqlResult::TYPE_DATETIME: *_retval = 22; break; case mozISqlResult::TYPE_BOOL: *_retval = 1; break; default: *_retval = columnInfo->mSize; } return NS_OK; } NS_IMETHODIMP mozSqlResult::Enumerate(mozISqlResultEnumerator** _retval) { mozISqlResultEnumerator* enumerator = new mozSqlResultEnumerator(this); if (! enumerator) return NS_ERROR_OUT_OF_MEMORY; NS_ADDREF(*_retval = enumerator); return NS_OK; } NS_IMETHODIMP mozSqlResult::Open(mozISqlInputStream** _retval) { mozSqlResultStream* stream = new mozSqlResultStream(this); if (! stream) return NS_ERROR_OUT_OF_MEMORY; NS_ADDREF(*_retval = stream); return NS_OK; } NS_IMETHODIMP mozSqlResult::Reload() { mozISqlResult* result = this; nsresult rv = mConnection->ExecuteQuery(mQuery, &result); if (NS_FAILED(rv)) return rv; NS_RELEASE(result); return NS_OK; } NS_IMETHODIMP mozSqlResult::GetResourceAtIndex(PRInt32 aRowIndex, nsIRDFResource** _retval) { if (aRowIndex < 0 || aRowIndex >= mRows.Count()) return NS_ERROR_INVALID_ARG; NS_ADDREF(*_retval = ((Row*)mRows[aRowIndex])->mSource); return NS_OK; } NS_IMETHODIMP mozSqlResult::GetIndexOfResource(nsIRDFResource *aResource, PRInt32* _retval) { *_retval = -1; for (PRInt32 i = 0; i < mRows.Count(); i++) { if (((Row*)mRows[i])->mSource == aResource) { *_retval = i; break; } } return NS_OK; } NS_IMETHODIMP mozSqlResult::GetURI(char **aURI) { *aURI = nsCRT::strdup("rdf:result"); if (! *aURI) return NS_ERROR_OUT_OF_MEMORY; return NS_OK; } NS_IMETHODIMP mozSqlResult::GetSource(nsIRDFResource* aPoperty, nsIRDFNode* aTarget, PRBool aTruthValue, nsIRDFResource** _retval) { return NS_ERROR_NOT_IMPLEMENTED; } NS_IMETHODIMP mozSqlResult::GetSources(nsIRDFResource* aProperty, nsIRDFNode* aTarget, PRBool aTruthValue, nsISimpleEnumerator** _retval) { return NS_ERROR_NOT_IMPLEMENTED; } NS_IMETHODIMP mozSqlResult::GetTarget(nsIRDFResource* aSource, nsIRDFResource* aProperty, PRBool aTruthValue, nsIRDFNode** _retval) { *_retval = nsnull; nsVoidKey key(aSource); Row* row = static_cast(mSources.Get(&key)); if (! row) return NS_RDF_NO_VALUE; PRInt32 columnIndex = -1; for (PRInt32 i = 0; i < mColumnInfo.Count(); i++) { nsIRDFResource* property = ((ColumnInfo*)mColumnInfo[i])->mProperty; if (property == aProperty) { columnIndex = i; break; } } if (columnIndex == -1) return NS_RDF_NO_VALUE; nsCOMPtr node; Cell* cell = row->mCells[columnIndex]; if (cell->IsNull()) if (mDisplayNullAsText) node = kNullLiteral; else node = kEmptyLiteral; else { PRInt32 type = cell->GetType(); if (type == mozISqlResult::TYPE_STRING) { nsCOMPtr literal; gRDFService->GetLiteral(cell->mString, getter_AddRefs(literal)); node = literal; } else if (type == mozISqlResult::TYPE_INT) { nsCOMPtr literal; gRDFService->GetIntLiteral(cell->mInt, getter_AddRefs(literal)); node = literal; } else if (type == mozISqlResult::TYPE_FLOAT || type == mozISqlResult::TYPE_DECIMAL) { nsCOMPtr literal; gRDFService->GetIntLiteral(cell->mInt, getter_AddRefs(literal)); node = literal; } else if (type == mozISqlResult::TYPE_DATE || type == mozISqlResult::TYPE_TIME || type == mozISqlResult::TYPE_DATETIME) { nsCOMPtr literal; gRDFService->GetDateLiteral(cell->mDate, getter_AddRefs(literal)); node = literal; } else if (type == mozISqlResult::TYPE_BOOL) node = cell->mBool ? kTrueLiteral : kFalseLiteral; } NS_IF_ADDREF(*_retval = node); return NS_OK; } NS_IMETHODIMP mozSqlResult::GetTargets(nsIRDFResource* aSource, nsIRDFResource* aProperty, PRBool aTruthValue, nsISimpleEnumerator** _retval) { if (aSource == kSQL_ResultRoot && aProperty == kNC_Child && aTruthValue) { nsISimpleEnumerator* enumerator = new mozSqlResultEnumerator(this); if (! enumerator) return NS_ERROR_OUT_OF_MEMORY; NS_ADDREF(*_retval = enumerator); return NS_OK; } return NS_RDF_NO_VALUE; } NS_IMETHODIMP mozSqlResult::Assert(nsIRDFResource* aSource, nsIRDFResource* aProperty, nsIRDFNode* aTarget, PRBool aTruthValue) { return NS_ERROR_NOT_IMPLEMENTED; } NS_IMETHODIMP mozSqlResult::Unassert(nsIRDFResource* aSource, nsIRDFResource* aProperty, nsIRDFNode* aTarget) { return NS_ERROR_NOT_IMPLEMENTED; } NS_IMETHODIMP mozSqlResult::Change(nsIRDFResource* aSource, nsIRDFResource* aProperty, nsIRDFNode* aOldTarget, nsIRDFNode* aNewTarget) { return NS_ERROR_NOT_IMPLEMENTED; } NS_IMETHODIMP mozSqlResult::Move(nsIRDFResource* aOldSource, nsIRDFResource* aNewSource, nsIRDFResource* aProperty, nsIRDFNode* aTarget) { return NS_ERROR_NOT_IMPLEMENTED; } NS_IMETHODIMP mozSqlResult::HasAssertion(nsIRDFResource* aSource, nsIRDFResource* aProperty, nsIRDFNode *aTarget, PRBool aTruthValue, PRBool* _retval) { *_retval = PR_FALSE; if (aSource == kSQL_ResultRoot && aProperty == kNC_Child && aTruthValue) { nsVoidKey key(aTarget); Row* row = static_cast(mSources.Get(&key)); if (row) *_retval = PR_TRUE; } return NS_OK; } NS_IMETHODIMP mozSqlResult::AddObserver(nsIRDFObserver *aObserver) { mObservers.AppendObject(aObserver); return NS_OK; } NS_IMETHODIMP mozSqlResult::RemoveObserver(nsIRDFObserver *aObserver) { mObservers.RemoveObject(aObserver); return NS_OK; } NS_IMETHODIMP mozSqlResult::HasArcIn(nsIRDFNode* aNode, nsIRDFResource* aArc, PRBool* _retval) { return NS_ERROR_NOT_IMPLEMENTED; } NS_IMETHODIMP mozSqlResult::HasArcOut(nsIRDFResource* aSource, nsIRDFResource*aArc, PRBool* _retval) { return NS_ERROR_NOT_IMPLEMENTED; } NS_IMETHODIMP mozSqlResult::ArcLabelsIn(nsIRDFNode* aTarget, nsISimpleEnumerator** _retval) { return NS_ERROR_NOT_IMPLEMENTED; } NS_IMETHODIMP mozSqlResult::ArcLabelsOut(nsIRDFResource* aSource, nsISimpleEnumerator** _retval) { return NS_ERROR_NOT_IMPLEMENTED; } NS_IMETHODIMP mozSqlResult::GetAllResources(nsISimpleEnumerator** _retval) { nsISimpleEnumerator* enumerator = new mozSqlResultEnumerator(this); if (! enumerator) return NS_ERROR_OUT_OF_MEMORY; NS_ADDREF(*_retval = enumerator); return NS_OK; } NS_IMETHODIMP mozSqlResult::GetAllCmds(nsIRDFResource* aSource, nsISimpleEnumerator** _retval) { return NS_ERROR_NOT_IMPLEMENTED; } NS_IMETHODIMP mozSqlResult::IsCommandEnabled(nsISupportsArray* aSources, nsIRDFResource* aCommand, nsISupportsArray* aArguments, PRBool* _retval) { return NS_ERROR_NOT_IMPLEMENTED; } NS_IMETHODIMP mozSqlResult::DoCommand(nsISupportsArray* aSources, nsIRDFResource* aCommand, nsISupportsArray* aArguments) { return NS_ERROR_NOT_IMPLEMENTED; } NS_IMETHODIMP mozSqlResult::BeginUpdateBatch() { for (PRInt32 i = 0; i < mObservers.Count(); i++) { mObservers[i]->OnBeginUpdateBatch(this); } return NS_OK; } NS_IMETHODIMP mozSqlResult::EndUpdateBatch() { for (PRInt32 i = 0; i < mObservers.Count(); i++) { mObservers[i]->OnEndUpdateBatch(this); } return NS_OK; } NS_IMETHODIMP mozSqlResult::GetLoaded(PRBool* aResult) { *aResult = PR_TRUE; return NS_OK; } NS_IMETHODIMP mozSqlResult::Init(const char* aURI) { return NS_ERROR_NOT_IMPLEMENTED; } NS_IMETHODIMP mozSqlResult::Refresh(PRBool aBlocking) { if (aBlocking) return Reload(); return NS_ERROR_NOT_IMPLEMENTED; } NS_IMETHODIMP mozSqlResult::Flush() { return NS_ERROR_NOT_IMPLEMENTED; } NS_IMETHODIMP mozSqlResult::FlushTo(const char *aURI) { return NS_ERROR_NOT_IMPLEMENTED; } /* NS_IMETHODIMP mozSqlResult::GetRowCount(PRInt32 *aRowCount) { *aRowCount = mRows.Count(); return NS_OK; } */ NS_IMETHODIMP mozSqlResult::GetSelection(nsITreeSelection * *aSelection) { NS_IF_ADDREF(*aSelection = mSelection); return NS_OK; } NS_IMETHODIMP mozSqlResult::SetSelection(nsITreeSelection * aSelection) { mSelection = aSelection; return NS_OK; } NS_IMETHODIMP mozSqlResult::GetRowProperties(PRInt32 index, nsISupportsArray *properties) { return NS_OK; } NS_IMETHODIMP mozSqlResult::GetCellProperties(PRInt32 row, nsITreeColumn* col, nsISupportsArray *properties) { return NS_OK; } NS_IMETHODIMP mozSqlResult::GetColumnProperties(nsITreeColumn* aCol, nsISupportsArray *properties) { return NS_OK; } NS_IMETHODIMP mozSqlResult::IsContainer(PRInt32 index, PRBool *_retval) { *_retval = PR_FALSE; return NS_OK; } NS_IMETHODIMP mozSqlResult::IsContainerOpen(PRInt32 index, PRBool *_retval) { *_retval = PR_FALSE; return NS_OK; } NS_IMETHODIMP mozSqlResult::IsContainerEmpty(PRInt32 index, PRBool *_retval) { *_retval = PR_FALSE; return NS_OK; } NS_IMETHODIMP mozSqlResult::IsSeparator(PRInt32 index, PRBool *_retval) { *_retval = PR_FALSE; return NS_OK; } NS_IMETHODIMP mozSqlResult::IsSorted(PRBool *_retval) { *_retval = PR_FALSE; return NS_OK; } NS_IMETHODIMP mozSqlResult::CanDrop(PRInt32 index, PRInt32 orientation, PRBool *_retval) { *_retval = PR_FALSE; return NS_OK; } NS_IMETHODIMP mozSqlResult::Drop(PRInt32 row, PRInt32 orientation) { return NS_OK; } NS_IMETHODIMP mozSqlResult::GetParentIndex(PRInt32 rowIndex, PRInt32 *_retval) { *_retval = -1; return NS_OK; } NS_IMETHODIMP mozSqlResult::HasNextSibling(PRInt32 rowIndex, PRInt32 afterIndex, PRBool *_retval) { *_retval = PR_FALSE; return NS_OK; } NS_IMETHODIMP mozSqlResult::GetLevel(PRInt32 index, PRInt32 *_retval) { *_retval = 0; return NS_OK; } NS_IMETHODIMP mozSqlResult::GetImageSrc(PRInt32 row, nsITreeColumn* col, nsAString & _retval) { _retval.Truncate(); return NS_OK; } NS_IMETHODIMP mozSqlResult::GetProgressMode(PRInt32 row, nsITreeColumn* col, PRInt32 *_retval) { *_retval = 0; return NS_OK; } NS_IMETHODIMP mozSqlResult::GetCellValue(PRInt32 row, nsITreeColumn* col, nsAString & _retval) { PRInt32 columnIndex; col->GetIndex(&columnIndex); Cell* cell = ((Row*)mRows[row])->mCells[columnIndex]; if (! cell->IsNull()) { PRInt32 type = cell->GetType(); if (type == mozISqlResult::TYPE_BOOL) { if (cell->mBool) _retval.AssignLiteral("true"); else _retval.AssignLiteral("false"); } } return NS_OK; } NS_IMETHODIMP mozSqlResult::GetCellText(PRInt32 row, nsITreeColumn* col, nsAString & _retval) { PRInt32 columnIndex; col->GetIndex(&columnIndex); Cell* cell = ((Row*)mRows[row])->mCells[columnIndex]; if (cell->IsNull()) { if (mDisplayNullAsText) _retval.AssignLiteral("null"); } else { PRInt32 type = cell->GetType(); if (type == mozISqlResult::TYPE_STRING) _retval.Assign(cell->mString); else if (type == mozISqlResult::TYPE_INT) { nsAutoString s; s.AppendInt(cell->mInt); _retval.Assign(s); } else if (type == mozISqlResult::TYPE_FLOAT || type == mozISqlResult::TYPE_DECIMAL) { nsAutoString s; s.AppendFloat(cell->mFloat); _retval.Assign(s); } else if (type == mozISqlResult::TYPE_DATE || type == mozISqlResult::TYPE_TIME || type == mozISqlResult::TYPE_DATETIME) { nsAutoString value; mozSqlResult::gFormat->FormatPRTime(nsnull, type != mozISqlResult::TYPE_TIME ? kDateFormatShort : kDateFormatNone, type != mozISqlResult::TYPE_DATE ? kTimeFormatSeconds : kTimeFormatNone, PRTime(cell->mDate), value); _retval.Assign(value); } else if (type == mozISqlResult::TYPE_BOOL) { if (cell->mBool) _retval.AssignLiteral("true"); else _retval.AssignLiteral("false"); } } return NS_OK; } NS_IMETHODIMP mozSqlResult::SetTree(nsITreeBoxObject *tree) { mBoxObject = tree; return NS_OK; } NS_IMETHODIMP mozSqlResult::ToggleOpenState(PRInt32 index) { return NS_OK; } NS_IMETHODIMP mozSqlResult::CycleHeader(nsITreeColumn* aCol) { return NS_OK; } NS_IMETHODIMP mozSqlResult::SelectionChanged() { return NS_OK; } NS_IMETHODIMP mozSqlResult::CycleCell(PRInt32 row, nsITreeColumn* aCol) { return NS_OK; } NS_IMETHODIMP mozSqlResult::IsEditable(PRInt32 row, nsITreeColumn* col, PRBool *_retval) { return CanUpdate(_retval); } NS_IMETHODIMP mozSqlResult::IsSelectable(PRInt32 row, nsITreeColumn* col, PRBool *_retval) { *_retval = PR_FALSE; return NS_OK; } NS_IMETHODIMP mozSqlResult::SetCellValue(PRInt32 row, nsITreeColumn* col, const nsAString& value) { PRInt32 columnIndex; col->GetIndex(&columnIndex); Row* srcRow = (Row*)mRows[row]; Row* buffer = Row::Create(mAllocator, nsnull, mColumnInfo, srcRow); Cell* cell = buffer->mCells[columnIndex]; if (value.EqualsLiteral("true")) { cell->mBool = PR_TRUE; } else if (value.EqualsLiteral("false")) { cell->mBool = PR_FALSE; } PRInt32 count; nsresult rv = UpdateRow(row, buffer, &count); if (NS_FAILED(rv)) return rv; if (mBoxObject) mBoxObject->InvalidateCell(row, col); return NS_OK; } NS_IMETHODIMP mozSqlResult::SetCellText(PRInt32 row, nsITreeColumn* col, const nsAString& value) { return NS_OK; } NS_IMETHODIMP mozSqlResult::PerformAction(const PRUnichar *action) { return NS_OK; } NS_IMETHODIMP mozSqlResult::PerformActionOnRow(const PRUnichar *action, PRInt32 row) { return NS_OK; } NS_IMETHODIMP mozSqlResult::PerformActionOnCell(const PRUnichar *action, PRInt32 row, nsITreeColumn* aCol) { return NS_OK; } void mozSqlResult::ClearColumnInfo() { for (PRInt32 i = 0; i < mColumnInfo.Count(); i++) { ColumnInfo* columnInfo = (ColumnInfo*)mColumnInfo[i]; ColumnInfo::Destroy(mAllocator, columnInfo); } mColumnInfo.Clear(); } void mozSqlResult::ClearRows() { for (PRInt32 i = 0; i < mRows.Count(); i++) { Row* row = (Row*)mRows[i]; Row::Destroy(mAllocator, mColumnInfo.Count(), row); } mRows.Clear(); mSources.Reset(); } nsresult mozSqlResult::EnsureTableName() { if (!mTableName.IsEmpty()) return NS_OK; nsAString::const_iterator start, end; mQuery.BeginReading(start); mQuery.EndReading(end); NS_NAMED_LITERAL_STRING(from, "from"); nsAString::const_iterator iter = end; if (FindInReadable(from, start, iter, nsCaseInsensitiveStringComparator())) { while (iter != end && nsCRT::IsAsciiSpace(*iter)) ++iter; start = iter; while (iter != end && !nsCRT::IsAsciiSpace(*iter)) ++iter; mTableName.Assign(Substring(start, iter)); } else return NS_ERROR_FAILURE; return NS_OK; } nsresult mozSqlResult::EnsurePrimaryKeys() { if (mPrimaryKeys) return NS_OK; nsAutoString schema; nsAutoString table; nsAString::const_iterator start, s; nsAString::const_iterator end, e; mTableName.BeginReading(start); mTableName.EndReading(end); s = start; e = end; if (FindInReadable(NS_LITERAL_STRING("."), s, e)) { schema.Assign(Substring(start, s)); table.Assign(Substring(e, end)); } else { table.Assign(mTableName); } nsCOMPtr result; nsresult rv = mConnection->GetPrimaryKeys(schema, table, getter_AddRefs(result)); if (NS_FAILED(rv)) return rv; nsCOMPtr primaryKeys; rv = result->Enumerate(getter_AddRefs(primaryKeys)); if (NS_FAILED(rv)) return rv; rv = primaryKeys->First(); if (NS_FAILED(rv)) return rv; mPrimaryKeys = primaryKeys; return NS_OK; } void mozSqlResult::AppendValue(Cell* aCell, nsAutoString& aValues) { if (aCell->IsNull()) aValues.AppendLiteral("NULL"); else if (aCell->IsDefault()) aValues.AppendLiteral("DEFAULT"); else { PRInt32 type = aCell->GetType(); if (type == mozISqlResult::TYPE_STRING) { aValues.Append(PRUnichar('\'')); aValues.Append(aCell->mString); aValues.Append(PRUnichar('\'')); } else if (type == mozISqlResult::TYPE_INT) aValues.AppendInt(aCell->mInt); else if (type == mozISqlResult::TYPE_FLOAT || type == mozISqlResult::TYPE_DECIMAL) aValues.AppendFloat(aCell->mFloat); else if (type == mozISqlResult::TYPE_DATE || type == mozISqlResult::TYPE_TIME || type == mozISqlResult::TYPE_DATETIME) { aValues.Append(PRUnichar('\'')); nsAutoString value; gFormat->FormatPRTime(nsnull, type != mozISqlResult::TYPE_TIME ? kDateFormatLong : kDateFormatNone, type != mozISqlResult::TYPE_DATE ? kTimeFormatSeconds : kTimeFormatNone, PRTime(aCell->mDate), value); aValues.Append(value); aValues.Append(PRUnichar('\'')); } else if (type == mozISqlResult::TYPE_BOOL) { aValues.Append(PRUnichar('\'')); aValues.AppendInt(aCell->mBool); aValues.Append(PRUnichar('\'')); } } } nsresult mozSqlResult::AppendKeys(Row* aRow, nsAutoString& aKeys) { mPrimaryKeys->BeforeFirst(); PRBool hasNext = PR_FALSE; do { if (hasNext) aKeys.AppendLiteral(" AND "); mPrimaryKeys->Next(&hasNext); nsAutoString value; mPrimaryKeys->GetString(2, value); aKeys.Append(value); aKeys.Append(PRUnichar('=')); PRInt32 index; GetColumnIndex(value, &index); if (index == -1) { mErrorMessage.AssignLiteral("MOZSQL: The result doesn't contain all primary key fields"); return NS_ERROR_FAILURE; } Cell* cell = aRow->mCells[index]; AppendValue(cell, aKeys); } while(hasNext); return NS_OK; } nsresult mozSqlResult::GetValues(Row* aRow, mozISqlResult** aResult, PRBool aUseID) { nsAutoString query(mQuery); nsAString::const_iterator start; nsAString::const_iterator end; query.BeginReading(start); query.EndReading(end); NS_NAMED_LITERAL_STRING(where, "WHERE"); nsAString::const_iterator s = start; nsAString::const_iterator e = end; if (FindInReadable(where, s, e, nsCaseInsensitiveStringComparator())) { nsAutoString keys(PRUnichar(' ')); if (aUseID) { nsAutoString IDName; ((mozSqlConnection*)mConnection.get())->GetIDName(IDName); PRInt32 lastID; mConnection->GetLastID(&lastID); keys.Append(IDName); keys.Append(PRUnichar('=')); keys.AppendInt(lastID); } else { nsresult rv = AppendKeys(aRow, keys); if (NS_FAILED(rv)) return rv; } keys.AppendLiteral(" AND "); query.Insert(keys, Distance(start, e)); } else { NS_NAMED_LITERAL_STRING(from, "FROM"); s = start; e = end; if (FindInReadable(from, s, e, nsCaseInsensitiveStringComparator())) { while (e != end && nsCRT::IsAsciiSpace(*e)) ++e; while (e != end && !nsCRT::IsAsciiSpace(*e)) ++e; nsAutoString keys(NS_LITERAL_STRING(" WHERE ")); if (aUseID) { nsAutoString IDName; ((mozSqlConnection*)mConnection.get())->GetIDName(IDName); PRInt32 lastID; mConnection->GetLastID(&lastID); keys.Append(IDName); keys.Append(PRUnichar('=')); keys.AppendInt(lastID); } else { nsresult rv = AppendKeys(aRow, keys); if (NS_FAILED(rv)) return rv; } query.Insert(keys, Distance(start, e)); } } nsCOMPtr result; nsresult rv = mConnection->ExecuteQuery(query, getter_AddRefs(result)); if (NS_FAILED(rv)) { mConnection->GetErrorMessage(mErrorMessage); return rv; } NS_ADDREF(*aResult = result); return NS_OK; } nsresult mozSqlResult::CopyValues(mozISqlResult* aResult, Row* aRow) { nsCOMPtr enumerator; nsresult rv = aResult->Enumerate(getter_AddRefs(enumerator)); if (NS_FAILED(rv)) return rv; rv = enumerator->First(); if (NS_FAILED(rv)) return rv; PRInt32 columnCount; aResult->GetColumnCount(&columnCount); for (PRInt32 i = 0; i < columnCount; i++) { Cell* cell = aRow->mCells[i]; PRBool isNull; enumerator->IsNull(i, &isNull); if (isNull) cell->SetNull(PR_TRUE); else { cell->SetNull(PR_FALSE); PRInt32 type; aResult->GetColumnType(i, &type); if (type == mozISqlResult::TYPE_STRING) { nsAutoString value; enumerator->GetString(i, value); cell->SetString(ToNewUnicode(value)); } else if (type == mozISqlResult::TYPE_INT) enumerator->GetInt(i, &cell->mInt); else if (type == mozISqlResult::TYPE_FLOAT) enumerator->GetFloat(i, &cell->mFloat); else if (type == mozISqlResult::TYPE_DECIMAL) enumerator->GetDecimal(i, &cell->mFloat); else if (type == mozISqlResult::TYPE_DATE) enumerator->GetDate(i, &cell->mDate); else if (type == mozISqlResult::TYPE_TIME) enumerator->GetDate(i, &cell->mDate); else if (type == mozISqlResult::TYPE_DATETIME) enumerator->GetDate(i, &cell->mDate); else if (type == mozISqlResult::TYPE_BOOL) enumerator->GetBool(i, &cell->mBool); } } return NS_OK; } nsresult mozSqlResult::InsertRow(Row* aSrcRow, PRInt32* _retval) { *_retval = -1; nsresult rv = EnsureTableName(); if (NS_FAILED(rv)) return rv; rv = EnsurePrimaryKeys(); if (NS_FAILED(rv)) return rv; nsAutoString names; nsAutoString values; names.Append(PRUnichar('(')); values.Append(PRUnichar('(')); PRInt32 i; for (i = 0; i < mColumnInfo.Count(); i++) { if (i) { names.AppendLiteral(", "); values.AppendLiteral(", "); } names.Append(((ColumnInfo*)mColumnInfo[i])->mName); Cell* cell = aSrcRow->mCells[i]; AppendValue(cell, values); } names.Append(PRUnichar(')')); values.Append(PRUnichar(')')); PRInt32 affectedRows; rv = mConnection->ExecuteUpdate(NS_LITERAL_STRING("INSERT INTO ") + mTableName + names + NS_LITERAL_STRING(" VALUES") + values, &affectedRows); if (NS_FAILED(rv)) { mConnection->GetErrorMessage(mErrorMessage); return rv; } nsAutoString IDName; ((mozSqlConnection*)mConnection.get())->GetIDName(IDName); // assume that if the IDName is empty that we don't need to re-get the last row if (!IDName.IsEmpty()){ nsCOMPtr result; rv = GetValues(aSrcRow, getter_AddRefs(result), PR_TRUE); if (NS_FAILED(rv)) return rv; PRInt32 rowCount; result->GetRowCount(&rowCount); if (rowCount == 0) { *_retval = 0; return NS_OK; } rv = CopyValues(result, aSrcRow); if (NS_FAILED(rv)) return rv; } nsCOMPtr resource; gRDFService->GetAnonymousResource(getter_AddRefs(resource)); Row* row = Row::Create(mAllocator, resource, mColumnInfo, aSrcRow); mRows.AppendElement(row); nsVoidKey key(resource); mSources.Put(&key, row); for (i = 0; i < mObservers.Count(); i++) mObservers[i]->OnAssert(this, kSQL_ResultRoot, kNC_Child, resource); if (mBoxObject) mBoxObject->RowCountChanged(mRows.Count() - 1, 1); *_retval = 1; return NS_OK; } nsresult mozSqlResult::UpdateRow(PRInt32 aRowIndex, Row* aSrcRow, PRInt32* _retval) { *_retval = -1; nsresult rv = EnsureTableName(); if (NS_FAILED(rv)) return rv; rv = EnsurePrimaryKeys(); if (NS_FAILED(rv)) return rv; nsAutoString values; PRInt32 i; for (i = 0; i < mColumnInfo.Count(); i++) { if (i) values.AppendLiteral(", "); values.Append(((ColumnInfo*)mColumnInfo[i])->mName); values.Append(PRUnichar('=')); Cell* cell = aSrcRow->mCells[i]; AppendValue(cell, values); } Row* row = (Row*)mRows[aRowIndex]; nsAutoString keys; rv = AppendKeys(row, keys); if (NS_FAILED(rv)) return rv; PRInt32 affectedRows; rv = mConnection->ExecuteUpdate(NS_LITERAL_STRING("UPDATE ") + mTableName + NS_LITERAL_STRING(" SET ") + values + NS_LITERAL_STRING(" WHERE ") + keys, &affectedRows); if (NS_FAILED(rv)) { mConnection->GetErrorMessage(mErrorMessage); return rv; } nsCOMPtr result; rv = GetValues(aSrcRow, getter_AddRefs(result), PR_FALSE); if (NS_FAILED(rv)) return rv; PRInt32 rowCount; result->GetRowCount(&rowCount); if (rowCount == 0) { mRows.RemoveElementAt(aRowIndex); nsVoidKey key(row->mSource); mSources.Remove(&key); for (PRInt32 i = 0; i < mObservers.Count(); i++) mObservers[i]->OnUnassert(this, kSQL_ResultRoot, kNC_Child, row->mSource); if (mBoxObject) mBoxObject->RowCountChanged(aRowIndex, -1); Row::Destroy(mAllocator, mColumnInfo.Count(), row); *_retval = 0; return NS_OK; } rv = CopyValues(result, row); if (NS_FAILED(rv)) return rv; for (i = 0; i < mColumnInfo.Count(); i++) { nsCOMPtr oldNode; nsCOMPtr newNode; Cell* cell = row->mCells[i]; if (cell->IsNull()) if (mDisplayNullAsText) newNode = kNullLiteral; else newNode = kEmptyLiteral; else { PRInt32 type = cell->GetType(); if (type == mozISqlResult::TYPE_STRING) { nsCOMPtr literal; PRUnichar* value = cell->mString; gRDFService->GetLiteral(value, getter_AddRefs(literal)); newNode = literal; } else if (type == mozISqlResult::TYPE_INT) { nsCOMPtr literal; PRInt32 value = cell->mInt; gRDFService->GetIntLiteral(value, getter_AddRefs(literal)); newNode = literal; } else if (type == mozISqlResult::TYPE_FLOAT || type == mozISqlResult::TYPE_DECIMAL) { nsCOMPtr literal; PRInt32 value = cell->mInt; gRDFService->GetIntLiteral(value, getter_AddRefs(literal)); newNode = literal; } else if (type == mozISqlResult::TYPE_DATE || type == mozISqlResult::TYPE_TIME || type == mozISqlResult::TYPE_DATETIME) { nsCOMPtr literal; PRInt64 value = cell->mDate; gRDFService->GetDateLiteral(value, getter_AddRefs(literal)); newNode = literal; } else if (type == mozISqlResult::TYPE_BOOL) newNode = cell->mBool ? kTrueLiteral : kFalseLiteral; } for (PRInt32 j = 0; j < mObservers.Count(); j++) { nsIRDFResource* source = row->mSource; nsIRDFResource* property = ((ColumnInfo*)mColumnInfo[i])->mProperty; mObservers[j]->OnChange(this, source, property, oldNode, newNode); } } if (mBoxObject) mBoxObject->InvalidateRow(aRowIndex); *_retval = 1; return NS_OK; } nsresult mozSqlResult::DeleteRow(PRInt32 aRowIndex, PRInt32* _retval) { *_retval = -1; nsresult rv = EnsureTableName(); if (NS_FAILED(rv)) return rv; rv = EnsurePrimaryKeys(); if (NS_FAILED(rv)) return rv; Row* row = (Row*)mRows[aRowIndex]; nsAutoString keys; rv = AppendKeys(row, keys); if (NS_FAILED(rv)) return rv; PRInt32 affectedRows; rv = mConnection->ExecuteUpdate(NS_LITERAL_STRING("DELETE FROM ") + mTableName + NS_LITERAL_STRING(" WHERE ") + keys, &affectedRows); if (NS_FAILED(rv)) { mConnection->GetErrorMessage(mErrorMessage); return rv; } mRows.RemoveElementAt(aRowIndex); nsVoidKey key(row->mSource); mSources.Remove(&key); for (PRInt32 i = 0; i < mObservers.Count(); i++) mObservers[i]->OnUnassert(this, kSQL_ResultRoot, kNC_Child, row->mSource); if (mBoxObject) mBoxObject->RowCountChanged(aRowIndex, -1); Row::Destroy(mAllocator, mColumnInfo.Count(), row); *_retval = 1; return NS_OK; } nsresult mozSqlResult::GetCondition(Row* aRow, nsAString& aCurrentCondition) { nsresult rv = EnsureTableName(); if (NS_FAILED(rv)) return rv; rv = EnsurePrimaryKeys(); if (NS_FAILED(rv)) return rv; nsAutoString keys; rv = AppendKeys(aRow, keys); if (NS_FAILED(rv)) return rv; aCurrentCondition = keys; return NS_OK; } mozSqlResultEnumerator::mozSqlResultEnumerator(mozSqlResult* aResult) : mResult(aResult), mCurrentIndex(-1), mCurrentRow(nsnull) { NS_ADDREF(mResult); mBuffer = Row::Create(mResult->mAllocator, nsnull, mResult->mColumnInfo); } mozSqlResultEnumerator::~mozSqlResultEnumerator() { Row::Destroy(mResult->mAllocator, mResult->mColumnInfo.Count(), mBuffer); NS_RELEASE(mResult); } NS_IMPL_ISUPPORTS2(mozSqlResultEnumerator, mozISqlResultEnumerator, nsISimpleEnumerator) NS_IMETHODIMP mozSqlResultEnumerator::GetErrorMessage(nsAString& aErrorMessage) { aErrorMessage = mResult->mErrorMessage; return NS_OK; } NS_IMETHODIMP mozSqlResultEnumerator::Next(PRBool* _retval) { if (mCurrentIndex + 1 > mResult->mRows.Count() - 1) return NS_ERROR_FAILURE; mCurrentIndex++; mCurrentRow = (Row*)mResult->mRows[mCurrentIndex]; *_retval = mCurrentIndex < mResult->mRows.Count() - 1; return NS_OK; } NS_IMETHODIMP mozSqlResultEnumerator::Previous(PRBool* _retval) { if (mCurrentIndex - 1 < 0) return NS_ERROR_FAILURE; mCurrentIndex--; mCurrentRow = (Row*)mResult->mRows[mCurrentIndex]; *_retval = mCurrentIndex > 0; return NS_OK; } NS_IMETHODIMP mozSqlResultEnumerator::BeforeFirst() { mCurrentIndex = -1; mCurrentRow = nsnull; return NS_OK; } NS_IMETHODIMP mozSqlResultEnumerator::First() { if (mResult->mRows.Count() == 0) return NS_ERROR_FAILURE; mCurrentIndex = 0; mCurrentRow = (Row*)mResult->mRows[mCurrentIndex]; return NS_OK; } NS_IMETHODIMP mozSqlResultEnumerator::Last() { if (mResult->mRows.Count() == 0) return NS_ERROR_FAILURE; mCurrentIndex = mResult->mRows.Count() - 1; mCurrentRow = (Row*)mResult->mRows[mCurrentIndex]; return NS_OK; } NS_IMETHODIMP mozSqlResultEnumerator::Relative(PRInt32 aRows) { if (mResult->mRows.Count() == 0) return NS_ERROR_FAILURE; PRInt32 newIndex = mCurrentIndex + aRows; if (newIndex < 0 || newIndex > mResult->mRows.Count() - 1) return NS_ERROR_FAILURE; mCurrentIndex = newIndex; mCurrentRow = (Row*)mResult->mRows[mCurrentIndex]; return NS_OK; } NS_IMETHODIMP mozSqlResultEnumerator::Absolute(PRInt32 aRowIndex) { if (mResult->mRows.Count() == 0) return NS_ERROR_FAILURE; if (aRowIndex < 0 || aRowIndex > mResult->mRows.Count() - 1) return NS_ERROR_FAILURE; mCurrentIndex = aRowIndex; mCurrentRow = (Row*)mResult->mRows[mCurrentIndex]; return NS_OK; } NS_IMETHODIMP mozSqlResultEnumerator::IsNull(PRInt32 aColumnIndex, PRBool* _retval) { if (! mCurrentRow) return NS_ERROR_FAILURE; Cell* cell = mCurrentRow->mCells[aColumnIndex]; *_retval = cell->IsNull(); return NS_OK; } NS_IMETHODIMP mozSqlResultEnumerator::GetVariant(PRInt32 aColumnIndex, nsIVariant** _retval) { if (! mCurrentRow) return NS_ERROR_FAILURE; nsresult rv; nsCOMPtr variant = do_CreateInstance(NS_VARIANT_CONTRACTID, &rv); if (NS_FAILED(rv)) return rv; Cell* cell = mCurrentRow->mCells[aColumnIndex]; if (! cell->IsNull()) { PRInt32 type = cell->GetType(); if (type == mozISqlResult::TYPE_STRING) variant->SetAsWString(cell->mString); else if (type == mozISqlResult::TYPE_INT) variant->SetAsInt32(cell->mInt); else if (type == mozISqlResult::TYPE_FLOAT || type == mozISqlResult::TYPE_DECIMAL) variant->SetAsFloat(cell->mFloat); else if (type == mozISqlResult::TYPE_DATE || type == mozISqlResult::TYPE_TIME || type == mozISqlResult::TYPE_DATETIME) { nsAutoString value; mozSqlResult::gFormat->FormatPRTime(nsnull, type != mozISqlResult::TYPE_TIME ? kDateFormatShort : kDateFormatNone, type != mozISqlResult::TYPE_DATE ? kTimeFormatSeconds : kTimeFormatNone, PRTime(cell->mDate), value); variant->SetAsAString(value); } else if (type == mozISqlResult::TYPE_BOOL) variant->SetAsBool(cell->mBool); } NS_ADDREF(*_retval = variant); return NS_OK; } NS_IMETHODIMP mozSqlResultEnumerator::GetString(PRInt32 aColumnIndex, nsAString& _retval) { if (! mCurrentRow) return NS_ERROR_FAILURE; Cell* cell = mCurrentRow->mCells[aColumnIndex]; if (cell->GetType() != mozISqlResult::TYPE_STRING) return NS_ERROR_FAILURE; if (! cell->IsNull()) _retval.Assign(cell->mString); return NS_OK; } NS_IMETHODIMP mozSqlResultEnumerator::GetInt(PRInt32 aColumnIndex, PRInt32* _retval) { if (aColumnIndex < 0 || aColumnIndex >= mResult->mColumnInfo.Count()) return NS_ERROR_INVALID_ARG; if (! mCurrentRow) return NS_ERROR_FAILURE; Cell* cell = mCurrentRow->mCells[aColumnIndex]; if (cell->GetType() != mozISqlResult::TYPE_INT) return NS_ERROR_FAILURE; *_retval = cell->IsNull() ? 0 : cell->mInt; return NS_OK; } NS_IMETHODIMP mozSqlResultEnumerator::GetFloat(PRInt32 aColumnIndex, float* _retval) { if (aColumnIndex < 0 || aColumnIndex >= mResult->mColumnInfo.Count()) return NS_ERROR_INVALID_ARG; if (! mCurrentRow) return NS_ERROR_FAILURE; Cell* cell = mCurrentRow->mCells[aColumnIndex]; if (cell->GetType() != mozISqlResult::TYPE_FLOAT) return NS_ERROR_FAILURE; *_retval = cell->IsNull() ? 0 : cell->mFloat; return NS_OK; } NS_IMETHODIMP mozSqlResultEnumerator::GetDecimal(PRInt32 aColumnIndex, float* _retval) { if (aColumnIndex < 0 || aColumnIndex >= mResult->mColumnInfo.Count()) return NS_ERROR_INVALID_ARG; if (! mCurrentRow) return NS_ERROR_FAILURE; Cell* cell = mCurrentRow->mCells[aColumnIndex]; if (cell->GetType() != mozISqlResult::TYPE_DECIMAL) return NS_ERROR_FAILURE; *_retval = cell->IsNull() ? 0 : cell->mFloat; return NS_OK; } NS_IMETHODIMP mozSqlResultEnumerator::GetDate(PRInt32 aColumnIndex, PRInt64* _retval) { if (aColumnIndex < 0 || aColumnIndex >= mResult->mColumnInfo.Count()) return NS_ERROR_INVALID_ARG; if (! mCurrentRow) return NS_ERROR_FAILURE; Cell* cell = mCurrentRow->mCells[aColumnIndex]; if (cell->GetType() != mozISqlResult::TYPE_DATE) return NS_ERROR_FAILURE; *_retval = cell->IsNull() ? 0 : cell->mDate; return NS_OK; } NS_IMETHODIMP mozSqlResultEnumerator::GetBool(PRInt32 aColumnIndex, PRBool* _retval) { if (aColumnIndex < 0 || aColumnIndex >= mResult->mColumnInfo.Count()) return NS_ERROR_INVALID_ARG; if (! mCurrentRow) return NS_ERROR_FAILURE; Cell* cell = mCurrentRow->mCells[aColumnIndex]; if (cell->GetType() != mozISqlResult::TYPE_BOOL) return NS_ERROR_FAILURE; *_retval = cell->IsNull() ? 0 : cell->mBool; return NS_OK; } NS_IMETHODIMP mozSqlResultEnumerator::SetNull(PRInt32 aColumnIndex) { if (aColumnIndex < 0 || aColumnIndex >= mResult->mColumnInfo.Count()) return NS_ERROR_INVALID_ARG; if (! mBuffer) return NS_ERROR_FAILURE; Cell* cell = mBuffer->mCells[aColumnIndex]; cell->SetNull(PR_TRUE); return NS_OK; } NS_IMETHODIMP mozSqlResultEnumerator::SetDefault(PRInt32 aColumnIndex) { if (aColumnIndex < 0 || aColumnIndex >= mResult->mColumnInfo.Count()) return NS_ERROR_INVALID_ARG; if (! mBuffer) return NS_ERROR_FAILURE; Cell* cell = mBuffer->mCells[aColumnIndex]; cell->SetDefault(PR_TRUE); return NS_OK; } NS_IMETHODIMP mozSqlResultEnumerator::Copy(PRInt32 aColumnIndex) { if (aColumnIndex < 0 || aColumnIndex >= mResult->mColumnInfo.Count()) return NS_ERROR_INVALID_ARG; if (! mCurrentRow) return NS_ERROR_FAILURE; if (! mBuffer) return NS_ERROR_FAILURE; Cell* currentCell = mCurrentRow->mCells[aColumnIndex]; Cell* bufferCell = mBuffer->mCells[aColumnIndex]; Cell::Copy(currentCell, bufferCell); return NS_OK; } NS_IMETHODIMP mozSqlResultEnumerator::SetVariant(PRInt32 aColumnIndex, nsIVariant* aValue) { if (aColumnIndex < 0 || aColumnIndex >= mResult->mColumnInfo.Count()) return NS_ERROR_INVALID_ARG; if (! mBuffer) return NS_ERROR_FAILURE; Cell* cell = mBuffer->mCells[aColumnIndex]; cell->SetNull(PR_FALSE); PRInt32 type = cell->GetType(); if (type == mozISqlResult::TYPE_STRING) { PRUnichar* value; aValue->GetAsWString(&value); cell->SetString(value); } else if (type == mozISqlResult::TYPE_INT) { PRInt32 value; aValue->GetAsInt32(&value); cell->mInt = value; } else if (type == mozISqlResult::TYPE_FLOAT || type == mozISqlResult::TYPE_DECIMAL) { float value; aValue->GetAsFloat(&value); cell->mFloat = value; } else if (type == mozISqlResult::TYPE_DATE || type == mozISqlResult::TYPE_TIME || type == mozISqlResult::TYPE_DATETIME) { nsCAutoString value; aValue->GetAsACString(value); PR_ParseTimeString(value.get(), PR_FALSE, &cell->mDate); } else if (type == mozISqlResult::TYPE_BOOL) { PRBool value; aValue->GetAsBool(&value); cell->mBool = value; } return NS_OK; } NS_IMETHODIMP mozSqlResultEnumerator::SetString(PRInt32 aColumnIndex, const nsAString& aValue) { if (aColumnIndex < 0 || aColumnIndex >= mResult->mColumnInfo.Count()) return NS_ERROR_INVALID_ARG; if (! mBuffer) return NS_ERROR_FAILURE; Cell* cell = mBuffer->mCells[aColumnIndex]; if (cell->GetType() != mozISqlResult::TYPE_STRING) return NS_ERROR_FAILURE; cell->SetNull(PR_FALSE); cell->SetString(ToNewUnicode(aValue)); return NS_OK; } NS_IMETHODIMP mozSqlResultEnumerator::SetInt(PRInt32 aColumnIndex, PRInt32 aValue) { if (aColumnIndex < 0 || aColumnIndex >= mResult->mColumnInfo.Count()) return NS_ERROR_INVALID_ARG; if (! mBuffer) return NS_ERROR_FAILURE; Cell* cell = mBuffer->mCells[aColumnIndex]; if (cell->GetType() != mozISqlResult::TYPE_INT) return NS_ERROR_FAILURE; cell->SetNull(PR_FALSE); cell->mInt = aValue; return NS_OK; } NS_IMETHODIMP mozSqlResultEnumerator::SetFloat(PRInt32 aColumnIndex, float aValue) { if (aColumnIndex < 0 || aColumnIndex >= mResult->mColumnInfo.Count()) return NS_ERROR_INVALID_ARG; if (! mBuffer) return NS_ERROR_FAILURE; Cell* cell = mBuffer->mCells[aColumnIndex]; if (cell->GetType() != mozISqlResult::TYPE_FLOAT) return NS_ERROR_FAILURE; cell->SetNull(PR_FALSE); cell->mFloat = aValue; return NS_OK; } NS_IMETHODIMP mozSqlResultEnumerator::SetDecimal(PRInt32 aColumnIndex, float aValue) { if (aColumnIndex < 0 || aColumnIndex >= mResult->mColumnInfo.Count()) return NS_ERROR_INVALID_ARG; if (! mBuffer) return NS_ERROR_FAILURE; Cell* cell = mBuffer->mCells[aColumnIndex]; if (cell->GetType() != mozISqlResult::TYPE_DECIMAL) return NS_ERROR_FAILURE; cell->SetNull(PR_FALSE); cell->mFloat = aValue; return NS_OK; } NS_IMETHODIMP mozSqlResultEnumerator::SetDate(PRInt32 aColumnIndex, PRInt64 aValue) { if (aColumnIndex < 0 || aColumnIndex >= mResult->mColumnInfo.Count()) return NS_ERROR_INVALID_ARG; if (! mBuffer) return NS_ERROR_FAILURE; Cell* cell = mBuffer->mCells[aColumnIndex]; if (cell->GetType() != mozISqlResult::TYPE_DATE) return NS_ERROR_FAILURE; cell->SetNull(PR_FALSE); cell->mDate = aValue; return NS_OK; } NS_IMETHODIMP mozSqlResultEnumerator::SetBool(PRInt32 aColumnIndex, PRBool aValue) { if (aColumnIndex < 0 || aColumnIndex >= mResult->mColumnInfo.Count()) return NS_ERROR_INVALID_ARG; if (! mBuffer) return NS_ERROR_FAILURE; Cell* cell = mBuffer->mCells[aColumnIndex]; if (cell->GetType() != mozISqlResult::TYPE_BOOL) return NS_ERROR_FAILURE; cell->SetNull(PR_FALSE); cell->mBool = aValue; return NS_OK; } NS_IMETHODIMP mozSqlResultEnumerator::SetNullValues() { for (PRInt32 i = 0; i < mResult->mColumnInfo.Count(); i++) { Cell* cell = mBuffer->mCells[i]; cell->SetNull(PR_TRUE); } return NS_OK; } NS_IMETHODIMP mozSqlResultEnumerator::SetDefaultValues() { for (PRInt32 i = 0; i < mResult->mColumnInfo.Count(); i++) { Cell* cell = mBuffer->mCells[i]; cell->SetDefault(PR_TRUE); } return NS_OK; } NS_IMETHODIMP mozSqlResultEnumerator::CopyValues() { if (! mCurrentRow) return NS_ERROR_FAILURE; Row::Copy(mResult->mColumnInfo.Count(), mCurrentRow, mBuffer); return NS_OK; } NS_IMETHODIMP mozSqlResultEnumerator::CanInsert(PRBool* _retval) { return mResult->CanInsert(_retval); } NS_IMETHODIMP mozSqlResultEnumerator::CanUpdate(PRBool* _retval) { return mResult->CanUpdate(_retval); } NS_IMETHODIMP mozSqlResultEnumerator::CanDelete(PRBool* _retval) { return mResult->CanDelete(_retval); } NS_IMETHODIMP mozSqlResultEnumerator::InsertRow(PRInt32* _retval) { return mResult->InsertRow(mBuffer, _retval); } NS_IMETHODIMP mozSqlResultEnumerator::UpdateRow(PRInt32* _retval) { return mResult->UpdateRow(mCurrentIndex, mBuffer, _retval); } NS_IMETHODIMP mozSqlResultEnumerator::DeleteRow(PRInt32* _retval) { nsresult rv = mResult->DeleteRow(mCurrentIndex, _retval); if (NS_FAILED(rv)) return rv; mCurrentIndex = -1; mCurrentRow = nsnull; return NS_OK; } NS_IMETHODIMP mozSqlResultEnumerator::GetCurrentCondition(nsAString& aCurrentCondition) { if (! mCurrentRow) return NS_ERROR_FAILURE; return mResult->GetCondition(mCurrentRow, aCurrentCondition); } NS_IMETHODIMP mozSqlResultEnumerator::HasMoreElements(PRBool* _retval) { *_retval = mCurrentIndex < mResult->mRows.Count() - 1; return NS_OK; } NS_IMETHODIMP mozSqlResultEnumerator::GetNext(nsISupports** _retval) { PRBool hasNext; Next(&hasNext); NS_ADDREF(*_retval = mCurrentRow->mSource); return NS_OK; } mozSqlResultStream::mozSqlResultStream(mozSqlResult* aResult) : mResult(aResult), mInitialized(PR_FALSE), mPosition(0) { NS_ADDREF(mResult); } mozSqlResultStream::~mozSqlResultStream() { NS_RELEASE(mResult); } NS_IMPL_ISUPPORTS2(mozSqlResultStream, mozISqlInputStream, nsIInputStream) NS_IMETHODIMP mozSqlResultStream::GetColumnHeader(PRInt32 aColumnIndex, nsAString& aHeader) { return NS_OK; } NS_IMETHODIMP mozSqlResultStream::SetColumnHeader(PRInt32 aColumnIndex, const nsAString& aHeader) { return NS_OK; } NS_IMETHODIMP mozSqlResultStream::Close() { return NS_OK; } NS_IMETHODIMP mozSqlResultStream::Available(PRUint32* _retval) { nsresult rv = EnsureBuffer(); if (NS_FAILED(rv)) return rv; *_retval = mBuffer.Length() - mPosition; return NS_OK; } NS_IMETHODIMP mozSqlResultStream::Read(char* aBuffer, PRUint32 aCount, PRUint32* _retval) { if (aCount == 0) { *_retval = 0; return NS_OK; } nsresult rv = EnsureBuffer(); if (NS_FAILED(rv)) return rv; if (aCount > mBuffer.Length() - mPosition) aCount = mBuffer.Length() - mPosition; memcpy(aBuffer, mBuffer.get() + mPosition, aCount); mPosition += aCount; *_retval = aCount; return NS_OK; } NS_IMETHODIMP mozSqlResultStream::ReadSegments(nsWriteSegmentFun aWriter, void* aClosure, PRUint32 aCount, PRUint32* _retval) { if (aCount == 0) { *_retval = 0; return NS_OK; } nsresult rv = EnsureBuffer(); if (NS_FAILED(rv)) return rv; if (aCount > mBuffer.Length() - mPosition) aCount = mBuffer.Length() - mPosition; rv = aWriter(this, aClosure, mBuffer.get() + mPosition, 0, aCount, _retval); if (NS_SUCCEEDED(rv)) mPosition += aCount; return NS_OK; } NS_IMETHODIMP mozSqlResultStream::IsNonBlocking(PRBool* _retval) { *_retval = PR_TRUE; return NS_OK; } nsresult mozSqlResultStream::EnsureBuffer() { if (!mInitialized) { mBuffer.AppendLiteral("\n"); mBuffer.AppendLiteral("\n\n"); PRInt32 rowCount = mResult->mRows.Count(); PRInt32 columnCount = mResult->mColumnInfo.Count(); for (PRInt32 i = 0; i < rowCount; i++) { mBuffer.AppendLiteral("\n"); Row* row = (Row*)mResult->mRows[i]; for (PRInt32 j = 0; j < columnCount; j++) { mBuffer.AppendLiteral("\n"); Cell* cell = row->mCells[j]; if (cell->IsNull()) mBuffer.AppendLiteral("null"); else { PRInt32 type = cell->GetType(); if (type == mozISqlResult::TYPE_STRING) mBuffer.Append(NS_ConvertUTF16toUTF8(cell->mString)); else if (type == mozISqlResult::TYPE_INT) mBuffer.AppendInt(cell->mInt); else if (type == mozISqlResult::TYPE_FLOAT || type == mozISqlResult::TYPE_DECIMAL) mBuffer.AppendFloat(cell->mFloat); else if (type == mozISqlResult::TYPE_DATE || type == mozISqlResult::TYPE_TIME || type == mozISqlResult::TYPE_DATETIME) { nsAutoString value; mozSqlResult::gFormat->FormatPRTime(nsnull, type != mozISqlResult::TYPE_TIME ? kDateFormatLong : kDateFormatNone, type != mozISqlResult::TYPE_DATE ? kTimeFormatSeconds : kTimeFormatNone, PRTime(cell->mDate), value); mBuffer.Append(NS_ConvertUTF16toUTF8(value)); } else if (type == mozISqlResult::TYPE_BOOL) { if (cell->mBool) mBuffer.AppendLiteral("true"); else mBuffer.AppendLiteral("false"); } } mBuffer.AppendLiteral("\n"); } mBuffer.AppendLiteral("\n"); } mBuffer.AppendLiteral("\n\n"); mInitialized = PR_TRUE; } return NS_OK; }