persistentstorage/dbms/utable/UT_DML.CPP
changeset 0 08ec8eefde2f
equal deleted inserted replaced
-1:000000000000 0:08ec8eefde2f
       
     1 // Copyright (c) 1998-2009 Nokia Corporation and/or its subsidiary(-ies).
       
     2 // All rights reserved.
       
     3 // This component and the accompanying materials are made available
       
     4 // under the terms of "Eclipse Public License v1.0"
       
     5 // which accompanies this distribution, and is available
       
     6 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     7 //
       
     8 // Initial Contributors:
       
     9 // Nokia Corporation - initial contribution.
       
    10 //
       
    11 // Contributors:
       
    12 //
       
    13 // Description:
       
    14 // SQL DML statements for Table framework
       
    15 // 
       
    16 //
       
    17 
       
    18 #include "UT_STD.H"
       
    19 
       
    20 // Class CSqlValues
       
    21 
       
    22 inline CSqlValues::TEntry::TEntry(const RSqlLiteral& aValue)
       
    23 	:iValue(aValue)
       
    24 	{}
       
    25 
       
    26 CSqlValues::CSqlValues()
       
    27 	:iValues(EGranularity)
       
    28 	{}
       
    29 
       
    30 CSqlValues::~CSqlValues()
       
    31 //
       
    32 // close all the literal objects
       
    33 //
       
    34 	{
       
    35 	for (TInt ii=iValues.Count();--ii>=0;)
       
    36 		iValues[ii].iValue.Close();
       
    37 	iValues.Close();
       
    38 	}
       
    39 
       
    40 void CSqlValues::AddL(const RSqlLiteral& aLiteral)
       
    41 	{
       
    42 	TEntry e(aLiteral);
       
    43 	__DEBUG(e.iType=TDbColType(-1);)
       
    44 	__LEAVE_IF_ERROR(iValues.Append(e));
       
    45 	}
       
    46 
       
    47 void CSqlValues::BindL(const CDbDataSource& aSource)
       
    48 //
       
    49 // Bind the values to a column set and optional column name list
       
    50 //
       
    51 	{
       
    52 	iValues.Compress();				// we have finished adding values
       
    53 	TInt columns=iValues.Count();
       
    54 	__ASSERT(columns>0);
       
    55 	if (aSource.ColumnCount()<columns)
       
    56 		__LEAVE(KErrArgument);		// insert-statement is bad
       
    57 	for (TInt ii=0;ii<columns;++ii)
       
    58 		{
       
    59 		TEntry& e=iValues[ii];
       
    60 		__ASSERT(e.iType==-1);
       
    61 		e.iType=aSource.ColumnDef(ii+1).Type();
       
    62 		if (e.iValue.IsNull())
       
    63 			continue;
       
    64 		switch (e.iType)
       
    65 			{
       
    66 		default:	// cannot set this kind of column from SQL
       
    67 			__LEAVE(KErrGeneral);
       
    68 			break;
       
    69 		case EDbColBit:
       
    70 		case EDbColUint8:
       
    71 		case EDbColUint16:
       
    72 		case EDbColUint32:
       
    73 			e.iValue.ToUint32L();
       
    74 			break;
       
    75 		case EDbColInt8:
       
    76 		case EDbColInt16:
       
    77 		case EDbColInt32:
       
    78 			e.iValue.ToInt32L();
       
    79 			break;
       
    80 		case EDbColInt64:
       
    81 			e.iValue.ToInt64L();
       
    82 			break;
       
    83 		case EDbColReal32:
       
    84 			e.iValue.ToReal32L();
       
    85 			break;
       
    86 		case EDbColReal64:
       
    87 			e.iValue.ToReal64L();
       
    88 			break;
       
    89 		case EDbColDateTime:
       
    90 			e.iValue.ToTimeL();
       
    91 			break;
       
    92 		case EDbColText8:
       
    93 		case EDbColLongText8:
       
    94 			e.iValue.ToText8L();
       
    95 			break;
       
    96 		case EDbColText16:
       
    97 		case EDbColLongText16:
       
    98 			e.iValue.ToText16L();
       
    99 			break;
       
   100 			}
       
   101 		}
       
   102 	}
       
   103 
       
   104 void CSqlValues::WriteL(CDbDataSource& aSource,CDbTable& aTable) const
       
   105 //
       
   106 // Set the row buffer with the values
       
   107 //
       
   108 	{
       
   109 	__ASSERT(iValues.Count()>0);
       
   110 	CDbBlobSpace* blobstore=0;
       
   111 	TInt columns=iValues.Count();
       
   112 	for (TInt ii=0;ii<columns;++ii)
       
   113 		{
       
   114 		TDbColumn col(aSource.Column(ii+1));
       
   115 		const TEntry& e=iValues[ii];
       
   116 		if (TDbCol::IsLong(e.iType))
       
   117 			{	// check if we need to delete a blob
       
   118 			if (!blobstore)
       
   119 				blobstore=aTable.BlobsL();
       
   120 			__ASSERT(blobstore);
       
   121 			const TDbBlob& blob=TDbColumnC(col).Blob();
       
   122 			if (!blob.IsInline())
       
   123 				blobstore->DeleteL(blob.Id());
       
   124 			}
       
   125 		if (e.iValue.IsNull())
       
   126 			{	// null value
       
   127 			col.SetNull();
       
   128 			continue;
       
   129 			}
       
   130 		switch (e.iType)
       
   131 			{
       
   132 		default:
       
   133 			__ASSERT(0);
       
   134 		case EDbColBit:
       
   135 		case EDbColUint8:
       
   136 		case EDbColUint16:
       
   137 		case EDbColUint32:
       
   138 			col.SetL(e.iValue.Uint32());
       
   139 			break;
       
   140 		case EDbColInt8:
       
   141 		case EDbColInt16:
       
   142 		case EDbColInt32:
       
   143 			col.SetL(e.iValue.Int32());
       
   144 			break;
       
   145 		case EDbColInt64:
       
   146 			col.SetL(e.iValue.Int64());
       
   147 			break;
       
   148 		case EDbColReal32:
       
   149 			col.SetL(e.iValue.Real32());
       
   150 			break;
       
   151 		case EDbColReal64:
       
   152 			col.SetL(e.iValue.Real64());
       
   153 			break;
       
   154 		case EDbColDateTime:
       
   155 			col.SetL(e.iValue.Time());
       
   156 			break;
       
   157 		case EDbColText8:
       
   158 			col.SetL(e.iValue.Text8());
       
   159 			break;
       
   160 		case EDbColText16:
       
   161 			col.SetL(e.iValue.Text16());
       
   162 			break;
       
   163 		case EDbColLongText8:
       
   164 			{
       
   165 			const TDesC8& val=e.iValue.Text8();
       
   166 			const TUint8* ptr=val.Ptr();
       
   167 			TInt size=val.Length();
       
   168 			if (size>blobstore->InlineLimit())
       
   169 				col.SetBlobL(blobstore->CreateL(EDbColLongText8,ptr,size),size);
       
   170 			else
       
   171 				col.SetBlobL(ptr,size);
       
   172 			}
       
   173 			break;
       
   174 		case EDbColLongText16:
       
   175 			{
       
   176 			const TDesC16& val=e.iValue.Text16();
       
   177 			const TUint8* ptr=REINTERPRET_CAST(const TUint8*,val.Ptr());
       
   178 			TInt size=val.Length()<<1;
       
   179 			if (size>blobstore->InlineLimit())
       
   180 				col.SetBlobL(blobstore->CreateL(EDbColLongText16,ptr,size),size);
       
   181 			else
       
   182 				col.SetBlobL(ptr,size);
       
   183 			}
       
   184 			break;
       
   185 			}
       
   186 		}
       
   187 	}
       
   188 
       
   189 // Class CSqlDMLStatement
       
   190 
       
   191 CSqlDMLStatement::~CSqlDMLStatement()
       
   192 	{
       
   193 	delete iValues;
       
   194 	}
       
   195 
       
   196 CSqlValues& CSqlDMLStatement::ValuesL()
       
   197 	{
       
   198 	CSqlValues* v=iValues;
       
   199 	if (!v)
       
   200 		iValues=v=new(ELeave) CSqlValues;
       
   201 	return *v;
       
   202 	}
       
   203 
       
   204 // Class CSqlInsertStatement
       
   205 
       
   206 CSqlInsertStatement* CSqlInsertStatement::NewLC()
       
   207 	{
       
   208 	CSqlInsertStatement* self=new(ELeave) CSqlInsertStatement;
       
   209 	CleanupStack::PushL(self);
       
   210 	return self;
       
   211 	}
       
   212 
       
   213 CDbIncremental* CSqlInsertStatement::ExecuteL(CDbTableDatabase& aDatabase,TDbTextComparison aComparison,TInt& aRows)
       
   214 //
       
   215 // Execute an insert-statement. This does not requre incremental work, so return 0
       
   216 //
       
   217 	{
       
   218 	aRows=1;	// 1 row changed after insertion
       
   219 	CSqlQuery* query=&Query();
       
   220 	RDbAccessPlan plan(query,aComparison);
       
   221 	plan.BuildLC(aDatabase,RDbRowSet::EInsertOnly,TDbWindow());
       
   222 	CDbDataSource& src=plan.Source();
       
   223 	Values().BindL(src);
       
   224 	src.NewRowL(KDbNullRecordId);
       
   225 	RDbTransaction& t=plan.Table().Database().Transaction();
       
   226 	t.DMLBeginLC();
       
   227 	Values().WriteL(src,plan.Table());
       
   228 	src.PrepareToWriteRowL(src.EAppend);
       
   229 	src.WriteRowL(src.EAppend,src.ENoSynch);
       
   230 	t.DMLCommitL();
       
   231 	CleanupStack::Pop();				// transaction complete
       
   232 	CleanupStack::PopAndDestroy();		// plan
       
   233 	return 0;	// no incremental work to be done
       
   234 	}
       
   235 
       
   236 // Class CDbIncrementalDML
       
   237 
       
   238 CDbIncrementalDML* CDbIncrementalDML::NewL(CSqlModifyStatement& aStatement,CDbTableDatabase& aDatabase,TDbTextComparison aComparison)
       
   239 	{
       
   240 	CSqlQuery* query=&aStatement.Query();
       
   241 	RDbAccessPlan plan(query,aComparison);
       
   242 	plan.BuildLC(aDatabase,RDbRowSet::EUpdatable,TDbWindow());
       
   243 	CDbIncrementalDML* self=new(ELeave) CDbIncrementalDML(plan);
       
   244 	CleanupStack::PopAndDestroy();	// plan
       
   245 	if (aStatement.IsUpdate())
       
   246 		{
       
   247 		CleanupStack::PushL(self);
       
   248 		self->iValues=aStatement.AdoptValues();
       
   249 		self->iValues->BindL(*self->iSource);
       
   250 		CleanupStack::Pop();	// self
       
   251 		}
       
   252 	self->iSource->Reset();
       
   253 	self->Transaction().DMLBegin();
       
   254 	self->SetState(EEvaluating);
       
   255 	return self;
       
   256 	}
       
   257 
       
   258 CDbIncrementalDML::~CDbIncrementalDML()
       
   259 	{
       
   260 	if (iState!=ECommitted && iState!=EInitialising)
       
   261 		Transaction().DMLRollback();
       
   262 	delete iSource;
       
   263 	delete iValues;
       
   264 	}
       
   265 
       
   266 TBool CDbIncrementalDML::NextL(TInt& aRows)
       
   267 	{
       
   268 	__ASSERT(iState!=ECommitted);
       
   269 	if (iState==EFailed)
       
   270 		__LEAVE(KErrDied);
       
   271 	TState s=iState;
       
   272 	iState=EFailed;
       
   273 	TInt work=256;
       
   274 	TDbPosition next=EDbNext;
       
   275 	if (s==EEvaluating)
       
   276 		{	// evaluate the data source
       
   277 		TBool atrow=EFalse;
       
   278 		if (iSource->EvaluateL(work,iRecord,atrow))
       
   279 			{
       
   280 			iState=EEvaluating;
       
   281 			return ETrue;	// more to do
       
   282 			}
       
   283 		iRecord=KDbNullRecordId;
       
   284 		next=EDbFirst;
       
   285 		s=EUpdating;
       
   286 		}
       
   287 	// iterate across the data source
       
   288 	for (;;)
       
   289 		{
       
   290 		if (s==EDeleting)
       
   291 			{
       
   292 			Transaction().DMLBeginLC();
       
   293 			CDbDataSource::TDelete del=iSource->DeleteRowL(iRecord,CDbDataSource::ESynch);
       
   294 			Transaction().DMLCommitL();
       
   295 			CleanupStack::Pop();				// transaction complete
       
   296 			++aRows;
       
   297 			work-=4;
       
   298 			switch (del)
       
   299 				{
       
   300 			case CDbDataSource::EDeletedAtEnd:
       
   301 				Transaction().DMLTouch();
       
   302 				Transaction().DMLCommitL();
       
   303 				iState=ECommitted;
       
   304 				return EFalse;
       
   305 			case CDbDataSource::EDeletedInLimbo:
       
   306 				s=EUpdating;
       
   307 				// coverity[fallthrough]
       
   308 			case CDbDataSource::EDeletedAtNext:
       
   309 				if (work<0)
       
   310 					{	// exhausted
       
   311 					iState=s;
       
   312 					return ETrue;
       
   313 					}
       
   314 				}
       
   315 			}
       
   316 		else
       
   317 			{
       
   318 			switch (iSource->GotoL(work,next,iRecord))
       
   319 				{
       
   320 			default:
       
   321 				__ASSERT(0);
       
   322 			case CDbDataSource::ESuccess:
       
   323 				next=EDbNext;
       
   324 				if (!IsUpdate())
       
   325 					{
       
   326 					s=EDeleting;
       
   327 					break;
       
   328 					}
       
   329 				iSource->ReadRowL(iRecord);
       
   330 				iValues->WriteL(*iSource,iTable);
       
   331 				iSource->PrepareToWriteRowL(CDbDataSource::EReplace);
       
   332 				Transaction().DMLBeginLC();
       
   333 				iSource->WriteRowL(CDbDataSource::EReplace,CDbDataSource::ESynch);
       
   334 				Transaction().DMLCommitL();
       
   335 				CleanupStack::Pop();				// transaction complete
       
   336 				++aRows;
       
   337 				work-=8;
       
   338 				break;
       
   339 			case CDbDataSource::ESynchFailure:
       
   340 				// dead
       
   341 				__LEAVE(KErrDied);
       
   342 			case CDbDataSource::EExhausted:
       
   343 				// more to do
       
   344 				iState=EUpdating;
       
   345 				return ETrue;
       
   346 			case CDbDataSource::ENoRow:
       
   347 				// completed the operation!
       
   348 				Transaction().DMLTouch();
       
   349 				Transaction().DMLCommitL();
       
   350 				iState=ECommitted;
       
   351 				return EFalse;
       
   352 				}
       
   353 			}
       
   354 		}
       
   355 	}
       
   356 
       
   357 
       
   358 // Class CSqlModifyStatement
       
   359 
       
   360 CSqlModifyStatement* CSqlModifyStatement::NewLC()
       
   361 	{
       
   362 	CSqlModifyStatement* self=new(ELeave) CSqlModifyStatement;
       
   363 	CleanupStack::PushL(self);
       
   364 	return self;
       
   365 	}
       
   366 
       
   367 CDbIncremental* CSqlModifyStatement::ExecuteL(CDbTableDatabase& aDatabase,TDbTextComparison aComparison,TInt& aRows)
       
   368 //
       
   369 // Execute an update/delete-statement, returning the incremental object that does the work
       
   370 //
       
   371 	{
       
   372 	aRows=0;		// no rows affected initially
       
   373 	return CDbIncrementalDML::NewL(*this,aDatabase,aComparison);
       
   374 	}