os/persistentdata/persistentstorage/dbms/utable/UT_ORDER.CPP
author sl
Tue, 10 Jun 2014 14:32:02 +0200
changeset 1 260cb5ec6c19
permissions -rw-r--r--
Update contrib.
sl@0
     1
// Copyright (c) 1998-2009 Nokia Corporation and/or its subsidiary(-ies).
sl@0
     2
// All rights reserved.
sl@0
     3
// This component and the accompanying materials are made available
sl@0
     4
// under the terms of "Eclipse Public License v1.0"
sl@0
     5
// which accompanies this distribution, and is available
sl@0
     6
// at the URL "http://www.eclipse.org/legal/epl-v10.html".
sl@0
     7
//
sl@0
     8
// Initial Contributors:
sl@0
     9
// Nokia Corporation - initial contribution.
sl@0
    10
//
sl@0
    11
// Contributors:
sl@0
    12
//
sl@0
    13
// Description:
sl@0
    14
// Order-by stage for the cursor data "pipeline"
sl@0
    15
// 
sl@0
    16
//
sl@0
    17
sl@0
    18
#include "UT_STD.H"
sl@0
    19
#include "D32COMP.H"
sl@0
    20
#include <d32dbmsconstants.h>
sl@0
    21
sl@0
    22
#ifdef _DEBUG
sl@0
    23
#define _CHECK_ORDERING		// forces a full test of the ordering after sorting
sl@0
    24
#endif
sl@0
    25
sl@0
    26
#define MAX( a, b ) ( (a) > (b) ? (a) : (b) )
sl@0
    27
sl@0
    28
/* The key structure.
sl@0
    29
sl@0
    30
Each key value is always aligned on a 32-bit boundary to allow word reads and writes
sl@0
    31
integral values are always atored as 32-bit values just as for the row buffer
sl@0
    32
Text columns are encoded as follows (trailing padding is omitted from the description)
sl@0
    33
sl@0
    34
  Text8 columns			<byte n><n ASCII characters>
sl@0
    35
  n is the [character] length of the column
sl@0
    36
sl@0
    37
  Text16 columns		<short n><n UNICODE characters>
sl@0
    38
  n is the [character] length of the column
sl@0
    39
sl@0
    40
  LongText8 columns		<word n><n ASCII characters>
sl@0
    41
                 or		<word n|ETrunc><32 ASCII characters><blobId>
sl@0
    42
  n is [byte] size of the column
sl@0
    43
sl@0
    44
  LongText16 columns	<word n><n/2 UNICODE characters>
sl@0
    45
                  or	<word n|ETrunc><16 UNICODE characters><blobId>
sl@0
    46
  n is [byte] size of the column
sl@0
    47
sl@0
    48
*/
sl@0
    49
sl@0
    50
sl@0
    51
class CDbOrderByStage::HOrdering
sl@0
    52
	{
sl@0
    53
private:
sl@0
    54
	struct TKeyCol
sl@0
    55
		{
sl@0
    56
		TDbColNo iOrdinal;
sl@0
    57
		TUint8 iType;
sl@0
    58
		TUint8 iOrder;
sl@0
    59
		TUint8 iLength;
sl@0
    60
		};
sl@0
    61
	struct TBlobKey
sl@0
    62
		{
sl@0
    63
		enum {ETrunc=(TInt)0x80000000};
sl@0
    64
		enum {ETruncSize=32};		// store 32 bytes of truncated BLOBs
sl@0
    65
	public:
sl@0
    66
		inline TInt Size() const;
sl@0
    67
	public:
sl@0
    68
		TInt iSize;
sl@0
    69
		union {TUint8 iData8[ETruncSize]; TUint16 iData16[ETruncSize>>1];};
sl@0
    70
		TDbBlobId iId;
sl@0
    71
		};
sl@0
    72
public:
sl@0
    73
	static HOrdering* NewL(CDbTable& aTable,const CDbKey& aKey);
sl@0
    74
	TAny* EntryL(TAny* aPtr,const RDbTableRow& aRow) const;
sl@0
    75
	TInt CompareL(const TAny* aLeft,const TAny* aRight) const;
sl@0
    76
	TInt MaxSize() const;
sl@0
    77
private:
sl@0
    78
	inline HOrdering(TInt aCount,TDbTextComparison aComparison,CDbTable& aTable);
sl@0
    79
	MStreamBuf* BlobLC(TDbBlobId aId,TDbColType aType) const;
sl@0
    80
	TInt CompareLongText8L(const TBlobKey& aLeft,const TBlobKey& aRight) const;
sl@0
    81
	TInt CompareLongText16L(const TBlobKey& aLeft,const TBlobKey& aRight) const;
sl@0
    82
private:
sl@0
    83
	CDbTable& iTable;
sl@0
    84
	const TTextOps& iTextOps;
sl@0
    85
	const TKeyCol* iEndOfKeys;
sl@0
    86
	TKeyCol iKeys[1];	// one or more keys
sl@0
    87
	};
sl@0
    88
sl@0
    89
// Class HDbOrdering
sl@0
    90
sl@0
    91
inline TInt CDbOrderByStage::HOrdering::TBlobKey::Size() const
sl@0
    92
	{
sl@0
    93
	TInt size=_FOFF(TBlobKey,iData8[iSize+3]);
sl@0
    94
	return (size&ETrunc) ? sizeof(TBlobKey) : size&~3;
sl@0
    95
	}
sl@0
    96
sl@0
    97
inline CDbOrderByStage::HOrdering::HOrdering(TInt aCount,TDbTextComparison aComparison,CDbTable& aTable) :
sl@0
    98
	iTable(aTable),
sl@0
    99
	iTextOps(TTextOps::Ops(aComparison)),
sl@0
   100
	iEndOfKeys(&iKeys[aCount])
sl@0
   101
	{
sl@0
   102
	}
sl@0
   103
sl@0
   104
//
sl@0
   105
// Construct the ordering based on the key definition (must be valid for the table)
sl@0
   106
// and the column set provided
sl@0
   107
//
sl@0
   108
CDbOrderByStage::HOrdering* CDbOrderByStage::HOrdering::NewL(CDbTable& aTable,const CDbKey& aKey)
sl@0
   109
	{
sl@0
   110
	TInt count=aKey.Count();
sl@0
   111
	__ASSERT(count>0);
sl@0
   112
	HOrdering* self=new(User::AllocLC(_FOFF(HOrdering,iKeys[count])))
sl@0
   113
								HOrdering(count,aKey.Comparison(),aTable);
sl@0
   114
	TKeyCol* pKey=&self->iKeys[0];
sl@0
   115
	const HDbColumnSet& columns=aTable.Def().Columns();
sl@0
   116
	for (TInt ii=0;ii<count;++pKey,++ii)
sl@0
   117
		{
sl@0
   118
		const TDbKeyCol& key=aKey[ii];
sl@0
   119
		pKey->iOrder=TUint8(key.iOrder);
sl@0
   120
		pKey->iOrdinal=columns.ColNoL(key.iName);
sl@0
   121
		if (pKey->iOrdinal==KDbNullColNo)
sl@0
   122
			__LEAVE(KErrNotFound);
sl@0
   123
		const TDbColumnDef& col=columns[pKey->iOrdinal];
sl@0
   124
		switch (pKey->iType=col.iType)
sl@0
   125
			{
sl@0
   126
		default:
sl@0
   127
			break;
sl@0
   128
		case EDbColText8:
sl@0
   129
		case EDbColText16:
sl@0
   130
			{
sl@0
   131
			TInt l=col.iMaxLength;
sl@0
   132
			if (l<256)
sl@0
   133
				{
sl@0
   134
				pKey->iLength=TUint8(l);
sl@0
   135
				break;
sl@0
   136
				}
sl@0
   137
			}
sl@0
   138
			// fall through to argument error
sl@0
   139
		case EDbColBinary:
sl@0
   140
		case EDbColLongBinary:
sl@0
   141
			__LEAVE(KErrArgument);
sl@0
   142
			}
sl@0
   143
		}
sl@0
   144
	CleanupStack::Pop();
sl@0
   145
	return self;
sl@0
   146
	}
sl@0
   147
sl@0
   148
TInt CDbOrderByStage::HOrdering::MaxSize() const
sl@0
   149
	{
sl@0
   150
	TInt maxsize=0;
sl@0
   151
	const TKeyCol* const end=iEndOfKeys;
sl@0
   152
	const TKeyCol* key=&iKeys[0];
sl@0
   153
	__ASSERT(key<end);
sl@0
   154
	do	{
sl@0
   155
		TInt s;
sl@0
   156
		switch (key->iType)
sl@0
   157
			{
sl@0
   158
		default:
sl@0
   159
			s=sizeof(TUint32);
sl@0
   160
			break;
sl@0
   161
		case EDbColInt64:
sl@0
   162
			s=sizeof(TInt64);
sl@0
   163
			break;
sl@0
   164
		case EDbColDateTime:
sl@0
   165
			s=sizeof(TTime);
sl@0
   166
			break;
sl@0
   167
		case EDbColReal64:
sl@0
   168
			s=sizeof(TReal64);
sl@0
   169
			break;
sl@0
   170
		case EDbColText8:
sl@0
   171
			s=Align4(key->iLength+1);
sl@0
   172
			break;
sl@0
   173
		case EDbColText16:
sl@0
   174
			s=Align4((key->iLength<<1)+1);
sl@0
   175
			break;
sl@0
   176
		case EDbColLongText8:
sl@0
   177
		case EDbColLongText16:
sl@0
   178
			s=MAX(__Align8(sizeof(TUint32)+KDbMaxInlineBlobSize),sizeof(TBlobKey));
sl@0
   179
			break;
sl@0
   180
			}
sl@0
   181
		maxsize+=s;
sl@0
   182
		} while (++key<end);
sl@0
   183
	return maxsize;
sl@0
   184
	}
sl@0
   185
sl@0
   186
MStreamBuf* CDbOrderByStage::HOrdering::BlobLC(TDbBlobId aId,TDbColType aType) const
sl@0
   187
	{
sl@0
   188
	return iTable.BlobsL()->ReadLC(aId,aType);
sl@0
   189
	}
sl@0
   190
sl@0
   191
//
sl@0
   192
// Construct an entry at aPtr from the record given
sl@0
   193
// iMaxSize bytes are assumed to be available at aPtr
sl@0
   194
// return the actual size of the entry
sl@0
   195
//
sl@0
   196
TAny* CDbOrderByStage::HOrdering::EntryL(TAny* aPtr,const RDbTableRow& aRow) const
sl@0
   197
	{
sl@0
   198
	__ASSERT(Align4(aPtr)==aPtr);
sl@0
   199
	TUint32* ptr=(TUint32*)aPtr;		// 32-bit words are nice
sl@0
   200
	const TKeyCol* const end=iEndOfKeys;
sl@0
   201
	const TKeyCol* key=iKeys;
sl@0
   202
	__ASSERT(key<end);
sl@0
   203
	do	{
sl@0
   204
		const TDbCell* cell=aRow.ColCell(key->iOrdinal);
sl@0
   205
		TDbColType type=TDbColType(key->iType);
sl@0
   206
		if (cell->Length()==0)
sl@0
   207
			{	// null column
sl@0
   208
			const TUint K64BitColumnMask=(1u<<EDbColInt64)|(1u<<EDbColReal64)|(1u<<EDbColDateTime);
sl@0
   209
			*ptr++=0;
sl@0
   210
			if (K64BitColumnMask&(1u<<type))
sl@0
   211
				*ptr++=0;		// 8-byte column
sl@0
   212
			continue;
sl@0
   213
			}
sl@0
   214
		switch (type)
sl@0
   215
			{
sl@0
   216
		default:
sl@0
   217
			__ASSERT(0);
sl@0
   218
		case EDbColBit:
sl@0
   219
		case EDbColUint8:
sl@0
   220
		case EDbColUint16:
sl@0
   221
		case EDbColUint32:
sl@0
   222
		case EDbColInt8:
sl@0
   223
		case EDbColInt16:
sl@0
   224
		case EDbColInt32:
sl@0
   225
		case EDbColReal32:
sl@0
   226
			*ptr++=*(const TUint32*)cell->Data();
sl@0
   227
			break;
sl@0
   228
		case EDbColInt64:
sl@0
   229
		case EDbColDateTime:
sl@0
   230
		case EDbColReal64:
sl@0
   231
			{
sl@0
   232
			const TUint32* data=(const TUint32*)cell->Data();
sl@0
   233
			*ptr++=*data++;
sl@0
   234
			*ptr++=*data;
sl@0
   235
			}
sl@0
   236
			break;
sl@0
   237
		case EDbColText8:
sl@0
   238
			{
sl@0
   239
			TInt size=cell->Length();
sl@0
   240
			*(TUint8*)ptr=TUint8(size);
sl@0
   241
			ptr=(TUint32*)Align4(Mem::Copy(PtrAdd(ptr,1),cell->Data(),size));
sl@0
   242
			}
sl@0
   243
			break;
sl@0
   244
		case EDbColText16:
sl@0
   245
			{
sl@0
   246
			TInt size=cell->Length();
sl@0
   247
			*(TUint16*)ptr=TUint16(size>>1);
sl@0
   248
			ptr=(TUint32*)Align4(Mem::Copy(PtrAdd(ptr,2),cell->Data(),size));
sl@0
   249
			}
sl@0
   250
			break;
sl@0
   251
		case EDbColLongText8:
sl@0
   252
		case EDbColLongText16:
sl@0
   253
			{
sl@0
   254
			const TDbBlob& blob=*(const TDbBlob*)cell->Data();
sl@0
   255
			TInt size=blob.Size();
sl@0
   256
			if (blob.IsInline())
sl@0
   257
				{
sl@0
   258
				*ptr++=size;
sl@0
   259
				ptr=(TUint32*)Align4(Mem::Copy(ptr,blob.Data(),size));
sl@0
   260
				}
sl@0
   261
			else
sl@0
   262
				{
sl@0
   263
				TInt rsize=size;
sl@0
   264
				if (size>TBlobKey::ETruncSize)
sl@0
   265
					{
sl@0
   266
					size|=TBlobKey::ETrunc;
sl@0
   267
					rsize=TBlobKey::ETruncSize;
sl@0
   268
					}
sl@0
   269
				*ptr++=size;
sl@0
   270
				BlobLC(blob.Id(),TDbColType(key->iType))->ReadL(ptr,rsize);
sl@0
   271
				CleanupStack::PopAndDestroy();
sl@0
   272
				ptr=Align4(PtrAdd(ptr,rsize));
sl@0
   273
				if (size&TBlobKey::ETrunc)
sl@0
   274
					*ptr++=blob.Id();
sl@0
   275
				}
sl@0
   276
			}
sl@0
   277
			break;
sl@0
   278
			}
sl@0
   279
		} while (++key<end);
sl@0
   280
	return ptr;
sl@0
   281
	}
sl@0
   282
sl@0
   283
TInt CDbOrderByStage::HOrdering::CompareLongText8L( const CDbOrderByStage::HOrdering::TBlobKey& aLeft, const CDbOrderByStage::HOrdering::TBlobKey& aRight ) const
sl@0
   284
	{
sl@0
   285
	TUint sizel = aLeft.iSize;
sl@0
   286
	TUint sizer = aRight.iSize;
sl@0
   287
	TUint s = sizel;
sl@0
   288
	if ( sizer < s )
sl@0
   289
		s = sizer;
sl@0
   290
	if ( s > static_cast<TUint>( TBlobKey::ETruncSize ) && ( ( sizel | sizer ) & static_cast<TUint>( TBlobKey::ETrunc ) ) )
sl@0
   291
		s = TBlobKey::ETruncSize;
sl@0
   292
	TInt rr = iTextOps.Compare( aLeft.iData8, s, aRight.iData8, s );
sl@0
   293
	if ( rr )
sl@0
   294
		return rr;
sl@0
   295
//
sl@0
   296
// matches up to the same-length inlined data...
sl@0
   297
// now it gets interesting
sl@0
   298
//
sl@0
   299
	if ( ( ( sizel | sizer ) & static_cast<TUint>( TBlobKey::ETrunc ) ) == 0 )
sl@0
   300
		return sizel - sizer;		// neither are truncated
sl@0
   301
	if ( s == sizel )
sl@0
   302
		return -1;		// left completely match against truncated right
sl@0
   303
	if ( s == sizer )
sl@0
   304
		return 1;		// right completely matched against truncated left
sl@0
   305
sl@0
   306
	s = Min( TInt( sizel & ~TBlobKey::ETrunc ), TInt( sizer & ~TBlobKey::ETrunc ) );		// minimum real length
sl@0
   307
	if ( sizel & static_cast<TUint>( TBlobKey::ETrunc ) )
sl@0
   308
		{
sl@0
   309
		MStreamBuf& bufL = *BlobLC( aLeft.iId, EDbColLongText8 );
sl@0
   310
		if ( sizer & static_cast<TUint>( TBlobKey::ETrunc ) )
sl@0
   311
			{	// both out-of-line
sl@0
   312
			rr = Comp::Compare8L( bufL, *BlobLC( aRight.iId, EDbColLongText8 ), s, iTextOps );
sl@0
   313
			CleanupStack::PopAndDestroy();
sl@0
   314
			}
sl@0
   315
		else	// left side only out-of-line
sl@0
   316
			rr = Comp::Compare8L( bufL, aRight.iData8, s, iTextOps );
sl@0
   317
		}
sl@0
   318
	else
sl@0
   319
		{	// right side only out-of-line
sl@0
   320
		__ASSERT( sizer & static_cast<TUint>( TBlobKey::ETrunc ) );
sl@0
   321
		rr = -Comp::Compare8L( *BlobLC( aRight.iId, EDbColLongText8 ), aLeft.iData8, s, iTextOps );
sl@0
   322
		}
sl@0
   323
	CleanupStack::PopAndDestroy();
sl@0
   324
	return rr ? rr : ( sizel & ~TBlobKey::ETrunc ) - ( sizer & ~TBlobKey::ETrunc );
sl@0
   325
	}
sl@0
   326
sl@0
   327
TInt CDbOrderByStage::HOrdering::CompareLongText16L( const CDbOrderByStage::HOrdering::TBlobKey& aLeft, const CDbOrderByStage::HOrdering::TBlobKey& aRight ) const
sl@0
   328
	{
sl@0
   329
	TUint sizeL = aLeft.iSize  & ~TBlobKey::ETrunc; // set truncation bit to 0 to get true size
sl@0
   330
	TUint sizeR = aRight.iSize & ~TBlobKey::ETrunc;
sl@0
   331
	TBool truncL = aLeft.iSize  & TBlobKey::ETrunc; // data is truncated if TBlobKey::ETrunc bit is 1
sl@0
   332
	TBool truncR = aRight.iSize & TBlobKey::ETrunc;
sl@0
   333
	
sl@0
   334
	if (!(truncL | truncR)) // neither side is truncated, compare full strings
sl@0
   335
		{		
sl@0
   336
		return iTextOps.Order( aLeft.iData16, sizeL>>1, aRight.iData16, sizeR>>1 );
sl@0
   337
		}
sl@0
   338
		
sl@0
   339
	TInt result;
sl@0
   340
	TUint sizeMin = Min( TInt(sizeL), TInt(sizeR) ); // minimum real length
sl@0
   341
	if ( truncL )
sl@0
   342
		{
sl@0
   343
		MStreamBuf& bufL = *BlobLC( aLeft.iId, EDbColLongText16 );
sl@0
   344
		if ( truncR )
sl@0
   345
			{	// both out-of-line
sl@0
   346
			result = Comp::Compare16L( bufL, *BlobLC( aRight.iId, EDbColLongText16 ), sizeMin, iTextOps );
sl@0
   347
			CleanupStack::PopAndDestroy();
sl@0
   348
			}
sl@0
   349
		else	// left side only out-of-line
sl@0
   350
			result = Comp::Compare16L( bufL, aRight.iData16, sizeMin, iTextOps );
sl@0
   351
		}
sl@0
   352
	else
sl@0
   353
		{	// right side only out-of-line
sl@0
   354
		__ASSERT( truncR );
sl@0
   355
		result = -Comp::Compare16L( *BlobLC( aRight.iId, EDbColLongText16 ), aLeft.iData16, sizeMin, iTextOps );
sl@0
   356
		}
sl@0
   357
	CleanupStack::PopAndDestroy();
sl@0
   358
	return result ? result : ( sizeL ) - ( sizeR );
sl@0
   359
	}
sl@0
   360
sl@0
   361
TInt CDbOrderByStage::HOrdering::CompareL(const TAny* aLeft,const TAny* aRight) const
sl@0
   362
//
sl@0
   363
// compare the keys
sl@0
   364
//
sl@0
   365
	{
sl@0
   366
	
sl@0
   367
    __ASSERT(aLeft != NULL);
sl@0
   368
    __ASSERT(aRight != NULL);
sl@0
   369
sl@0
   370
	const TUint8* left=(const TUint8*)aLeft;
sl@0
   371
	const TUint8* right=(const TUint8*)aRight;
sl@0
   372
	const TKeyCol* end=iEndOfKeys;
sl@0
   373
	const TKeyCol* key=&iKeys[0];
sl@0
   374
	TInt rr;
sl@0
   375
	for (;;)
sl@0
   376
		{
sl@0
   377
		switch (key->iType)
sl@0
   378
			{
sl@0
   379
		default:
sl@0
   380
			__ASSERT(0);
sl@0
   381
		case EDbColBit:
sl@0
   382
		case EDbColUint8:
sl@0
   383
		case EDbColUint16:
sl@0
   384
		case EDbColUint32:
sl@0
   385
			rr=Comp::Compare(*(const TUint32*)left,*(const TUint32*)right);
sl@0
   386
			left+=sizeof(TUint32);
sl@0
   387
			right+=sizeof(TUint32);
sl@0
   388
			break;
sl@0
   389
		case EDbColInt8:
sl@0
   390
		case EDbColInt16:
sl@0
   391
		case EDbColInt32:
sl@0
   392
			rr=Comp::Compare(*(const TInt32*)left,*(const TInt32*)right);
sl@0
   393
			left+=sizeof(TInt32);
sl@0
   394
			right+=sizeof(TInt32);
sl@0
   395
			break;
sl@0
   396
		case EDbColInt64:
sl@0
   397
			rr=Comp::Compare(*(const TInt64*)left,*(const TInt64*)right);
sl@0
   398
			left+=sizeof(TInt64);
sl@0
   399
			right+=sizeof(TInt64);
sl@0
   400
			break;
sl@0
   401
		case EDbColDateTime:
sl@0
   402
			rr=Comp::Compare(*(const TTime*)left,*(const TTime*)right);
sl@0
   403
			left+=sizeof(TTime);
sl@0
   404
			right+=sizeof(TTime);
sl@0
   405
			break;
sl@0
   406
		case EDbColReal32:
sl@0
   407
			rr=Comp::Compare(*(const TReal32*)left,*(const TReal32*)right);
sl@0
   408
			left+=sizeof(TReal32);
sl@0
   409
			right+=sizeof(TReal32);
sl@0
   410
			break;
sl@0
   411
		case EDbColReal64:
sl@0
   412
			rr=Comp::Compare(*(const TReal64*)left,*(const TReal64*)right);
sl@0
   413
			left+=sizeof(TReal64);
sl@0
   414
			right+=sizeof(TReal64);
sl@0
   415
			break;
sl@0
   416
		case EDbColText8:
sl@0
   417
			{
sl@0
   418
			TInt sizel=*left++;
sl@0
   419
			TInt sizer=*right++;
sl@0
   420
			rr=iTextOps.Compare(left,sizel,right,sizer);
sl@0
   421
			left=Align4(left+sizel);
sl@0
   422
			right=Align4(right+sizer);
sl@0
   423
			}
sl@0
   424
			break;
sl@0
   425
		case EDbColText16:
sl@0
   426
			{
sl@0
   427
			const TUint16* l16=reinterpret_cast<const TUint16*>(left);
sl@0
   428
			const TUint16* r16=reinterpret_cast<const TUint16*>(right);
sl@0
   429
			TInt sizel=*l16++;
sl@0
   430
			TInt sizer=*r16++;
sl@0
   431
			rr=iTextOps.Order(l16,sizel,r16,sizer);
sl@0
   432
			left=Align4(reinterpret_cast<const TUint8*>(l16+sizel));
sl@0
   433
			right=Align4(reinterpret_cast<const TUint8*>(r16+sizer));
sl@0
   434
			}
sl@0
   435
			break;
sl@0
   436
		case EDbColLongText8:
sl@0
   437
			{
sl@0
   438
			const TBlobKey* ltext=(const TBlobKey*)left;
sl@0
   439
			const TBlobKey* rtext=(const TBlobKey*)right;
sl@0
   440
			rr=CompareLongText8L(*ltext,*rtext);
sl@0
   441
			left+=ltext->Size();
sl@0
   442
			right+=rtext->Size();
sl@0
   443
			}
sl@0
   444
			break;
sl@0
   445
		case EDbColLongText16:
sl@0
   446
			{
sl@0
   447
			const TBlobKey* ltext=(const TBlobKey*)left;
sl@0
   448
			const TBlobKey* rtext=(const TBlobKey*)right;
sl@0
   449
			rr=CompareLongText16L(*ltext,*rtext);
sl@0
   450
			left+=ltext->Size();
sl@0
   451
			right+=rtext->Size();
sl@0
   452
			}
sl@0
   453
			break;
sl@0
   454
			}
sl@0
   455
		if (rr!=0)
sl@0
   456
			break;
sl@0
   457
		if (++key==end)
sl@0
   458
			break;
sl@0
   459
		}
sl@0
   460
	return key->iOrder==TDbKeyCol::EAsc ? rr : -rr;
sl@0
   461
	}
sl@0
   462
sl@0
   463
//
sl@0
   464
sl@0
   465
NONSHARABLE_CLASS(CDbOrderByStage::CKeys) : public CBase
sl@0
   466
	{
sl@0
   467
public:		// should be private but VC++ 4.0 whinges
sl@0
   468
	struct TKey
sl@0
   469
		{
sl@0
   470
		TUint32 iId;
sl@0
   471
		TUint8 iKey[4];		// and then some
sl@0
   472
		};
sl@0
   473
private:
sl@0
   474
	enum {EKeysGranularity=32};
sl@0
   475
	struct TPage
sl@0
   476
		{
sl@0
   477
		TPage* iNext;
sl@0
   478
		TKey iEntries[1];
sl@0
   479
		};
sl@0
   480
	enum {EMinPageSize=0x200,EMinKeyElements=2};
sl@0
   481
public:
sl@0
   482
	CKeys(TInt aMaxKeySize);
sl@0
   483
	~CKeys();
sl@0
   484
//
sl@0
   485
	void AddL(TDbRecordId aRecordId,const RDbTableRow& aRow,const HOrdering& aOrder);
sl@0
   486
	void SortL(const HOrdering& aOrder);
sl@0
   487
	void GetRecordsL(CArrayFix<TDbRecordId>& aRecords);
sl@0
   488
#ifdef _CHECK_ORDERING
sl@0
   489
	void VerifyOrderingL(const HOrdering& aOrder);
sl@0
   490
#endif
sl@0
   491
private:
sl@0
   492
	void SortL(TKey* aData[],TInt aElem,const HOrdering& aOrder);
sl@0
   493
	TKey& NewKeyL();
sl@0
   494
	void KeyComplete(TAny* aEnd);
sl@0
   495
	void Release();
sl@0
   496
private:
sl@0
   497
	RPointerArray<TKey> iKeys;
sl@0
   498
	TInt iMaxKeySize;
sl@0
   499
	TInt iPageSize;
sl@0
   500
	TPage* iPages;
sl@0
   501
	TKey* iNext;
sl@0
   502
	TKey* iEnd;
sl@0
   503
	};
sl@0
   504
sl@0
   505
// Class CDbOrderByStage::CKeys
sl@0
   506
sl@0
   507
CDbOrderByStage::CKeys::CKeys(TInt aMaxKeySize)
sl@0
   508
	:iKeys(EKeysGranularity),iMaxKeySize(_FOFF(TKey,iKey[aMaxKeySize])),
sl@0
   509
	 iPageSize(Max(EMinPageSize+iMaxKeySize,iMaxKeySize*EMinKeyElements))
sl@0
   510
	{}
sl@0
   511
sl@0
   512
CDbOrderByStage::CKeys::~CKeys()
sl@0
   513
	{
sl@0
   514
	iKeys.Close();
sl@0
   515
	Release();
sl@0
   516
	}
sl@0
   517
sl@0
   518
void CDbOrderByStage::CKeys::SortL(CDbOrderByStage::CKeys::TKey* aData[],TInt aElem,const HOrdering& aOrder)
sl@0
   519
//
sl@0
   520
// Sort the array of row keys
sl@0
   521
// Uses Heap-sort
sl@0
   522
//
sl@0
   523
	{
sl@0
   524
	__ASSERT(aElem>1);
sl@0
   525
	TInt heap=aElem>>1;
sl@0
   526
	--aElem;
sl@0
   527
	for (;;)
sl@0
   528
		{
sl@0
   529
		TKey* key;
sl@0
   530
		if (heap!=0)
sl@0
   531
			key=aData[--heap];
sl@0
   532
		else
sl@0
   533
			{
sl@0
   534
			key=aData[aElem];
sl@0
   535
			aData[aElem]=aData[0];
sl@0
   536
			if (--aElem==0)
sl@0
   537
				{
sl@0
   538
				aData[0]=key;
sl@0
   539
				break;
sl@0
   540
				}
sl@0
   541
			}
sl@0
   542
		TInt ix=heap;
sl@0
   543
		TInt parent;
sl@0
   544
		for (parent=ix;;parent=ix)
sl@0
   545
			{
sl@0
   546
			ix=(ix<<1)+1;
sl@0
   547
			if (ix<=aElem)
sl@0
   548
				{
sl@0
   549
				if (ix<aElem && aOrder.CompareL(aData[ix]->iKey,aData[ix+1]->iKey)<0)
sl@0
   550
					++ix;
sl@0
   551
				}
sl@0
   552
			else
sl@0
   553
				break;
sl@0
   554
			if (aOrder.CompareL(aData[ix]->iKey,key->iKey)<=0)
sl@0
   555
				break;
sl@0
   556
			aData[parent]=aData[ix];
sl@0
   557
			}
sl@0
   558
		aData[parent]=key;
sl@0
   559
		}
sl@0
   560
	}
sl@0
   561
sl@0
   562
void CDbOrderByStage::CKeys::AddL(TDbRecordId aRecordId,const RDbTableRow& aRow,const HOrdering& aOrder)
sl@0
   563
//
sl@0
   564
// Create a key for the row and store it
sl@0
   565
//
sl@0
   566
	{
sl@0
   567
	TKey& key=NewKeyL();
sl@0
   568
	key.iId=aRecordId.Value();
sl@0
   569
	TAny* end=aOrder.EntryL(&key.iKey[0],aRow);
sl@0
   570
	__LEAVE_IF_ERROR(iKeys.Append(&key));
sl@0
   571
	KeyComplete(end);
sl@0
   572
	}
sl@0
   573
sl@0
   574
void CDbOrderByStage::CKeys::SortL(const HOrdering& aOrder)
sl@0
   575
	{
sl@0
   576
	TInt elem=iKeys.Count();
sl@0
   577
	if (elem>1)
sl@0
   578
		SortL(&iKeys[0],elem,aOrder);
sl@0
   579
	}
sl@0
   580
sl@0
   581
void CDbOrderByStage::CKeys::GetRecordsL(CArrayFix<TDbRecordId>& aRecords)
sl@0
   582
	{
sl@0
   583
	TInt elem=iKeys.Count();
sl@0
   584
	if (elem==0)
sl@0
   585
		return;
sl@0
   586
	TKey** const base=&iKeys[0];
sl@0
   587
	TKey** ptr=base+elem;
sl@0
   588
	do	{
sl@0
   589
		--ptr;
sl@0
   590
		*REINTERPRET_CAST(TDbRecordId*,ptr)=(*ptr)->iId;
sl@0
   591
		} while (ptr>base);
sl@0
   592
	Release();		// discard key memory before adding records
sl@0
   593
	aRecords.InsertL(0,REINTERPRET_CAST(const TDbRecordId*,base),elem);
sl@0
   594
	iKeys.Reset();
sl@0
   595
	}
sl@0
   596
sl@0
   597
void CDbOrderByStage::CKeys::Release()
sl@0
   598
//
sl@0
   599
// Discard all of the allocated pages
sl@0
   600
//
sl@0
   601
	{
sl@0
   602
	TPage* p=iPages;
sl@0
   603
	while (p)
sl@0
   604
		{
sl@0
   605
		TPage* n=p->iNext;
sl@0
   606
		User::Free(p);
sl@0
   607
		p=n;
sl@0
   608
		}
sl@0
   609
	iPages=0;
sl@0
   610
	iNext=iEnd=0;
sl@0
   611
	}
sl@0
   612
sl@0
   613
CDbOrderByStage::CKeys::TKey& CDbOrderByStage::CKeys::NewKeyL()
sl@0
   614
//
sl@0
   615
// Allocate a key entry for the raw key data
sl@0
   616
//
sl@0
   617
	{
sl@0
   618
	TKey* p=iNext;
sl@0
   619
	if (PtrAdd(p,iMaxKeySize)>iEnd)
sl@0
   620
		{	// not enough space for a maximum key
sl@0
   621
		TPage* page=iPages;
sl@0
   622
		if (page)
sl@0
   623
			{	// compress the current page
sl@0
   624
			__DEBUG(page=(TPage*))User::ReAlloc(page,(TUint8*)iNext-(TUint8*)page);
sl@0
   625
			__ASSERT(page==iPages);		// if it moves we are dead
sl@0
   626
			}
sl@0
   627
		page=(TPage*)User::AllocL(_FOFF(TPage,iEntries)+iPageSize);
sl@0
   628
		page->iNext=iPages;
sl@0
   629
		iPages=page;
sl@0
   630
		p=iNext=&page->iEntries[0];
sl@0
   631
		iEnd=PtrAdd(p,iPageSize);
sl@0
   632
		}
sl@0
   633
	return *p;
sl@0
   634
	}
sl@0
   635
sl@0
   636
void CDbOrderByStage::CKeys::KeyComplete(TAny* aEnd)
sl@0
   637
//
sl@0
   638
// Key is complete, prepare for the next one
sl@0
   639
//
sl@0
   640
	{
sl@0
   641
	__ASSERT(aEnd==Align4(aEnd));
sl@0
   642
	__ASSERT(iNext<=aEnd&&aEnd<=iEnd);
sl@0
   643
	iNext=STATIC_CAST(TKey*,aEnd);
sl@0
   644
	}
sl@0
   645
sl@0
   646
#ifdef _CHECK_ORDERING
sl@0
   647
void CDbOrderByStage::CKeys::VerifyOrderingL(const HOrdering& aOrder)
sl@0
   648
	{
sl@0
   649
// this performs a full O(N*N) comparison of the record set
sl@0
   650
	if (iKeys.Count()==0)
sl@0
   651
		return;
sl@0
   652
	TKey* const* data=&iKeys[0];
sl@0
   653
	for (TInt ii=iKeys.Count();--ii>=0;)
sl@0
   654
		{
sl@0
   655
		for (TInt jj=iKeys.Count();--jj>=0;)
sl@0
   656
			{
sl@0
   657
			TInt rr=aOrder.CompareL(data[ii]->iKey,data[jj]->iKey);
sl@0
   658
			if (ii==jj)
sl@0
   659
				__ASSERT_ALWAYS(rr==0,User::Invariant());
sl@0
   660
			else if (ii<jj)
sl@0
   661
				__ASSERT_ALWAYS(rr<=0,User::Invariant());
sl@0
   662
			else
sl@0
   663
				__ASSERT_ALWAYS(rr>=0,User::Invariant());
sl@0
   664
			}
sl@0
   665
		}
sl@0
   666
	}
sl@0
   667
#endif
sl@0
   668
sl@0
   669
// Class CDbOrderByStage
sl@0
   670
sl@0
   671
inline const RDbTableRow& CDbOrderByStage::Row()
sl@0
   672
	{return iRow;}
sl@0
   673
inline CDbOrderByStage::CKeys& CDbOrderByStage::Keys()
sl@0
   674
	{__ASSERT(iKeys);return *iKeys;}
sl@0
   675
inline const CDbOrderByStage::HOrdering& CDbOrderByStage::Order()
sl@0
   676
	{__ASSERT(iOrder);return *iOrder;}
sl@0
   677
sl@0
   678
CDbOrderByStage::CDbOrderByStage(const RDbTableRow& aRow)
sl@0
   679
	: CDbBasicWindowStage(KDbUnlimitedWindow),iRow(aRow)
sl@0
   680
	{
sl@0
   681
	__ASSERT(iState==EReset);
sl@0
   682
	}
sl@0
   683
sl@0
   684
CDbOrderByStage::~CDbOrderByStage()
sl@0
   685
	{
sl@0
   686
	delete iOrder;
sl@0
   687
	delete iKeys;
sl@0
   688
	}
sl@0
   689
sl@0
   690
void CDbOrderByStage::ConstructL(const CDbKey& aOrderBy)
sl@0
   691
//
sl@0
   692
// Build the key structures to support the partial and complete ordering
sl@0
   693
//
sl@0
   694
	{
sl@0
   695
	iOrder=HOrdering::NewL(Row().Table(),aOrderBy);
sl@0
   696
	}
sl@0
   697
sl@0
   698
void CDbOrderByStage::Reset()
sl@0
   699
//
sl@0
   700
// Reset the window to initial state
sl@0
   701
//
sl@0
   702
	{
sl@0
   703
	delete iKeys;
sl@0
   704
	iKeys=0;
sl@0
   705
	iState=EReset;
sl@0
   706
	CDbBasicWindowStage::Reset();
sl@0
   707
	}
sl@0
   708
sl@0
   709
TBool CDbOrderByStage::ReadL(TInt& aWork,TDbPosition aNext)
sl@0
   710
//
sl@0
   711
// Read some more record keys
sl@0
   712
//
sl@0
   713
	{
sl@0
   714
	TDbRecordId id(KDbNullRecordIdValue);
sl@0
   715
	TGoto r;
sl@0
   716
	while ((r=CDbDataStage::GotoL(aWork,aNext,id))==ESuccess)
sl@0
   717
		{
sl@0
   718
		CDbDataStage::ReadRowL(id);
sl@0
   719
		Keys().AddL(id,Row(),Order());
sl@0
   720
		aNext=EDbNext;
sl@0
   721
		}
sl@0
   722
	switch (r)
sl@0
   723
		{
sl@0
   724
	default:
sl@0
   725
		__ASSERT(0);
sl@0
   726
	case ESynchFailure:
sl@0
   727
		__LEAVE(KErrNotReady);
sl@0
   728
	case EExhausted:
sl@0
   729
		return ETrue;
sl@0
   730
	case ENoRow:
sl@0
   731
		return EFalse;
sl@0
   732
		}
sl@0
   733
	}
sl@0
   734
sl@0
   735
TBool CDbOrderByStage::DoEvaluateL(TInt& aWork)
sl@0
   736
//
sl@0
   737
// Build the key collection, and finally sort it
sl@0
   738
//
sl@0
   739
	{
sl@0
   740
	TState s=iState;
sl@0
   741
	iState=EFailed;
sl@0
   742
	switch (s)
sl@0
   743
		{
sl@0
   744
	default:
sl@0
   745
		__ASSERT(0);
sl@0
   746
	case EFailed:
sl@0
   747
		__LEAVE(KErrNotReady);
sl@0
   748
	case EReset:
sl@0
   749
		__ASSERT(!iKeys);
sl@0
   750
		iKeys=new(ELeave) CKeys(Order().MaxSize());
sl@0
   751
		// drop through to EEvaluate
sl@0
   752
	case EEvaluate:
sl@0
   753
		if (ReadL(aWork,s==EReset ? EDbFirst : EDbNext))
sl@0
   754
			{
sl@0
   755
			iState=EEvaluate;
sl@0
   756
			return ETrue;
sl@0
   757
			}
sl@0
   758
		// drop through to ESort
sl@0
   759
	case ESort:
sl@0
   760
		Keys().SortL(Order());
sl@0
   761
#ifdef _CHECK_ORDERING
sl@0
   762
		Keys().VerifyOrderingL(Order());
sl@0
   763
#endif
sl@0
   764
		// drop through to EAdd
sl@0
   765
	case EAdd:
sl@0
   766
		Keys().GetRecordsL(iRecords);
sl@0
   767
		delete iKeys;
sl@0
   768
		iKeys=0;
sl@0
   769
		// drop through to EComplete
sl@0
   770
	case EComplete:
sl@0
   771
		iState=EComplete;
sl@0
   772
		return EFalse;
sl@0
   773
		}
sl@0
   774
	}
sl@0
   775
sl@0
   776
TBool CDbOrderByStage::Unevaluated()
sl@0
   777
//
sl@0
   778
// Return whether it is worth Evaluating
sl@0
   779
//
sl@0
   780
	{
sl@0
   781
	if (iState==EComplete)
sl@0
   782
		return CDbDataStage::Unevaluated();
sl@0
   783
	return iState!=EFailed;
sl@0
   784
	}
sl@0
   785
sl@0
   786
sl@0
   787
// Class CDbReorderWindowStage
sl@0
   788
sl@0
   789
CDbReorderWindowStage::CDbReorderWindowStage()
sl@0
   790
	: CDbBasicWindowStage(KDbUnlimitedWindow),iRows(EGranularity)
sl@0
   791
	{
sl@0
   792
	__ASSERT(iState==EReset);
sl@0
   793
	}
sl@0
   794
sl@0
   795
CDbReorderWindowStage::~CDbReorderWindowStage()
sl@0
   796
	{
sl@0
   797
	iRows.Close();
sl@0
   798
	}
sl@0
   799
sl@0
   800
void CDbReorderWindowStage::Reset()
sl@0
   801
//
sl@0
   802
// Reset the window to initial state
sl@0
   803
//
sl@0
   804
	{
sl@0
   805
	iRows.Reset();
sl@0
   806
	iState=EReset;
sl@0
   807
	CDbBasicWindowStage::Reset();
sl@0
   808
	}
sl@0
   809
sl@0
   810
TBool CDbReorderWindowStage::ReadL(TInt& aWork,TDbPosition aNext)
sl@0
   811
//
sl@0
   812
// Read some more row ids
sl@0
   813
//
sl@0
   814
	{
sl@0
   815
	TDbRecordId id(KDbNullRecordIdValue);
sl@0
   816
	TGoto r;
sl@0
   817
	while ((r=CDbDataStage::GotoL(aWork,aNext,id))==ESuccess)
sl@0
   818
		{
sl@0
   819
		__LEAVE_IF_ERROR(iRows.Append(id.Value()));
sl@0
   820
		aNext=EDbNext;
sl@0
   821
		}
sl@0
   822
	switch (r)
sl@0
   823
		{
sl@0
   824
	default:
sl@0
   825
		__ASSERT(0);
sl@0
   826
	case ESynchFailure:
sl@0
   827
		__LEAVE(KErrNotReady);
sl@0
   828
	case EExhausted:
sl@0
   829
		return ETrue;
sl@0
   830
	case ENoRow:
sl@0
   831
		return EFalse;
sl@0
   832
		}
sl@0
   833
	}
sl@0
   834
sl@0
   835
TBool CDbReorderWindowStage::DoEvaluateL(TInt& aWork)
sl@0
   836
//
sl@0
   837
// Build the key collection, and finally sort it
sl@0
   838
//
sl@0
   839
	{
sl@0
   840
	TState s=iState;
sl@0
   841
	iState=EFailed;
sl@0
   842
	switch (s)
sl@0
   843
		{
sl@0
   844
	default:
sl@0
   845
		__ASSERT(0);
sl@0
   846
	case EFailed:
sl@0
   847
		__LEAVE(KErrNotReady);
sl@0
   848
	case EReset:
sl@0
   849
	case EEvaluate:
sl@0
   850
		if (ReadL(aWork,s==EReset ? EDbFirst : EDbNext))
sl@0
   851
			{
sl@0
   852
			iState=EEvaluate;
sl@0
   853
			return ETrue;
sl@0
   854
			}
sl@0
   855
		if (iRows.Count())
sl@0
   856
			{
sl@0
   857
			iRows.Sort();
sl@0
   858
			iRecords.AppendL((const TDbRecordId*)&iRows[0],iRows.Count());
sl@0
   859
			iRows.Reset();
sl@0
   860
			}
sl@0
   861
		// coverity[fallthrough]
sl@0
   862
	case EComplete:
sl@0
   863
		iState=EComplete;
sl@0
   864
		return EFalse;
sl@0
   865
		}
sl@0
   866
	}
sl@0
   867
sl@0
   868
TBool CDbReorderWindowStage::Unevaluated()
sl@0
   869
//
sl@0
   870
// Return whether it is worth Evaluating
sl@0
   871
//
sl@0
   872
	{
sl@0
   873
	if (iState==EComplete)
sl@0
   874
		return CDbDataStage::Unevaluated();
sl@0
   875
	return iState!=EFailed;
sl@0
   876
	}
sl@0
   877