1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/os/persistentdata/persistentstorage/dbms/usql/UQ_LIKE.CPP Fri Jun 15 03:10:57 2012 +0200
1.3 @@ -0,0 +1,547 @@
1.4 +// Copyright (c) 1998-2009 Nokia Corporation and/or its subsidiary(-ies).
1.5 +// All rights reserved.
1.6 +// This component and the accompanying materials are made available
1.7 +// under the terms of "Eclipse Public License v1.0"
1.8 +// which accompanies this distribution, and is available
1.9 +// at the URL "http://www.eclipse.org/legal/epl-v10.html".
1.10 +//
1.11 +// Initial Contributors:
1.12 +// Nokia Corporation - initial contribution.
1.13 +//
1.14 +// Contributors:
1.15 +//
1.16 +// Description:
1.17 +// SQL Like predicate node
1.18 +//
1.19 +//
1.20 +
1.21 +#include "UQ_STD.H"
1.22 +
1.23 +inline TUint8* TextCopy(TUint8* aDest,const TUint8* aSrc,TInt aLen)
1.24 + {return Mem::Copy(aDest,aSrc,aLen);}
1.25 +inline TUint16* TextCopy(TUint16* aDest,const TUint16* aSrc,TInt aLen)
1.26 + {return (TUint16*)Mem::Copy(aDest,aSrc,aLen<<1);}
1.27 +
1.28 +// template Class HMatcherPattern
1.29 +
1.30 +template <class T,class D>
1.31 +inline HMatcherPattern<T,D>* HMatcherPattern<T,D>::Realloc(HMatcherPattern<T,D>* aThis,TInt aSize)
1.32 + {return STATIC_CAST(TThis*,User::ReAlloc(aThis,_FOFF(TThis,iPattern[aSize])));}
1.33 +
1.34 +/**
1.35 +Creates a HMatcherPattern that converts the pattern into more manageable pieces
1.36 +based on a delimeter that is the wildcard * (asterisk).
1.37 +
1.38 +Characters between * (asterisks) must not number greater than KMaxSegmentLength.
1.39 +If only one * exists then the length is taken from the start and end of pattern.
1.40 +If these segments contain ? (question mark) wildcard than they must not number
1.41 +greater than KMaxSegmentLength-2.
1.42 +
1.43 +The user is responsible for the returned pointer's memory.
1.44 +
1.45 +@param aPattern The search pattern to match.
1.46 +@param aEscape ESCAPE clause
1.47 +@leave KErrNoMemory if no more memory is available.
1.48 +@leave KErrArgument if the search pattern segment length is greater
1.49 + than KMaxSegmentLength,
1.50 +@return The newly constructed pattern pointer.
1.51 +@see KMaxSegmentLength
1.52 +*/
1.53 +template <class T,class D>
1.54 +HMatcherPattern<T,D>* HMatcherPattern<T,D>::NewL(const D& aPattern, TBool aEscape)
1.55 + {
1.56 + TThis* self=0;
1.57 + TInt r=Construct(self,aPattern,aEscape);
1.58 + if (r!=KErrNone)
1.59 + {
1.60 + User::Free(self);
1.61 + __LEAVE(r);
1.62 + }
1.63 + return self;
1.64 + }
1.65 +
1.66 +template <class T,class D>
1.67 +TInt HMatcherPattern<T,D>::MatchL(const D& aDes,const TTextOps& aTextOp) const
1.68 +//
1.69 +// Test the pattern against the supplied descriptor
1.70 +//
1.71 + {
1.72 + TDesMatcher<T,D> matcher(aDes);
1.73 + return matcher.MatchL(*this,aTextOp);
1.74 + }
1.75 +
1.76 +template <class T,class D>
1.77 +TInt HMatcherPattern<T,D>::MatchL(MStreamBuf& aBuf,TInt aLength,const TTextOps& aTextOp) const
1.78 +//
1.79 +// Test the pattern against the supplied stream
1.80 +//
1.81 + {
1.82 + TStreamMatcher<T,D> matcher(aBuf,aLength);
1.83 + return matcher.MatchL(*this,aTextOp);
1.84 + }
1.85 +
1.86 +/**
1.87 +Breaks up a given search pattern into manageable segments.
1.88 +
1.89 +The pattern is broken into segments. These segments are organised
1.90 +from the segment delimeter that is the wildcard * (asterisk).
1.91 +So in effect a segment may contain other wildcards (i.e. ?) or
1.92 +the entire pattern (no embedded asterisks) as these at least MUST match.
1.93 +
1.94 +The cell is created and updated with the segments type and length, and also
1.95 +the segment itself.
1.96 +
1.97 +Not including asterisks, the segment must be no longer than length KMaxSegmentLength.
1.98 +However, if the segment has a ? (question mark) wildcard within it then the
1.99 +segment must be no longer than length KMaxSegmentLength-2.
1.100 +
1.101 +This is due to the way the Find and Match functions of TDes work. Match understands
1.102 +wildcards whilst Find does not.
1.103 +
1.104 +The match algorithm depends on KMaxSegmentLength being smaller than the
1.105 +text read buffer, and for efficiency should not be more than half the size
1.106 +of the read buffer. Also KMaxSegmentLength must currently fit into 8 bits,
1.107 +as it is embedded into a single character in an 8-bit text matching buffer.
1.108 +[So increasing KMaxSegmentLength is not a simple exercise.]
1.109 +
1.110 +The search is repeated for each segment within the pattern. Increasing the cell
1.111 +size and inserting each segment and associated segment data.
1.112 +
1.113 +On reaching the end of the pattern this data is passed back to the user.
1.114 +The user is responsible for this returned pointers memory.
1.115 +
1.116 +@param aCell On return points to a cell matching this pattern.
1.117 +@param aPattern The search pattern to match.
1.118 +@param aEscape ESCAPE clause
1.119 +@return KErrNoMemory if no memory is available to create or
1.120 + increase the size of a cell,
1.121 + KErrArgument if the search pattern segment length is greater
1.122 + than KMaxSegmentLength,
1.123 + KErrNone if the match was successful.
1.124 +@see KMaxSegmentLength
1.125 +*/
1.126 +template <class T,class D>
1.127 +TInt HMatcherPattern<T,D>::Construct(HMatcherPattern<T,D>*& aCell,const D& aPattern,TBool aEscape)
1.128 + {
1.129 + const T* pM=aPattern.Ptr();
1.130 + const T* const eM=pM+aPattern.Length();
1.131 + TInt size=(eM-pM)+KPatternGranularity;
1.132 + TThis* self=Realloc(0,size);
1.133 + if (!self)
1.134 + return KErrNoMemory;
1.135 + aCell=self;
1.136 + T* seg=&self->iPattern[0];
1.137 + const T* end=&self->iPattern[size];
1.138 + TInt term; // terminating code
1.139 +
1.140 + if (eM==pM)
1.141 + term=ENull;
1.142 + else
1.143 + {
1.144 + term=EStop;
1.145 + do
1.146 + {
1.147 + //Following code is for the implementation of limited-ESCAPE-clause
1.148 + if(aEscape)
1.149 + {
1.150 + const T* here=pM;
1.151 + TInt len = aPattern.Length();
1.152 + if (len>KMaxSegmentLength)
1.153 + return KErrArgument;
1.154 + *seg++=T(EEscape );
1.155 + *seg++=T(len);
1.156 + seg=TextCopy(seg,here,len);
1.157 + break;
1.158 + }
1.159 + T m=*pM;
1.160 + if (m==KMatchAny)
1.161 + {
1.162 + term=ESuccess;
1.163 + do
1.164 + {
1.165 + if (++pM==eM)
1.166 + break;
1.167 + m=*pM;
1.168 + } while (m==KMatchAny);
1.169 + if (pM==eM)
1.170 + break;
1.171 + }
1.172 + const T* here=pM;
1.173 + TInt type;
1.174 + if (m==KMatchOne)
1.175 + {
1.176 + while (++pM<eM && *pM==KMatchOne) {;}
1.177 + type=ESkip;
1.178 + }
1.179 + else
1.180 + {
1.181 + type=0;
1.182 + while (++pM<eM)
1.183 + {
1.184 + m=*pM;
1.185 + if (m==KMatchAny)
1.186 + break;
1.187 + if (m==KMatchOne)
1.188 + type|=EWild;
1.189 + }
1.190 + if (term==EStop)
1.191 + type|=EBeginning;
1.192 + else if (pM==eM)
1.193 + type|=EEnd;
1.194 + else
1.195 + {
1.196 + type|=EMiddle;
1.197 + if (type&EWild)
1.198 + { // include '*'s in segment for matching
1.199 + --here;
1.200 + ++pM;
1.201 + }
1.202 + }
1.203 + }
1.204 + *seg++=T(type);
1.205 + TInt len=pM-here;
1.206 + if (len>KMaxSegmentLength)
1.207 + return KErrArgument;
1.208 + *seg++=T(len);
1.209 + if (type==ESkip)
1.210 + len=0;
1.211 + if (seg+4+len>end)
1.212 + {
1.213 + TInt newsize=end-&self->iPattern[0]+KPatternGranularity;
1.214 + self=Realloc(self,newsize);
1.215 + if (!self)
1.216 + return KErrNoMemory;
1.217 + seg+=&self->iPattern[0]-&aCell->iPattern[0];
1.218 + end=&self->iPattern[newsize];
1.219 + aCell=self;
1.220 + }
1.221 + if (type==(EMiddle|EWild))
1.222 + {
1.223 + *seg++=T(KMatchAny);
1.224 + ++here;
1.225 + --len;
1.226 + }
1.227 + seg=TextCopy(seg,here,len);
1.228 + } while (pM<eM);
1.229 + }
1.230 + *seg++=T(term);
1.231 + aCell=Realloc(self,seg-&self->iPattern[0]);
1.232 + return KErrNone;
1.233 + }
1.234 +
1.235 +// class TMatcher
1.236 +
1.237 +template <class T,class D>
1.238 +TBool TMatcher<T,D>::MatchL(const HMatcherPattern<T,D>& aPattern,const TTextOps& aTextOp)
1.239 + {
1.240 + const T* pM=&aPattern.iPattern[0];
1.241 + const T* eB;
1.242 + const T* pB=UnderflowL(eB);
1.243 + for (;;)
1.244 + {
1.245 + TInt segment=*pM;
1.246 + switch (segment&EMask)
1.247 + {
1.248 + case ENull:
1.249 + return pB==eB;
1.250 + case ESuccess:
1.251 + return ETrue;
1.252 + case EStop:
1.253 + if (pB==eB)
1.254 + pB=UnderflowL(eB);
1.255 + return pB==eB;
1.256 + case ESkip:
1.257 + {
1.258 + TInt len=*++pM;
1.259 + TInt skip=len+pB-eB;
1.260 + if (skip>0)
1.261 + {
1.262 + pB=UnderflowL(eB)+skip;
1.263 + if (pB>eB)
1.264 + return EFalse;
1.265 + }
1.266 + else
1.267 + pB+=len;
1.268 + ++pM;
1.269 + }
1.270 + break;
1.271 + //Following code is for the implementation of limited-ESCAPE-clause
1.272 + case EEscape:
1.273 + {
1.274 + TInt len=*++pM;
1.275 + ++pM;
1.276 + TInt bLen=eB-pB;
1.277 + if (bLen<len)
1.278 + return EFalse;
1.279 + if (aTextOp.Find(pB,bLen,pM,len)<0)
1.280 + return EFalse;
1.281 + pM+=len;
1.282 + pB+=bLen;
1.283 + }
1.284 + break;
1.285 + case EBeginning:
1.286 + {
1.287 + TInt len=*++pM;
1.288 + ++pM;
1.289 + if (eB-pB<len)
1.290 + return EFalse;
1.291 + if (segment&EWild)
1.292 + {
1.293 + if (aTextOp.Match(pB,len,pM,len)<0)
1.294 + return EFalse;
1.295 + }
1.296 + else
1.297 + {
1.298 + if (aTextOp.Compare(pB,len,pM,len)!=0)
1.299 + return EFalse;
1.300 + }
1.301 + pM+=len;
1.302 + pB+=len;
1.303 + }
1.304 + break;
1.305 + case EMiddle:
1.306 + {
1.307 + TInt len=*++pM;
1.308 + ++pM;
1.309 + TInt match=len;
1.310 + if (segment&EWild)
1.311 + match-=2; // the number of characters to match
1.312 + TInt left=eB-pB;
1.313 + if (left<match)
1.314 + pB=UnderflowL(eB,left);
1.315 + for (;;)
1.316 + {
1.317 + TInt bLen=eB-pB;
1.318 + if (bLen<match)
1.319 + return EFalse;
1.320 + TInt pos=segment&EWild ? aTextOp.Match(pB,bLen,pM,len) : aTextOp.Find(pB,bLen,pM,len);
1.321 + if (pos>=0)
1.322 + { // found it
1.323 + pB+=pos+match;
1.324 + break;
1.325 + }
1.326 + // not found, next chunk of data please.
1.327 + pB=UnderflowL(eB,match-1);
1.328 + }
1.329 + pM+=len;
1.330 + }
1.331 + break;
1.332 + case EEnd: // match the last segment
1.333 + {
1.334 + TInt len=*++pM;
1.335 + ++pM;
1.336 + TInt left=eB-pB;
1.337 + if (left<len)
1.338 + {
1.339 + pB=UnderflowL(eB,left);
1.340 + if (eB-pB<len)
1.341 + return EFalse;
1.342 + }
1.343 + while (eB-pB>len)
1.344 + pB=UnderflowL(eB,len);
1.345 + if (segment&EWild)
1.346 + {
1.347 + if (aTextOp.Match(pB,len,pM,len)<0)
1.348 + return EFalse;
1.349 + }
1.350 + else
1.351 + {
1.352 + if (aTextOp.Compare(pB,len,pM,len)!=0)
1.353 + return EFalse;
1.354 + }
1.355 + }
1.356 + return ETrue;
1.357 + }
1.358 + }
1.359 + }
1.360 +
1.361 +// Class TDesMatcher
1.362 +
1.363 +template <class T,class D>
1.364 +inline TDesMatcher<T,D>::TDesMatcher(const D& aDes)
1.365 + {iEnd=(iPtr=aDes.Ptr())+aDes.Length();}
1.366 +
1.367 +template <class T,class D>
1.368 +const T* TDesMatcher<T,D>::UnderflowL(const T*& aEnd,TInt aRetain)
1.369 + {
1.370 + const T* ptr=iPtr-aRetain;
1.371 + aEnd=iPtr=iEnd;
1.372 + return ptr;
1.373 + }
1.374 +
1.375 +// Class TStreamMatcher
1.376 +
1.377 +template <class T,class D>
1.378 +inline TStreamMatcher<T,D>::TStreamMatcher(MStreamBuf& aStreamBuf,TInt aLength)
1.379 + :iStream(&aStreamBuf),iRemain(aLength),iEnd(&iBuffer[EBufSize])
1.380 + {}
1.381 +
1.382 +template <class T,class D>
1.383 +const T* TStreamMatcher<T,D>::UnderflowL(const T*& aEnd,TInt aRetain)
1.384 + {
1.385 + if (iRemain==0)
1.386 + { // no more stream data, don't move etc.
1.387 + aEnd=iEnd;
1.388 + return iEnd-aRetain;
1.389 + }
1.390 + else
1.391 + {
1.392 + T* rp=&iBuffer[0];
1.393 + if (aRetain)
1.394 + rp=TextCopy(rp,iEnd-aRetain,aRetain);
1.395 + TInt read=Min(EBufSize-aRetain,iRemain);
1.396 + iStream.ReadL(rp,read);
1.397 + iRemain-=read;
1.398 + aEnd=iEnd=rp+read;
1.399 + return iBuffer;
1.400 + }
1.401 + }
1.402 +
1.403 +// Class RSqlLiteral
1.404 +
1.405 +void RSqlLiteral::ToPattern8L(TBool aEscape)
1.406 +//
1.407 +// Convert a Buf8 to an 8-bit pattern
1.408 +//
1.409 + {
1.410 + __ASSERT(iType==EBuf8);
1.411 + HMatcherPattern8* pattern=HMatcherPattern8::NewL(Text8(),aEscape);
1.412 + User::Free(iVal.iAlloc);
1.413 + iVal.iAlloc=pattern;
1.414 + iType=EPattern8;
1.415 + }
1.416 +
1.417 +void RSqlLiteral::ToPattern16L(TBool aEscape)
1.418 +//
1.419 +// Convert a Buf8 to an 8-bit pattern
1.420 +//
1.421 + {
1.422 + __ASSERT(iType==EBuf16);
1.423 + HMatcherPattern16* pattern=HMatcherPattern16::NewL(Text16(),aEscape);
1.424 + User::Free(iVal.iAlloc);
1.425 + iVal.iAlloc=pattern;
1.426 + iType=EPattern16;
1.427 + }
1.428 +
1.429 +
1.430 +// Class CSqlLikePredicate
1.431 +
1.432 +LOCAL_C TInt MatchLength(const TText* aPtr,const TText* aEnd)
1.433 + {
1.434 + TInt match=0;
1.435 + while (aPtr<aEnd)
1.436 + {
1.437 + TText c=*aPtr++;
1.438 + if (c!=KMatchAny)
1.439 + {
1.440 + ++match;
1.441 + if (c=='\'')
1.442 + ++aPtr;
1.443 + }
1.444 + }
1.445 + return match;
1.446 + }
1.447 +//Following code is for the implementation of limited-ESCAPE-clause
1.448 +LOCAL_C TInt MatchLengthEscape(const TText* aPtr,const TText* aEnd)
1.449 + {
1.450 + TInt match=0;
1.451 + while (aPtr<aEnd)
1.452 + {
1.453 + TText c=*aPtr++;
1.454 + {
1.455 + ++match;
1.456 + if (c=='\'')
1.457 + ++aPtr;
1.458 + }
1.459 + }
1.460 + return match;
1.461 + }
1.462 +
1.463 +
1.464 +CSqlLikePredicate::CSqlLikePredicate(TType aType,const TDesC& aColumn,const RSqlLiteral& aPattern)
1.465 + : CSqlLiteralNode(aType,aColumn,aPattern)
1.466 + {
1.467 + __ASSERT(aType==ELike||aType==ENotLike);
1.468 + }
1.469 +
1.470 +void CSqlLikePredicate::BindL(const RDbTableRow& aSource)
1.471 +//
1.472 +// Compile the Pattern for LongText columns and evaluate the match length
1.473 +//
1.474 + {
1.475 + TInt matchsize;
1.476 + if(iIsEscape)//Following code is for the implementation of limited-ESCAPE-clause
1.477 + {
1.478 + matchsize = MatchLengthEscape(Value().Ptr(),Value().End());
1.479 + }
1.480 + else
1.481 + {
1.482 + matchsize = MatchLength(Value().Ptr(),Value().End());
1.483 + }
1.484 + CSqlLiteralNode::BindL(aSource);
1.485 + switch (ColType())
1.486 + {
1.487 + default: // type mismatch: should be caught by Literal::Bind
1.488 + __ASSERT(0);
1.489 + case EDbColText8:
1.490 + break;
1.491 + case EDbColLongText8:
1.492 + Value().ToPattern8L(iIsEscape);
1.493 + break;
1.494 + case EDbColLongText16:
1.495 + Value().ToPattern16L(iIsEscape);
1.496 + matchsize<<=1;
1.497 + break;
1.498 + case EDbColText16:
1.499 + matchsize<<=1;
1.500 + break;
1.501 + }
1.502 + iMatchSize=matchsize;
1.503 + }
1.504 +
1.505 +TBool CSqlLikePredicate::EvaluateL(const TTextOps& aTextOp) const
1.506 + {
1.507 + __ASSERT(IsBound());
1.508 + TDbColType type=ColType();
1.509 + TDbColumnC column(Column());
1.510 + TInt match;
1.511 + if (TDbCol::IsLong(type))
1.512 + {
1.513 + const TDbBlob& blob=column.Blob();
1.514 + if (blob.Size()<iMatchSize)
1.515 + match=EFalse;
1.516 + else if (blob.IsInline())
1.517 + match=type==EDbColLongText8 ?
1.518 + Value().Pattern8().MatchL(blob.PtrC8(),aTextOp) :
1.519 + Value().Pattern16().MatchL(blob.PtrC16(),aTextOp);
1.520 + else
1.521 + {
1.522 + MStreamBuf& buf=StreamLC(blob);
1.523 + match=type==EDbColLongText8 ?
1.524 + Value().Pattern8().MatchL(buf,blob.Size(),aTextOp) :
1.525 + Value().Pattern16().MatchL(buf,blob.Size()>>1,aTextOp);
1.526 + CleanupStack::PopAndDestroy();
1.527 + }
1.528 + }
1.529 + else if (column.Size()<iMatchSize)
1.530 + match=EFalse;
1.531 + else
1.532 + {
1.533 + if(iIsEscape) //Following code is for the implementation of limited-ESCAPE-clause
1.534 + {
1.535 + match=type==EDbColText8 ?
1.536 + aTextOp.Find(column.PtrC8(),Value().Text8()) :
1.537 + aTextOp.Find(column.PtrC16(),Value().Text16());
1.538 + }
1.539 + else
1.540 + {
1.541 + match=type==EDbColText8 ?
1.542 + aTextOp.Match(column.PtrC8(),Value().Text8()) :
1.543 + aTextOp.Match(column.PtrC16(),Value().Text16());
1.544 +
1.545 + }
1.546 +
1.547 + match=match>=0;
1.548 + }
1.549 + return NodeType()==ELike ? match : !match;
1.550 + }