diff -r 000000000000 -r 08ec8eefde2f persistentstorage/dbms/pcdbms/utable/UT_DML.CPP --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/persistentstorage/dbms/pcdbms/utable/UT_DML.CPP Fri Jan 22 11:06:30 2010 +0200 @@ -0,0 +1,394 @@ +// 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()0); + CDbBlobSpace* blobstore=0; + TInt columns=iValues.Count(); + for (TInt ii=0;iiDeleteL(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; + case EDbColBinary: + { + const TDesC8& val=e.iValue.Blob(); +// const TUint8* ptr=REINTERPRET_CAST(const TUint8*,val.Ptr()); +// TInt size=val.Length(); + col.SetL(val); +// col.SetBlobL(ptr,size); + } + break; + case EDbColLongBinary: + { + const TDesC8& val=e.iValue.Blob(); + const TUint8* ptr=REINTERPRET_CAST(const TUint8*,val.Ptr()); + TInt size=val.Length(); + col.SetBlobL(blobstore->CreateL(EDbColLongBinary,ptr,size),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; + 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); + }