Mozilla/mozilla/extensions/sql/base/src/mozSqlResult.cpp

2295 lines
54 KiB
C++

/* ***** 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 <stdio.h>
#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<Row*>(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<nsIRDFNode> 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<nsIRDFLiteral> literal;
gRDFService->GetLiteral(cell->mString, getter_AddRefs(literal));
node = literal;
}
else if (type == mozISqlResult::TYPE_INT) {
nsCOMPtr<nsIRDFInt> literal;
gRDFService->GetIntLiteral(cell->mInt, getter_AddRefs(literal));
node = literal;
}
else if (type == mozISqlResult::TYPE_FLOAT ||
type == mozISqlResult::TYPE_DECIMAL) {
nsCOMPtr<nsIRDFInt> 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<nsIRDFDate> 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<Row*>(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<mozISqlResult> result;
nsresult rv = mConnection->GetPrimaryKeys(schema, table, getter_AddRefs(result));
if (NS_FAILED(rv))
return rv;
nsCOMPtr<mozISqlResultEnumerator> 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<mozISqlResult> 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<mozISqlResultEnumerator> 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<mozISqlResult> 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<nsIRDFResource> 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<mozISqlResult> 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<nsIRDFNode> oldNode;
nsCOMPtr<nsIRDFNode> 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<nsIRDFLiteral> literal;
PRUnichar* value = cell->mString;
gRDFService->GetLiteral(value, getter_AddRefs(literal));
newNode = literal;
}
else if (type == mozISqlResult::TYPE_INT) {
nsCOMPtr<nsIRDFInt> literal;
PRInt32 value = cell->mInt;
gRDFService->GetIntLiteral(value, getter_AddRefs(literal));
newNode = literal;
}
else if (type == mozISqlResult::TYPE_FLOAT ||
type == mozISqlResult::TYPE_DECIMAL) {
nsCOMPtr<nsIRDFInt> 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<nsIRDFDate> 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<nsIWritableVariant> 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("<?xml version=\"1.0\"?>\n");
mBuffer.AppendLiteral("<document>\n<body>\n");
PRInt32 rowCount = mResult->mRows.Count();
PRInt32 columnCount = mResult->mColumnInfo.Count();
for (PRInt32 i = 0; i < rowCount; i++) {
mBuffer.AppendLiteral("<row>\n");
Row* row = (Row*)mResult->mRows[i];
for (PRInt32 j = 0; j < columnCount; j++) {
mBuffer.AppendLiteral("<cell>\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("</cell>\n");
}
mBuffer.AppendLiteral("</row>\n");
}
mBuffer.AppendLiteral("</body>\n</document>\n");
mInitialized = PR_TRUE;
}
return NS_OK;
}