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: #include "U32STD_DBMS.H" sl@0: #include sl@0: sl@0: // class TRecordSize sl@0: sl@0: TUint8 const TRecordSize::FieldSizes[]= sl@0: { sl@0: 0, // EDbColBit sl@0: sizeof(TInt8), // EDbColInt8 sl@0: sizeof(TUint8), // EDbColUint8 sl@0: sizeof(TInt16), // EDbColInt16 sl@0: sizeof(TUint16), // EDbColUint16 sl@0: sizeof(TInt32), // EDbColInt32 sl@0: sizeof(TUint32), // EDbColUint32 sl@0: sizeof(TInt64), // EDbColInt64 sl@0: sizeof(TReal32), // EDbColReal32 sl@0: sizeof(TReal64), // EDbColReal64 sl@0: sizeof(TTime) // EDbColDateTime sl@0: }; sl@0: sl@0: TBool TRecordSize::Set(const HDbColumnSet& aColumns) sl@0: // sl@0: // Calculate stats for the record size and shape from the definition sl@0: // sl@0: { sl@0: TInt fix=0,null=0,var=0,blob=0; sl@0: HDbColumnSet::TIteratorC const end=aColumns.End(); sl@0: HDbColumnSet::TIteratorC col=aColumns.Begin(); sl@0: do sl@0: { sl@0: TBool notnull=col->iAttributes&TDbCol::ENotNull; sl@0: if (notnull==0) sl@0: ++fix; sl@0: TDbColType type=col->Type(); sl@0: __ASSERT(type>=EDbColBit&&type<=EDbColLongBinary); sl@0: if (type==EDbColBit) sl@0: ++fix; sl@0: else if (type<=EDbColDateTime) sl@0: { sl@0: TInt bits=FixedFieldSize(type)<<3; sl@0: if (notnull) sl@0: fix+=bits; sl@0: else sl@0: null+=bits; sl@0: } sl@0: else if (type<=EDbColBinary) sl@0: { sl@0: TInt size=col->iMaxLength; sl@0: if (type==EDbColText16) sl@0: size<<=1; sl@0: var+=8+(size<<3); sl@0: } sl@0: else sl@0: ++blob; sl@0: } while(++col>3; sl@0: if (max>KDbStoreMaxRecordLength) sl@0: return ETrue; sl@0: // sl@0: // Assuming a Maximally full record, how much excess space is available for Blobs? sl@0: // sl@0: iInlineLimit=KDbMaxInlineBlobSize; sl@0: if (blob) sl@0: { // use the spare space for extra inlining sl@0: TInt spare=(KDbStoreMaxRecordLength-max); sl@0: TInt inl=spare/blob+KMinInlineLimit-1; sl@0: if (inl>1)+(var>>4)+blob*(1+(16<<3))+7)>>3; sl@0: TInt clustering=KClusterLimit/average; sl@0: if (clustering==0) sl@0: clustering=1; sl@0: else if (clustering>KMaxClustering) sl@0: clustering=KMaxClustering; sl@0: iClustering=clustering; sl@0: return EFalse; sl@0: } sl@0: sl@0: void TRecordSize::CheckSizeL(const HDbColumnSet& aColumns) sl@0: // sl@0: // Check that the columns definition is a valid size sl@0: // sl@0: { sl@0: TRecordSize size; sl@0: if (size.Set(aColumns)) sl@0: __LEAVE(KErrTooBig); sl@0: } sl@0: sl@0: TInt TRecordSize::InlineLimit(const HDbColumnSet& aColumns) sl@0: // sl@0: // Evaluate the inline limit for the column set. It is assumed to be valid sl@0: // sl@0: { sl@0: TRecordSize size; sl@0: __DEBUG(TBool chk =)size.Set(aColumns); sl@0: __ASSERT(!chk); sl@0: return size.InlineLimit(); sl@0: } sl@0: sl@0: // Streaming column definitions sl@0: sl@0: LOCAL_C void ExternalizeL(const TDbColumnDef& aCol,RWriteStream& aStream) sl@0: { sl@0: aStream<<*aCol.iName; sl@0: aStream.WriteUint8L(aCol.iType); sl@0: aStream.WriteUint8L(aCol.iAttributes); sl@0: switch (aCol.iType) sl@0: { sl@0: case EDbColBinary: sl@0: case EDbColText8: sl@0: case EDbColText16: sl@0: aStream.WriteUint8L(aCol.iMaxLength); sl@0: break; sl@0: default: sl@0: break; sl@0: } sl@0: } sl@0: sl@0: LOCAL_C void InternalizeL(TDbColumnDef& aCol,RReadStream& aStream) sl@0: { sl@0: aCol.iName=HBufC::NewL(aStream,KDbMaxColName); sl@0: TDbColType type=TDbColType(aStream.ReadUint8L()); sl@0: aCol.iType=TUint8(type); sl@0: aCol.iAttributes=aStream.ReadUint8L(); sl@0: if (type>EDbColLongBinary || (aCol.iAttributes&~(TDbCol::ENotNull|TDbCol::EAutoIncrement))!=0) sl@0: __LEAVE(KErrCorrupt); sl@0: if (type>=EDbColText8 && type<=EDbColBinary) sl@0: { sl@0: aCol.iMaxLength=aStream.ReadUint8L(); sl@0: if (aCol.iMaxLength==0) sl@0: __LEAVE(KErrCorrupt); sl@0: } sl@0: else sl@0: aCol.iMaxLength=KDbUndefinedLength; sl@0: } sl@0: sl@0: inline RWriteStream& operator<<(RWriteStream& aStream,const TDbColumnDef& aCol) sl@0: {ExternalizeL(aCol,aStream);return aStream;} sl@0: inline RReadStream& operator>>(RReadStream& aStream,TDbColumnDef& aCol) sl@0: {InternalizeL(aCol,aStream);return aStream;} sl@0: sl@0: // Streaming key columns sl@0: sl@0: LOCAL_C void ExternalizeL(const TDbKeyCol& aKeyCol,RWriteStream& aStream) sl@0: { sl@0: aStream<>des; sl@0: TUint len=aStream.ReadUint8L(); sl@0: aKeyCol.iLength=len!=0 ? TInt(len) : KDbUndefinedLength; sl@0: aKeyCol.iOrder=TDbKeyCol::TOrder(aStream.ReadUint8L()); sl@0: if (aKeyCol.iOrder>TDbKeyCol::EDesc) sl@0: __LEAVE(KErrCorrupt); sl@0: } sl@0: sl@0: inline RWriteStream& operator<<(RWriteStream& aStream,const TDbKeyCol& aCol) sl@0: {ExternalizeL(aCol,aStream);return aStream;} sl@0: inline RReadStream& operator>>(RReadStream& aStream,TDbKeyCol& aCol) sl@0: {InternalizeL(aCol,aStream);return aStream;} sl@0: sl@0: sl@0: // Class CDbStoreIndexDef sl@0: sl@0: CDbStoreIndexDef::CDbStoreIndexDef() sl@0: {} sl@0: sl@0: CDbStoreIndexDef* CDbStoreIndexDef::NewLC(const TDesC& aName) sl@0: { sl@0: CDbStoreIndexDef* self=new(ELeave) CDbStoreIndexDef; sl@0: CleanupStack::PushL(self); sl@0: self->ConstructL(aName); sl@0: return self; sl@0: } sl@0: sl@0: CDbStoreIndexDef* CDbStoreIndexDef::NewLC(const TDesC& aName,const CDbKey& aKey,const HDbColumnSet& aColumns) sl@0: { sl@0: CDbStoreIndexDef* self=NewLC(aName); sl@0: CDbKey& key=self->Key(); sl@0: TInt max=aKey.Count(); sl@0: for (TInt ii=0;ii>name; sl@0: CDbStoreIndexDef* self=NewLC(name); sl@0: CDbKey& key=self->Key(); sl@0: TDbTextComparison comp=TDbTextComparison(aStream.ReadUint8L()); sl@0: if (comp>EDbCompareCollated) sl@0: __LEAVE(KErrCorrupt); sl@0: key.SetComparison(comp); sl@0: if (aStream.ReadUint8L()) sl@0: key.MakeUnique(); sl@0: TCardinality count; sl@0: aStream>>count; sl@0: for (TInt ii=count;ii>0;--ii) sl@0: { sl@0: TDbKeyCol keycol; sl@0: aStream>>keycol; sl@0: key.AddL(keycol); sl@0: } sl@0: aStream>>self->iTokenId; sl@0: CleanupStack::Pop(); sl@0: return self; sl@0: } sl@0: sl@0: void CDbStoreIndexDef::ExternalizeL(RWriteStream& aStream) const sl@0: { sl@0: aStream<=0;) sl@0: { sl@0: const TDbKeyCol& keyCol=aKey[ii]; sl@0: len+=Align4(KeySize(keyCol,*aColSet.ColumnL(keyCol.iName))); sl@0: } sl@0: if (len>KMaxIndexKeySize) sl@0: __LEAVE(KErrTooBig); sl@0: } sl@0: sl@0: sl@0: // Class CDbStoreDef sl@0: sl@0: LOCAL_C void SetColumnL(TDbColumnDef& aDef,const TDbCol& aCol,TUint aFlag=0) sl@0: { sl@0: aDef.SetL(aCol); sl@0: if (aDef.iAttributes&TDbCol::EAutoIncrement) sl@0: aDef.iAttributes|=TDbCol::ENotNull; // auto-increment => not-null sl@0: aDef.iFlags=TUint8(aFlag); sl@0: TDbColType type=aCol.iType; sl@0: if (type>=EDbColText8 && type<=EDbColBinary) sl@0: { sl@0: if (aCol.iMaxLength==KDbUndefinedLength) sl@0: aDef.iMaxLength=KDbStoreMaxColumnLength; sl@0: else if (aCol.iMaxLength>KDbStoreMaxColumnLength) sl@0: __LEAVE(KErrNotSupported); sl@0: } sl@0: else sl@0: aDef.iMaxLength=KDbUndefinedLength; sl@0: } sl@0: sl@0: LOCAL_C HDbColumnSet::TIterator CheckColumnsL(HDbColumnSet::TIterator anIter,const CDbColSet& aColSet,TInt aNotNull,TUint aFlag=0) sl@0: // sl@0: // Check the columns from aColset into anIter, according to ENotNull attribute sl@0: // Validate as we go sl@0: // sl@0: { sl@0: for (TDbColSetIter iter(aColSet);iter;++iter) sl@0: { sl@0: TInt att=iter->iAttributes; sl@0: if (att&TDbCol::EAutoIncrement) sl@0: att|=TDbCol::ENotNull; // auto-increment => not-null sl@0: if ((att&TDbCol::ENotNull)==aNotNull) sl@0: { sl@0: SetColumnL(*anIter,*iter,aFlag); sl@0: ++anIter; sl@0: } sl@0: } sl@0: return anIter; sl@0: } sl@0: sl@0: CDbStoreDef::CDbStoreDef() sl@0: {} sl@0: sl@0: CDbStoreDef* CDbStoreDef::NewLC(const TDesC& aName,TInt aColumnCount) sl@0: { sl@0: CDbStoreDef* self=new(ELeave) CDbStoreDef; sl@0: CleanupStack::PushL(self); sl@0: self->ConstructL(aName,aColumnCount); sl@0: return self; sl@0: } sl@0: sl@0: CDbStoreDef* CDbStoreDef::NewLC(const TDesC& aName,const CDbColSet& aColSet) sl@0: // sl@0: // Construct a table definition from the column set supplied sl@0: // sl@0: { sl@0: CDbStoreDef* self=NewLC(aName,aColSet.Count()); sl@0: HDbColumnSet& columns=self->Columns(); sl@0: HDbColumnSet::TIterator def=CheckColumnsL(columns.Begin(),aColSet,TDbCol::ENotNull); sl@0: def=CheckColumnsL(def,aColSet,0); sl@0: __ASSERT(def==columns.End()); sl@0: TRecordSize::CheckSizeL(columns); sl@0: self->Changed(); sl@0: return self; sl@0: } sl@0: sl@0: CDbStoreDef* CDbStoreDef::NewL(RReadStream& aStream) sl@0: // sl@0: // Construct a table definition from persistent storage sl@0: // sl@0: { sl@0: TDbName name; sl@0: aStream>>name; sl@0: TCardinality count; sl@0: aStream>>count; sl@0: CDbStoreDef* self=NewLC(name,count); sl@0: HDbColumnSet& columns=self->Columns(); sl@0: HDbColumnSet::TIterator iter=columns.Begin(); sl@0: const HDbColumnSet::TIteratorC end=columns.End(); sl@0: do sl@0: { sl@0: aStream>>*iter; sl@0: } while (++iter>count; sl@0: TInt cluster=count; sl@0: if (cluster==0 || cluster>KMaxClustering) sl@0: __LEAVE(KErrCorrupt); sl@0: aStream>>self->iTokenId; sl@0: RDbIndexes& indexes=self->Indexes(); sl@0: aStream>>count; sl@0: for (TInt ii=count;ii>0;--ii) sl@0: indexes.Add(CDbStoreIndexDef::NewL(aStream)); sl@0: self->Changed(); sl@0: CleanupStack::Pop(); sl@0: return self; sl@0: } sl@0: sl@0: void CDbStoreDef::Changed() sl@0: // sl@0: // The definition has changed, following creation or alteration of the table sl@0: // Recalculate cached data for the definition. sl@0: // sl@0: { sl@0: CDbTableDef::Changed(); sl@0: __DEBUG(TBool dbg =)iInfo.Set(Columns()); sl@0: __ASSERT(!dbg); sl@0: } sl@0: sl@0: void CDbStoreDef::ExternalizeL(RWriteStream& aStream) const sl@0: { sl@0: aStream< ixIter(Indexes().AsQue()); sl@0: for (const CDbStoreIndexDef* def;(def=ixIter++)!=0;) sl@0: aStream<<*def; sl@0: } sl@0: sl@0: void CDbStoreDef::AlteredColumnSetL(HDbColumnSet& aSet,const CDbColSet& aChange,const CDbColSet& aAdd) sl@0: // sl@0: // Generate an altered column set sl@0: // We can hijack the non-user attribs of the column sets for marking changes sl@0: // sl@0: { sl@0: // add not-null columns to the front sl@0: HDbColumnSet::TIterator newCol=CheckColumnsL(aSet.Begin(),aAdd,TDbCol::ENotNull,TDbColumnDef::EAdded); sl@0: // copy current set, minus deleted ones, apply text column length changes sl@0: TDbColSetIter change(aChange); sl@0: HDbColumnSet::TIterator col=Columns().Begin(); sl@0: HDbColumnSet::TIteratorC const end=Columns().End(); sl@0: do sl@0: { sl@0: TUint flag=col->iFlags; sl@0: if (flag&TDbColumnDef::EDropped) sl@0: continue; sl@0: if (flag&(TDbColumnDef::EChangedType|TDbColumnDef::EChangedLen)) sl@0: { sl@0: // check allowed changes sl@0: SetColumnL(*newCol,*change); sl@0: ++change; sl@0: if (flag&TDbColumnDef::EChangedType) sl@0: { // validate type changes (only text->longtext etc) sl@0: if (!TDbCol::IsLong(newCol->Type()) || newCol->iType-col->iType!=3) sl@0: __LEAVE(KErrNotSupported); sl@0: } sl@0: else sl@0: { sl@0: col->iFlags=TUint8(flag&~TDbColumnDef::EChangedLen); // no real changes req'd sl@0: if (newCol->iMaxLengthiMaxLength) sl@0: __LEAVE(KErrNotSupported); // can only extend columns sl@0: } sl@0: } sl@0: else sl@0: newCol->SetL(*col); sl@0: ++newCol; sl@0: } while (++col