persistentstorage/dbms/ustor/US_SCHMA.CPP
changeset 0 08ec8eefde2f
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/persistentstorage/dbms/ustor/US_SCHMA.CPP	Fri Jan 22 11:06:30 2010 +0200
@@ -0,0 +1,507 @@
+// Copyright (c) 1998-2009 Nokia Corporation and/or its subsidiary(-ies).
+// All rights reserved.
+// This component and the accompanying materials are made available
+// under the terms of "Eclipse Public License v1.0"
+// which accompanies this distribution, and is available
+// at the URL "http://www.eclipse.org/legal/epl-v10.html".
+//
+// Initial Contributors:
+// Nokia Corporation - initial contribution.
+//
+// Contributors:
+//
+// Description:
+//
+
+#include "US_STD.H"
+#include <d32dbmsconstants.h>
+
+// class TRecordSize
+
+TUint8 const TRecordSize::FieldSizes[]=
+	{
+	0,					// EDbColBit
+	sizeof(TInt8),		// EDbColInt8
+	sizeof(TUint8),		// EDbColUint8
+	sizeof(TInt16),		// EDbColInt16
+	sizeof(TUint16),	// EDbColUint16
+	sizeof(TInt32),		// EDbColInt32
+	sizeof(TUint32),	// EDbColUint32
+	sizeof(TInt64),		// EDbColInt64
+	sizeof(TReal32),	// EDbColReal32
+	sizeof(TReal64),	// EDbColReal64
+	sizeof(TTime)		// EDbColDateTime
+	};
+
+TBool TRecordSize::Set(const HDbColumnSet& aColumns)
+//
+// Calculate stats for the record size and shape from the definition
+//
+	{
+	TInt fix=0,null=0,var=0,blob=0;
+	HDbColumnSet::TIteratorC const end=aColumns.End();
+	HDbColumnSet::TIteratorC col=aColumns.Begin();
+	do
+		{
+		TBool notnull=col->iAttributes&TDbCol::ENotNull;
+		if (notnull==0)
+			++fix;
+		TDbColType type=col->Type();
+		__ASSERT(type>=EDbColBit&&type<=EDbColLongBinary);
+		if (type==EDbColBit)
+			++fix;
+		else if (type<=EDbColDateTime)
+			{
+			TInt bits=FixedFieldSize(type)<<3;
+			if (notnull)
+				fix+=bits;
+			else
+				null+=bits;
+			}
+		else if (type<=EDbColBinary)
+			{
+			TInt size=col->iMaxLength;
+			if (type==EDbColText16)
+				size<<=1;
+			var+=8+(size<<3);
+			}
+		else
+			++blob;
+		} while(++col<end);
+//
+// assuming Blobs take at least 16 bytes + 1 bit
+	TInt max=(fix+null+var+blob*(1+(KMinInlineLimit<<3))+7)>>3;
+	if (max>KDbStoreMaxRecordLength)
+		return ETrue;
+//
+// Assuming a Maximally full record, how much excess space is available for Blobs?
+//
+	iInlineLimit=KDbMaxInlineBlobSize;
+	if (blob)
+		{	// use the spare space for extra inlining
+		TInt spare=(KDbStoreMaxRecordLength-max);
+		TInt inl=spare/blob+KMinInlineLimit-1;
+		if (inl<KDbMaxInlineBlobSize)
+			iInlineLimit=inl;
+		}
+//
+// Calculate the average cluster size for a column set
+// This assumes that the nullable columns are present 50%, Variable average 1/16
+// Blobs achieve 16 bytes, or inline limit (if smaller)
+//
+	TInt average=(fix+(null>>1)+(var>>4)+blob*(1+(16<<3))+7)>>3;
+	TInt clustering=KClusterLimit/average;
+	if (clustering==0)
+		clustering=1;
+	else if (clustering>KMaxClustering)
+		clustering=KMaxClustering;
+	iClustering=clustering;
+	return EFalse;
+	}
+
+void TRecordSize::CheckSizeL(const HDbColumnSet& aColumns)
+//
+// Check that the columns definition is a valid size
+//
+	{
+	TRecordSize size;
+	if (size.Set(aColumns))
+		__LEAVE(KErrTooBig);
+	}
+
+TInt TRecordSize::InlineLimit(const HDbColumnSet& aColumns)
+//
+// Evaluate the inline limit for the column set. It is assumed to be valid
+//
+	{
+	TRecordSize size;
+	__DEBUG(TBool chk=) size.Set(aColumns);
+	__ASSERT(!chk);
+	return size.InlineLimit();
+	}
+
+// Streaming column definitions
+
+LOCAL_C void ExternalizeL(const TDbColumnDef& aCol,RWriteStream& aStream)
+	{
+	aStream<<*aCol.iName;
+	aStream.WriteUint8L(aCol.iType);
+	aStream.WriteUint8L(aCol.iAttributes);
+	switch (aCol.iType)
+		{
+	case EDbColBinary:
+	case EDbColText8:
+	case EDbColText16:
+		aStream.WriteUint8L(aCol.iMaxLength);
+		break;
+	default:
+		break;
+		}
+	}
+
+LOCAL_C void InternalizeL(TDbColumnDef& aCol,RReadStream& aStream)
+	{
+	aCol.iName=HBufC::NewL(aStream,KDbMaxColName);
+	TDbColType type=TDbColType(aStream.ReadUint8L());
+	aCol.iType=TUint8(type);
+	aCol.iAttributes=aStream.ReadUint8L();
+	if (type>EDbColLongBinary || (aCol.iAttributes&~(TDbCol::ENotNull|TDbCol::EAutoIncrement))!=0)
+		__LEAVE(KErrCorrupt);
+	if (type>=EDbColText8 && type<=EDbColBinary)
+		{
+		aCol.iMaxLength=aStream.ReadUint8L();
+		if (aCol.iMaxLength==0)
+			__LEAVE(KErrCorrupt);
+		}
+	else
+		aCol.iMaxLength=KDbUndefinedLength;
+	}
+
+inline RWriteStream& operator<<(RWriteStream& aStream,const TDbColumnDef& aCol)
+	{ExternalizeL(aCol,aStream);return aStream;}
+inline RReadStream& operator>>(RReadStream& aStream,TDbColumnDef& aCol)
+	{InternalizeL(aCol,aStream);return aStream;}
+
+// Streaming key columns
+
+LOCAL_C void ExternalizeL(const TDbKeyCol& aKeyCol,RWriteStream& aStream)
+	{
+	aStream<<aKeyCol.iName;
+	aStream.WriteUint8L(aKeyCol.iLength!=KDbUndefinedLength ? aKeyCol.iLength : 0);
+	aStream.WriteUint8L(aKeyCol.iOrder);
+	}
+
+LOCAL_C void InternalizeL(TDbKeyCol& aKeyCol,RReadStream& aStream)
+	{
+	TPtr des=aKeyCol.iName.Des();
+	aStream>>des;
+	TUint len=aStream.ReadUint8L();
+	aKeyCol.iLength=len!=0 ? TInt(len) : KDbUndefinedLength;
+	aKeyCol.iOrder=TDbKeyCol::TOrder(aStream.ReadUint8L());
+	if (aKeyCol.iOrder>TDbKeyCol::EDesc)
+		__LEAVE(KErrCorrupt);
+	}
+
+inline RWriteStream& operator<<(RWriteStream& aStream,const TDbKeyCol& aCol)
+	{ExternalizeL(aCol,aStream);return aStream;}
+inline RReadStream& operator>>(RReadStream& aStream,TDbKeyCol& aCol)
+	{InternalizeL(aCol,aStream);return aStream;}
+
+
+// Class CDbStoreIndexDef
+
+CDbStoreIndexDef::CDbStoreIndexDef()
+	{}
+
+CDbStoreIndexDef* CDbStoreIndexDef::NewLC(const TDesC& aName)
+	{
+	CDbStoreIndexDef* self=new(ELeave) CDbStoreIndexDef;
+	CleanupStack::PushL(self);
+	self->ConstructL(aName);
+	return self;
+	}
+
+CDbStoreIndexDef* CDbStoreIndexDef::NewLC(const TDesC& aName,const CDbKey& aKey,const HDbColumnSet& aColumns)
+	{
+	CDbStoreIndexDef* self=NewLC(aName);
+	CDbKey& key=self->Key();
+	TInt max=aKey.Count();
+	for (TInt ii=0;ii<max;++ii)
+		{
+		TDbKeyCol kCol=aKey[ii];		
+		const TDbColumnDef* colptr = aColumns.ColumnL(kCol.iName);
+		if(!colptr)
+			{
+			__LEAVE(KErrNotFound); 
+			}
+		const TDbColumnDef& col=*colptr;
+		switch (col.iType)
+			{
+		default:
+			break;
+		case EDbColText8:
+		case EDbColText16:
+			if (kCol.iLength==KDbUndefinedLength)
+				kCol.iLength=col.iMaxLength;
+			break;
+		case EDbColLongText8:
+		case EDbColLongText16:
+			if (kCol.iLength==KDbUndefinedLength)
+				__LEAVE(KErrArgument);
+			break;
+		case EDbColBinary:
+		case EDbColLongBinary:
+			__LEAVE(KErrArgument);
+			break;
+			}
+		key.AddL(kCol);
+		}
+	if (aKey.IsUnique())
+		key.MakeUnique();
+	if (aKey.IsPrimary())
+		key.MakePrimary();
+	key.SetComparison(aKey.Comparison());
+	CheckSizeL(key,aColumns);
+	return self;
+	}
+
+CDbStoreIndexDef* CDbStoreIndexDef::NewL(RReadStream& aStream)
+//
+// Construct an index definition from persistent storage
+//
+	{
+	TDbName name;
+	aStream>>name;
+	CDbStoreIndexDef* self=NewLC(name);
+	CDbKey& key=self->Key();
+	TDbTextComparison comp=TDbTextComparison(aStream.ReadUint8L());
+	if (comp>EDbCompareCollated)
+		__LEAVE(KErrCorrupt);
+	key.SetComparison(comp);
+	if (aStream.ReadUint8L())
+		key.MakeUnique();
+	TCardinality count;
+	aStream>>count;
+	for (TInt ii=count;ii>0;--ii)
+		{
+		TDbKeyCol keycol;
+		aStream>>keycol;
+		key.AddL(keycol);
+		}
+	aStream>>self->iTokenId;
+	CleanupStack::Pop();
+	return self;
+	}
+
+void CDbStoreIndexDef::ExternalizeL(RWriteStream& aStream) const
+	{
+	aStream<<Name();
+	const CDbKey& key=Key();
+	aStream.WriteUint8L(TUint8(key.Comparison()));
+	aStream.WriteUint8L(key.IsUnique());
+	TInt max=key.Count();
+	aStream<<TCardinality(max);
+	for (TInt ii=0;ii<max;++ii)
+		aStream<<key[ii];
+	aStream<<iTokenId;
+	}
+
+TInt CDbStoreIndexDef::KeySize(const TDbKeyCol& aKeyCol,const TDbColumnDef& aColumn)
+	{
+	LOCAL_D const TUint8 KFixedSize[]=
+		{
+		sizeof(TUint32),
+		sizeof(TInt32),
+		sizeof(TUint32),
+		sizeof(TInt32),
+		sizeof(TUint32),
+		sizeof(TInt32),
+		sizeof(TUint32),
+		sizeof(TInt64),
+		sizeof(TReal32),
+		sizeof(TReal64),
+		sizeof(TTime)
+		};
+	TDbColType t=aColumn.Type();
+	if (TUint(t)<sizeof(KFixedSize)/sizeof(KFixedSize[0]))
+		return KFixedSize[t];
+	switch (t)
+		{
+	default:
+		__ASSERT(0);
+	case EDbColText8:
+	case EDbColLongText8:
+		return aKeyCol.iLength;
+	case EDbColText16:
+	case EDbColLongText16:
+		return aKeyCol.iLength<<1;
+		}
+	}
+
+void CDbStoreIndexDef::CheckSizeL(const CDbKey& aKey,const HDbColumnSet& aColSet)
+//
+// Check the size of the key for the index definition
+//
+	{
+	TInt len=aKey.IsUnique()?0:sizeof(TDbRecordId);
+	for (TInt ii=aKey.Count();--ii>=0;)
+		{
+		const TDbKeyCol& keyCol=aKey[ii];
+		len+=Align4(KeySize(keyCol,*aColSet.ColumnL(keyCol.iName)));
+		}
+	if (len>KMaxIndexKeySize)
+		__LEAVE(KErrTooBig);
+	}
+
+
+// Class CDbStoreDef
+
+LOCAL_C void SetColumnL(TDbColumnDef& aDef,const TDbCol& aCol,TUint aFlag=0)
+	{
+	aDef.SetL(aCol);
+	if (aDef.iAttributes&TDbCol::EAutoIncrement)
+		aDef.iAttributes|=TDbCol::ENotNull;	// auto-increment => not-null
+	aDef.iFlags=TUint8(aFlag);
+	TDbColType type=aCol.iType;
+	if (type>=EDbColText8 && type<=EDbColBinary)
+		{
+		if (aCol.iMaxLength==KDbUndefinedLength)
+			aDef.iMaxLength=KDbStoreMaxColumnLength;
+		else if (aCol.iMaxLength>KDbStoreMaxColumnLength)
+			__LEAVE(KErrNotSupported);
+		}
+	else
+		aDef.iMaxLength=KDbUndefinedLength;
+	}
+
+LOCAL_C HDbColumnSet::TIterator CheckColumnsL(HDbColumnSet::TIterator anIter,const CDbColSet& aColSet,TInt aNotNull,TUint aFlag=0)
+//
+// Check the columns from aColset into anIter, according to ENotNull attribute
+// Validate as we go
+//
+	{
+	for (TDbColSetIter iter(aColSet);iter;++iter)
+		{
+		TInt att=iter->iAttributes;
+		if (att&TDbCol::EAutoIncrement)
+			att|=TDbCol::ENotNull;		// auto-increment => not-null
+		if ((att&TDbCol::ENotNull)==aNotNull)
+			{
+			SetColumnL(*anIter,*iter,aFlag);
+			++anIter;
+			}
+		}
+	return anIter;
+	}
+
+CDbStoreDef::CDbStoreDef()
+	{}
+
+CDbStoreDef* CDbStoreDef::NewLC(const TDesC& aName,TInt aColumnCount)
+	{
+	CDbStoreDef* self=new(ELeave) CDbStoreDef;
+	CleanupStack::PushL(self);
+	self->ConstructL(aName,aColumnCount);
+	return self;
+	}
+
+CDbStoreDef* CDbStoreDef::NewLC(const TDesC& aName,const CDbColSet& aColSet)
+//
+// Construct a table definition from the column set supplied
+//
+	{
+	CDbStoreDef* self=NewLC(aName,aColSet.Count());
+	HDbColumnSet& columns=self->Columns();
+	HDbColumnSet::TIterator def=CheckColumnsL(columns.Begin(),aColSet,TDbCol::ENotNull);
+	def=CheckColumnsL(def,aColSet,0);
+	__ASSERT(def==columns.End());
+	TRecordSize::CheckSizeL(columns);
+	self->Changed();
+	return self;
+	}
+
+CDbStoreDef* CDbStoreDef::NewL(RReadStream& aStream)
+//
+// Construct a table definition from persistent storage
+//
+	{
+	TDbName name;
+	aStream>>name;
+	TCardinality count;
+	aStream>>count;
+	CDbStoreDef* self=NewLC(name,count);
+	HDbColumnSet& columns=self->Columns();
+	HDbColumnSet::TIterator iter=columns.Begin();
+	const HDbColumnSet::TIteratorC end=columns.End();
+	do
+		{
+		aStream>>*iter;
+		} while (++iter<end);
+	aStream>>count;
+	TInt cluster=count;
+	if (cluster==0 || cluster>KMaxClustering)
+		__LEAVE(KErrCorrupt);
+	aStream>>self->iTokenId;
+	RDbIndexes& indexes=self->Indexes();
+	aStream>>count;
+	for (TInt ii=count;ii>0;--ii)
+		indexes.Add(CDbStoreIndexDef::NewL(aStream));
+	self->Changed();
+	CleanupStack::Pop();
+	return self;
+	}
+
+void CDbStoreDef::Changed()
+//
+// The definition has changed, following creation or alteration of the table
+// Recalculate cached data for the definition.
+//
+	{
+	CDbTableDef::Changed();
+	__DEBUG(TBool dbg=) iInfo.Set(Columns());
+	__ASSERT(!dbg);
+	}
+
+void CDbStoreDef::ExternalizeL(RWriteStream& aStream) const
+	{
+	aStream<<Name();
+	const HDbColumnSet& columns=Columns();
+	aStream<<TCardinality(columns.Count());
+	HDbColumnSet::TIteratorC iter=columns.Begin();
+	const HDbColumnSet::TIteratorC end=columns.End();
+	do
+		{
+		aStream<<*iter;
+		} while (++iter<end);
+	aStream<<TCardinality(Clustering());	// old stuff, not needed
+	aStream<<iTokenId;
+	aStream<<TCardinality(Indexes().Count());
+	TSglQueIterC<CDbStoreIndexDef> ixIter(Indexes().AsQue());
+	for (const CDbStoreIndexDef* def;(def=ixIter++)!=0;)
+		aStream<<*def;
+	}
+
+void CDbStoreDef::AlteredColumnSetL(HDbColumnSet& aSet,const CDbColSet& aChange,const CDbColSet& aAdd)
+//
+// Generate an altered column set
+// We can hijack the non-user attribs of the column sets for marking changes
+//
+	{
+	// add not-null columns to the front
+	HDbColumnSet::TIterator newCol=CheckColumnsL(aSet.Begin(),aAdd,TDbCol::ENotNull,TDbColumnDef::EAdded);
+	// copy current set, minus deleted ones, apply text column length changes
+	TDbColSetIter change(aChange);
+	HDbColumnSet::TIterator col=Columns().Begin();
+	HDbColumnSet::TIteratorC const end=Columns().End();
+	do
+		{
+		TUint flag=col->iFlags;
+		if (flag&TDbColumnDef::EDropped)
+			continue;
+		if (flag&(TDbColumnDef::EChangedType|TDbColumnDef::EChangedLen))
+			{
+			// check allowed changes
+			SetColumnL(*newCol,*change);
+			++change;
+			if (flag&TDbColumnDef::EChangedType)
+				{	// validate type changes (only text->longtext etc)
+				if (!TDbCol::IsLong(newCol->Type()) || newCol->iType-col->iType!=3)
+					__LEAVE(KErrNotSupported);
+				}
+			else
+				{
+				col->iFlags=TUint8(flag&~TDbColumnDef::EChangedLen);	// no real changes req'd
+				if (newCol->iMaxLength<col->iMaxLength)
+					__LEAVE(KErrNotSupported);					// can only extend columns
+				}
+			}
+		else
+			newCol->SetL(*col);
+		++newCol;
+		} while (++col<end);
+	// add nullable columns to the end
+	newCol=CheckColumnsL(newCol,aAdd,0,TDbColumnDef::EAdded);
+	__ASSERT(newCol==aSet.End());
+	TRecordSize::CheckSizeL(aSet);
+	}
+