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