persistentstorage/dbms/utable/UT_DML.CPP
changeset 0 08ec8eefde2f
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/persistentstorage/dbms/utable/UT_DML.CPP	Fri Jan 22 11:06:30 2010 +0200
@@ -0,0 +1,374 @@
+// Copyright (c) 1998-2009 Nokia Corporation and/or its subsidiary(-ies).
+// All rights reserved.
+// This component and the accompanying materials are made available
+// under the terms of "Eclipse Public License v1.0"
+// which accompanies this distribution, and is available
+// at the URL "http://www.eclipse.org/legal/epl-v10.html".
+//
+// Initial Contributors:
+// Nokia Corporation - initial contribution.
+//
+// Contributors:
+//
+// Description:
+// SQL DML statements for Table framework
+// 
+//
+
+#include "UT_STD.H"
+
+// Class CSqlValues
+
+inline CSqlValues::TEntry::TEntry(const RSqlLiteral& aValue)
+	:iValue(aValue)
+	{}
+
+CSqlValues::CSqlValues()
+	:iValues(EGranularity)
+	{}
+
+CSqlValues::~CSqlValues()
+//
+// close all the literal objects
+//
+	{
+	for (TInt ii=iValues.Count();--ii>=0;)
+		iValues[ii].iValue.Close();
+	iValues.Close();
+	}
+
+void CSqlValues::AddL(const RSqlLiteral& aLiteral)
+	{
+	TEntry e(aLiteral);
+	__DEBUG(e.iType=TDbColType(-1);)
+	__LEAVE_IF_ERROR(iValues.Append(e));
+	}
+
+void CSqlValues::BindL(const CDbDataSource& aSource)
+//
+// Bind the values to a column set and optional column name list
+//
+	{
+	iValues.Compress();				// we have finished adding values
+	TInt columns=iValues.Count();
+	__ASSERT(columns>0);
+	if (aSource.ColumnCount()<columns)
+		__LEAVE(KErrArgument);		// insert-statement is bad
+	for (TInt ii=0;ii<columns;++ii)
+		{
+		TEntry& e=iValues[ii];
+		__ASSERT(e.iType==-1);
+		e.iType=aSource.ColumnDef(ii+1).Type();
+		if (e.iValue.IsNull())
+			continue;
+		switch (e.iType)
+			{
+		default:	// cannot set this kind of column from SQL
+			__LEAVE(KErrGeneral);
+			break;
+		case EDbColBit:
+		case EDbColUint8:
+		case EDbColUint16:
+		case EDbColUint32:
+			e.iValue.ToUint32L();
+			break;
+		case EDbColInt8:
+		case EDbColInt16:
+		case EDbColInt32:
+			e.iValue.ToInt32L();
+			break;
+		case EDbColInt64:
+			e.iValue.ToInt64L();
+			break;
+		case EDbColReal32:
+			e.iValue.ToReal32L();
+			break;
+		case EDbColReal64:
+			e.iValue.ToReal64L();
+			break;
+		case EDbColDateTime:
+			e.iValue.ToTimeL();
+			break;
+		case EDbColText8:
+		case EDbColLongText8:
+			e.iValue.ToText8L();
+			break;
+		case EDbColText16:
+		case EDbColLongText16:
+			e.iValue.ToText16L();
+			break;
+			}
+		}
+	}
+
+void CSqlValues::WriteL(CDbDataSource& aSource,CDbTable& aTable) const
+//
+// Set the row buffer with the values
+//
+	{
+	__ASSERT(iValues.Count()>0);
+	CDbBlobSpace* blobstore=0;
+	TInt columns=iValues.Count();
+	for (TInt ii=0;ii<columns;++ii)
+		{
+		TDbColumn col(aSource.Column(ii+1));
+		const TEntry& e=iValues[ii];
+		if (TDbCol::IsLong(e.iType))
+			{	// check if we need to delete a blob
+			if (!blobstore)
+				blobstore=aTable.BlobsL();
+			__ASSERT(blobstore);
+			const TDbBlob& blob=TDbColumnC(col).Blob();
+			if (!blob.IsInline())
+				blobstore->DeleteL(blob.Id());
+			}
+		if (e.iValue.IsNull())
+			{	// null value
+			col.SetNull();
+			continue;
+			}
+		switch (e.iType)
+			{
+		default:
+			__ASSERT(0);
+		case EDbColBit:
+		case EDbColUint8:
+		case EDbColUint16:
+		case EDbColUint32:
+			col.SetL(e.iValue.Uint32());
+			break;
+		case EDbColInt8:
+		case EDbColInt16:
+		case EDbColInt32:
+			col.SetL(e.iValue.Int32());
+			break;
+		case EDbColInt64:
+			col.SetL(e.iValue.Int64());
+			break;
+		case EDbColReal32:
+			col.SetL(e.iValue.Real32());
+			break;
+		case EDbColReal64:
+			col.SetL(e.iValue.Real64());
+			break;
+		case EDbColDateTime:
+			col.SetL(e.iValue.Time());
+			break;
+		case EDbColText8:
+			col.SetL(e.iValue.Text8());
+			break;
+		case EDbColText16:
+			col.SetL(e.iValue.Text16());
+			break;
+		case EDbColLongText8:
+			{
+			const TDesC8& val=e.iValue.Text8();
+			const TUint8* ptr=val.Ptr();
+			TInt size=val.Length();
+			if (size>blobstore->InlineLimit())
+				col.SetBlobL(blobstore->CreateL(EDbColLongText8,ptr,size),size);
+			else
+				col.SetBlobL(ptr,size);
+			}
+			break;
+		case EDbColLongText16:
+			{
+			const TDesC16& val=e.iValue.Text16();
+			const TUint8* ptr=REINTERPRET_CAST(const TUint8*,val.Ptr());
+			TInt size=val.Length()<<1;
+			if (size>blobstore->InlineLimit())
+				col.SetBlobL(blobstore->CreateL(EDbColLongText16,ptr,size),size);
+			else
+				col.SetBlobL(ptr,size);
+			}
+			break;
+			}
+		}
+	}
+
+// Class CSqlDMLStatement
+
+CSqlDMLStatement::~CSqlDMLStatement()
+	{
+	delete iValues;
+	}
+
+CSqlValues& CSqlDMLStatement::ValuesL()
+	{
+	CSqlValues* v=iValues;
+	if (!v)
+		iValues=v=new(ELeave) CSqlValues;
+	return *v;
+	}
+
+// Class CSqlInsertStatement
+
+CSqlInsertStatement* CSqlInsertStatement::NewLC()
+	{
+	CSqlInsertStatement* self=new(ELeave) CSqlInsertStatement;
+	CleanupStack::PushL(self);
+	return self;
+	}
+
+CDbIncremental* CSqlInsertStatement::ExecuteL(CDbTableDatabase& aDatabase,TDbTextComparison aComparison,TInt& aRows)
+//
+// Execute an insert-statement. This does not requre incremental work, so return 0
+//
+	{
+	aRows=1;	// 1 row changed after insertion
+	CSqlQuery* query=&Query();
+	RDbAccessPlan plan(query,aComparison);
+	plan.BuildLC(aDatabase,RDbRowSet::EInsertOnly,TDbWindow());
+	CDbDataSource& src=plan.Source();
+	Values().BindL(src);
+	src.NewRowL(KDbNullRecordId);
+	RDbTransaction& t=plan.Table().Database().Transaction();
+	t.DMLBeginLC();
+	Values().WriteL(src,plan.Table());
+	src.PrepareToWriteRowL(src.EAppend);
+	src.WriteRowL(src.EAppend,src.ENoSynch);
+	t.DMLCommitL();
+	CleanupStack::Pop();				// transaction complete
+	CleanupStack::PopAndDestroy();		// plan
+	return 0;	// no incremental work to be done
+	}
+
+// Class CDbIncrementalDML
+
+CDbIncrementalDML* CDbIncrementalDML::NewL(CSqlModifyStatement& aStatement,CDbTableDatabase& aDatabase,TDbTextComparison aComparison)
+	{
+	CSqlQuery* query=&aStatement.Query();
+	RDbAccessPlan plan(query,aComparison);
+	plan.BuildLC(aDatabase,RDbRowSet::EUpdatable,TDbWindow());
+	CDbIncrementalDML* self=new(ELeave) CDbIncrementalDML(plan);
+	CleanupStack::PopAndDestroy();	// plan
+	if (aStatement.IsUpdate())
+		{
+		CleanupStack::PushL(self);
+		self->iValues=aStatement.AdoptValues();
+		self->iValues->BindL(*self->iSource);
+		CleanupStack::Pop();	// self
+		}
+	self->iSource->Reset();
+	self->Transaction().DMLBegin();
+	self->SetState(EEvaluating);
+	return self;
+	}
+
+CDbIncrementalDML::~CDbIncrementalDML()
+	{
+	if (iState!=ECommitted && iState!=EInitialising)
+		Transaction().DMLRollback();
+	delete iSource;
+	delete iValues;
+	}
+
+TBool CDbIncrementalDML::NextL(TInt& aRows)
+	{
+	__ASSERT(iState!=ECommitted);
+	if (iState==EFailed)
+		__LEAVE(KErrDied);
+	TState s=iState;
+	iState=EFailed;
+	TInt work=256;
+	TDbPosition next=EDbNext;
+	if (s==EEvaluating)
+		{	// evaluate the data source
+		TBool atrow=EFalse;
+		if (iSource->EvaluateL(work,iRecord,atrow))
+			{
+			iState=EEvaluating;
+			return ETrue;	// more to do
+			}
+		iRecord=KDbNullRecordId;
+		next=EDbFirst;
+		s=EUpdating;
+		}
+	// iterate across the data source
+	for (;;)
+		{
+		if (s==EDeleting)
+			{
+			Transaction().DMLBeginLC();
+			CDbDataSource::TDelete del=iSource->DeleteRowL(iRecord,CDbDataSource::ESynch);
+			Transaction().DMLCommitL();
+			CleanupStack::Pop();				// transaction complete
+			++aRows;
+			work-=4;
+			switch (del)
+				{
+			case CDbDataSource::EDeletedAtEnd:
+				Transaction().DMLTouch();
+				Transaction().DMLCommitL();
+				iState=ECommitted;
+				return EFalse;
+			case CDbDataSource::EDeletedInLimbo:
+				s=EUpdating;
+				// coverity[fallthrough]
+			case CDbDataSource::EDeletedAtNext:
+				if (work<0)
+					{	// exhausted
+					iState=s;
+					return ETrue;
+					}
+				}
+			}
+		else
+			{
+			switch (iSource->GotoL(work,next,iRecord))
+				{
+			default:
+				__ASSERT(0);
+			case CDbDataSource::ESuccess:
+				next=EDbNext;
+				if (!IsUpdate())
+					{
+					s=EDeleting;
+					break;
+					}
+				iSource->ReadRowL(iRecord);
+				iValues->WriteL(*iSource,iTable);
+				iSource->PrepareToWriteRowL(CDbDataSource::EReplace);
+				Transaction().DMLBeginLC();
+				iSource->WriteRowL(CDbDataSource::EReplace,CDbDataSource::ESynch);
+				Transaction().DMLCommitL();
+				CleanupStack::Pop();				// transaction complete
+				++aRows;
+				work-=8;
+				break;
+			case CDbDataSource::ESynchFailure:
+				// dead
+				__LEAVE(KErrDied);
+			case CDbDataSource::EExhausted:
+				// more to do
+				iState=EUpdating;
+				return ETrue;
+			case CDbDataSource::ENoRow:
+				// completed the operation!
+				Transaction().DMLTouch();
+				Transaction().DMLCommitL();
+				iState=ECommitted;
+				return EFalse;
+				}
+			}
+		}
+	}
+
+
+// Class CSqlModifyStatement
+
+CSqlModifyStatement* CSqlModifyStatement::NewLC()
+	{
+	CSqlModifyStatement* self=new(ELeave) CSqlModifyStatement;
+	CleanupStack::PushL(self);
+	return self;
+	}
+
+CDbIncremental* CSqlModifyStatement::ExecuteL(CDbTableDatabase& aDatabase,TDbTextComparison aComparison,TInt& aRows)
+//
+// Execute an update/delete-statement, returning the incremental object that does the work
+//
+	{
+	aRows=0;		// no rows affected initially
+	return CDbIncrementalDML::NewL(*this,aDatabase,aComparison);
+	}