|
1 /* |
|
2 * Copyright (c) 2007-2009 Nokia Corporation and/or its subsidiary(-ies). |
|
3 * All rights reserved. |
|
4 * This component and the accompanying materials are made available |
|
5 * under the terms of the License "Eclipse Public License v1.0" |
|
6 * which accompanies this distribution, and is available |
|
7 * at the URL "http://www.eclipse.org/legal/epl-v10.html". |
|
8 * |
|
9 * Initial Contributors: |
|
10 * Nokia Corporation - initial contribution. |
|
11 * |
|
12 * Contributors: |
|
13 * |
|
14 * Description: |
|
15 * Implements a read-only interface for UPS Database. |
|
16 * |
|
17 */ |
|
18 |
|
19 |
|
20 /** |
|
21 @file |
|
22 @internalTechnology |
|
23 @prototype |
|
24 */ |
|
25 |
|
26 #include "upsdbw.h" |
|
27 #include "upscommon.h" |
|
28 |
|
29 using namespace UserPromptService; |
|
30 |
|
31 |
|
32 // |
|
33 //CDecisionView |
|
34 // |
|
35 |
|
36 CDecisionView::CDecisionView():CActive(EPriorityStandard) |
|
37 /** |
|
38 Constructor for decision view object. |
|
39 */ |
|
40 { |
|
41 CActiveScheduler::Add(this); |
|
42 } |
|
43 |
|
44 |
|
45 |
|
46 CDecisionView::~CDecisionView() |
|
47 /** |
|
48 Destructor for the decision view object. |
|
49 */ |
|
50 { |
|
51 iDbView.Close(); |
|
52 delete iColSet; |
|
53 Deque(); |
|
54 } |
|
55 |
|
56 |
|
57 EXPORT_C CDecisionView* CDecisionView::NewLC() |
|
58 /** |
|
59 Creates a decision view object. The function leaves, if creation of the view object fails. |
|
60 |
|
61 @return A pointer to the newly allocated view object, if creation is successful. |
|
62 The pointer is also put onto the cleanup stack. |
|
63 */ |
|
64 { |
|
65 CDecisionView* self = new(ELeave) CDecisionView(); |
|
66 CleanupStack::PushL(self); |
|
67 return self; |
|
68 } |
|
69 |
|
70 |
|
71 void CDecisionView::DoCancel() |
|
72 //From CActive |
|
73 { |
|
74 iDbView.Cancel(); |
|
75 if (iClientStatus) |
|
76 { |
|
77 User::RequestComplete(iClientStatus, KErrCancel); |
|
78 } |
|
79 } |
|
80 |
|
81 |
|
82 TInt CDecisionView::RunError(TInt aError) |
|
83 //From CActive |
|
84 { |
|
85 if (iClientStatus) |
|
86 { |
|
87 User::RequestComplete(iClientStatus, aError); |
|
88 } |
|
89 return KErrNone; |
|
90 } |
|
91 |
|
92 |
|
93 void CDecisionView::RunL() |
|
94 //From CActive |
|
95 { |
|
96 TInt status = iStatus.Int(); |
|
97 User::LeaveIfError(status); |
|
98 |
|
99 if(status > 0) |
|
100 { |
|
101 iDbView.Evaluate(iStatus); |
|
102 SetActive(); |
|
103 } |
|
104 else |
|
105 { |
|
106 User::RequestComplete(iClientStatus,status); |
|
107 } |
|
108 } |
|
109 |
|
110 |
|
111 EXPORT_C void CDecisionView::EvaluateView(TRequestStatus& aStatus) |
|
112 /** |
|
113 Performs all steps of the view evaluation, returning immediately and |
|
114 signalling when all steps are complete. |
|
115 |
|
116 @param aStatus The request status used to contain completion information for the function. |
|
117 On completion, the status value should be interpreted as follows: |
|
118 0, evaluation is complete.< 0, an error code. |
|
119 */ |
|
120 { |
|
121 __ASSERT_ALWAYS(!IsActive(), User::Panic(KDecisionViewPanic,KErrInUse)); |
|
122 |
|
123 aStatus = KRequestPending; |
|
124 iClientStatus = &aStatus; |
|
125 |
|
126 iDbView.Evaluate(iStatus); |
|
127 |
|
128 SetActive(); |
|
129 |
|
130 } |
|
131 |
|
132 |
|
133 CDecisionRecord* CDecisionView::GenerateRecordL(RDbRowSet& aRowSet, CDbColSet* aColSet) |
|
134 /** |
|
135 Retrieves all decision record fileds from the given rowset and generates |
|
136 a decision record from these information. |
|
137 |
|
138 @param aRowSet A database rowset object. |
|
139 @param aColSet A database column set object. |
|
140 |
|
141 @return The newly,created decision record if it is successful; otherwise, leaves. |
|
142 */ |
|
143 { |
|
144 TSecureId clientSid(aRowSet.ColUint32(aColSet->ColNo(KColClientSid))); //Client Secure Id |
|
145 TSecureId serverId = TSecureId(aRowSet.ColUint32(aColSet->ColNo(KColServerSid))); //Service Secure Id |
|
146 TUid evaluatorId = TUid::Uid(aRowSet.ColUint32(aColSet->ColNo(KColEvaluatorId))); //Evaluator Uid |
|
147 TUid serviceId = TUid::Uid(aRowSet.ColUint32(aColSet->ColNo(KColServiceId))); //Service Uid |
|
148 TPtrC8 fingerprint = aRowSet.ColDes8(aColSet->ColNo(KColFingerprint)); //Fingerprint |
|
149 TPtrC8 clientEntity = aRowSet.ColDes8(aColSet->ColNo(KColClientEntity)); //Client Entity |
|
150 TInt8 result = aRowSet.ColInt8(aColSet->ColNo(KColResult)); //Result |
|
151 TUint16 ver = aRowSet.ColUint16(aColSet->ColNo(KColMajorPolicyVersion)); //Major Policy Version |
|
152 TUint32 recordId = aRowSet.ColUint32(aColSet->ColNo(KColRecordId)); //Unique Record ID |
|
153 TUint32 evaluatorInfo = aRowSet.ColUint32(aColSet->ColNo(KColEvaluatorInfo)); //EvaluatorInfo |
|
154 |
|
155 //a stream is used to read long columns |
|
156 TDbColNo col = aColSet->ColNo(KColDescription); |
|
157 TInt len = aRowSet.ColLength(col); |
|
158 |
|
159 RBuf description; |
|
160 CleanupClosePushL(description); |
|
161 description.CreateL(len); |
|
162 |
|
163 RDbColReadStream str; |
|
164 str.OpenLC(aRowSet,col); |
|
165 str.ReadL(description,len); |
|
166 str.Close(); |
|
167 CleanupStack::PopAndDestroy(&str); |
|
168 |
|
169 CDecisionRecord *retval = CDecisionRecord::NewL(clientSid,evaluatorId,serviceId,serverId,fingerprint, |
|
170 clientEntity,description,result,ver,evaluatorInfo,recordId); |
|
171 |
|
172 CleanupStack::PopAndDestroy(&description); |
|
173 return retval; |
|
174 } |
|
175 |
|
176 |
|
177 EXPORT_C CDecisionRecord* CDecisionView::NextDecisionL() |
|
178 /** |
|
179 Moves the cursor to the next row in the view object and returns the current decision row. |
|
180 If there are no more rows, the cursor is positioned to the end of the view object. |
|
181 |
|
182 @return 0, If the cursor is positioned at the end of the view. Otherwise, current record. |
|
183 */ |
|
184 { |
|
185 CDecisionRecord *record(0); |
|
186 |
|
187 if(iDbView.NextL()) |
|
188 { |
|
189 iDbView.GetL(); |
|
190 record = GenerateRecordL(iDbView,iColSet); |
|
191 } |
|
192 else |
|
193 { |
|
194 iDbView.Close(); |
|
195 } |
|
196 |
|
197 return record; |
|
198 } |
|
199 |
|
200 |
|
201 // |
|
202 //CDecisionDb |
|
203 // |
|
204 |
|
205 |
|
206 CDecisionDb::CDecisionDb() |
|
207 /** |
|
208 Constructor for read-only decision database object |
|
209 */ |
|
210 { |
|
211 |
|
212 } |
|
213 |
|
214 |
|
215 CDecisionDb::~CDecisionDb() |
|
216 /** |
|
217 Destructor for read-only decision database object |
|
218 */ |
|
219 { |
|
220 |
|
221 } |
|
222 |
|
223 const TDesC* CDecisionDb::GetComparisonOperator(const TUint32& aFlag) const |
|
224 /** |
|
225 Finds and returns the correspondent comparision operator string. |
|
226 |
|
227 @param aFlag |
|
228 */ |
|
229 { |
|
230 UserPromptService::TComparisonOp op = static_cast<UserPromptService::TComparisonOp>(aFlag & 0xFFFF0000); |
|
231 switch (op) |
|
232 { |
|
233 case UserPromptService::EEqual: |
|
234 { |
|
235 return &KSQLQueryEqual; |
|
236 } |
|
237 case UserPromptService::ENotEqual: |
|
238 { |
|
239 return &KSQLQueryNotEqual; |
|
240 } |
|
241 case UserPromptService::ELessThan: |
|
242 { |
|
243 return &KSQLQueryLessThan; |
|
244 } |
|
245 case UserPromptService::EGreaterThan: |
|
246 { |
|
247 return &KSQLQueryGreaterThan; |
|
248 } |
|
249 case UserPromptService::ELessThanOrEqual: |
|
250 { |
|
251 return &KSQLQueryLessThanOrEqual; |
|
252 } |
|
253 case UserPromptService::EGreaterThanOrEqual: |
|
254 { |
|
255 return &KSQLQueryGreaterThanOrEqual; |
|
256 } |
|
257 } |
|
258 return &KSQLQueryEqual; |
|
259 } |
|
260 |
|
261 |
|
262 void CDecisionDb::CreateSqlStatementLC(CDecisionFilter& aFilter, RBuf& aSql) |
|
263 /** |
|
264 Creates an sql statement from a given filter. |
|
265 |
|
266 @param aFilter A filter object used to create the SQL statement. |
|
267 @param aSql The newly created SQL statement. |
|
268 */ |
|
269 { |
|
270 //Estimate the maximum required buffer (maxLen) to save the sql statement. |
|
271 //KSQLQueryBase must be in the statement at least. |
|
272 TInt maxLen = KBaseSQLLength; |
|
273 |
|
274 //Get the bits belonging to ID values (ClientSid,EvaluatorId,ServiceId,ServerSid) |
|
275 TUint32 combinedFlags = (aFilter.iSetFlag[KPosClientSid] | aFilter.iSetFlag[KPosEvaluatorId] | |
|
276 aFilter.iSetFlag[KPosServiceId] | aFilter.iSetFlag[KPosServerSid] | |
|
277 aFilter.iSetFlag[KPosFingerprint] | aFilter.iSetFlag[KPosClientEntity]| |
|
278 aFilter.iSetFlag[KPosMajorPolicyVersion] | aFilter.iSetFlag[KPosRecordId] | |
|
279 aFilter.iSetFlag[KPosDescription] | aFilter.iSetFlag[KPosResult] | |
|
280 aFilter.iSetFlag[KPosEvaluatorInfo]); |
|
281 |
|
282 TUint16 flag = combinedFlags & 0x000006CF; |
|
283 //Count how many bits are set, and add KMaxIntCondition for each set bit |
|
284 while(flag != 0) |
|
285 { |
|
286 flag &= (flag-1); |
|
287 maxLen += KMaxIntCondition; |
|
288 } |
|
289 //Get the bits belonging to string values (Fingerprint and ClientEntity) |
|
290 flag = combinedFlags & 0x00000130; |
|
291 //Count how many bits are set, and add KMaxStringCondition length for each set bit |
|
292 while(flag != 0) |
|
293 { |
|
294 flag &= (flag-1); |
|
295 maxLen += KMaxStringCondition; |
|
296 } |
|
297 |
|
298 //Allocate the estimated number of bytes for the sql statement |
|
299 aSql.CreateL(maxLen); |
|
300 aSql.CleanupClosePushL(); |
|
301 //First copy the basic SQL statement |
|
302 aSql.AppendFormat(KSQLQueryBase,&KDecisionTable); |
|
303 |
|
304 //If the filter is empty, there is no condition to add to the sql statement. |
|
305 //So, simply return the base sql statement. In this case, all rows of |
|
306 //the decision table are listed. |
|
307 if(maxLen == KBaseSQLLength) |
|
308 { |
|
309 return; |
|
310 } |
|
311 |
|
312 //Filter is not empty, add 'WHERE' key word into the statement |
|
313 aSql.Append(KSQLQueryWhere); |
|
314 |
|
315 TBool multiple = EFalse; |
|
316 //Append server SID if exists in the filter |
|
317 AppendQueryInteger(aFilter.iServerSid.iId, aSql, multiple, aFilter.iSetFlag[KPosServerSid], KSetServerSid, KColServerSid); |
|
318 //Append service UID if exists in the filter |
|
319 AppendQueryInteger(aFilter.iServiceId.iUid, aSql, multiple, aFilter.iSetFlag[KPosServiceId], KSetServiceId, KColServiceId); |
|
320 //Append client SID if exists in the filter |
|
321 AppendQueryInteger(aFilter.iClientSid.iId, aSql, multiple, aFilter.iSetFlag[KPosClientSid], KSetClientSid, KColClientSid); |
|
322 //Append evaluator UID if exists in the filter |
|
323 AppendQueryInteger(aFilter.iEvaluatorId.iUid, aSql, multiple, aFilter.iSetFlag[KPosEvaluatorId], KSetEvaluatorId, KColEvaluatorId); |
|
324 //Append major policy version if exists in the filter |
|
325 AppendQueryInteger(aFilter.iMajorPolicyVersion, aSql, multiple, aFilter.iSetFlag[KPosMajorPolicyVersion], KSetMajorPolicyVersion, KColMajorPolicyVersion); |
|
326 //Append record id if exists in the filter |
|
327 AppendQueryInteger(aFilter.iRecordId, aSql, multiple, aFilter.iSetFlag[KPosRecordId], KSetRecordId, KColRecordId); |
|
328 //Append result if exists in the filter |
|
329 AppendQueryInteger(aFilter.iResult, aSql, multiple, aFilter.iSetFlag[KPosResult], KSetResult, KColResult); |
|
330 //Append evaluator info if exists in the filter |
|
331 AppendQueryInteger(aFilter.iEvaluatorInfo, aSql, multiple, aFilter.iSetFlag[KPosEvaluatorInfo], KSetEvaluatorInfo, KColEvaluatorInfo); |
|
332 //Append description if exists in the filter |
|
333 AppendQueryStringL(*aFilter.iDescription, aSql, multiple, aFilter.iSetFlag[KPosDescription], KSetDescription, KColDescription); |
|
334 |
|
335 //Append fingerprint if exists in the filter |
|
336 //Convert 8-bit value to 16-bit |
|
337 if(aFilter.iFingerprint) |
|
338 { |
|
339 HBufC* fp = HBufC::NewLC(aFilter.iFingerprint->Length()); |
|
340 TPtr ptrFp(fp->Des()); |
|
341 ptrFp.Copy(*aFilter.iFingerprint); |
|
342 |
|
343 AppendQueryStringL(*fp, aSql, multiple, aFilter.iSetFlag[KPosFingerprint], KSetFingerprint, KColFingerprint); |
|
344 CleanupStack::PopAndDestroy(fp); |
|
345 } |
|
346 |
|
347 //Append client entity if exists in the filter |
|
348 //Convert 8-bit value to 16-bit |
|
349 if(aFilter.iClientEntity) |
|
350 { |
|
351 HBufC* ce = HBufC::NewLC(aFilter.iClientEntity->Length()); |
|
352 TPtr ptrCe(ce->Des()); |
|
353 ptrCe.Copy(*aFilter.iClientEntity); |
|
354 |
|
355 AppendQueryStringL(*ce, aSql, multiple, aFilter.iSetFlag[KPosClientEntity], KSetClientEntity, KColClientEntity); |
|
356 CleanupStack::PopAndDestroy(ce); |
|
357 } |
|
358 } |
|
359 |
|
360 |
|
361 void CDecisionDb::AppendQueryInteger(const TUint32& aValue, TDes& aSql, TBool& aMultiple, const TUint32& aFlag, const TUint32& aSetCol, const TDesC& aColName) |
|
362 /** |
|
363 Appends an integer-based query key field to an SQL query string. |
|
364 |
|
365 @param aValue The integer value which will be added to the query. |
|
366 @param aSql The SQL query string. |
|
367 @param aMultiple EFalse, if there is only one query key in the query string. Otherwise, ETrue. |
|
368 @param aFlag The flag value corresponding to the query key. |
|
369 @param aSetCol A constant value indicating whether or not a specific column is set. |
|
370 @param aColName The column name of the query key. |
|
371 */ |
|
372 { |
|
373 if(aFlag & aSetCol) |
|
374 { |
|
375 if(aMultiple) |
|
376 { |
|
377 aSql.Append(KSQLQueryAnd); |
|
378 } |
|
379 else |
|
380 { |
|
381 aMultiple=ETrue; |
|
382 } |
|
383 |
|
384 aSql.Append(aColName); |
|
385 aSql.AppendFormat(KSQLQueryString,GetComparisonOperator(aFlag)); |
|
386 aSql.AppendFormat(KSQLQueryConditionInt,aValue); |
|
387 } |
|
388 } |
|
389 |
|
390 |
|
391 void CDecisionDb::AppendQueryStringL(const TDesC& aValue, TDes& aSql, TBool& aMultiple, const TUint32& aFlag, const TUint32& aSetCol, const TDesC& aColName) |
|
392 /** |
|
393 Appends an string query key to an SQL query string. |
|
394 |
|
395 @param aValue The string value which will be added to the query. |
|
396 @param aSql The SQL query string. |
|
397 @param aMultiple EFalse, if there is only one query key in the query string. Otherwise, ETrue. |
|
398 @param aFlag The flag value corresponding to the query key. |
|
399 @param aSetCol A constant value indicating whether or not a specific column is set. |
|
400 @param aColName The column name of the query key. |
|
401 */ |
|
402 { |
|
403 if(aFlag & aSetCol) |
|
404 { |
|
405 if(aMultiple) |
|
406 { |
|
407 aSql.Append(KSQLQueryAnd); |
|
408 } |
|
409 else |
|
410 { |
|
411 aMultiple=ETrue; |
|
412 } |
|
413 |
|
414 aSql.Append(aColName); |
|
415 |
|
416 if(aValue.Length() != 0) |
|
417 { |
|
418 //Scan for single quote |
|
419 RBuf dbValue; |
|
420 DoubleSingleQuotesL(aValue, dbValue); |
|
421 dbValue.CleanupClosePushL(); |
|
422 |
|
423 aSql.AppendFormat(KSQLQueryString,GetComparisonOperator(aFlag)); |
|
424 aSql.AppendFormat(KSQLQueryConditionString,&dbValue); |
|
425 |
|
426 CleanupStack::PopAndDestroy(&dbValue); |
|
427 } |
|
428 else |
|
429 { |
|
430 aSql.Append(KSQLQueryNull); |
|
431 } |
|
432 } |
|
433 } |
|
434 |
|
435 |
|
436 void CDecisionDb::DoubleSingleQuotesL(const TDesC& aSource, RBuf& aDestination) |
|
437 /** |
|
438 Copies a source descriptor into a destination descriptor. If a single quote |
|
439 character is found an extra single quote is copied to the destination. |
|
440 Because, it is not possible to search for a string in SQL with single quote ('). |
|
441 |
|
442 @param aSource A source descriptor. |
|
443 @param aDestination A destination descriptor. |
|
444 */ |
|
445 { |
|
446 _LIT(KSingleQuote,"'"); |
|
447 |
|
448 aDestination.Close(); |
|
449 |
|
450 if(aSource.FindF(KSingleQuote) > KErrNotFound) |
|
451 { |
|
452 const TUint16 KSingleQuoteHex = 0x27; |
|
453 TInt len = aSource.Length(); |
|
454 |
|
455 //Define a temporary buffer and set its maximum size to twice of the original (if it contained all quotes!) |
|
456 RBuf temp; |
|
457 temp.CreateL(len*2); |
|
458 CleanupClosePushL(temp); |
|
459 |
|
460 const TUint16 *ptrSrc = aSource.Ptr(); |
|
461 TUint16 *ptrDes = (TUint16 *)temp.Ptr(); |
|
462 TInt srcIndex=0; |
|
463 TInt desIndex=0; |
|
464 |
|
465 for(srcIndex=0; srcIndex<len; ++srcIndex,++desIndex) |
|
466 { |
|
467 ptrDes[desIndex] = ptrSrc[srcIndex]; |
|
468 if(ptrSrc[srcIndex] == KSingleQuoteHex) //is single quote? |
|
469 { |
|
470 ptrDes[++desIndex] = ptrSrc[srcIndex];//add extra single quote |
|
471 } |
|
472 } |
|
473 |
|
474 //Set the actual length |
|
475 temp.SetLength(desIndex); |
|
476 //Copy temp into destination. destination's maximum length is the same as the length of temp |
|
477 aDestination.CreateL(temp); |
|
478 CleanupStack::PopAndDestroy(&temp); |
|
479 } |
|
480 else |
|
481 { |
|
482 //there is no single quote, just copy it |
|
483 aDestination.CreateL(aSource); |
|
484 } |
|
485 } |
|
486 |
|
487 |
|
488 EXPORT_C CDecisionView *CDecisionDb::CreateViewL(CDecisionFilter& aFilter) |
|
489 /** |
|
490 Generates an SQL view rowset to the decision table by using a filter. |
|
491 The view rowset contains a set of rows which depend on the filter. |
|
492 |
|
493 @param aFilter A filter object to query the decision database |
|
494 @param aDecisionView A decision view object containing handle to the newly created SQL view rowset. |
|
495 */ |
|
496 { |
|
497 RBuf sqlStatement; |
|
498 CreateSqlStatementLC(aFilter, sqlStatement); |
|
499 |
|
500 CDecisionView *dbView = CDecisionView::NewLC(); |
|
501 |
|
502 User::LeaveIfError(dbView->iDbView.Prepare(iDatabase,TDbQuery(sqlStatement),TDbWindow::EUnlimited)); |
|
503 |
|
504 dbView->iColSet = dbView->iDbView.ColSetL(); |
|
505 |
|
506 CleanupStack::Pop(dbView); |
|
507 CleanupStack::PopAndDestroy(&sqlStatement); //sqlStatement |
|
508 |
|
509 return dbView; |
|
510 } |
|
511 |