|
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 case EDbColBinary: |
|
101 case EDbColLongBinary: |
|
102 e.iValue.ToBlobL(); |
|
103 break; |
|
104 } |
|
105 } |
|
106 } |
|
107 |
|
108 void CSqlValues::WriteL(CDbDataSource& aSource,CDbTable& aTable) const |
|
109 // |
|
110 // Set the row buffer with the values |
|
111 // |
|
112 { |
|
113 __ASSERT(iValues.Count()>0); |
|
114 CDbBlobSpace* blobstore=0; |
|
115 TInt columns=iValues.Count(); |
|
116 for (TInt ii=0;ii<columns;++ii) |
|
117 { |
|
118 TDbColumn col(aSource.Column(ii+1)); |
|
119 const TEntry& e=iValues[ii]; |
|
120 if (TDbCol::IsLong(e.iType)) |
|
121 { // check if we need to delete a blob |
|
122 if (!blobstore) |
|
123 blobstore=aTable.BlobsL(); |
|
124 __ASSERT(blobstore); |
|
125 const TDbBlob& blob=TDbColumnC(col).Blob(); |
|
126 if (!blob.IsInline()) |
|
127 blobstore->DeleteL(blob.Id()); |
|
128 } |
|
129 if (e.iValue.IsNull()) |
|
130 { // null value |
|
131 col.SetNull(); |
|
132 continue; |
|
133 } |
|
134 switch (e.iType) |
|
135 { |
|
136 default: |
|
137 __ASSERT(0); |
|
138 case EDbColBit: |
|
139 case EDbColUint8: |
|
140 case EDbColUint16: |
|
141 case EDbColUint32: |
|
142 col.SetL(e.iValue.Uint32()); |
|
143 break; |
|
144 case EDbColInt8: |
|
145 case EDbColInt16: |
|
146 case EDbColInt32: |
|
147 col.SetL(e.iValue.Int32()); |
|
148 break; |
|
149 case EDbColInt64: |
|
150 col.SetL(e.iValue.Int64()); |
|
151 break; |
|
152 case EDbColReal32: |
|
153 col.SetL(e.iValue.Real32()); |
|
154 break; |
|
155 case EDbColReal64: |
|
156 col.SetL(e.iValue.Real64()); |
|
157 break; |
|
158 case EDbColDateTime: |
|
159 col.SetL(e.iValue.Time()); |
|
160 break; |
|
161 case EDbColText8: |
|
162 col.SetL(e.iValue.Text8()); |
|
163 break; |
|
164 case EDbColText16: |
|
165 col.SetL(e.iValue.Text16()); |
|
166 break; |
|
167 case EDbColLongText8: |
|
168 { |
|
169 const TDesC8& val=e.iValue.Text8(); |
|
170 const TUint8* ptr=val.Ptr(); |
|
171 TInt size=val.Length(); |
|
172 if (size>blobstore->InlineLimit()) |
|
173 col.SetBlobL(blobstore->CreateL(EDbColLongText8,ptr,size),size); |
|
174 else |
|
175 col.SetBlobL(ptr,size); |
|
176 } |
|
177 break; |
|
178 case EDbColLongText16: |
|
179 { |
|
180 const TDesC16& val=e.iValue.Text16(); |
|
181 const TUint8* ptr=REINTERPRET_CAST(const TUint8*,val.Ptr()); |
|
182 TInt size=val.Length()<<1; |
|
183 if (size>blobstore->InlineLimit()) |
|
184 col.SetBlobL(blobstore->CreateL(EDbColLongText16,ptr,size),size); |
|
185 else |
|
186 col.SetBlobL(ptr,size); |
|
187 } |
|
188 break; |
|
189 case EDbColBinary: |
|
190 { |
|
191 const TDesC8& val=e.iValue.Blob(); |
|
192 // const TUint8* ptr=REINTERPRET_CAST(const TUint8*,val.Ptr()); |
|
193 // TInt size=val.Length(); |
|
194 col.SetL(val); |
|
195 // col.SetBlobL(ptr,size); |
|
196 } |
|
197 break; |
|
198 case EDbColLongBinary: |
|
199 { |
|
200 const TDesC8& val=e.iValue.Blob(); |
|
201 const TUint8* ptr=REINTERPRET_CAST(const TUint8*,val.Ptr()); |
|
202 TInt size=val.Length(); |
|
203 col.SetBlobL(blobstore->CreateL(EDbColLongBinary,ptr,size),size); |
|
204 } |
|
205 break; |
|
206 } |
|
207 } |
|
208 } |
|
209 |
|
210 // Class CSqlDMLStatement |
|
211 |
|
212 CSqlDMLStatement::~CSqlDMLStatement() |
|
213 { |
|
214 delete iValues; |
|
215 } |
|
216 |
|
217 CSqlValues& CSqlDMLStatement::ValuesL() |
|
218 { |
|
219 CSqlValues* v=iValues; |
|
220 if (!v) |
|
221 iValues=v=new(ELeave) CSqlValues; |
|
222 return *v; |
|
223 } |
|
224 |
|
225 // Class CSqlInsertStatement |
|
226 |
|
227 CSqlInsertStatement* CSqlInsertStatement::NewLC() |
|
228 { |
|
229 CSqlInsertStatement* self=new(ELeave) CSqlInsertStatement; |
|
230 CleanupStack::PushL(self); |
|
231 return self; |
|
232 } |
|
233 |
|
234 CDbIncremental* CSqlInsertStatement::ExecuteL(CDbTableDatabase& aDatabase,TDbTextComparison aComparison,TInt& aRows) |
|
235 // |
|
236 // Execute an insert-statement. This does not requre incremental work, so return 0 |
|
237 // |
|
238 { |
|
239 aRows=1; // 1 row changed after insertion |
|
240 CSqlQuery* query=&Query(); |
|
241 RDbAccessPlan plan(query,aComparison); |
|
242 plan.BuildLC(aDatabase,RDbRowSet::EInsertOnly,TDbWindow()); |
|
243 CDbDataSource& src=plan.Source(); |
|
244 Values().BindL(src); |
|
245 src.NewRowL(KDbNullRecordId); |
|
246 RDbTransaction& t=plan.Table().Database().Transaction(); |
|
247 t.DMLBeginLC(); |
|
248 Values().WriteL(src,plan.Table()); |
|
249 src.PrepareToWriteRowL(src.EAppend); |
|
250 src.WriteRowL(src.EAppend,src.ENoSynch); |
|
251 t.DMLCommitL(); |
|
252 CleanupStack::Pop(); // transaction complete |
|
253 CleanupStack::PopAndDestroy(); // plan |
|
254 return 0; // no incremental work to be done |
|
255 } |
|
256 |
|
257 // Class CDbIncrementalDML |
|
258 |
|
259 CDbIncrementalDML* CDbIncrementalDML::NewL(CSqlModifyStatement& aStatement,CDbTableDatabase& aDatabase,TDbTextComparison aComparison) |
|
260 { |
|
261 CSqlQuery* query=&aStatement.Query(); |
|
262 RDbAccessPlan plan(query,aComparison); |
|
263 plan.BuildLC(aDatabase,RDbRowSet::EUpdatable,TDbWindow()); |
|
264 CDbIncrementalDML* self=new(ELeave) CDbIncrementalDML(plan); |
|
265 CleanupStack::PopAndDestroy(); // plan |
|
266 if (aStatement.IsUpdate()) |
|
267 { |
|
268 CleanupStack::PushL(self); |
|
269 self->iValues=aStatement.AdoptValues(); |
|
270 self->iValues->BindL(*self->iSource); |
|
271 CleanupStack::Pop(); // self |
|
272 } |
|
273 self->iSource->Reset(); |
|
274 self->Transaction().DMLBegin(); |
|
275 self->SetState(EEvaluating); |
|
276 return self; |
|
277 } |
|
278 |
|
279 CDbIncrementalDML::~CDbIncrementalDML() |
|
280 { |
|
281 if (iState!=ECommitted && iState!=EInitialising) |
|
282 Transaction().DMLRollback(); |
|
283 delete iSource; |
|
284 delete iValues; |
|
285 } |
|
286 |
|
287 TBool CDbIncrementalDML::NextL(TInt& aRows) |
|
288 { |
|
289 __ASSERT(iState!=ECommitted); |
|
290 if (iState==EFailed) |
|
291 __LEAVE(KErrDied); |
|
292 TState s=iState; |
|
293 iState=EFailed; |
|
294 TInt work=256; |
|
295 TDbPosition next=EDbNext; |
|
296 if (s==EEvaluating) |
|
297 { // evaluate the data source |
|
298 TBool atrow=EFalse; |
|
299 if (iSource->EvaluateL(work,iRecord,atrow)) |
|
300 { |
|
301 iState=EEvaluating; |
|
302 return ETrue; // more to do |
|
303 } |
|
304 iRecord=KDbNullRecordId; |
|
305 next=EDbFirst; |
|
306 s=EUpdating; |
|
307 } |
|
308 // iterate across the data source |
|
309 for (;;) |
|
310 { |
|
311 if (s==EDeleting) |
|
312 { |
|
313 Transaction().DMLBeginLC(); |
|
314 CDbDataSource::TDelete del=iSource->DeleteRowL(iRecord,CDbDataSource::ESynch); |
|
315 Transaction().DMLCommitL(); |
|
316 CleanupStack::Pop(); // transaction complete |
|
317 ++aRows; |
|
318 work-=4; |
|
319 switch (del) |
|
320 { |
|
321 case CDbDataSource::EDeletedAtEnd: |
|
322 Transaction().DMLTouch(); |
|
323 Transaction().DMLCommitL(); |
|
324 iState=ECommitted; |
|
325 return EFalse; |
|
326 case CDbDataSource::EDeletedInLimbo: |
|
327 s=EUpdating; |
|
328 case CDbDataSource::EDeletedAtNext: |
|
329 if (work<0) |
|
330 { // exhausted |
|
331 iState=s; |
|
332 return ETrue; |
|
333 } |
|
334 } |
|
335 } |
|
336 else |
|
337 { |
|
338 switch (iSource->GotoL(work,next,iRecord)) |
|
339 { |
|
340 default: |
|
341 __ASSERT(0); |
|
342 case CDbDataSource::ESuccess: |
|
343 next=EDbNext; |
|
344 if (!IsUpdate()) |
|
345 { |
|
346 s=EDeleting; |
|
347 break; |
|
348 } |
|
349 iSource->ReadRowL(iRecord); |
|
350 iValues->WriteL(*iSource,iTable); |
|
351 iSource->PrepareToWriteRowL(CDbDataSource::EReplace); |
|
352 Transaction().DMLBeginLC(); |
|
353 iSource->WriteRowL(CDbDataSource::EReplace,CDbDataSource::ESynch); |
|
354 Transaction().DMLCommitL(); |
|
355 CleanupStack::Pop(); // transaction complete |
|
356 ++aRows; |
|
357 work-=8; |
|
358 break; |
|
359 case CDbDataSource::ESynchFailure: |
|
360 // dead |
|
361 __LEAVE(KErrDied); |
|
362 case CDbDataSource::EExhausted: |
|
363 // more to do |
|
364 iState=EUpdating; |
|
365 return ETrue; |
|
366 case CDbDataSource::ENoRow: |
|
367 // completed the operation! |
|
368 Transaction().DMLTouch(); |
|
369 Transaction().DMLCommitL(); |
|
370 iState=ECommitted; |
|
371 return EFalse; |
|
372 } |
|
373 } |
|
374 } |
|
375 } |
|
376 |
|
377 |
|
378 // Class CSqlModifyStatement |
|
379 |
|
380 CSqlModifyStatement* CSqlModifyStatement::NewLC() |
|
381 { |
|
382 CSqlModifyStatement* self=new(ELeave) CSqlModifyStatement; |
|
383 CleanupStack::PushL(self); |
|
384 return self; |
|
385 } |
|
386 |
|
387 CDbIncremental* CSqlModifyStatement::ExecuteL(CDbTableDatabase& aDatabase,TDbTextComparison aComparison,TInt& aRows) |
|
388 // |
|
389 // Execute an update/delete-statement, returning the incremental object that does the work |
|
390 // |
|
391 { |
|
392 aRows=0; // no rows affected initially |
|
393 return CDbIncrementalDML::NewL(*this,aDatabase,aComparison); |
|
394 } |