diff -r 000000000000 -r bde4ae8d615e os/persistentdata/persistentstorage/dbms/usql/UQ_LIKE.CPP --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/os/persistentdata/persistentstorage/dbms/usql/UQ_LIKE.CPP Fri Jun 15 03:10:57 2012 +0200 @@ -0,0 +1,547 @@ +// 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 Like predicate node +// +// + +#include "UQ_STD.H" + +inline TUint8* TextCopy(TUint8* aDest,const TUint8* aSrc,TInt aLen) + {return Mem::Copy(aDest,aSrc,aLen);} +inline TUint16* TextCopy(TUint16* aDest,const TUint16* aSrc,TInt aLen) + {return (TUint16*)Mem::Copy(aDest,aSrc,aLen<<1);} + +// template Class HMatcherPattern + +template <class T,class D> +inline HMatcherPattern<T,D>* HMatcherPattern<T,D>::Realloc(HMatcherPattern<T,D>* aThis,TInt aSize) + {return STATIC_CAST(TThis*,User::ReAlloc(aThis,_FOFF(TThis,iPattern[aSize])));} + +/** +Creates a HMatcherPattern that converts the pattern into more manageable pieces +based on a delimeter that is the wildcard * (asterisk). + +Characters between * (asterisks) must not number greater than KMaxSegmentLength. +If only one * exists then the length is taken from the start and end of pattern. +If these segments contain ? (question mark) wildcard than they must not number +greater than KMaxSegmentLength-2. + +The user is responsible for the returned pointer's memory. + +@param aPattern The search pattern to match. +@param aEscape ESCAPE clause +@leave KErrNoMemory if no more memory is available. +@leave KErrArgument if the search pattern segment length is greater + than KMaxSegmentLength, +@return The newly constructed pattern pointer. +@see KMaxSegmentLength +*/ +template <class T,class D> +HMatcherPattern<T,D>* HMatcherPattern<T,D>::NewL(const D& aPattern, TBool aEscape) + { + TThis* self=0; + TInt r=Construct(self,aPattern,aEscape); + if (r!=KErrNone) + { + User::Free(self); + __LEAVE(r); + } + return self; + } + +template <class T,class D> +TInt HMatcherPattern<T,D>::MatchL(const D& aDes,const TTextOps& aTextOp) const +// +// Test the pattern against the supplied descriptor +// + { + TDesMatcher<T,D> matcher(aDes); + return matcher.MatchL(*this,aTextOp); + } + +template <class T,class D> +TInt HMatcherPattern<T,D>::MatchL(MStreamBuf& aBuf,TInt aLength,const TTextOps& aTextOp) const +// +// Test the pattern against the supplied stream +// + { + TStreamMatcher<T,D> matcher(aBuf,aLength); + return matcher.MatchL(*this,aTextOp); + } + +/** +Breaks up a given search pattern into manageable segments. + +The pattern is broken into segments. These segments are organised +from the segment delimeter that is the wildcard * (asterisk). +So in effect a segment may contain other wildcards (i.e. ?) or +the entire pattern (no embedded asterisks) as these at least MUST match. + +The cell is created and updated with the segments type and length, and also +the segment itself. + +Not including asterisks, the segment must be no longer than length KMaxSegmentLength. +However, if the segment has a ? (question mark) wildcard within it then the +segment must be no longer than length KMaxSegmentLength-2. + +This is due to the way the Find and Match functions of TDes work. Match understands +wildcards whilst Find does not. + +The match algorithm depends on KMaxSegmentLength being smaller than the +text read buffer, and for efficiency should not be more than half the size +of the read buffer. Also KMaxSegmentLength must currently fit into 8 bits, +as it is embedded into a single character in an 8-bit text matching buffer. +[So increasing KMaxSegmentLength is not a simple exercise.] + +The search is repeated for each segment within the pattern. Increasing the cell +size and inserting each segment and associated segment data. + +On reaching the end of the pattern this data is passed back to the user. +The user is responsible for this returned pointers memory. + +@param aCell On return points to a cell matching this pattern. +@param aPattern The search pattern to match. +@param aEscape ESCAPE clause +@return KErrNoMemory if no memory is available to create or + increase the size of a cell, + KErrArgument if the search pattern segment length is greater + than KMaxSegmentLength, + KErrNone if the match was successful. +@see KMaxSegmentLength +*/ +template <class T,class D> +TInt HMatcherPattern<T,D>::Construct(HMatcherPattern<T,D>*& aCell,const D& aPattern,TBool aEscape) + { + const T* pM=aPattern.Ptr(); + const T* const eM=pM+aPattern.Length(); + TInt size=(eM-pM)+KPatternGranularity; + TThis* self=Realloc(0,size); + if (!self) + return KErrNoMemory; + aCell=self; + T* seg=&self->iPattern[0]; + const T* end=&self->iPattern[size]; + TInt term; // terminating code + + if (eM==pM) + term=ENull; + else + { + term=EStop; + do + { + //Following code is for the implementation of limited-ESCAPE-clause + if(aEscape) + { + const T* here=pM; + TInt len = aPattern.Length(); + if (len>KMaxSegmentLength) + return KErrArgument; + *seg++=T(EEscape ); + *seg++=T(len); + seg=TextCopy(seg,here,len); + break; + } + T m=*pM; + if (m==KMatchAny) + { + term=ESuccess; + do + { + if (++pM==eM) + break; + m=*pM; + } while (m==KMatchAny); + if (pM==eM) + break; + } + const T* here=pM; + TInt type; + if (m==KMatchOne) + { + while (++pM<eM && *pM==KMatchOne) {;} + type=ESkip; + } + else + { + type=0; + while (++pM<eM) + { + m=*pM; + if (m==KMatchAny) + break; + if (m==KMatchOne) + type|=EWild; + } + if (term==EStop) + type|=EBeginning; + else if (pM==eM) + type|=EEnd; + else + { + type|=EMiddle; + if (type&EWild) + { // include '*'s in segment for matching + --here; + ++pM; + } + } + } + *seg++=T(type); + TInt len=pM-here; + if (len>KMaxSegmentLength) + return KErrArgument; + *seg++=T(len); + if (type==ESkip) + len=0; + if (seg+4+len>end) + { + TInt newsize=end-&self->iPattern[0]+KPatternGranularity; + self=Realloc(self,newsize); + if (!self) + return KErrNoMemory; + seg+=&self->iPattern[0]-&aCell->iPattern[0]; + end=&self->iPattern[newsize]; + aCell=self; + } + if (type==(EMiddle|EWild)) + { + *seg++=T(KMatchAny); + ++here; + --len; + } + seg=TextCopy(seg,here,len); + } while (pM<eM); + } + *seg++=T(term); + aCell=Realloc(self,seg-&self->iPattern[0]); + return KErrNone; + } + +// class TMatcher + +template <class T,class D> +TBool TMatcher<T,D>::MatchL(const HMatcherPattern<T,D>& aPattern,const TTextOps& aTextOp) + { + const T* pM=&aPattern.iPattern[0]; + const T* eB; + const T* pB=UnderflowL(eB); + for (;;) + { + TInt segment=*pM; + switch (segment&EMask) + { + case ENull: + return pB==eB; + case ESuccess: + return ETrue; + case EStop: + if (pB==eB) + pB=UnderflowL(eB); + return pB==eB; + case ESkip: + { + TInt len=*++pM; + TInt skip=len+pB-eB; + if (skip>0) + { + pB=UnderflowL(eB)+skip; + if (pB>eB) + return EFalse; + } + else + pB+=len; + ++pM; + } + break; + //Following code is for the implementation of limited-ESCAPE-clause + case EEscape: + { + TInt len=*++pM; + ++pM; + TInt bLen=eB-pB; + if (bLen<len) + return EFalse; + if (aTextOp.Find(pB,bLen,pM,len)<0) + return EFalse; + pM+=len; + pB+=bLen; + } + break; + case EBeginning: + { + TInt len=*++pM; + ++pM; + if (eB-pB<len) + return EFalse; + if (segment&EWild) + { + if (aTextOp.Match(pB,len,pM,len)<0) + return EFalse; + } + else + { + if (aTextOp.Compare(pB,len,pM,len)!=0) + return EFalse; + } + pM+=len; + pB+=len; + } + break; + case EMiddle: + { + TInt len=*++pM; + ++pM; + TInt match=len; + if (segment&EWild) + match-=2; // the number of characters to match + TInt left=eB-pB; + if (left<match) + pB=UnderflowL(eB,left); + for (;;) + { + TInt bLen=eB-pB; + if (bLen<match) + return EFalse; + TInt pos=segment&EWild ? aTextOp.Match(pB,bLen,pM,len) : aTextOp.Find(pB,bLen,pM,len); + if (pos>=0) + { // found it + pB+=pos+match; + break; + } + // not found, next chunk of data please. + pB=UnderflowL(eB,match-1); + } + pM+=len; + } + break; + case EEnd: // match the last segment + { + TInt len=*++pM; + ++pM; + TInt left=eB-pB; + if (left<len) + { + pB=UnderflowL(eB,left); + if (eB-pB<len) + return EFalse; + } + while (eB-pB>len) + pB=UnderflowL(eB,len); + if (segment&EWild) + { + if (aTextOp.Match(pB,len,pM,len)<0) + return EFalse; + } + else + { + if (aTextOp.Compare(pB,len,pM,len)!=0) + return EFalse; + } + } + return ETrue; + } + } + } + +// Class TDesMatcher + +template <class T,class D> +inline TDesMatcher<T,D>::TDesMatcher(const D& aDes) + {iEnd=(iPtr=aDes.Ptr())+aDes.Length();} + +template <class T,class D> +const T* TDesMatcher<T,D>::UnderflowL(const T*& aEnd,TInt aRetain) + { + const T* ptr=iPtr-aRetain; + aEnd=iPtr=iEnd; + return ptr; + } + +// Class TStreamMatcher + +template <class T,class D> +inline TStreamMatcher<T,D>::TStreamMatcher(MStreamBuf& aStreamBuf,TInt aLength) + :iStream(&aStreamBuf),iRemain(aLength),iEnd(&iBuffer[EBufSize]) + {} + +template <class T,class D> +const T* TStreamMatcher<T,D>::UnderflowL(const T*& aEnd,TInt aRetain) + { + if (iRemain==0) + { // no more stream data, don't move etc. + aEnd=iEnd; + return iEnd-aRetain; + } + else + { + T* rp=&iBuffer[0]; + if (aRetain) + rp=TextCopy(rp,iEnd-aRetain,aRetain); + TInt read=Min(EBufSize-aRetain,iRemain); + iStream.ReadL(rp,read); + iRemain-=read; + aEnd=iEnd=rp+read; + return iBuffer; + } + } + +// Class RSqlLiteral + +void RSqlLiteral::ToPattern8L(TBool aEscape) +// +// Convert a Buf8 to an 8-bit pattern +// + { + __ASSERT(iType==EBuf8); + HMatcherPattern8* pattern=HMatcherPattern8::NewL(Text8(),aEscape); + User::Free(iVal.iAlloc); + iVal.iAlloc=pattern; + iType=EPattern8; + } + +void RSqlLiteral::ToPattern16L(TBool aEscape) +// +// Convert a Buf8 to an 8-bit pattern +// + { + __ASSERT(iType==EBuf16); + HMatcherPattern16* pattern=HMatcherPattern16::NewL(Text16(),aEscape); + User::Free(iVal.iAlloc); + iVal.iAlloc=pattern; + iType=EPattern16; + } + + +// Class CSqlLikePredicate + +LOCAL_C TInt MatchLength(const TText* aPtr,const TText* aEnd) + { + TInt match=0; + while (aPtr<aEnd) + { + TText c=*aPtr++; + if (c!=KMatchAny) + { + ++match; + if (c=='\'') + ++aPtr; + } + } + return match; + } +//Following code is for the implementation of limited-ESCAPE-clause +LOCAL_C TInt MatchLengthEscape(const TText* aPtr,const TText* aEnd) + { + TInt match=0; + while (aPtr<aEnd) + { + TText c=*aPtr++; + { + ++match; + if (c=='\'') + ++aPtr; + } + } + return match; + } + + +CSqlLikePredicate::CSqlLikePredicate(TType aType,const TDesC& aColumn,const RSqlLiteral& aPattern) + : CSqlLiteralNode(aType,aColumn,aPattern) + { + __ASSERT(aType==ELike||aType==ENotLike); + } + +void CSqlLikePredicate::BindL(const RDbTableRow& aSource) +// +// Compile the Pattern for LongText columns and evaluate the match length +// + { + TInt matchsize; + if(iIsEscape)//Following code is for the implementation of limited-ESCAPE-clause + { + matchsize = MatchLengthEscape(Value().Ptr(),Value().End()); + } + else + { + matchsize = MatchLength(Value().Ptr(),Value().End()); + } + CSqlLiteralNode::BindL(aSource); + switch (ColType()) + { + default: // type mismatch: should be caught by Literal::Bind + __ASSERT(0); + case EDbColText8: + break; + case EDbColLongText8: + Value().ToPattern8L(iIsEscape); + break; + case EDbColLongText16: + Value().ToPattern16L(iIsEscape); + matchsize<<=1; + break; + case EDbColText16: + matchsize<<=1; + break; + } + iMatchSize=matchsize; + } + +TBool CSqlLikePredicate::EvaluateL(const TTextOps& aTextOp) const + { + __ASSERT(IsBound()); + TDbColType type=ColType(); + TDbColumnC column(Column()); + TInt match; + if (TDbCol::IsLong(type)) + { + const TDbBlob& blob=column.Blob(); + if (blob.Size()<iMatchSize) + match=EFalse; + else if (blob.IsInline()) + match=type==EDbColLongText8 ? + Value().Pattern8().MatchL(blob.PtrC8(),aTextOp) : + Value().Pattern16().MatchL(blob.PtrC16(),aTextOp); + else + { + MStreamBuf& buf=StreamLC(blob); + match=type==EDbColLongText8 ? + Value().Pattern8().MatchL(buf,blob.Size(),aTextOp) : + Value().Pattern16().MatchL(buf,blob.Size()>>1,aTextOp); + CleanupStack::PopAndDestroy(); + } + } + else if (column.Size()<iMatchSize) + match=EFalse; + else + { + if(iIsEscape) //Following code is for the implementation of limited-ESCAPE-clause + { + match=type==EDbColText8 ? + aTextOp.Find(column.PtrC8(),Value().Text8()) : + aTextOp.Find(column.PtrC16(),Value().Text16()); + } + else + { + match=type==EDbColText8 ? + aTextOp.Match(column.PtrC8(),Value().Text8()) : + aTextOp.Match(column.PtrC16(),Value().Text16()); + + } + + match=match>=0; + } + return NodeType()==ELike ? match : !match; + }