--- /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()<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;
+ case EDbColBinary:
+ case EDbColLongBinary:
+ e.iValue.ToBlobL();
+ 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;
+ 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);
+ }