1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/os/persistentdata/persistentstorage/dbms/pcdbms/utable/UT_DML.CPP Fri Jun 15 03:10:57 2012 +0200
1.3 @@ -0,0 +1,394 @@
1.4 +// Copyright (c) 1998-2009 Nokia Corporation and/or its subsidiary(-ies).
1.5 +// All rights reserved.
1.6 +// This component and the accompanying materials are made available
1.7 +// under the terms of "Eclipse Public License v1.0"
1.8 +// which accompanies this distribution, and is available
1.9 +// at the URL "http://www.eclipse.org/legal/epl-v10.html".
1.10 +//
1.11 +// Initial Contributors:
1.12 +// Nokia Corporation - initial contribution.
1.13 +//
1.14 +// Contributors:
1.15 +//
1.16 +// Description:
1.17 +// SQL DML statements for Table framework
1.18 +//
1.19 +//
1.20 +
1.21 +#include "UT_STD.H"
1.22 +
1.23 +// Class CSqlValues
1.24 +
1.25 +inline CSqlValues::TEntry::TEntry(const RSqlLiteral& aValue)
1.26 + :iValue(aValue)
1.27 + {}
1.28 +
1.29 +CSqlValues::CSqlValues()
1.30 + :iValues(EGranularity)
1.31 + {}
1.32 +
1.33 +CSqlValues::~CSqlValues()
1.34 +//
1.35 +// close all the literal objects
1.36 +//
1.37 + {
1.38 + for (TInt ii=iValues.Count();--ii>=0;)
1.39 + iValues[ii].iValue.Close();
1.40 + iValues.Close();
1.41 + }
1.42 +
1.43 +void CSqlValues::AddL(const RSqlLiteral& aLiteral)
1.44 + {
1.45 + TEntry e(aLiteral);
1.46 + __DEBUG(e.iType=TDbColType(-1);)
1.47 + __LEAVE_IF_ERROR(iValues.Append(e));
1.48 + }
1.49 +
1.50 +void CSqlValues::BindL(const CDbDataSource& aSource)
1.51 +//
1.52 +// Bind the values to a column set and optional column name list
1.53 +//
1.54 + {
1.55 + iValues.Compress(); // we have finished adding values
1.56 + TInt columns=iValues.Count();
1.57 + __ASSERT(columns>0);
1.58 + if (aSource.ColumnCount()<columns)
1.59 + __LEAVE(KErrArgument); // insert-statement is bad
1.60 + for (TInt ii=0;ii<columns;++ii)
1.61 + {
1.62 + TEntry& e=iValues[ii];
1.63 + __ASSERT(e.iType==-1);
1.64 + e.iType=aSource.ColumnDef(ii+1).Type();
1.65 + if (e.iValue.IsNull())
1.66 + continue;
1.67 + switch (e.iType)
1.68 + {
1.69 + default: // cannot set this kind of column from SQL
1.70 + __LEAVE(KErrGeneral);
1.71 + break;
1.72 + case EDbColBit:
1.73 + case EDbColUint8:
1.74 + case EDbColUint16:
1.75 + case EDbColUint32:
1.76 + e.iValue.ToUint32L();
1.77 + break;
1.78 + case EDbColInt8:
1.79 + case EDbColInt16:
1.80 + case EDbColInt32:
1.81 + e.iValue.ToInt32L();
1.82 + break;
1.83 + case EDbColInt64:
1.84 + e.iValue.ToInt64L();
1.85 + break;
1.86 + case EDbColReal32:
1.87 + e.iValue.ToReal32L();
1.88 + break;
1.89 + case EDbColReal64:
1.90 + e.iValue.ToReal64L();
1.91 + break;
1.92 + case EDbColDateTime:
1.93 + e.iValue.ToTimeL();
1.94 + break;
1.95 + case EDbColText8:
1.96 + case EDbColLongText8:
1.97 + e.iValue.ToText8L();
1.98 + break;
1.99 + case EDbColText16:
1.100 + case EDbColLongText16:
1.101 + e.iValue.ToText16L();
1.102 + break;
1.103 + case EDbColBinary:
1.104 + case EDbColLongBinary:
1.105 + e.iValue.ToBlobL();
1.106 + break;
1.107 + }
1.108 + }
1.109 + }
1.110 +
1.111 +void CSqlValues::WriteL(CDbDataSource& aSource,CDbTable& aTable) const
1.112 +//
1.113 +// Set the row buffer with the values
1.114 +//
1.115 + {
1.116 + __ASSERT(iValues.Count()>0);
1.117 + CDbBlobSpace* blobstore=0;
1.118 + TInt columns=iValues.Count();
1.119 + for (TInt ii=0;ii<columns;++ii)
1.120 + {
1.121 + TDbColumn col(aSource.Column(ii+1));
1.122 + const TEntry& e=iValues[ii];
1.123 + if (TDbCol::IsLong(e.iType))
1.124 + { // check if we need to delete a blob
1.125 + if (!blobstore)
1.126 + blobstore=aTable.BlobsL();
1.127 + __ASSERT(blobstore);
1.128 + const TDbBlob& blob=TDbColumnC(col).Blob();
1.129 + if (!blob.IsInline())
1.130 + blobstore->DeleteL(blob.Id());
1.131 + }
1.132 + if (e.iValue.IsNull())
1.133 + { // null value
1.134 + col.SetNull();
1.135 + continue;
1.136 + }
1.137 + switch (e.iType)
1.138 + {
1.139 + default:
1.140 + __ASSERT(0);
1.141 + case EDbColBit:
1.142 + case EDbColUint8:
1.143 + case EDbColUint16:
1.144 + case EDbColUint32:
1.145 + col.SetL(e.iValue.Uint32());
1.146 + break;
1.147 + case EDbColInt8:
1.148 + case EDbColInt16:
1.149 + case EDbColInt32:
1.150 + col.SetL(e.iValue.Int32());
1.151 + break;
1.152 + case EDbColInt64:
1.153 + col.SetL(e.iValue.Int64());
1.154 + break;
1.155 + case EDbColReal32:
1.156 + col.SetL(e.iValue.Real32());
1.157 + break;
1.158 + case EDbColReal64:
1.159 + col.SetL(e.iValue.Real64());
1.160 + break;
1.161 + case EDbColDateTime:
1.162 + col.SetL(e.iValue.Time());
1.163 + break;
1.164 + case EDbColText8:
1.165 + col.SetL(e.iValue.Text8());
1.166 + break;
1.167 + case EDbColText16:
1.168 + col.SetL(e.iValue.Text16());
1.169 + break;
1.170 + case EDbColLongText8:
1.171 + {
1.172 + const TDesC8& val=e.iValue.Text8();
1.173 + const TUint8* ptr=val.Ptr();
1.174 + TInt size=val.Length();
1.175 + if (size>blobstore->InlineLimit())
1.176 + col.SetBlobL(blobstore->CreateL(EDbColLongText8,ptr,size),size);
1.177 + else
1.178 + col.SetBlobL(ptr,size);
1.179 + }
1.180 + break;
1.181 + case EDbColLongText16:
1.182 + {
1.183 + const TDesC16& val=e.iValue.Text16();
1.184 + const TUint8* ptr=REINTERPRET_CAST(const TUint8*,val.Ptr());
1.185 + TInt size=val.Length()<<1;
1.186 + if (size>blobstore->InlineLimit())
1.187 + col.SetBlobL(blobstore->CreateL(EDbColLongText16,ptr,size),size);
1.188 + else
1.189 + col.SetBlobL(ptr,size);
1.190 + }
1.191 + break;
1.192 + case EDbColBinary:
1.193 + {
1.194 + const TDesC8& val=e.iValue.Blob();
1.195 +// const TUint8* ptr=REINTERPRET_CAST(const TUint8*,val.Ptr());
1.196 +// TInt size=val.Length();
1.197 + col.SetL(val);
1.198 +// col.SetBlobL(ptr,size);
1.199 + }
1.200 + break;
1.201 + case EDbColLongBinary:
1.202 + {
1.203 + const TDesC8& val=e.iValue.Blob();
1.204 + const TUint8* ptr=REINTERPRET_CAST(const TUint8*,val.Ptr());
1.205 + TInt size=val.Length();
1.206 + col.SetBlobL(blobstore->CreateL(EDbColLongBinary,ptr,size),size);
1.207 + }
1.208 + break;
1.209 + }
1.210 + }
1.211 + }
1.212 +
1.213 +// Class CSqlDMLStatement
1.214 +
1.215 +CSqlDMLStatement::~CSqlDMLStatement()
1.216 + {
1.217 + delete iValues;
1.218 + }
1.219 +
1.220 +CSqlValues& CSqlDMLStatement::ValuesL()
1.221 + {
1.222 + CSqlValues* v=iValues;
1.223 + if (!v)
1.224 + iValues=v=new(ELeave) CSqlValues;
1.225 + return *v;
1.226 + }
1.227 +
1.228 +// Class CSqlInsertStatement
1.229 +
1.230 +CSqlInsertStatement* CSqlInsertStatement::NewLC()
1.231 + {
1.232 + CSqlInsertStatement* self=new(ELeave) CSqlInsertStatement;
1.233 + CleanupStack::PushL(self);
1.234 + return self;
1.235 + }
1.236 +
1.237 +CDbIncremental* CSqlInsertStatement::ExecuteL(CDbTableDatabase& aDatabase,TDbTextComparison aComparison,TInt& aRows)
1.238 +//
1.239 +// Execute an insert-statement. This does not requre incremental work, so return 0
1.240 +//
1.241 + {
1.242 + aRows=1; // 1 row changed after insertion
1.243 + CSqlQuery* query=&Query();
1.244 + RDbAccessPlan plan(query,aComparison);
1.245 + plan.BuildLC(aDatabase,RDbRowSet::EInsertOnly,TDbWindow());
1.246 + CDbDataSource& src=plan.Source();
1.247 + Values().BindL(src);
1.248 + src.NewRowL(KDbNullRecordId);
1.249 + RDbTransaction& t=plan.Table().Database().Transaction();
1.250 + t.DMLBeginLC();
1.251 + Values().WriteL(src,plan.Table());
1.252 + src.PrepareToWriteRowL(src.EAppend);
1.253 + src.WriteRowL(src.EAppend,src.ENoSynch);
1.254 + t.DMLCommitL();
1.255 + CleanupStack::Pop(); // transaction complete
1.256 + CleanupStack::PopAndDestroy(); // plan
1.257 + return 0; // no incremental work to be done
1.258 + }
1.259 +
1.260 +// Class CDbIncrementalDML
1.261 +
1.262 +CDbIncrementalDML* CDbIncrementalDML::NewL(CSqlModifyStatement& aStatement,CDbTableDatabase& aDatabase,TDbTextComparison aComparison)
1.263 + {
1.264 + CSqlQuery* query=&aStatement.Query();
1.265 + RDbAccessPlan plan(query,aComparison);
1.266 + plan.BuildLC(aDatabase,RDbRowSet::EUpdatable,TDbWindow());
1.267 + CDbIncrementalDML* self=new(ELeave) CDbIncrementalDML(plan);
1.268 + CleanupStack::PopAndDestroy(); // plan
1.269 + if (aStatement.IsUpdate())
1.270 + {
1.271 + CleanupStack::PushL(self);
1.272 + self->iValues=aStatement.AdoptValues();
1.273 + self->iValues->BindL(*self->iSource);
1.274 + CleanupStack::Pop(); // self
1.275 + }
1.276 + self->iSource->Reset();
1.277 + self->Transaction().DMLBegin();
1.278 + self->SetState(EEvaluating);
1.279 + return self;
1.280 + }
1.281 +
1.282 +CDbIncrementalDML::~CDbIncrementalDML()
1.283 + {
1.284 + if (iState!=ECommitted && iState!=EInitialising)
1.285 + Transaction().DMLRollback();
1.286 + delete iSource;
1.287 + delete iValues;
1.288 + }
1.289 +
1.290 +TBool CDbIncrementalDML::NextL(TInt& aRows)
1.291 + {
1.292 + __ASSERT(iState!=ECommitted);
1.293 + if (iState==EFailed)
1.294 + __LEAVE(KErrDied);
1.295 + TState s=iState;
1.296 + iState=EFailed;
1.297 + TInt work=256;
1.298 + TDbPosition next=EDbNext;
1.299 + if (s==EEvaluating)
1.300 + { // evaluate the data source
1.301 + TBool atrow=EFalse;
1.302 + if (iSource->EvaluateL(work,iRecord,atrow))
1.303 + {
1.304 + iState=EEvaluating;
1.305 + return ETrue; // more to do
1.306 + }
1.307 + iRecord=KDbNullRecordId;
1.308 + next=EDbFirst;
1.309 + s=EUpdating;
1.310 + }
1.311 + // iterate across the data source
1.312 + for (;;)
1.313 + {
1.314 + if (s==EDeleting)
1.315 + {
1.316 + Transaction().DMLBeginLC();
1.317 + CDbDataSource::TDelete del=iSource->DeleteRowL(iRecord,CDbDataSource::ESynch);
1.318 + Transaction().DMLCommitL();
1.319 + CleanupStack::Pop(); // transaction complete
1.320 + ++aRows;
1.321 + work-=4;
1.322 + switch (del)
1.323 + {
1.324 + case CDbDataSource::EDeletedAtEnd:
1.325 + Transaction().DMLTouch();
1.326 + Transaction().DMLCommitL();
1.327 + iState=ECommitted;
1.328 + return EFalse;
1.329 + case CDbDataSource::EDeletedInLimbo:
1.330 + s=EUpdating;
1.331 + case CDbDataSource::EDeletedAtNext:
1.332 + if (work<0)
1.333 + { // exhausted
1.334 + iState=s;
1.335 + return ETrue;
1.336 + }
1.337 + }
1.338 + }
1.339 + else
1.340 + {
1.341 + switch (iSource->GotoL(work,next,iRecord))
1.342 + {
1.343 + default:
1.344 + __ASSERT(0);
1.345 + case CDbDataSource::ESuccess:
1.346 + next=EDbNext;
1.347 + if (!IsUpdate())
1.348 + {
1.349 + s=EDeleting;
1.350 + break;
1.351 + }
1.352 + iSource->ReadRowL(iRecord);
1.353 + iValues->WriteL(*iSource,iTable);
1.354 + iSource->PrepareToWriteRowL(CDbDataSource::EReplace);
1.355 + Transaction().DMLBeginLC();
1.356 + iSource->WriteRowL(CDbDataSource::EReplace,CDbDataSource::ESynch);
1.357 + Transaction().DMLCommitL();
1.358 + CleanupStack::Pop(); // transaction complete
1.359 + ++aRows;
1.360 + work-=8;
1.361 + break;
1.362 + case CDbDataSource::ESynchFailure:
1.363 + // dead
1.364 + __LEAVE(KErrDied);
1.365 + case CDbDataSource::EExhausted:
1.366 + // more to do
1.367 + iState=EUpdating;
1.368 + return ETrue;
1.369 + case CDbDataSource::ENoRow:
1.370 + // completed the operation!
1.371 + Transaction().DMLTouch();
1.372 + Transaction().DMLCommitL();
1.373 + iState=ECommitted;
1.374 + return EFalse;
1.375 + }
1.376 + }
1.377 + }
1.378 + }
1.379 +
1.380 +
1.381 +// Class CSqlModifyStatement
1.382 +
1.383 +CSqlModifyStatement* CSqlModifyStatement::NewLC()
1.384 + {
1.385 + CSqlModifyStatement* self=new(ELeave) CSqlModifyStatement;
1.386 + CleanupStack::PushL(self);
1.387 + return self;
1.388 + }
1.389 +
1.390 +CDbIncremental* CSqlModifyStatement::ExecuteL(CDbTableDatabase& aDatabase,TDbTextComparison aComparison,TInt& aRows)
1.391 +//
1.392 +// Execute an update/delete-statement, returning the incremental object that does the work
1.393 +//
1.394 + {
1.395 + aRows=0; // no rows affected initially
1.396 + return CDbIncrementalDML::NewL(*this,aDatabase,aComparison);
1.397 + }