// 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:
// SQL Literal value and node classes
// 
//

#include "UQ_STD.H"

// internalising literal strings, overload selectors

inline HBufC8* Alloc8L(const TDesC8& aDes)
	{return aDes.AllocL();}
inline HBufC8* Alloc8L(const TDesC16& aDes)
	{HBufC8* cell=HBufC8::NewL(aDes.Length());cell->Des().Copy(aDes);return cell;}
inline HBufC16* Alloc16L(const TDesC16& aDes)
	{return aDes.AllocL();}
inline HBufC16* Alloc16L(const TDesC8& aDes)
	{HBufC16* cell=HBufC16::NewL(aDes.Length());cell->Des().Copy(aDes);return cell;}

template <class B,class T>
inline B* DoInternString(B* aBuf,T*)
	{
	const T* base=aBuf->Ptr();
	const T* from=base;
	const T* end=base+aBuf->Length();
	for (;;)
		{
		if (from==end)
			return aBuf;
		if (*from++=='\'')
			break;
		}
	T* to=(T*)from;
	++from;
	while (from<end)
		{
		T c=*from++;
		if (c=='\'')
			++from;
		*to++=c;
		}
	aBuf->Des().SetLength(to-base);
	return aBuf;
	}

template <class B>
inline B* InternString(B* aBuf)
	{return DoInternString(aBuf,PtrType(*aBuf));}

// Class RSqlLiteral

void RSqlLiteral::Close()
//
// Free any allocated cell
//
	{
	if(iBuffer)
		delete iBuffer;
	if (IsAlloc())
		User::Free(iVal.iAlloc);
		
	}

void RSqlLiteral::ToInt32L()
//
// Convert a numeric type to Int32
//
	{
	ToInt64L();
	const TInt64& v=iVal.iInt64;
	TInt32 l = I64LOW(v);
	TInt32 h = I64HIGH(v);
	if (h==(l>>31))	// domain check, in signed 32-bit range
		{
		iVal.iInt32=l;
		iType=EInt32;
		}
	else
		__LEAVE(KErrOverflow);	// cannot convert
	}

void RSqlLiteral::ToUint32L()
//
// Convert a numeric type to Uint32
//
	{
	ToInt64L();
	const TInt64& v=iVal.iInt64;
	if (I64HIGH(v)==0)		// domain check, in unsigned 32-bit range
		{
		iVal.iUint32 = I64LOW(v);
		iType=EUint32;
		}
	else
		__LEAVE(KErrOverflow);	// cannot convert
	}

void RSqlLiteral::ToInt64L()
//
// Convert a numeric type to int64
//
	{
	__ASSERT(IsBasic());	// only apply conversions once
	TType t=iType;
	if (t==EReal64)
		{
		iVal.iInt64() = static_cast<TInt64>(Real64());
		iType=EInt64;
		}
	else if (t!=EInt64)
		__LEAVE(KErrGeneral);
	}

void RSqlLiteral::ToReal64L()
//
// Convert a numeric type to real64
//
	{
	__ASSERT(IsBasic());	// only apply conversions once
	TType t=iType;
	if (t==EInt64)
		{
		iVal.iReal64=I64REAL(Int64());
		iType=EReal64;
		}
	else if (t!=EReal64)
		__LEAVE(KErrGeneral);
	}

void RSqlLiteral::ToReal32L()
//
// Convert a numeric type to real32
//
	{
	ToReal64L();
	__LEAVE_IF_ERROR(TRealX(iVal.iReal64).GetTReal(iVal.iReal32));
	iType=EReal32;
	}

void RSqlLiteral::ToTimeL()
//
// Ensure we are a time
//
	{
	__ASSERT(IsBasic());	// only apply conversions once
	if (iType!=ETime)
		__LEAVE(KErrGeneral);	// type mismatch
	}

void RSqlLiteral::ToText8L()
//
// Convert a ptr to a text8
//
	{
	__ASSERT(IsBasic());	// only apply conversions once
	if (iType==EPtr)
		{
		iVal.iAlloc=InternString(Alloc8L(DesC()));
		iType=EBuf8;
		}
	else
		__LEAVE(KErrGeneral);	// type mismatch
	}

void RSqlLiteral::ToText16L()
//
// Convert a ptr to a text8
//
	{
	__ASSERT(IsBasic());	// only apply conversions once
	if (iType==EPtr)
		{
		iVal.iAlloc=InternString(Alloc16L(DesC()));
		iType=EBuf16;
		}
	else
		__LEAVE(KErrGeneral);	// type mismatch
	}

void RSqlLiteral::ToBlobL()
//
// Convert a hex encoded ptr to a blob
//
	{
	__ASSERT(IsBasic());	// only apply conversions once
	if (iType==EBlob)
		{
		RBuf8 blobBuf;
		HBufC* buf = Alloc16L(DesC());
		CleanupStack::PushL(buf);
		HexDecodeL(*buf, blobBuf);
		CleanupStack::PopAndDestroy(buf);
		iVal.iAlloc=Alloc8L(blobBuf);
		blobBuf.Close();
		iType=EBlob;
		}
	else
		__LEAVE(KErrGeneral);	// type mismatch
	}



// class CSqlLiteralNode

CSqlLiteralNode::CSqlLiteralNode(TType aType,const TDesC& aColumn,const RSqlLiteral& aLiteral)
	:CSqlBoundNode(aType,aColumn),iLiteral(aLiteral)
	{}

CSqlLiteralNode::~CSqlLiteralNode()
	{
	iLiteral.Close();
	}

void CSqlLiteralNode::BindL(const RDbTableRow& aSource)
	{
	CSqlBoundNode::BindL(aSource);
	switch (ColType())
		{
	default:	// type not allowed in evaluation expressions
		__LEAVE(KErrGeneral);
		break;
	case EDbColBit:
	case EDbColInt8:
	case EDbColUint8:
	case EDbColInt16:
	case EDbColUint16:
	case EDbColInt32:
	case EDbColUint32:
	case EDbColInt64:
		iLiteral.ToInt64L();
		break;
	case EDbColReal32:
	case EDbColReal64:
		iLiteral.ToReal64L();
		break;
	case EDbColDateTime:
		iLiteral.ToTimeL();
		break;
	case EDbColText8:
	case EDbColLongText8:
		iLiteral.ToText8L();
		break;
	case EDbColText16:
	case EDbColLongText16:
		iLiteral.ToText16L();
		break;
	case EDbColBinary:
	case EDbColLongBinary:
		iLiteral.ToBlobL();
		break;
		}
	}
// copy text to buffer for LIKE Escape support
TInt RSqlLiteral::CopyText()
	{
	if (iType==EPtr)
		{
		TInt length = iVal.iPtr.iEnd - iVal.iPtr.iPtr;
		if(iBuffer)
			delete iBuffer;
		if((iBuffer=HBufC::New(length+1)) == NULL)
	        	{
			return KErrNoMemory;
			}
		iBuffer->Des().Copy(iVal.iPtr.iPtr,length);
		iVal.iPtr.iPtr= &iBuffer->Des()[0];
		iBuffer->Des().Append(iVal.iPtr.iEnd,1);
		iVal.iPtr.iEnd=&iBuffer->Des()[length]; 
		}
	else
		return KErrGeneral;	// type mismatch
	return KErrNone;
	}

