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: //#define __READBIT_CLASS sl@0: //#define __WRITEBIT_CLASS sl@0: sl@0: #ifdef __READBIT_CLASS sl@0: class TReadBitSequence sl@0: { sl@0: public: sl@0: inline TReadBitSequence(); sl@0: inline TBool HasBits() const; sl@0: TUint Read(const TUint8*& aPtr); sl@0: private: sl@0: TUint iBits; sl@0: }; sl@0: inline TReadBitSequence::TReadBitSequence() sl@0: :iBits(0) {} sl@0: inline TBool TReadBitSequence::HasBits() const sl@0: {return (iBits&0x2000000);} sl@0: TUint TReadBitSequence::Read(const TUint8*& aPtr) sl@0: { sl@0: iBits>>=1; sl@0: if ((iBits&0x1000000)==0) sl@0: iBits=*aPtr++ | 0xff000000u; sl@0: return iBits&1; sl@0: } sl@0: #define READBITINIT(This) TReadBitSequence This sl@0: #define READHASBITS(This) This.HasBits() sl@0: #define READBIT(This,ptr) This.Read(ptr) sl@0: #define SKIPBIT(This,ptr) READBIT(This,ptr) sl@0: #else sl@0: #define READBITINIT(This) TUint This##_bits=0 sl@0: #define READHASBITS(This) (This##_bits&0x2000000) sl@0: #define SKIPBIT(This,ptr) (This##_bits>>=1,(This##_bits&0x1000000 ? void(0) : void(This##_bits=*ptr++|0xff000000u))) sl@0: #define READBIT(This,ptr) (SKIPBIT(This,ptr),This##_bits&1) sl@0: #endif sl@0: sl@0: #ifdef __WRITEBIT_CLASS sl@0: class TWriteBitSequence sl@0: { sl@0: public: sl@0: inline TWriteBitSequence(); sl@0: TUint8* Write(TUint8* aPtr,TUint aBit); sl@0: void Flush(); sl@0: private: sl@0: TUint iBits; sl@0: TUint8* iPtr; sl@0: }; sl@0: inline TWriteBitSequence::TWriteBitSequence() sl@0: :iBits(0),iPtr(0) {} sl@0: TUint8* TWriteBitSequence::Write(TUint8* aPtr,TUint aBit) sl@0: { sl@0: TUint bits=iBits>>1; sl@0: if ((bits&0x1000000)==0) sl@0: { sl@0: if (iPtr) sl@0: *iPtr=TUint8(bits); sl@0: iPtr=aPtr++; sl@0: bits=0xff000000; sl@0: } sl@0: if (aBit) sl@0: bits|=0x100; sl@0: iBits=bits; sl@0: return aPtr; sl@0: } sl@0: void TWriteBitSequence::Flush() sl@0: { sl@0: TUint8* ptr=iPtr; sl@0: if (ptr) sl@0: { sl@0: TUint bits=iBits; sl@0: do bits>>=1; while (bits&0x1000000); sl@0: *ptr=TUint8(bits); sl@0: } sl@0: } sl@0: #define WRITEBITINIT(This) TWriteBitSequence This sl@0: #define WRITEBIT(This,ptr,bit) ptr=This.Write(ptr,bit) sl@0: #define WRITEZEROBIT(This,ptr) ptr=This.Write(ptr,0) sl@0: #define FLUSHBITS(This) This.Flush() sl@0: #else sl@0: #define WRITEBITINIT(This) TUint32 This##_bits=0; TUint8* This##_ptr=0 sl@0: #define NEXTBIT(This,ptr) This##_bits>>=1;if ((This##_bits&0x1000000)==0){if (This##_ptr) *This##_ptr=TUint8(This##_bits);This##_ptr=ptr++;This##_bits=0xff000000;} sl@0: #define WRITEZEROBIT(This,ptr) {NEXTBIT(This,ptr)} sl@0: #define WRITEBIT(This,ptr,bit) {NEXTBIT(This,ptr) if (bit) This##_bits|=0x100;} sl@0: #define FLUSHBITS(This) {if (This##_ptr){do This##_bits>>=1; while (This##_bits&0x1000000);*This##_ptr=TUint8(This##_bits);}} sl@0: #endif sl@0: sl@0: LOCAL_C const TUint8* Read32(const TUint8* aPtr,TUint32* aDest) sl@0: // fast read for non-aligned little-endian 32-bit data sl@0: { sl@0: TUint32 x=*aPtr++; sl@0: x|=*aPtr++<<8; sl@0: x|=*aPtr++<<16; sl@0: x|=*aPtr++<<24; sl@0: *aDest=x; sl@0: return aPtr; sl@0: } sl@0: sl@0: LOCAL_C TUint8* Write32(TUint8* aPtr,TUint32 aVal) sl@0: // fast transfer for non-aligned little-endian 32-bit data sl@0: { sl@0: *aPtr++=TUint8(aVal); sl@0: *aPtr++=TUint8(aVal>>8); sl@0: *aPtr++=TUint8(aVal>>16); sl@0: *aPtr++=TUint8(aVal>>24); sl@0: return aPtr; sl@0: } sl@0: sl@0: inline const TUint8* Read16(const TUint8* aPtr,TUint32* aDest) sl@0: // Read unsigned 16-bit value into aDest storage sl@0: { sl@0: TUint x=*aPtr++; sl@0: x|=*aPtr++<<8; sl@0: *aDest=TUint16(x); sl@0: return aPtr; sl@0: } sl@0: sl@0: inline const TUint8* Read16s(const TUint8* aPtr,TUint32* aDest) sl@0: // Read signed 16-bit value into aDest storage sl@0: { sl@0: TInt x=*aPtr++<<16; sl@0: x|=*aPtr++<<24; sl@0: *aDest=x>>16; sl@0: return aPtr; sl@0: } sl@0: sl@0: inline TUint8* Write16(TUint8* aPtr,TUint aVal) sl@0: // Write little-endian rep of the low 16 bits of aVal sl@0: { sl@0: *aPtr++=TUint8(aVal); sl@0: *aPtr++=TUint8(aVal>>8); sl@0: return aPtr; sl@0: } sl@0: sl@0: LOCAL_C TUint8* WriteCardinality(TUint8* aPtr,TUint aVal) sl@0: // compress cardinality into the data stream sl@0: { sl@0: __ASSERT(aVal<(1u<<30)); sl@0: if ((aVal>>7)==0) sl@0: { sl@0: *aPtr++=TUint8(aVal<<1); sl@0: return aPtr; sl@0: } sl@0: aVal=(aVal<<2)|1; sl@0: if ((aVal>>16)==0) sl@0: { sl@0: *aPtr++=TUint8(aVal); sl@0: *aPtr++=TUint8(aVal>>8); sl@0: return aPtr; sl@0: } sl@0: return Write32(aPtr,aVal|2); sl@0: } sl@0: sl@0: LOCAL_C TUint ReadCardinality(const TUint8* aPtr) sl@0: // extract cardinality from the data stream sl@0: { sl@0: TUint x=aPtr[0]; sl@0: if ((x&1)==0) sl@0: return x>>1; sl@0: x|=aPtr[1]<<8; sl@0: if (x&2) sl@0: { sl@0: x|=aPtr[2]<<16; sl@0: x|=aPtr[3]<<24; sl@0: } sl@0: return x>>2; sl@0: } sl@0: sl@0: LOCAL_C const TUint8* ReadCardinality(const TUint8* aPtr,TInt& aVal) sl@0: // extract cardinality from the data stream sl@0: { sl@0: TUint x=*aPtr++; sl@0: if ((x&1)==0) sl@0: x>>=1; sl@0: else sl@0: { sl@0: x|=*aPtr++<<8; sl@0: if (x&2) sl@0: { sl@0: x|=*aPtr++<<16; sl@0: x|=*aPtr++<<24; sl@0: } sl@0: x>>=2; sl@0: } sl@0: aVal=x; sl@0: return aPtr; sl@0: } sl@0: sl@0: LOCAL_C TInt SizeOfCardinality(TUint aVal) sl@0: // report the externalized size of the Compressed value in bytes sl@0: { sl@0: if ((aVal>>7)==0) sl@0: return 1; sl@0: return (aVal>>14)==0 ? 2 : 4; sl@0: } sl@0: sl@0: LOCAL_C TUint8* WriteBlobId(TUint8* aPtr,TDbBlobId aId) sl@0: { sl@0: return WriteCardinality(aPtr,(aId>>24)|(aId<<8>>4)); sl@0: } sl@0: sl@0: LOCAL_C const TUint8* ReadBlobId(const TUint8* aPtr,TDbBlobId& aId) sl@0: { sl@0: aPtr=ReadCardinality(aPtr,*reinterpret_cast(&aId)); sl@0: aId=(aId>>4)|(aId<<28>>4); sl@0: return aPtr; sl@0: } sl@0: sl@0: LOCAL_C TInt SizeOfBlobId(TDbBlobId aId) sl@0: { sl@0: return SizeOfCardinality((aId>>24)|(aId<<8>>4)); sl@0: } sl@0: sl@0: // Class CDbStoreTable sl@0: sl@0: CDbStoreTable::CDbStoreTable(CDbStoreDatabase& aDatabase,const CDbTableDef& aDef) sl@0: : CDbTable(aDatabase,aDef) sl@0: {} sl@0: sl@0: CDbRecordSpace* CDbStoreTable::RecordSpaceL() sl@0: // sl@0: // open records handler sl@0: // sl@0: { sl@0: return CDbStoreRecords::NewL(Database().ClusterCacheL(),Def()); sl@0: } sl@0: sl@0: CDbBlobSpace* CDbStoreTable::BlobSpaceL() sl@0: // sl@0: // Open a blobs accessor for the table sl@0: // sl@0: { sl@0: return new(ELeave) CDbStoreBlobs(Database(),Def().InlineLimit()); sl@0: } sl@0: sl@0: CDbRecordIndex* CDbStoreTable::RecordIndexL(const CDbTableIndexDef& anIndex) sl@0: // sl@0: // Open an index sl@0: // sl@0: { sl@0: return CDbStoreIndex::NewL(Database(),(const CDbStoreIndexDef&)anIndex,Def()); sl@0: } sl@0: sl@0: static TUint8* CompressUnicode(TUint8* aRec,const TAny* aData,TInt aSize) sl@0: // sl@0: // initially assume the compressed data requires 1 byte for the length data sl@0: // Copy it if more is necessary. This avoids having to run the compressor twice sl@0: // sl@0: { sl@0: TMemoryUnicodeSource source(reinterpret_cast(aData)); sl@0: TUnicodeCompressor compressor; sl@0: TInt output; sl@0: compressor.CompressL(aRec+1,source,KMaxTInt,aSize>>1,&output); sl@0: TInt lenSize=SizeOfCardinality(output); sl@0: if (lenSize!=1) sl@0: Mem::Copy(aRec+lenSize,aRec+1,output); // needs more space for length sl@0: return WriteCardinality(aRec,output)+output; sl@0: } sl@0: sl@0: static TInt SizeOfCompressedUnicode(const TAny* aData,TInt aSize) sl@0: // sl@0: // bytes required to store the unicode data sl@0: // sl@0: { sl@0: TMemoryUnicodeSource source(reinterpret_cast(aData)); sl@0: TInt size=TUnicodeCompressor::CompressedSizeL(source,aSize>>1); sl@0: return SizeOfCardinality(size)+size; sl@0: } sl@0: sl@0: static const TUint8* ExpandUnicodeL(const TUint8* aRec,TAny* aTarget,const TAny* aLimit,TInt& aChars) sl@0: // sl@0: // Read compressed unicode from the record sl@0: // sl@0: { sl@0: TInt bytes; sl@0: aRec=ReadCardinality(aRec,bytes); sl@0: TMemoryUnicodeSink unicode(reinterpret_cast(aTarget)); sl@0: TUnicodeExpander expander; sl@0: TInt used; sl@0: expander.ExpandL(unicode,aRec,(TUint16*)aLimit-(TUint16*)aTarget,bytes,&aChars,&used); sl@0: return bytes==used ? aRec+bytes : 0; // signal corruption in data, could not fit text in space sl@0: } sl@0: sl@0: static TInt SizeOfExpandedUnicodeL(const TUint8* aData,TInt aSize) sl@0: // sl@0: // bytes required to store the unicode data sl@0: // sl@0: { sl@0: return TUnicodeExpander::ExpandedSizeL(aData,aSize)<<1; sl@0: } sl@0: sl@0: TInt CDbStoreTable::RecordLength(const RDbRow& aRow) sl@0: // sl@0: // Calculate the size of a record sl@0: // sl@0: { sl@0: TInt bits=SizeOfCardinality(OptimizedRowLength(aRow))<<3; // record buffer size sl@0: HDbColumnSet::TIteratorC col=Def().Columns().Begin(); sl@0: const TDbCell* const last=aRow.Last(); sl@0: for (const TDbCell* column=aRow.First();columnNext()) sl@0: { sl@0: __ASSERT(colLength(); sl@0: if ((col->iAttributes&TDbCol::ENotNull)==0) sl@0: { //nullable sl@0: ++bits; sl@0: if (size==0) sl@0: continue; // no data sl@0: } sl@0: __ASSERT(size>0); // must be non-null to reach here sl@0: TDbColType type=col->Type(); sl@0: __ASSERT(type>=EDbColBit&&type<=EDbColLongBinary); sl@0: if (type==EDbColBit) sl@0: ++bits; sl@0: else if (type<=EDbColDateTime) sl@0: bits+=TRecordSize::FixedFieldSize(type)<<3; sl@0: else if (type==EDbColText16) sl@0: bits+=SizeOfCompressedUnicode(column->Data(),size)<<3; sl@0: else if (type<=EDbColBinary) sl@0: bits+=8+(size<<3); sl@0: else sl@0: { sl@0: __ASSERT(type<=EDbColLongBinary); sl@0: const TDbBlob& blob=*(const TDbBlob*)column->Data(); sl@0: if (!blob.IsInline()) sl@0: bits+=1+((SizeOfBlobId(blob.Id())+SizeOfCardinality(blob.Size()))<<3); sl@0: else if (type!=EDbColLongText16) sl@0: bits+=9+(blob.Size()<<3); sl@0: else sl@0: bits+=1+(SizeOfCompressedUnicode(blob.Data(),blob.Size())<<3); sl@0: } sl@0: } sl@0: __ASSERT(bits<=(KDbStoreMaxRecordLength<<3)); sl@0: return (bits+7)>>3; sl@0: } sl@0: sl@0: TInt CDbStoreTable::OptimizedRowLength(const RDbRow& aRow) sl@0: // sl@0: // Calculate the minimal row buffer size (in words) to store the row data sl@0: // sl@0: { sl@0: HDbColumnSet::TIteratorC col=Def().Columns().Begin(); sl@0: const TDbCell* const last=aRow.Last(); sl@0: TInt cellHead=0; sl@0: TInt words=0; sl@0: for (const TDbCell* column=aRow.First();columnNext()) sl@0: { sl@0: ++cellHead; sl@0: __ASSERT(colLength(); sl@0: if (size==0) sl@0: continue; sl@0: words+=cellHead; sl@0: cellHead=0; sl@0: TDbColType type=col->Type(); sl@0: __ASSERT(type>=EDbColBit&&type<=EDbColLongBinary); sl@0: if (type<=EDbColDateTime) sl@0: __ASSERT(size==(size>>2<<2)); sl@0: else if (type<=EDbColBinary) sl@0: ; sl@0: else sl@0: size=((const TDbBlob*)column->Data())->CellSize(); sl@0: words+=(size+3)>>2; sl@0: } sl@0: return words; sl@0: } sl@0: sl@0: void CDbStoreTable::CopyFromRow(TUint8* aRecord,const RDbRow& aRow) sl@0: // sl@0: // translate the row buffer into its persistent format in the record buffer sl@0: // sl@0: { sl@0: aRecord=WriteCardinality(aRecord,OptimizedRowLength(aRow)); // internal size sl@0: // sl@0: WRITEBITINIT(bits); sl@0: HDbColumnSet::TIteratorC iter=Def().Columns().Begin(); sl@0: const TDbCell* const last=aRow.Last(); sl@0: for (const TDbCell* column=aRow.First();columnNext()) sl@0: { sl@0: __ASSERT(iterLength(); sl@0: if ((iter->iAttributes&TDbCol::ENotNull)==0) sl@0: { // nullable sl@0: WRITEBIT(bits,aRecord,size!=0); sl@0: if (size==0) sl@0: continue; // no data sl@0: } sl@0: __ASSERT(size>0); // must be non-null to reach here sl@0: const TUint32* data=(const TUint32*)column->Data(); sl@0: TDbColType type=iter->Type(); sl@0: switch (type) sl@0: { sl@0: default: sl@0: __ASSERT(0); sl@0: case EDbColBit: sl@0: WRITEBIT(bits,aRecord,*data); sl@0: break; sl@0: case EDbColInt8: sl@0: case EDbColUint8: sl@0: *aRecord++=TUint8(*data); sl@0: break; sl@0: case EDbColInt16: sl@0: case EDbColUint16: sl@0: aRecord=Write16(aRecord,*data); sl@0: break; sl@0: #if defined(__DOUBLE_WORDS_SWAPPED__) sl@0: case EDbColReal64: sl@0: aRecord=Write32(aRecord,data[1]); // write low word out first sl@0: // drop through to write high word next sl@0: #endif sl@0: case EDbColInt32: sl@0: case EDbColUint32: sl@0: case EDbColReal32: sl@0: aRecord=Write32(aRecord,*data); sl@0: break; sl@0: #if !defined(__DOUBLE_WORDS_SWAPPED__) sl@0: case EDbColReal64: sl@0: #endif sl@0: case EDbColInt64: sl@0: case EDbColDateTime: sl@0: aRecord=Write32(aRecord,data[0]); sl@0: aRecord=Write32(aRecord,data[1]); sl@0: break; sl@0: case EDbColText16: sl@0: aRecord=CompressUnicode(aRecord,data,size); sl@0: break; sl@0: case EDbColText8: sl@0: case EDbColBinary: sl@0: *aRecord++=TUint8(size); sl@0: aRecord=Mem::Copy(aRecord,data,size); sl@0: break; sl@0: case EDbColLongText8: sl@0: case EDbColLongText16: sl@0: case EDbColLongBinary: sl@0: { sl@0: const TDbBlob& blob=*reinterpret_cast(data); sl@0: size=blob.Size(); sl@0: WRITEBIT(bits,aRecord,blob.IsInline()); sl@0: if (blob.IsInline()) sl@0: { sl@0: if (type==EDbColLongText16) sl@0: aRecord=CompressUnicode(aRecord,blob.Data(),size); sl@0: else sl@0: { sl@0: *aRecord++=TUint8(size); sl@0: aRecord=Mem::Copy(aRecord,blob.Data(),size); sl@0: } sl@0: } sl@0: else sl@0: { sl@0: aRecord=WriteBlobId(aRecord,blob.Id()); sl@0: aRecord=WriteCardinality(aRecord,size); sl@0: } sl@0: } sl@0: break; sl@0: } sl@0: } sl@0: FLUSHBITS(bits); sl@0: } sl@0: sl@0: const TUint8* CDbStoreTable::CopyToRowL(TDbCell* aCell,TInt aSize,const TUint8* aRec) sl@0: // sl@0: // translate persistent record into the row buffer sl@0: // sl@0: { sl@0: __ASSERT(aSize>0); sl@0: // sl@0: const TDbCell* const end=PtrAdd(aCell,aSize); sl@0: READBITINIT(bits); sl@0: HDbColumnSet::TIteratorC col=Def().Columns().Begin(); sl@0: HDbColumnSet::TIteratorC const cend=Def().Columns().End(); sl@0: for (;;) sl@0: { sl@0: TInt size=0; //null data sl@0: if (col->iAttributes&TDbCol::ENotNull || READBIT(bits,aRec)) // have data sl@0: { sl@0: if (TInt(end)-TInt(aCell)<=(TInt)sizeof(TUint32)) sl@0: return 0; sl@0: size=sizeof(TUint32); // for most types sl@0: TDbColType type=col->Type(); sl@0: switch (type) sl@0: { sl@0: default: sl@0: __ASSERT(0); sl@0: case EDbColBit: sl@0: *(TUint32*)aCell->Data()=READBIT(bits,aRec); sl@0: break; sl@0: case EDbColInt8: sl@0: *(TInt32*)aCell->Data()=*(const TInt8*)aRec; sl@0: aRec+=sizeof(TInt8); sl@0: break; sl@0: case EDbColUint8: sl@0: *(TUint32*)aCell->Data()=*aRec; sl@0: aRec+=sizeof(TUint8); sl@0: break; sl@0: case EDbColInt16: sl@0: aRec=Read16s(aRec,(TUint32*)aCell->Data()); sl@0: break; sl@0: case EDbColUint16: sl@0: aRec=Read16(aRec,(TUint32*)aCell->Data()); sl@0: break; sl@0: #if defined(__DOUBLE_WORDS_SWAPPED__) sl@0: case EDbColReal64: sl@0: if (TInt(end)-TInt(aCell)<=(TInt)sizeof(TReal64)) sl@0: return 0; sl@0: size=sizeof(TReal64); sl@0: aRec=Read32(aRec,(TUint32*)aCell->Data()+1); // transfer low word first, to high address sl@0: // drop through to transfer high word to low address! sl@0: #endif sl@0: case EDbColInt32: sl@0: case EDbColUint32: sl@0: case EDbColReal32: sl@0: aRec=Read32(aRec,(TUint32*)aCell->Data()); sl@0: break; sl@0: #if !defined(__DOUBLE_WORDS_SWAPPED__) sl@0: case EDbColReal64: sl@0: #endif sl@0: case EDbColInt64: sl@0: case EDbColDateTime: sl@0: if (TInt(end)-TInt(aCell)<=(TInt)sizeof(TInt64)) sl@0: return 0; sl@0: size=sizeof(TInt64); sl@0: aRec=Read32(aRec,(TUint32*)aCell->Data()); sl@0: aRec=Read32(aRec,(TUint32*)aCell->Data()+1); sl@0: break; sl@0: case EDbColText16: sl@0: { sl@0: TInt len; sl@0: aRec=ExpandUnicodeL(aRec,aCell->Data(),end,len); sl@0: if (!aRec) sl@0: return 0; sl@0: size=len<<1; sl@0: } sl@0: break; sl@0: case EDbColText8: sl@0: case EDbColBinary: sl@0: size=*aRec++; sl@0: if (TInt(end)-TInt(aCell)Data(),aRec,size); sl@0: aRec+=size; sl@0: break; sl@0: case EDbColLongText8: sl@0: case EDbColLongText16: sl@0: case EDbColLongBinary: sl@0: if (READBIT(bits,aRec)==0) sl@0: { // out of line Long column sl@0: if (TInt(end)-TInt(aCell)<=TDbBlob::RefSize()) sl@0: return 0; sl@0: TDbBlobId id; sl@0: aRec=ReadBlobId(aRec,id); sl@0: TInt sz; sl@0: aRec=ReadCardinality(aRec,sz); sl@0: new(aCell->Data()) TDbBlob(id,sz); sl@0: size=TDbBlob::RefSize(); sl@0: } sl@0: else if (type!=EDbColLongText16) sl@0: { // inline sl@0: size=*aRec++; sl@0: if (TInt(end)-TInt(aCell)Data()) TDbBlob(aRec,size); sl@0: aRec+=size; sl@0: size=TDbBlob::InlineSize(size); sl@0: } sl@0: else sl@0: { sl@0: TDbBlob* blob=new(aCell->Data()) TDbBlob; sl@0: TInt len; sl@0: aRec=ExpandUnicodeL(aRec,blob->InlineBuffer(),end,len); sl@0: if (!aRec) sl@0: return 0; sl@0: size=len<<1; sl@0: blob->SetSize(size); sl@0: size=TDbBlob::InlineSize(size); sl@0: } sl@0: break; sl@0: } sl@0: } sl@0: aCell->SetLength(size); sl@0: aCell=aCell->Next(); sl@0: if (aCell==end) sl@0: return aRec; sl@0: if (++col==cend) sl@0: return 0; sl@0: } sl@0: } sl@0: sl@0: void CDbStoreTable::CopyToRowL(RDbRow& aRow,const TDesC8& aRecord) sl@0: // sl@0: // translate persistent record into the row buffer sl@0: // sl@0: { sl@0: const TUint8* rec=aRecord.Ptr(); sl@0: const TUint8* end=rec+aRecord.Length(); sl@0: TInt size; sl@0: rec=ReadCardinality(rec,size); sl@0: size<<=2; sl@0: sl@0: //If such huge allocation is requested(KMaxTInt/2), it is highly likely the file is corrupt sl@0: if((size < 0) || (size >= KMaxTInt/2)) sl@0: { sl@0: aRow.SetSize(0); sl@0: __LEAVE(KErrCorrupt); sl@0: } sl@0: sl@0: if (size) sl@0: { sl@0: aRow.GrowL(size); sl@0: rec=CopyToRowL(aRow.First(),size,rec); sl@0: } sl@0: if (rec) sl@0: { sl@0: do sl@0: { sl@0: if (rec==end) sl@0: { sl@0: aRow.SetSize(size); sl@0: return; sl@0: } sl@0: } while (*rec++==0); sl@0: } sl@0: aRow.SetSize(0); sl@0: __LEAVE(KErrCorrupt); sl@0: } sl@0: sl@0: TUint8* CDbStoreTable::AlterRecordL(TUint8* aWPtr,const TUint8* aRPtr,TInt aLength,TInt aInlineLimit) sl@0: // sl@0: // Rewrite the record in the buffer by removing the data from the delete-list sl@0: // any changes are recorded in the iAltered member sl@0: // sl@0: { sl@0: // initially assume that the length count will be the same size after alteration sl@0: TInt lenSize=SizeOfCardinality(ReadCardinality(aRPtr)); sl@0: const TUint8* const rEnd=aRPtr+aLength; sl@0: aRPtr+=lenSize; sl@0: TUint8* wptr=aWPtr+lenSize; sl@0: TInt wRowSize=0; sl@0: TInt headers=0; sl@0: // sl@0: READBITINIT(rbits); sl@0: WRITEBITINIT(wbits); sl@0: const HDbColumnSet::TIteratorC cEnd=Def().Columns().End(); sl@0: HDbColumnSet::TIteratorC col=Def().Columns().Begin(); sl@0: do sl@0: { sl@0: if (aRPtr==rEnd && !READHASBITS(rbits)) sl@0: break; // no more data sl@0: TUint flg=col->iFlags; sl@0: if ((flg&TDbColumnDef::EDropped)==0) sl@0: ++headers; sl@0: if ((col->iAttributes&TDbCol::ENotNull)==0) sl@0: { // nullable sl@0: TUint notnull=READBIT(rbits,aRPtr); sl@0: if ((flg&TDbColumnDef::EDropped)==0) sl@0: WRITEBIT(wbits,wptr,notnull); sl@0: if (notnull==0) // null data sl@0: continue; sl@0: } sl@0: wRowSize+=headers; sl@0: headers=0; sl@0: TInt size; sl@0: TDbColType type=col->Type(); sl@0: switch (type) sl@0: { sl@0: default: sl@0: __ASSERT(0); sl@0: case EDbColBit: sl@0: size=READBIT(rbits,aRPtr); sl@0: if ((flg&TDbColumnDef::EDropped)==0) sl@0: { sl@0: WRITEBIT(wbits,wptr,size); sl@0: ++wRowSize; sl@0: } sl@0: continue; sl@0: case EDbColInt8: sl@0: case EDbColUint8: sl@0: case EDbColInt16: sl@0: case EDbColUint16: sl@0: case EDbColInt32: sl@0: case EDbColUint32: sl@0: case EDbColReal32: sl@0: case EDbColReal64: sl@0: case EDbColInt64: sl@0: case EDbColDateTime: sl@0: size=TRecordSize::FixedFieldSize(type); sl@0: if ((flg&TDbColumnDef::EDropped)==0) sl@0: { sl@0: wptr=Mem::Copy(wptr,aRPtr,size); sl@0: wRowSize+=(size+3)>>2; // # words sl@0: } sl@0: break; sl@0: case EDbColText8: sl@0: case EDbColBinary: sl@0: size=*aRPtr++; sl@0: if ((flg&(TDbColumnDef::EChangedType|TDbColumnDef::EDropped))==0) sl@0: { sl@0: wptr=Mem::Copy(wptr,aRPtr-1,size+1); // no change, copy the column sl@0: wRowSize+=(size+3)>>2; // # words sl@0: } sl@0: else if (flg&TDbColumnDef::EChangedType) sl@0: goto alterBlob8; // type change, into a LongColumn sl@0: else sl@0: __ASSERT(flg&TDbColumnDef::EDropped); // drop the column sl@0: break; sl@0: case EDbColText16: sl@0: { sl@0: TInt sz; sl@0: aRPtr=ReadCardinality(aRPtr,sz); sl@0: size=sz; sl@0: if ((flg&(TDbColumnDef::EChangedType|TDbColumnDef::EDropped))==0) sl@0: { sl@0: wptr=WriteCardinality(wptr,size); sl@0: wptr=Mem::Copy(wptr,aRPtr,size); // no change, copy the column sl@0: wRowSize+=(SizeOfExpandedUnicodeL(aRPtr,size)+3)>>2; sl@0: } sl@0: else if (flg&TDbColumnDef::EChangedType) sl@0: goto alterBlob16; // type change, into a LongColumn sl@0: else sl@0: __ASSERT(flg&TDbColumnDef::EDropped); // drop the column sl@0: } sl@0: break; sl@0: case EDbColLongText8: sl@0: case EDbColLongBinary: sl@0: case EDbColLongText16: sl@0: if (!READBIT(rbits,aRPtr)) sl@0: { // out-of-line sl@0: TDbBlobId id; sl@0: aRPtr=ReadBlobId(aRPtr,id); sl@0: TInt sz; sl@0: aRPtr=ReadCardinality(aRPtr,sz); sl@0: if (flg&TDbColumnDef::EDropped) sl@0: BlobsL()->DeleteL(id); // delete the stream sl@0: else sl@0: { sl@0: WRITEZEROBIT(wbits,wptr); // out-of-line sl@0: wptr=WriteBlobId(wptr,id); sl@0: wptr=WriteCardinality(wptr,sz); sl@0: wRowSize+=TDbBlob::RefSize()>>2; sl@0: } sl@0: size=0; sl@0: } sl@0: else if (type!=EDbColLongText16) sl@0: { // currently inline sl@0: size=*aRPtr++; sl@0: if (flg&TDbColumnDef::EDropped) sl@0: break; sl@0: // write long-column data, check inline status sl@0: alterBlob8: WRITEBIT(wbits,wptr,size<=aInlineLimit); sl@0: if (size<=aInlineLimit) sl@0: { // inlined sl@0: *wptr++=TUint8(size); // blob size sl@0: wptr=Mem::Copy(wptr,aRPtr,size); // blob data sl@0: wRowSize+=(TDbBlob::InlineSize(size)+3)>>2; sl@0: } sl@0: else sl@0: { sl@0: TDbBlobId id=BlobsL()->CreateL(type,aRPtr,size); sl@0: wptr=WriteBlobId(wptr,id); sl@0: wptr=WriteCardinality(wptr,size); sl@0: wRowSize+=TDbBlob::RefSize()>>2; sl@0: } sl@0: } sl@0: else sl@0: { // currently inline sl@0: TInt sz; sl@0: aRPtr=ReadCardinality(aRPtr,sz); sl@0: size=sz; sl@0: if (flg&TDbColumnDef::EDropped) sl@0: break; sl@0: // write long-column data, check inline status sl@0: alterBlob16: TInt len=SizeOfExpandedUnicodeL(aRPtr,size); sl@0: WRITEBIT(wbits,wptr,len<=aInlineLimit); sl@0: if (len<=aInlineLimit) sl@0: { // inlined sl@0: wptr=WriteCardinality(wptr,size); sl@0: wptr=Mem::Copy(wptr,aRPtr,size); // blob data sl@0: wRowSize+=(TDbBlob::InlineSize(len)+3)>>2; sl@0: } sl@0: else sl@0: { sl@0: TDbBlobId id=BlobsL()->CreateL(EDbColLongText8,aRPtr,size); // no unicode compressor! sl@0: wptr=WriteBlobId(wptr,id); sl@0: wptr=WriteCardinality(wptr,len); sl@0: wRowSize+=TDbBlob::RefSize()>>2; sl@0: } sl@0: } sl@0: break; sl@0: } sl@0: aRPtr+=size; sl@0: } while (++col(aIndex).iStats; sl@0: if (!stats.IsValid()) sl@0: IndexL(aIndex); // ensure that the index is loaded sl@0: return stats.Span(aInclusion,aLower,aUpper,TTextOps::Ops(aIndex.Key().Comparison())); sl@0: } sl@0: sl@0: // Class CDbStoreTable::CDiscarder sl@0: sl@0: CDbStoreTable::CDiscarder::CDiscarder() sl@0: {} sl@0: sl@0: CDbStoreTable::CDiscarder::~CDiscarder() sl@0: { sl@0: if (iTable) sl@0: iTable->Close(); sl@0: iRow.Close(); sl@0: } sl@0: sl@0: TInt CDbStoreTable::CDiscarder::OpenL(CDbStoreTable* aTable) sl@0: { sl@0: __ASSERT(!iTable); sl@0: iTable=aTable; sl@0: iRecords=&aTable->StoreRecordsL(); sl@0: iCluster=iRecords->Head(); sl@0: return iRecords->Count()+1; sl@0: } sl@0: sl@0: TInt CDbStoreTable::CDiscarder::StepL(TInt aStep) sl@0: { sl@0: __ASSERT(iTable); sl@0: TInt limit=iTable->Def().Columns().HasLongColumns() ? EBlobDiscardClusters : EDiscardClusters; sl@0: for (TInt inc=0;incDestroyL(); sl@0: return 0; sl@0: } sl@0: if (limit==EBlobDiscardClusters) sl@0: iRecords->AlterL(iCluster,*this); sl@0: aStep-=iRecords->DiscardL(iCluster); sl@0: } sl@0: return Max(aStep,1); sl@0: } sl@0: sl@0: TUint8* CDbStoreTable::CDiscarder::AlterRecordL(TUint8* aWPtr,const TUint8* aRPtr,TInt aLength) sl@0: // sl@0: // Scan for and discard all known BLOBs sl@0: // sl@0: { sl@0: iTable->CopyToRowL(iRow,TPtrC8(aRPtr,aLength)); sl@0: iTable->DiscardBlobsL(iRow); sl@0: return aWPtr; sl@0: } sl@0: sl@0: // class CDbStoreTable::CAlter sl@0: sl@0: CDbStoreTable::CAlter::CAlter() sl@0: {} sl@0: sl@0: CDbStoreTable::CAlter::~CAlter() sl@0: { sl@0: if (iTable) sl@0: iTable->Close(); sl@0: } sl@0: sl@0: void CDbStoreTable::CAlter::OpenL(CDbStoreTable* aTable,const HDbColumnSet& aNewSet) sl@0: // sl@0: // Prepare for alteration of the table data sl@0: // sl@0: { sl@0: __ASSERT(!iTable); sl@0: iTable=aTable; sl@0: iInlineLimit=TRecordSize::InlineLimit(aNewSet); sl@0: iRecords=&iTable->StoreRecordsL(); sl@0: iCluster=iRecords->Head(); sl@0: // sl@0: // Calculate the maximum possible expansion, based on the changes to the column set sl@0: // Currently the only alloed change which affects this is Text->LongText type changes sl@0: // these all add a single bit sl@0: // sl@0: TInt expand=0; sl@0: const HDbColumnSet& columns=iTable->Def().Columns(); sl@0: const HDbColumnSet::TIteratorC end=columns.End(); sl@0: HDbColumnSet::TIteratorC col=columns.Begin(); sl@0: do sl@0: { sl@0: if (col->iFlags&TDbColumnDef::EChangedType) sl@0: { sl@0: __ASSERT(col->iType>=EDbColText8&&col->iType<=EDbColBinary); sl@0: ++expand; sl@0: } sl@0: } while (++col>3; sl@0: } sl@0: sl@0: TInt CDbStoreTable::CAlter::StepL(TInt aStep) sl@0: // sl@0: // Do some steps to alter the table data sl@0: // sl@0: { sl@0: __ASSERT(iTable); sl@0: iStep=aStep; sl@0: iCluster=iRecords->AlterL(iCluster,*this); sl@0: return iCluster==KNullClusterId ? 0 : Max(iStep,1); sl@0: } sl@0: sl@0: TUint8* CDbStoreTable::CAlter::AlterRecordL(TUint8* aWPtr,const TUint8* aRPtr,TInt aLength) sl@0: // sl@0: // providing for CClusterCache::MAlter sl@0: // re-write the record sl@0: // sl@0: { sl@0: --iStep; sl@0: return iTable->AlterRecordL(aWPtr,aRPtr,aLength,iInlineLimit); sl@0: } sl@0: sl@0: TInt CDbStoreTable::CAlter::RecordExpansion(const TUint8*,TInt) sl@0: // sl@0: // providing for CClusterCache::MAlter sl@0: // just return the maximum possible expansion, rather than a record-specific one sl@0: // sl@0: { sl@0: return iExpansion; sl@0: }