sl@0: // Copyright (c) 1998-2009 Nokia Corporation and/or its subsidiary(-ies). sl@0: // All rights reserved. sl@0: // This component and the accompanying materials are made available sl@0: // under the terms of "Eclipse Public License v1.0" sl@0: // which accompanies this distribution, and is available sl@0: // at the URL "http://www.eclipse.org/legal/epl-v10.html". sl@0: // sl@0: // Initial Contributors: sl@0: // Nokia Corporation - initial contribution. sl@0: // sl@0: // Contributors: sl@0: // sl@0: // Description: sl@0: // sl@0: sl@0: #include "US_STD.H" sl@0: sl@0: // Class CDbStoreDatabase::CCompactor sl@0: sl@0: NONSHARABLE_CLASS(CDbStoreDatabase::CCompactor) : public CDbStoreDatabase::CStepper sl@0: { sl@0: public: sl@0: static CCompactor* NewL(CDbDatabase::TUtility aType, CStreamStore& aStore, sl@0: TInt& aReclaim, TInt& aStep); sl@0: ~CCompactor(); sl@0: private: sl@0: inline CCompactor(TInt& aReclaim); sl@0: // from CStepper sl@0: TInt StepL(TInt aStep); sl@0: private: sl@0: RStoreReclaim iReclaimer; sl@0: TInt& iReclaim; sl@0: }; sl@0: sl@0: inline CDbStoreDatabase::CCompactor::CCompactor(TInt& aReclaim) sl@0: :iReclaim(aReclaim) sl@0: { sl@0: } sl@0: sl@0: CDbStoreDatabase::CCompactor* CDbStoreDatabase::CCompactor::NewL(CDbDatabase::TUtility aType, sl@0: CStreamStore& aStore, sl@0: TInt& aReclaim,TInt& aStep) sl@0: { sl@0: CCompactor* self=new(ELeave) CCompactor(aReclaim); sl@0: CleanupStack::PushL(self); sl@0: if (aType==CDbDatabase::ECompact) sl@0: self->iReclaimer.CompactL(aStore,aStep); sl@0: else sl@0: self->iReclaimer.OpenL(aStore,aStep); sl@0: CleanupStack::Pop(); sl@0: return self; sl@0: } sl@0: sl@0: CDbStoreDatabase::CCompactor::~CCompactor() sl@0: { sl@0: iReclaimer.Close(); sl@0: } sl@0: sl@0: // sl@0: // Single step the compactor sl@0: // We cannot deal with the "in use" scenario as we could end up locking out forever sl@0: // that has to be left to clients using the RDbIncremental interface sl@0: // sl@0: TInt CDbStoreDatabase::CCompactor::StepL(TInt aStep) sl@0: { sl@0: iReclaimer.NextL(aStep); sl@0: if (aStep==0) sl@0: { sl@0: iReclaim=iReclaimer.Available(); sl@0: iReclaimer.Close(); sl@0: } sl@0: return aStep; sl@0: } sl@0: sl@0: sl@0: // Class CDbStoreDatabase sl@0: sl@0: EXPORT_C CDbStoreDatabase::CDbStoreDatabase() sl@0: :iReclaim(KErrGeneral) sl@0: { sl@0: } sl@0: sl@0: // sl@0: // Create a StoreDatabase object. This type shares the store sl@0: // sl@0: CDbStoreDatabase* CDbStoreDatabase::NewLC(CStreamStore* aStore) sl@0: { sl@0: __ASSERT(aStore); sl@0: CDbStoreDatabase* self=new(ELeave) CDbStoreDatabase; sl@0: CleanupStack::PushL(self); sl@0: self->iStore=aStore; sl@0: self->iSharedStore=1; sl@0: return self; sl@0: } sl@0: sl@0: sl@0: //SYMBIAN_REMOVE_TRIVIAL_ENCRYPTION version of the method. sl@0: CDbDatabase* CDbStoreDatabase::CreateL(CStreamStore* aStore,TStreamId& aStreamId) sl@0: { sl@0: CDbStoreDatabase* self=NewLC(aStore); sl@0: aStreamId=self->ConstructL(); sl@0: CDbDatabase* db=self->InterfaceL(); sl@0: CleanupStack::Pop(); // self sl@0: return db; sl@0: } sl@0: sl@0: // SYMBIAN_REMOVE_TRIVIAL_ENCRYPTION version of the method. sl@0: // Phase 2 construction for creating a new database sl@0: // Initialise a new database object, creating the required persistent structure sl@0: // sl@0: EXPORT_C TStreamId CDbStoreDatabase::ConstructL() sl@0: { sl@0: __ASSERT(iStore); // this must have been provided by now sl@0: iVersion=TUint8(EDbStoreVersion2); sl@0: InitPagePoolL(); sl@0: iPagePool->Create(Store()); sl@0: iTokenId=Store().ExtendL(); sl@0: ReplaceTokenL(0); sl@0: iSchemaId=Store().ExtendL(); sl@0: Schema().Loaded(); sl@0: ReplaceSchemaL(); sl@0: return iSchemaId; sl@0: } sl@0: sl@0: // SYMBIAN_REMOVE_TRIVIAL_ENCRYPTION version of the method. sl@0: // Open phase #2: Authenticate the client sl@0: // sl@0: EXPORT_C void CDbStoreDatabase::AuthenticateL() sl@0: { sl@0: if (!iPagePool) sl@0: { sl@0: // first client to open the database, so complete initialisation now sl@0: InitPagePoolL(); sl@0: SchemaL(); sl@0: } sl@0: } sl@0: sl@0: // SYMBIAN_REMOVE_TRIVIAL_ENCRYPTION version of the method. sl@0: void CDbStoreDatabase::InitPagePoolL() sl@0: { sl@0: iPagePool = new(ELeave) RStorePagePool; sl@0: } sl@0: sl@0: sl@0: CDbSource* CDbStoreDatabase::OpenL(CStreamStore* aStore,TStreamId aStreamId) sl@0: { sl@0: CDbStoreDatabase* self=NewLC(aStore); sl@0: self->RestoreL(aStreamId); sl@0: CDbSource* src=self->SourceL(); sl@0: CleanupStack::Pop(); // self sl@0: return src; sl@0: } sl@0: sl@0: // sl@0: // Phase 2 construction for opening a database sl@0: // Client must still authenticate before it can be used sl@0: // sl@0: EXPORT_C void CDbStoreDatabase::RestoreL(TStreamId aStreamId) sl@0: { sl@0: __ASSERT(iStore); // this must have been provided by now sl@0: iSchemaId=aStreamId; sl@0: // read the databse header for encryption information sl@0: RStoreReadStream strm; sl@0: strm.OpenLC(Store(),aStreamId); sl@0: ReadHeaderL(strm); sl@0: CleanupStack::PopAndDestroy(); // strm sl@0: } sl@0: sl@0: // sl@0: // Load the root stream header (up to the security key) sl@0: // sl@0: void CDbStoreDatabase::ReadHeaderL(RReadStream& aStream) sl@0: { sl@0: TUid uid; sl@0: aStream>>uid; sl@0: if (uid!=KDbmsStoreDatabase) sl@0: __LEAVE(KErrArgument); sl@0: aStream>>iVersion; sl@0: switch (iVersion) sl@0: { sl@0: case EDbStoreCompressed: sl@0: aStream>>CompressionL(); sl@0: break; sl@0: case EDbStoreVersion2: sl@0: break; sl@0: default: sl@0: __LEAVE(KErrNotSupported); sl@0: break; sl@0: } sl@0: } sl@0: sl@0: CDbStoreCompression& CDbStoreDatabase::CompressionL() sl@0: { sl@0: CDbStoreCompression* c=iCompression; sl@0: if (!c) sl@0: iFilter=iCompression=c=CDbStoreCompression::NewL(); sl@0: return *c; sl@0: } sl@0: sl@0: EXPORT_C CDbStoreDatabase::~CDbStoreDatabase() sl@0: { sl@0: if (iPageCache) sl@0: { sl@0: iPagePool->Release(); sl@0: delete iPageCache; sl@0: } sl@0: delete iClusterCache; sl@0: delete iPagePool; sl@0: delete iCompression; sl@0: if (!iSharedStore) sl@0: delete iStore; sl@0: } sl@0: sl@0: // sl@0: // Validate the column set first sl@0: // sl@0: EXPORT_C CDbTableDef* CDbStoreDatabase::CreateTableL(const TDesC& aName,const CDbColSet& aColSet,const CDbKey* aPrimaryKey) sl@0: { sl@0: if (aPrimaryKey) sl@0: __LEAVE(KErrNotSupported); // Store database does not support primary keys sl@0: CDbStoreDef* def=CDbStoreDef::NewLC(aName,aColSet); sl@0: def->SetTokenId(CDbStoreRecords::CreateL(ClusterCacheL())); sl@0: CleanupStack::Pop(); sl@0: return def; sl@0: } sl@0: sl@0: EXPORT_C CDbTableIndexDef* CDbStoreDatabase::CreateIndexL(const CDbTableDef& aTable,const TDesC& aName,const CDbKey& aKey) sl@0: { sl@0: CDbStoreIndexDef* def=CDbStoreIndexDef::NewLC(aName,aKey,aTable.Columns()); sl@0: def->SetTokenId(CDbStoreIndex::CreateL(*this,*def)); sl@0: CleanupStack::Pop(); // IndexDef sl@0: return def; sl@0: } sl@0: sl@0: // sl@0: // Destroy the entire database... sl@0: // sl@0: EXPORT_C void CDbStoreDatabase::DestroyL() sl@0: { sl@0: iPagePool->Discard(); sl@0: iPagePool->ReclaimAllL(); // reclaim all page pool space sl@0: iStore->DeleteL(iSchemaId); sl@0: iStore->DeleteL(iTokenId); sl@0: iStore->CommitL(); sl@0: } sl@0: sl@0: EXPORT_C CDbTable* CDbStoreDatabase::TableL(const CDbTableDef& aDef) sl@0: { sl@0: return new(ELeave) CDbStoreTable(*this,aDef); sl@0: } sl@0: sl@0: // sl@0: // load the schema for the database sl@0: // sl@0: EXPORT_C void CDbStoreDatabase::LoadSchemaL() sl@0: { sl@0: RDbStoreReadStream strm(*this); sl@0: strm.OpenLC(Store(),iSchemaId); sl@0: ReadHeaderL(strm); sl@0: strm.FilterL(strm.EMixed,iSchemaId.Value()); sl@0: strm>>iTokenId; sl@0: RDbTableSchema& schema=Schema(); sl@0: TCardinality tables; sl@0: strm>>tables; sl@0: for (TInt ii=tables;ii>0;--ii) sl@0: schema.Add(CDbStoreDef::NewL(strm)); sl@0: CleanupStack::PopAndDestroy(); sl@0: strm.OpenLC(Store(),iTokenId); sl@0: strm>>iFlags>>iPoolToken; sl@0: iPagePool->Open(Store(),iPoolToken); sl@0: CleanupStack::PopAndDestroy(); sl@0: } sl@0: sl@0: // sl@0: // Re-write the schema stream sl@0: // sl@0: void CDbStoreDatabase::ReplaceSchemaL() sl@0: { sl@0: RDbStoreWriteStream out(*this); sl@0: out.ReplaceLC(Store(),iSchemaId); sl@0: out< iter(Schema()); sl@0: TInt count=0; sl@0: while (iter++) sl@0: ++count; sl@0: out<Token(); sl@0: out.CommitL(); sl@0: CleanupStack::PopAndDestroy(); sl@0: } sl@0: sl@0: // sl@0: // Return some database property sl@0: // sl@0: EXPORT_C TInt CDbStoreDatabase::Property(CDbDatabase::TProperty aProperty) sl@0: { sl@0: switch (aProperty) sl@0: { sl@0: case CDbDatabase::EIsDamaged: sl@0: return iFlags&EDamaged ? 1 : 0; sl@0: case CDbDatabase::ECompactable: sl@0: return 1; sl@0: default: sl@0: return CDbTableDatabase::Property(aProperty); sl@0: } sl@0: } sl@0: sl@0: // sl@0: // mark the database as dirty sl@0: // sl@0: void CDbStoreDatabase::MarkL() sl@0: { sl@0: if (!(iFlags&EModified)) sl@0: { sl@0: RStoreWriteStream out; sl@0: out.OpenLC(Store(),iTokenId); sl@0: out.WriteUint8L(EDamaged); // mark as dirty sl@0: iPoolToken.Touch(); sl@0: out<Purge(); sl@0: delete iPageCache; sl@0: iPageCache=NULL; sl@0: } sl@0: if (iClusterCache) sl@0: { sl@0: delete iClusterCache; sl@0: iClusterCache=NULL; sl@0: } sl@0: } sl@0: sl@0: // sl@0: // Commit the store, and when all is well, clear the token sl@0: // sl@0: void CDbStoreDatabase::SynchStoreL(TDbLockType aLock) sl@0: { sl@0: if (iPageCache) sl@0: iPagePool->FlushL(); sl@0: TUint newflags=iFlags&~EModified; sl@0: if (aLock==EDbRecoveryLock) sl@0: newflags&=~EDamaged; sl@0: if (aLock==EDbRecoveryLock || iFlags&EModified) sl@0: ReplaceTokenL(newflags); sl@0: if (aLock>=EDbWriteLock || iSharedStore) sl@0: { sl@0: iStore->CommitL(); sl@0: iFlags=TUint8(newflags); sl@0: iPoolToken=iPagePool->Token(); sl@0: } sl@0: } sl@0: sl@0: // sl@0: // An index has been successfully recovered, commit it sl@0: // sl@0: void CDbStoreDatabase::IndexRecoveredL() sl@0: { sl@0: SynchStoreL(EDbSchemaLock); sl@0: } sl@0: sl@0: // sl@0: // Ensure all data is in the store sl@0: // sl@0: EXPORT_C void CDbStoreDatabase::SynchL(TDbLockType aLock) sl@0: { sl@0: if (aLock==EDbSchemaLock) sl@0: ReplaceSchemaL(); sl@0: if (iClusterCache) sl@0: iClusterCache->FlushL(); sl@0: SynchStoreL(aLock); sl@0: } sl@0: sl@0: // sl@0: // Unwind the store, throw out changes, etc sl@0: // sl@0: EXPORT_C void CDbStoreDatabase::Revert(TDbLockType aLock) sl@0: { sl@0: if (aLock>=EDbWriteLock) sl@0: { sl@0: if (iClusterCache) sl@0: iClusterCache->Discard(); sl@0: if (iPageCache) sl@0: iPagePool->Purge(); sl@0: if (iFlags&EModified) sl@0: iFlags|=EDamaged; sl@0: iPagePool->Open(Store(),iPoolToken); // reset the page pool sl@0: } sl@0: else if (!iSharedStore) // don't touch the store if not shared sl@0: return; sl@0: iStore->Revert(); sl@0: } sl@0: sl@0: // sl@0: // Ensure we have a cluster cache and return it sl@0: // sl@0: CClusterCache& CDbStoreDatabase::ClusterCacheL() sl@0: { sl@0: CClusterCache* cache=iClusterCache; sl@0: if (!cache) sl@0: iClusterCache=cache=CClusterCache::NewL(*this); sl@0: return *cache; sl@0: } sl@0: sl@0: // sl@0: // Ensure we have a page cache and return the pool sl@0: // sl@0: MPagePool& CDbStoreDatabase::PagePoolL() sl@0: { sl@0: if (!iPageCache) sl@0: { sl@0: iPageCache=CPageCache::NewL(EPageCachePages); sl@0: iPagePool->Set(*iPageCache); sl@0: } sl@0: return *iPagePool; sl@0: } sl@0: sl@0: // sl@0: // Create an incremental object that compacts the store sl@0: // sl@0: EXPORT_C CDbTableDatabase::CStepper* CDbStoreDatabase::UtilityL(CDbDatabase::TUtility aType,TInt& aStep) sl@0: { sl@0: switch (aType) sl@0: { sl@0: case CDbDatabase::EStats: sl@0: case CDbDatabase::ECompact: sl@0: return CCompactor::NewL(aType,Store(),iReclaim,aStep); sl@0: case CDbDatabase::ERecover: sl@0: return RecoverL(aStep); sl@0: default: sl@0: return CDbTableDatabase::UtilityL(aType,aStep); sl@0: } sl@0: } sl@0: sl@0: // sl@0: // Create an incremental object to destroy a table sl@0: // sl@0: EXPORT_C CDbTableDatabase::CStepper* CDbStoreDatabase::RecordDiscarderL(const CDbTableDef& aTable,TInt& aStep) sl@0: { sl@0: CDbStoreTable::CDiscarder* discarder=new(ELeave) CDbStoreTable::CDiscarder; sl@0: CleanupStack::PushL(discarder); sl@0: aStep=discarder->OpenL((CDbStoreTable*)TableL(aTable)); sl@0: CleanupStack::Pop(); sl@0: return discarder; sl@0: } sl@0: sl@0: // sl@0: // Create an incremental object to destroy an index sl@0: // sl@0: EXPORT_C CDbTableDatabase::CStepper* CDbStoreDatabase::IndexDiscarderL(const CDbTableDef& aTable,const CDbTableIndexDef& anIndex,TInt& aStep) sl@0: { sl@0: CDbStoreIndex::CDiscarder* discarder=new(ELeave) CDbStoreIndex::CDiscarder; sl@0: CleanupStack::PushL(discarder); sl@0: CDbStoreIndex* index=CDbStoreIndex::NewL(*this,(const CDbStoreIndexDef&)anIndex,aTable); sl@0: aStep=discarder->Open(index); sl@0: index->OpenL(); sl@0: CleanupStack::Pop(); sl@0: return discarder; sl@0: } sl@0: sl@0: // sl@0: // Provide a stepper to alter the table data sl@0: // if no data to alter, return 0 sl@0: // sl@0: EXPORT_C CDbTableDatabase::CStepper* CDbStoreDatabase::TableAlterL(CDbTableDef& aTable,const HDbColumnSet& aNewSet,TInt& aStep) sl@0: { sl@0: CDbStoreDef& def=STATIC_CAST(CDbStoreDef&,aTable); sl@0: // sl@0: aStep=CDbStoreRecords::CardinalityL(Store(),def); sl@0: if (!aStep) sl@0: return NULL; // no data to modify sl@0: sl@0: // check that all added columns are nullable sl@0: HDbColumnSet::TIteratorC col=aNewSet.Begin(); sl@0: HDbColumnSet::TIteratorC end=aNewSet.End(); sl@0: do sl@0: { sl@0: if (col->iFlags&TDbColumnDef::EAdded && col->iAttributes&TDbCol::ENotNull) sl@0: __LEAVE(KErrArgument); // added column is not nullable sl@0: } while (++coliFlags&(TDbColumnDef::EDropped|TDbColumnDef::EChangedType|TDbColumnDef::EChangedLen))) sl@0: { sl@0: if (++col==end) sl@0: { // no changes which affect layout, so no work required sl@0: aStep=0; sl@0: return NULL; sl@0: } sl@0: } sl@0: // work required sl@0: CDbStoreTable::CAlter* alter=new(ELeave) CDbStoreTable::CAlter; sl@0: CleanupStack::PushL(alter); sl@0: alter->OpenL((CDbStoreTable*)TableL(def),aNewSet); sl@0: CleanupStack::Pop(); sl@0: return alter; sl@0: } sl@0: sl@0: EXPORT_C void CDbStoreDatabase::Reserved_1() sl@0: { sl@0: } sl@0: sl@0: EXPORT_C void CDbStoreDatabase::Reserved_2() sl@0: { sl@0: } sl@0: