persistentstorage/dbms/ustor/US_SCHMA.CPP
changeset 0 08ec8eefde2f
equal deleted inserted replaced
-1:000000000000 0:08ec8eefde2f
       
     1 // Copyright (c) 1998-2009 Nokia Corporation and/or its subsidiary(-ies).
       
     2 // All rights reserved.
       
     3 // This component and the accompanying materials are made available
       
     4 // under the terms of "Eclipse Public License v1.0"
       
     5 // which accompanies this distribution, and is available
       
     6 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     7 //
       
     8 // Initial Contributors:
       
     9 // Nokia Corporation - initial contribution.
       
    10 //
       
    11 // Contributors:
       
    12 //
       
    13 // Description:
       
    14 //
       
    15 
       
    16 #include "US_STD.H"
       
    17 #include <d32dbmsconstants.h>
       
    18 
       
    19 // class TRecordSize
       
    20 
       
    21 TUint8 const TRecordSize::FieldSizes[]=
       
    22 	{
       
    23 	0,					// EDbColBit
       
    24 	sizeof(TInt8),		// EDbColInt8
       
    25 	sizeof(TUint8),		// EDbColUint8
       
    26 	sizeof(TInt16),		// EDbColInt16
       
    27 	sizeof(TUint16),	// EDbColUint16
       
    28 	sizeof(TInt32),		// EDbColInt32
       
    29 	sizeof(TUint32),	// EDbColUint32
       
    30 	sizeof(TInt64),		// EDbColInt64
       
    31 	sizeof(TReal32),	// EDbColReal32
       
    32 	sizeof(TReal64),	// EDbColReal64
       
    33 	sizeof(TTime)		// EDbColDateTime
       
    34 	};
       
    35 
       
    36 TBool TRecordSize::Set(const HDbColumnSet& aColumns)
       
    37 //
       
    38 // Calculate stats for the record size and shape from the definition
       
    39 //
       
    40 	{
       
    41 	TInt fix=0,null=0,var=0,blob=0;
       
    42 	HDbColumnSet::TIteratorC const end=aColumns.End();
       
    43 	HDbColumnSet::TIteratorC col=aColumns.Begin();
       
    44 	do
       
    45 		{
       
    46 		TBool notnull=col->iAttributes&TDbCol::ENotNull;
       
    47 		if (notnull==0)
       
    48 			++fix;
       
    49 		TDbColType type=col->Type();
       
    50 		__ASSERT(type>=EDbColBit&&type<=EDbColLongBinary);
       
    51 		if (type==EDbColBit)
       
    52 			++fix;
       
    53 		else if (type<=EDbColDateTime)
       
    54 			{
       
    55 			TInt bits=FixedFieldSize(type)<<3;
       
    56 			if (notnull)
       
    57 				fix+=bits;
       
    58 			else
       
    59 				null+=bits;
       
    60 			}
       
    61 		else if (type<=EDbColBinary)
       
    62 			{
       
    63 			TInt size=col->iMaxLength;
       
    64 			if (type==EDbColText16)
       
    65 				size<<=1;
       
    66 			var+=8+(size<<3);
       
    67 			}
       
    68 		else
       
    69 			++blob;
       
    70 		} while(++col<end);
       
    71 //
       
    72 // assuming Blobs take at least 16 bytes + 1 bit
       
    73 	TInt max=(fix+null+var+blob*(1+(KMinInlineLimit<<3))+7)>>3;
       
    74 	if (max>KDbStoreMaxRecordLength)
       
    75 		return ETrue;
       
    76 //
       
    77 // Assuming a Maximally full record, how much excess space is available for Blobs?
       
    78 //
       
    79 	iInlineLimit=KDbMaxInlineBlobSize;
       
    80 	if (blob)
       
    81 		{	// use the spare space for extra inlining
       
    82 		TInt spare=(KDbStoreMaxRecordLength-max);
       
    83 		TInt inl=spare/blob+KMinInlineLimit-1;
       
    84 		if (inl<KDbMaxInlineBlobSize)
       
    85 			iInlineLimit=inl;
       
    86 		}
       
    87 //
       
    88 // Calculate the average cluster size for a column set
       
    89 // This assumes that the nullable columns are present 50%, Variable average 1/16
       
    90 // Blobs achieve 16 bytes, or inline limit (if smaller)
       
    91 //
       
    92 	TInt average=(fix+(null>>1)+(var>>4)+blob*(1+(16<<3))+7)>>3;
       
    93 	TInt clustering=KClusterLimit/average;
       
    94 	if (clustering==0)
       
    95 		clustering=1;
       
    96 	else if (clustering>KMaxClustering)
       
    97 		clustering=KMaxClustering;
       
    98 	iClustering=clustering;
       
    99 	return EFalse;
       
   100 	}
       
   101 
       
   102 void TRecordSize::CheckSizeL(const HDbColumnSet& aColumns)
       
   103 //
       
   104 // Check that the columns definition is a valid size
       
   105 //
       
   106 	{
       
   107 	TRecordSize size;
       
   108 	if (size.Set(aColumns))
       
   109 		__LEAVE(KErrTooBig);
       
   110 	}
       
   111 
       
   112 TInt TRecordSize::InlineLimit(const HDbColumnSet& aColumns)
       
   113 //
       
   114 // Evaluate the inline limit for the column set. It is assumed to be valid
       
   115 //
       
   116 	{
       
   117 	TRecordSize size;
       
   118 	__DEBUG(TBool chk=) size.Set(aColumns);
       
   119 	__ASSERT(!chk);
       
   120 	return size.InlineLimit();
       
   121 	}
       
   122 
       
   123 // Streaming column definitions
       
   124 
       
   125 LOCAL_C void ExternalizeL(const TDbColumnDef& aCol,RWriteStream& aStream)
       
   126 	{
       
   127 	aStream<<*aCol.iName;
       
   128 	aStream.WriteUint8L(aCol.iType);
       
   129 	aStream.WriteUint8L(aCol.iAttributes);
       
   130 	switch (aCol.iType)
       
   131 		{
       
   132 	case EDbColBinary:
       
   133 	case EDbColText8:
       
   134 	case EDbColText16:
       
   135 		aStream.WriteUint8L(aCol.iMaxLength);
       
   136 		break;
       
   137 	default:
       
   138 		break;
       
   139 		}
       
   140 	}
       
   141 
       
   142 LOCAL_C void InternalizeL(TDbColumnDef& aCol,RReadStream& aStream)
       
   143 	{
       
   144 	aCol.iName=HBufC::NewL(aStream,KDbMaxColName);
       
   145 	TDbColType type=TDbColType(aStream.ReadUint8L());
       
   146 	aCol.iType=TUint8(type);
       
   147 	aCol.iAttributes=aStream.ReadUint8L();
       
   148 	if (type>EDbColLongBinary || (aCol.iAttributes&~(TDbCol::ENotNull|TDbCol::EAutoIncrement))!=0)
       
   149 		__LEAVE(KErrCorrupt);
       
   150 	if (type>=EDbColText8 && type<=EDbColBinary)
       
   151 		{
       
   152 		aCol.iMaxLength=aStream.ReadUint8L();
       
   153 		if (aCol.iMaxLength==0)
       
   154 			__LEAVE(KErrCorrupt);
       
   155 		}
       
   156 	else
       
   157 		aCol.iMaxLength=KDbUndefinedLength;
       
   158 	}
       
   159 
       
   160 inline RWriteStream& operator<<(RWriteStream& aStream,const TDbColumnDef& aCol)
       
   161 	{ExternalizeL(aCol,aStream);return aStream;}
       
   162 inline RReadStream& operator>>(RReadStream& aStream,TDbColumnDef& aCol)
       
   163 	{InternalizeL(aCol,aStream);return aStream;}
       
   164 
       
   165 // Streaming key columns
       
   166 
       
   167 LOCAL_C void ExternalizeL(const TDbKeyCol& aKeyCol,RWriteStream& aStream)
       
   168 	{
       
   169 	aStream<<aKeyCol.iName;
       
   170 	aStream.WriteUint8L(aKeyCol.iLength!=KDbUndefinedLength ? aKeyCol.iLength : 0);
       
   171 	aStream.WriteUint8L(aKeyCol.iOrder);
       
   172 	}
       
   173 
       
   174 LOCAL_C void InternalizeL(TDbKeyCol& aKeyCol,RReadStream& aStream)
       
   175 	{
       
   176 	TPtr des=aKeyCol.iName.Des();
       
   177 	aStream>>des;
       
   178 	TUint len=aStream.ReadUint8L();
       
   179 	aKeyCol.iLength=len!=0 ? TInt(len) : KDbUndefinedLength;
       
   180 	aKeyCol.iOrder=TDbKeyCol::TOrder(aStream.ReadUint8L());
       
   181 	if (aKeyCol.iOrder>TDbKeyCol::EDesc)
       
   182 		__LEAVE(KErrCorrupt);
       
   183 	}
       
   184 
       
   185 inline RWriteStream& operator<<(RWriteStream& aStream,const TDbKeyCol& aCol)
       
   186 	{ExternalizeL(aCol,aStream);return aStream;}
       
   187 inline RReadStream& operator>>(RReadStream& aStream,TDbKeyCol& aCol)
       
   188 	{InternalizeL(aCol,aStream);return aStream;}
       
   189 
       
   190 
       
   191 // Class CDbStoreIndexDef
       
   192 
       
   193 CDbStoreIndexDef::CDbStoreIndexDef()
       
   194 	{}
       
   195 
       
   196 CDbStoreIndexDef* CDbStoreIndexDef::NewLC(const TDesC& aName)
       
   197 	{
       
   198 	CDbStoreIndexDef* self=new(ELeave) CDbStoreIndexDef;
       
   199 	CleanupStack::PushL(self);
       
   200 	self->ConstructL(aName);
       
   201 	return self;
       
   202 	}
       
   203 
       
   204 CDbStoreIndexDef* CDbStoreIndexDef::NewLC(const TDesC& aName,const CDbKey& aKey,const HDbColumnSet& aColumns)
       
   205 	{
       
   206 	CDbStoreIndexDef* self=NewLC(aName);
       
   207 	CDbKey& key=self->Key();
       
   208 	TInt max=aKey.Count();
       
   209 	for (TInt ii=0;ii<max;++ii)
       
   210 		{
       
   211 		TDbKeyCol kCol=aKey[ii];		
       
   212 		const TDbColumnDef* colptr = aColumns.ColumnL(kCol.iName);
       
   213 		if(!colptr)
       
   214 			{
       
   215 			__LEAVE(KErrNotFound); 
       
   216 			}
       
   217 		const TDbColumnDef& col=*colptr;
       
   218 		switch (col.iType)
       
   219 			{
       
   220 		default:
       
   221 			break;
       
   222 		case EDbColText8:
       
   223 		case EDbColText16:
       
   224 			if (kCol.iLength==KDbUndefinedLength)
       
   225 				kCol.iLength=col.iMaxLength;
       
   226 			break;
       
   227 		case EDbColLongText8:
       
   228 		case EDbColLongText16:
       
   229 			if (kCol.iLength==KDbUndefinedLength)
       
   230 				__LEAVE(KErrArgument);
       
   231 			break;
       
   232 		case EDbColBinary:
       
   233 		case EDbColLongBinary:
       
   234 			__LEAVE(KErrArgument);
       
   235 			break;
       
   236 			}
       
   237 		key.AddL(kCol);
       
   238 		}
       
   239 	if (aKey.IsUnique())
       
   240 		key.MakeUnique();
       
   241 	if (aKey.IsPrimary())
       
   242 		key.MakePrimary();
       
   243 	key.SetComparison(aKey.Comparison());
       
   244 	CheckSizeL(key,aColumns);
       
   245 	return self;
       
   246 	}
       
   247 
       
   248 CDbStoreIndexDef* CDbStoreIndexDef::NewL(RReadStream& aStream)
       
   249 //
       
   250 // Construct an index definition from persistent storage
       
   251 //
       
   252 	{
       
   253 	TDbName name;
       
   254 	aStream>>name;
       
   255 	CDbStoreIndexDef* self=NewLC(name);
       
   256 	CDbKey& key=self->Key();
       
   257 	TDbTextComparison comp=TDbTextComparison(aStream.ReadUint8L());
       
   258 	if (comp>EDbCompareCollated)
       
   259 		__LEAVE(KErrCorrupt);
       
   260 	key.SetComparison(comp);
       
   261 	if (aStream.ReadUint8L())
       
   262 		key.MakeUnique();
       
   263 	TCardinality count;
       
   264 	aStream>>count;
       
   265 	for (TInt ii=count;ii>0;--ii)
       
   266 		{
       
   267 		TDbKeyCol keycol;
       
   268 		aStream>>keycol;
       
   269 		key.AddL(keycol);
       
   270 		}
       
   271 	aStream>>self->iTokenId;
       
   272 	CleanupStack::Pop();
       
   273 	return self;
       
   274 	}
       
   275 
       
   276 void CDbStoreIndexDef::ExternalizeL(RWriteStream& aStream) const
       
   277 	{
       
   278 	aStream<<Name();
       
   279 	const CDbKey& key=Key();
       
   280 	aStream.WriteUint8L(TUint8(key.Comparison()));
       
   281 	aStream.WriteUint8L(key.IsUnique());
       
   282 	TInt max=key.Count();
       
   283 	aStream<<TCardinality(max);
       
   284 	for (TInt ii=0;ii<max;++ii)
       
   285 		aStream<<key[ii];
       
   286 	aStream<<iTokenId;
       
   287 	}
       
   288 
       
   289 TInt CDbStoreIndexDef::KeySize(const TDbKeyCol& aKeyCol,const TDbColumnDef& aColumn)
       
   290 	{
       
   291 	LOCAL_D const TUint8 KFixedSize[]=
       
   292 		{
       
   293 		sizeof(TUint32),
       
   294 		sizeof(TInt32),
       
   295 		sizeof(TUint32),
       
   296 		sizeof(TInt32),
       
   297 		sizeof(TUint32),
       
   298 		sizeof(TInt32),
       
   299 		sizeof(TUint32),
       
   300 		sizeof(TInt64),
       
   301 		sizeof(TReal32),
       
   302 		sizeof(TReal64),
       
   303 		sizeof(TTime)
       
   304 		};
       
   305 	TDbColType t=aColumn.Type();
       
   306 	if (TUint(t)<sizeof(KFixedSize)/sizeof(KFixedSize[0]))
       
   307 		return KFixedSize[t];
       
   308 	switch (t)
       
   309 		{
       
   310 	default:
       
   311 		__ASSERT(0);
       
   312 	case EDbColText8:
       
   313 	case EDbColLongText8:
       
   314 		return aKeyCol.iLength;
       
   315 	case EDbColText16:
       
   316 	case EDbColLongText16:
       
   317 		return aKeyCol.iLength<<1;
       
   318 		}
       
   319 	}
       
   320 
       
   321 void CDbStoreIndexDef::CheckSizeL(const CDbKey& aKey,const HDbColumnSet& aColSet)
       
   322 //
       
   323 // Check the size of the key for the index definition
       
   324 //
       
   325 	{
       
   326 	TInt len=aKey.IsUnique()?0:sizeof(TDbRecordId);
       
   327 	for (TInt ii=aKey.Count();--ii>=0;)
       
   328 		{
       
   329 		const TDbKeyCol& keyCol=aKey[ii];
       
   330 		len+=Align4(KeySize(keyCol,*aColSet.ColumnL(keyCol.iName)));
       
   331 		}
       
   332 	if (len>KMaxIndexKeySize)
       
   333 		__LEAVE(KErrTooBig);
       
   334 	}
       
   335 
       
   336 
       
   337 // Class CDbStoreDef
       
   338 
       
   339 LOCAL_C void SetColumnL(TDbColumnDef& aDef,const TDbCol& aCol,TUint aFlag=0)
       
   340 	{
       
   341 	aDef.SetL(aCol);
       
   342 	if (aDef.iAttributes&TDbCol::EAutoIncrement)
       
   343 		aDef.iAttributes|=TDbCol::ENotNull;	// auto-increment => not-null
       
   344 	aDef.iFlags=TUint8(aFlag);
       
   345 	TDbColType type=aCol.iType;
       
   346 	if (type>=EDbColText8 && type<=EDbColBinary)
       
   347 		{
       
   348 		if (aCol.iMaxLength==KDbUndefinedLength)
       
   349 			aDef.iMaxLength=KDbStoreMaxColumnLength;
       
   350 		else if (aCol.iMaxLength>KDbStoreMaxColumnLength)
       
   351 			__LEAVE(KErrNotSupported);
       
   352 		}
       
   353 	else
       
   354 		aDef.iMaxLength=KDbUndefinedLength;
       
   355 	}
       
   356 
       
   357 LOCAL_C HDbColumnSet::TIterator CheckColumnsL(HDbColumnSet::TIterator anIter,const CDbColSet& aColSet,TInt aNotNull,TUint aFlag=0)
       
   358 //
       
   359 // Check the columns from aColset into anIter, according to ENotNull attribute
       
   360 // Validate as we go
       
   361 //
       
   362 	{
       
   363 	for (TDbColSetIter iter(aColSet);iter;++iter)
       
   364 		{
       
   365 		TInt att=iter->iAttributes;
       
   366 		if (att&TDbCol::EAutoIncrement)
       
   367 			att|=TDbCol::ENotNull;		// auto-increment => not-null
       
   368 		if ((att&TDbCol::ENotNull)==aNotNull)
       
   369 			{
       
   370 			SetColumnL(*anIter,*iter,aFlag);
       
   371 			++anIter;
       
   372 			}
       
   373 		}
       
   374 	return anIter;
       
   375 	}
       
   376 
       
   377 CDbStoreDef::CDbStoreDef()
       
   378 	{}
       
   379 
       
   380 CDbStoreDef* CDbStoreDef::NewLC(const TDesC& aName,TInt aColumnCount)
       
   381 	{
       
   382 	CDbStoreDef* self=new(ELeave) CDbStoreDef;
       
   383 	CleanupStack::PushL(self);
       
   384 	self->ConstructL(aName,aColumnCount);
       
   385 	return self;
       
   386 	}
       
   387 
       
   388 CDbStoreDef* CDbStoreDef::NewLC(const TDesC& aName,const CDbColSet& aColSet)
       
   389 //
       
   390 // Construct a table definition from the column set supplied
       
   391 //
       
   392 	{
       
   393 	CDbStoreDef* self=NewLC(aName,aColSet.Count());
       
   394 	HDbColumnSet& columns=self->Columns();
       
   395 	HDbColumnSet::TIterator def=CheckColumnsL(columns.Begin(),aColSet,TDbCol::ENotNull);
       
   396 	def=CheckColumnsL(def,aColSet,0);
       
   397 	__ASSERT(def==columns.End());
       
   398 	TRecordSize::CheckSizeL(columns);
       
   399 	self->Changed();
       
   400 	return self;
       
   401 	}
       
   402 
       
   403 CDbStoreDef* CDbStoreDef::NewL(RReadStream& aStream)
       
   404 //
       
   405 // Construct a table definition from persistent storage
       
   406 //
       
   407 	{
       
   408 	TDbName name;
       
   409 	aStream>>name;
       
   410 	TCardinality count;
       
   411 	aStream>>count;
       
   412 	CDbStoreDef* self=NewLC(name,count);
       
   413 	HDbColumnSet& columns=self->Columns();
       
   414 	HDbColumnSet::TIterator iter=columns.Begin();
       
   415 	const HDbColumnSet::TIteratorC end=columns.End();
       
   416 	do
       
   417 		{
       
   418 		aStream>>*iter;
       
   419 		} while (++iter<end);
       
   420 	aStream>>count;
       
   421 	TInt cluster=count;
       
   422 	if (cluster==0 || cluster>KMaxClustering)
       
   423 		__LEAVE(KErrCorrupt);
       
   424 	aStream>>self->iTokenId;
       
   425 	RDbIndexes& indexes=self->Indexes();
       
   426 	aStream>>count;
       
   427 	for (TInt ii=count;ii>0;--ii)
       
   428 		indexes.Add(CDbStoreIndexDef::NewL(aStream));
       
   429 	self->Changed();
       
   430 	CleanupStack::Pop();
       
   431 	return self;
       
   432 	}
       
   433 
       
   434 void CDbStoreDef::Changed()
       
   435 //
       
   436 // The definition has changed, following creation or alteration of the table
       
   437 // Recalculate cached data for the definition.
       
   438 //
       
   439 	{
       
   440 	CDbTableDef::Changed();
       
   441 	__DEBUG(TBool dbg=) iInfo.Set(Columns());
       
   442 	__ASSERT(!dbg);
       
   443 	}
       
   444 
       
   445 void CDbStoreDef::ExternalizeL(RWriteStream& aStream) const
       
   446 	{
       
   447 	aStream<<Name();
       
   448 	const HDbColumnSet& columns=Columns();
       
   449 	aStream<<TCardinality(columns.Count());
       
   450 	HDbColumnSet::TIteratorC iter=columns.Begin();
       
   451 	const HDbColumnSet::TIteratorC end=columns.End();
       
   452 	do
       
   453 		{
       
   454 		aStream<<*iter;
       
   455 		} while (++iter<end);
       
   456 	aStream<<TCardinality(Clustering());	// old stuff, not needed
       
   457 	aStream<<iTokenId;
       
   458 	aStream<<TCardinality(Indexes().Count());
       
   459 	TSglQueIterC<CDbStoreIndexDef> ixIter(Indexes().AsQue());
       
   460 	for (const CDbStoreIndexDef* def;(def=ixIter++)!=0;)
       
   461 		aStream<<*def;
       
   462 	}
       
   463 
       
   464 void CDbStoreDef::AlteredColumnSetL(HDbColumnSet& aSet,const CDbColSet& aChange,const CDbColSet& aAdd)
       
   465 //
       
   466 // Generate an altered column set
       
   467 // We can hijack the non-user attribs of the column sets for marking changes
       
   468 //
       
   469 	{
       
   470 	// add not-null columns to the front
       
   471 	HDbColumnSet::TIterator newCol=CheckColumnsL(aSet.Begin(),aAdd,TDbCol::ENotNull,TDbColumnDef::EAdded);
       
   472 	// copy current set, minus deleted ones, apply text column length changes
       
   473 	TDbColSetIter change(aChange);
       
   474 	HDbColumnSet::TIterator col=Columns().Begin();
       
   475 	HDbColumnSet::TIteratorC const end=Columns().End();
       
   476 	do
       
   477 		{
       
   478 		TUint flag=col->iFlags;
       
   479 		if (flag&TDbColumnDef::EDropped)
       
   480 			continue;
       
   481 		if (flag&(TDbColumnDef::EChangedType|TDbColumnDef::EChangedLen))
       
   482 			{
       
   483 			// check allowed changes
       
   484 			SetColumnL(*newCol,*change);
       
   485 			++change;
       
   486 			if (flag&TDbColumnDef::EChangedType)
       
   487 				{	// validate type changes (only text->longtext etc)
       
   488 				if (!TDbCol::IsLong(newCol->Type()) || newCol->iType-col->iType!=3)
       
   489 					__LEAVE(KErrNotSupported);
       
   490 				}
       
   491 			else
       
   492 				{
       
   493 				col->iFlags=TUint8(flag&~TDbColumnDef::EChangedLen);	// no real changes req'd
       
   494 				if (newCol->iMaxLength<col->iMaxLength)
       
   495 					__LEAVE(KErrNotSupported);					// can only extend columns
       
   496 				}
       
   497 			}
       
   498 		else
       
   499 			newCol->SetL(*col);
       
   500 		++newCol;
       
   501 		} while (++col<end);
       
   502 	// add nullable columns to the end
       
   503 	newCol=CheckColumnsL(newCol,aAdd,0,TDbColumnDef::EAdded);
       
   504 	__ASSERT(newCol==aSet.End());
       
   505 	TRecordSize::CheckSizeL(aSet);
       
   506 	}
       
   507