--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/persistentstorage/dbms/usql/UQ_LIKE.CPP Fri Jan 22 11:06:30 2010 +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;
+ }