Update contrib.
2 * Copyright (c) 2007-2009 Nokia Corporation and/or its subsidiary(-ies).
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".
9 * Initial Contributors:
10 * Nokia Corporation - initial contribution.
15 * Implements a writable interface for UPS Database.
27 #include "upscommon.h"
29 using namespace UserPromptService;
31 CDecisionDbW::CDecisionDbW()
33 Constructor for writable decision database object
40 CDecisionDbW::~CDecisionDbW()
42 Destructor for writable decision database object
51 EXPORT_C CDecisionDbW* CDecisionDbW::NewL(const TDesC& aDbName, RFs& aFs)
53 Creates a writable decision database object and connects to the database.
54 If the database does not exist or is corrupted, a new decision database is created.
55 The function leaves, if creation of the object or connection to the database fail.
57 @param aDbName The path of the decision database
58 @param aFs Handle to the file server session
60 @return A pointer to the newly allocated database object, if creation and connection are successful.
63 CDecisionDbW* self = CDecisionDbW::NewLC(aDbName, aFs);
64 CleanupStack::Pop(self);
69 EXPORT_C CDecisionDbW* CDecisionDbW::NewLC(const TDesC& aDbName, RFs& aFs)
71 Creates a writable decision database object and connects to the database.
72 If the database does not exist or is corrupted, a new decision database is created.
73 The function leaves, if creation of the object or connection to the database fail.
75 @param aDbName The path of the decision database
76 param aFs Handle to the file server session
78 @return A pointer to the newly allocated database object, if creation and connection
79 are successful. The pointer is also put onto the cleanup stack.
82 CDecisionDbW* self = new (ELeave) CDecisionDbW();
83 CleanupStack::PushL(self);
84 self->ConstructL(aDbName, aFs);
89 void CDecisionDbW::ConstructL(const TDesC& aDbName, RFs& aFs)
91 Second phase constructor for the decision database object. Connects to the decision database.
92 If the database does not existed or is corrupted, creates a new one. The function leaves,
93 if both database connection and creation fail.
95 @param aDbName The path of the decision database
96 @param aFs Handle to the file server session
99 //Construct the name of UPS decision database
100 iDbName = aDbName.AllocL();
102 //First try to open the decision database
103 TRAPD(error,OpenDatabaseL(aFs));
105 if((error == KErrNoMemory) || (error == KErrDiskFull))
110 // Makes sure that DB file is writable. (DEF122590)
111 aFs.SetAtt(iDbName->Des(),0, KEntryAttReadOnly);
113 if(error != KErrNone)
115 DEBUG_PRINTF2(_L("%S database file does not exist or is corrupted."), iDbName);
116 //The decision database does not exist or is corrupted, create a new one
117 CreateDatabaseL(aFs);
119 //Create a decision table in the decision database
122 //Create an index on the decision table
128 void CDecisionDbW::OpenDatabaseL(RFs& aFs)
130 Opens the decision database.
131 @param aFs Handle to the file server session
134 DEBUG_PRINTF2(_L("%S database file is being opened."), iDbName);
136 iStore = CPermanentFileStore::OpenL(aFs, *iDbName, EFileRead|EFileWrite);
137 iDatabase.OpenL(iStore, iStore->Root());
139 //Database does exist. However, make sure that the decision table also exists
140 CDbTableNames *tables = iDatabase.TableNamesL();
141 CleanupStack::PushL(tables);
142 if(1 != tables->Count())
144 DEBUG_PRINTF(_L("The decision table could not be found in the database file!"));
145 User::Leave(KErrNotFound);
147 CleanupStack::PopAndDestroy(tables);
149 //OK. The decision table does exist. What about the decision index?
150 CDbIndexNames *indexes = iDatabase.IndexNamesL(KDecisionTable);
151 CleanupStack::PushL(indexes);
152 if(2 != indexes->Count())
154 DEBUG_PRINTF(_L("The index on the decision table is missing!"));
155 User::Leave(KErrNotFound);
157 CleanupStack::PopAndDestroy(indexes);
159 if(iDatabase.IsDamaged())
161 User::LeaveIfError(iDatabase.Recover());
164 DEBUG_PRINTF2(_L("%S database file has been opened successfully."), iDbName);
168 void CDecisionDbW::CreateDatabaseL(RFs& aFs)
170 Creates a new, empty store database.
171 @param aFs Handle to the file server session
174 DEBUG_PRINTF2(_L("%S database is being created."), iDbName);
177 {//if database file exists but the table does not, iStore has already been allocated.
183 //Create a file store
184 iStore = CPermanentFileStore::ReplaceL(aFs, *iDbName, EFileRead|EFileWrite);
185 iStore->SetTypeL(iStore->Layout());
187 //Create UPS Decision Database in the file store
188 TStreamId sId = iDatabase.CreateL(iStore);
189 iStore->SetRootL(sId);
191 //Commit the database creation
194 DEBUG_PRINTF2(_L("%S database has been created successfully."), iDbName);
198 void CDecisionDbW::CreateTableL()
200 Creates the decision table in the decision database.
203 DEBUG_PRINTF(_L("The Ups decision table is being created."));
205 // Create a table definition
206 CDbColSet* columns=CDbColSet::NewLC();
208 // add the columns to the definition
209 TDbCol clientSid(KColClientSid,EDbColUint32);
210 clientSid.iAttributes = TDbCol::ENotNull;
211 columns->AddL(clientSid);
213 TDbCol evaluatorId(KColEvaluatorId,EDbColUint32);
214 evaluatorId.iAttributes = TDbCol::ENotNull;
215 columns->AddL(evaluatorId);
217 TDbCol serviceId(KColServiceId,EDbColUint32);
218 serviceId.iAttributes=TDbCol::ENotNull;
219 columns->AddL(serviceId);
221 TDbCol serverSid(KColServerSid,EDbColUint32);
222 serverSid.iAttributes=TDbCol::ENotNull;
223 columns->AddL(serverSid);
225 TDbCol fingerprint(KColFingerprint,EDbColText8,KUpsMaxFingerprintLength );
226 columns->AddL(fingerprint);
228 TDbCol clientEntity(KColClientEntity,EDbColText8,KUpsMaxClientEntityLength);
229 columns->AddL(clientEntity);
231 TDbCol description(KColDescription,EDbColLongText);
232 columns->AddL(description);
234 TDbCol result(KColResult,EDbColInt8);
235 result.iAttributes=TDbCol::ENotNull;
236 columns->AddL(result);
238 TDbCol evaluatorInfo(KColEvaluatorInfo,EDbColUint32);
239 columns->AddL(evaluatorInfo);
241 TDbCol policyVersion(KColMajorPolicyVersion,EDbColUint16);
242 policyVersion.iAttributes=TDbCol::ENotNull;
243 columns->AddL(policyVersion);
245 TDbCol recordId(KColRecordId,EDbColUint32);
246 recordId.iAttributes=TDbCol::ENotNull|TDbCol::EAutoIncrement;
247 columns->AddL(recordId);
249 // Create a table with the table definition
250 User::LeaveIfError(iDatabase.CreateTable(KDecisionTable,*columns));
252 // cleanup the column set
253 CleanupStack::PopAndDestroy(columns);
255 DEBUG_PRINTF(_L("The Ups decision table has been created successfully."));
259 void CDecisionDbW::CreateIndexL()
261 Creates an index on the decision table and makes it unique.
264 DEBUG_PRINTF(_L("The Ups decision index is being created on the decision table."));
266 // create the index key
267 CDbKey* key=CDbKey::NewLC();
269 // add the key columns
270 key->AddL(TDbKeyCol(KColClientSid));
271 key->AddL(TDbKeyCol(KColEvaluatorId));
272 key->AddL(TDbKeyCol(KColServiceId));
273 key->AddL(TDbKeyCol(KColServerSid));
274 key->AddL(TDbKeyCol(KColFingerprint));
275 key->AddL(TDbKeyCol(KColClientEntity));
276 key->AddL(TDbKeyCol(KColMajorPolicyVersion));
278 //Make the index key unique
281 // create the primary index
282 User::LeaveIfError(iDatabase.CreateIndex(KPrimaryIndex,KDecisionTable,*key));
284 //Now create the second index on the record id
286 // add the record id column
287 key->AddL(TDbKeyCol(KColRecordId));
290 // create the record id index
291 User::LeaveIfError(iDatabase.CreateIndex(KRecordIdIndex,KDecisionTable,*key));
294 CleanupStack::PopAndDestroy(key);
296 DEBUG_PRINTF(_L("The Ups decision index has been created successfully."));
300 EXPORT_C void CDecisionDbW::DeleteDatabaseL(RFs& aFs)
302 Delete the decision database completely.
303 @param aFs Handle to the file server session
306 DEBUG_PRINTF2(_L("%S database is being deleted."),iDbName);
311 User::LeaveIfError(aFs.Delete(*iDbName));
313 DEBUG_PRINTF2(_L("%S database has been deleted successfully."),iDbName);
317 void CDecisionDbW::UpdateCurrentRowL(RDbTable& aTable, CDecisionRecord& aRecord)
319 Updates the current row of the rowset by using the values the provided decision record.
321 @param aTable A table object which provides access to table data as a rowset.
322 @param aRecord A decision record object used to update the current row.
325 //Use CDbColSet to set fields
326 CDbColSet* colSet = aTable.ColSetL();
327 CleanupStack::PushL(colSet);
329 //Set the fields of the empty row
330 aTable.SetColL(colSet->ColNo(KColClientSid) ,(TUint32)aRecord.iClientSid.iId);
331 aTable.SetColL(colSet->ColNo(KColEvaluatorId),(TUint32)aRecord.iEvaluatorId.iUid);
332 aTable.SetColL(colSet->ColNo(KColServiceId) ,(TUint32)aRecord.iServiceId.iUid);
333 aTable.SetColL(colSet->ColNo(KColServerSid) ,(TUint32)aRecord.iServerSid.iId);
335 //Fingerprint may be null
336 if(aRecord.iFingerprint.Length() != 0)
338 aTable.SetColL(colSet->ColNo(KColFingerprint),aRecord.iFingerprint);
341 //ClientEntity may be null
342 if(aRecord.iClientEntity.Length() != 0)
344 aTable.SetColL(colSet->ColNo(KColClientEntity),aRecord.iClientEntity);
347 //Description may be null
348 if(aRecord.iDescription.Length() != 0)
350 //A long column is written by using an RDbColStream
351 RDbColWriteStream str;
352 TDbColNo col = colSet->ColNo(KColDescription);
354 str.OpenLC(aTable,col);
355 str.WriteL(aRecord.iDescription);
358 CleanupStack::PopAndDestroy(&str);
361 aTable.SetColL(colSet->ColNo(KColResult),aRecord.iResult);
362 aTable.SetColL(colSet->ColNo(KColEvaluatorInfo),(TUint32)aRecord.iEvaluatorInfo);
363 aTable.SetColL(colSet->ColNo(KColMajorPolicyVersion),aRecord.iMajorPolicyVersion);
365 CleanupStack::PopAndDestroy(colSet);
369 EXPORT_C void CDecisionDbW::CreateDecisionL(CDecisionRecord& aRecord)
371 Inserts a new decision record into the decision database.
373 @param aRecord A new decision record
376 //Create a database table object
378 User::LeaveIfError(dbTable.Open(iDatabase,KDecisionTable,dbTable.EInsertOnly));
379 CleanupClosePushL(dbTable);
381 //Set the rowset cursor to the beginning position
384 //Insert an empty row into the table
387 //Set the fields of newly inserted row
388 UpdateCurrentRowL(dbTable, aRecord);
393 CleanupStack::Pop(&dbTable);
399 void CDecisionDbW::PrepareForSearchL(RDbTable& aTable, CDecisionFilter& aFilter, TDbSeekMultiKey<KIndexColumnNumber>& aSeekKey)
401 Opens the provided table object on the decision database and sets the decision index
402 as the active index for this table. If successful, the rowset is reset to the beginning.
404 @param aTable A table object which provides access to table data as a rowset.
405 @param aFilter A filter object which is used to set the decision index.
406 @return The key value to lookup in the index.
409 User::LeaveIfError(aTable.Open(iDatabase, KDecisionTable, aTable.EUpdatable));
411 TUint16 flags = KSetClientSid|KSetEvaluatorId|KSetServiceId|KSetServerSid|KSetFingerprint|KSetClientEntity|KSetMajorPolicyVersion;
413 TUint16 combinedFlags = (0x00FF) & (aFilter.iSetFlag[KPosClientSid] | aFilter.iSetFlag[KPosEvaluatorId] |
414 aFilter.iSetFlag[KPosServiceId] | aFilter.iSetFlag[KPosServerSid] |
415 aFilter.iSetFlag[KPosFingerprint] | aFilter.iSetFlag[KPosClientEntity]|
416 aFilter.iSetFlag[KPosMajorPolicyVersion]);
418 //If any of these flags is not set, do not continue
419 if ((combinedFlags & flags) != flags)
421 DEBUG_PRINTF(_L("The provided filter does not have all required keys to look up a decision."));
422 User::Leave(KErrUpsMissingArgument);
425 aSeekKey.Add((TUint)aFilter.iClientSid.iId);
426 aSeekKey.Add((TUint)aFilter.iEvaluatorId.iUid);
427 aSeekKey.Add((TUint)aFilter.iServiceId.iUid);
428 aSeekKey.Add((TUint)aFilter.iServerSid.iId);
429 aSeekKey.Add(*aFilter.iFingerprint);
430 aSeekKey.Add(*aFilter.iClientEntity);
431 aSeekKey.Add(aFilter.iMajorPolicyVersion);
433 //Set the primary index
434 User::LeaveIfError(aTable.SetIndex(KPrimaryIndex));
439 EXPORT_C CDecisionRecord* CDecisionDbW::GetDecisionL(CDecisionFilter& aFilter)
441 Gets a decision record from the decision database. The functions returns the first matched
442 record. All the methods of the filter object except the client entity should be supplied to
443 get the intended decision record. If any other attribute of the filter object is missing,
444 either no decision might be found or a wrong decision may be retrieved
446 @param aFilter A filter object whose client id, policy evaluator id, service id,
447 server id, fingerprint (and client entity) attributes are set.
450 //Define a database table object handle
452 CleanupClosePushL(dbTable);
454 //Open the database table object and prepares it for searching
455 TDbSeekMultiKey<KIndexColumnNumber> seekKey;
456 PrepareForSearchL(dbTable,aFilter,seekKey);
458 //Define the decision record that will be returned
459 CDecisionRecord* retRecord(0);
461 if(dbTable.SeekL(seekKey))
464 CDbColSet* colSet = dbTable.ColSetL();
465 CleanupStack::PushL(colSet);
469 retRecord = CDecisionView::GenerateRecordL(dbTable,colSet);
471 CleanupStack::PopAndDestroy(colSet);
474 CleanupStack::PopAndDestroy(&dbTable);
480 EXPORT_C TBool CDecisionDbW::UpdateDecisionL(CDecisionFilter& aFilter, CDecisionRecord& aNewRecord)
482 //Define a database table object handle
484 CleanupClosePushL(dbTable);
486 //Open the database table object and prepares it for searching
487 TDbSeekMultiKey<KIndexColumnNumber> seekKey;
488 PrepareForSearchL(dbTable,aFilter,seekKey);
490 TBool retValue = ETrue; //return value
492 if(dbTable.SeekL(seekKey))
494 //Get the current row
496 //Prepare it for update
499 UpdateCurrentRowL(dbTable, aNewRecord);
508 CleanupStack::PopAndDestroy(&dbTable);
514 void CDecisionDbW::DoRemoveDecisionL(CDecisionFilter& aFilter)
516 Deletes a set of records from the decision database. This function is called
517 by RemoveDecisionsL in a loop to be able to catch and repair index corruptions.
519 @param aFilter A filter object
522 //Create the SQL statement
524 CreateSqlStatementLC(aFilter, sqlStatement);
527 CleanupClosePushL(dbView);
529 User::LeaveIfError(dbView.Prepare(iDatabase,TDbQuery(sqlStatement),TDbWindow::EUnlimited));
530 User::LeaveIfError(dbView.EvaluateAll());
532 //Begin the delete transaction and lock the database
533 User::LeaveIfError(iDatabase.Begin());
535 while(dbView.NextL())
540 CleanupStack::PopAndDestroy(&dbView);
541 CleanupStack::PopAndDestroy(&sqlStatement);
544 TInt result = iDatabase.Commit();
545 if(KErrNone != result)
547 DEBUG_PRINTF2(_L("Removing a decision has returned with %d. Rollback is now in proggress."),result);
548 iDatabase.Rollback();
553 EXPORT_C void CDecisionDbW::RemoveDecisionsL(CDecisionFilter& aFilter)
555 Deletes a set of records from the decision database. It is possible to delete a specific
556 decision record or a set of records based on a given filter. While this function is in
557 progress, the database is locked not to lead to an inconsistent data retrieving. If there
558 is any index corruption in the decision able, it is tried to be repaired automatically.
560 @param aFilter A filter object
568 TRAP(error,DoRemoveDecisionL(aFilter));
569 if(error == KErrCorrupt)
571 DEBUG_PRINTF2(_L("The database is corrupted and being recovered. Try %d"),loopCount);
572 error = iDatabase.Recover(); //Recover() may fail, so update error
574 }while(error==KErrCorrupt && loopCount<2);
576 User::LeaveIfError(error);
580 EXPORT_C CDecisionDbCompactor *CDecisionDbW::PrepareCompactionLC()
582 Creates a database compaction object to perform asynchronous compaction on the database.
584 @return A pointer to the newly created database compaction object
585 The pointer is also put onto the cleanup stack.
588 DEBUG_PRINTF(_L("The Ups database is being compacted."));
589 CDecisionDbCompactor *compactor = CDecisionDbCompactor::NewLC();
590 User::LeaveIfError(compactor->iDbIncremental.Compact(iDatabase,compactor->iStep()));