|
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 } |