blob: 4cd365f927b031b52797d7e2275737d474532420 [file] [log] [blame]
/**********************************************************************
// @@@ START COPYRIGHT @@@
//
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
//
// @@@ END COPYRIGHT @@@
**********************************************************************/
/* -*-C++-*-
*****************************************************************************
*
* File: <file>
* Description:
*
*
* Created: 10/17/95
* Language: C++
*
*
*
*
*****************************************************************************
*/
// -----------------------------------------------------------------------
#include "Platform.h"
#include <stddef.h>
#include <sys/types.h>
#include <regex.h>
#include "exp_clause_derived.h"
#include "exp_like.h"
#include "exp_function.h"
#include "unicode_char_set.h"
#include "nchar_mp.h"
///////////////////////////////////////////////////
// class LikePattern
///////////////////////////////////////////////////
LikePattern::LikePattern
( const LikePatternString& pattern
, CollHeap* exHeap
, CharInfo::CharSet cs
, CharInfo::Collation co
)
: LikePatternHeader
( LikePatternStringIterator::NON_WILDCARD
, new(exHeap) char[pattern.getLength()]
, exHeap
)
, error_(EXE_OK)
{
char* patternBuf = getPattern();
const char *currentChar;
LikePatternHeader* lastHeader = this;
LikePatternHeader* prevHeader = NULL;
LikePatternStringIterator i(pattern);
unsigned char *headerPattern;
UInt16 headerLength;
UInt16 encodedPatternLength = 0;
NABoolean systemCollationFlag = CollationInfo::isSystemCollation(co);
UInt16 nPasses;
Int32 effEncodedKeyLength;
if (systemCollationFlag)
nPasses = CollationInfo::getCollationNPasses(co);
else
nPasses = 1;
Int32 number_bytes;
Int32 len = pattern.getLength();
while (i != LikePatternStringIterator::END_OF_PATTERN)
{
currentChar = i.getCurrentChar();
switch(i)
{
case LikePatternStringIterator::NON_WILDCARD:
case LikePatternStringIterator::UNDERSCORE:
{
//
// Append the non-wildcard character or underscore to the current header.
//
number_bytes = Attributes::getFirstCharLength(currentChar, len, cs);
if(number_bytes <= 0)
{
error_ = EXE_INVALID_CHARACTER;
return;
}
lastHeader->append(i);
i += number_bytes + ((cs == CharInfo::UCS2) ? 1 : 0); // For UCS2, number_bytes is always 1
i.determineCharType();
len -= number_bytes;
break;
}
case LikePatternStringIterator::PERCENT:
{
if (i != lastHeader->getLastClause()->getType())
{
//
// Append a new header to the LikePattern.
//
lastHeader->endClauses();
patternBuf += lastHeader->getLength();
if(systemCollationFlag)
{
headerLength = lastHeader->getLength();
if(headerLength >0)
{
encodedPatternLength = headerLength*nPasses;
headerPattern = new (exHeap) unsigned char[encodedPatternLength];
ex_function_encode::encodeCollationSearchKey
(
(unsigned char *)lastHeader->getPattern(),
headerLength,
headerPattern,
encodedPatternLength,
effEncodedKeyLength,
nPasses,
co,
TRUE
);
lastHeader->setEncodedPattern(headerPattern);
lastHeader->setEncodedHeader(headerPattern);
}
lastHeader->setCollation(co);
}
lastHeader->append(new(exHeap)LikePatternHeader(i, patternBuf, exHeap));
prevHeader = lastHeader;
lastHeader = prevHeader->getNextHeader();
}
i += CharInfo::isSingleByteCharSet(cs) ? 1 : BYTES_PER_NAWCHAR ; // increase 1
i.determineCharType();
--len;
break;
}
default: // LikePatternStringIterator::ERROR:
error_ = EXE_INVALID_ESCAPE_SEQUENCE;
return;
}
}
lastHeader->endClauses();
if(systemCollationFlag)
{
headerLength = lastHeader->getLength();
if(headerLength > 0)
{
encodedPatternLength = headerLength*nPasses;
headerPattern = new (exHeap) unsigned char[encodedPatternLength];
ex_function_encode::encodeCollationSearchKey
(
(unsigned char *)lastHeader->getPattern(),
headerLength,
headerPattern,
encodedPatternLength,
effEncodedKeyLength,
nPasses,
co,
TRUE
);
lastHeader->setEncodedPattern(headerPattern);
lastHeader->setEncodedHeader(headerPattern);
}
lastHeader->setCollation(co);
}
//
// If there are more than two headers in the chain, move the last header to
// the second position in the chain. This will make it easier to test for
// pattern matches by allowing us to check the beginning and end of the
// pattern first.
//
if ((prevHeader != NULL) AND (prevHeader != this)) {
lastHeader->append(getNextHeader());
append(lastHeader);
prevHeader->append(NULL);
}
//
// If the pattern begins with a percent, set the character type
// appropriately.
//
if ((getLength() == 0) AND (getNextHeader() != NULL))
setType(LikePatternStringIterator::PERCENT);
}
LikePattern::~LikePattern()
{
//
// Delete the pattern buffer.
//
NADELETEBASIC(getPattern(), getExHeap());
//
// Delete the attached headers.
//
LikePatternHeader* header = getNextHeader();
while (header != NULL) {
LikePatternHeader* prevHeader = header;
header = header->getNextHeader();
delete prevHeader;
}
}
NABoolean LikePattern::matches
(const char* text, UInt16 textLen,
CharInfo::CharSet cs)
{
if(text == NULL) return FALSE;
const char* endOfText = &text[textLen];
Int32 number_bytes = 0;
Int32 numChrInHeader = 0;
Int32 numChrInRecord = 0;
Lng32 numOfChar = 0;
Int32 charToOffset = 0;
Int32 headerMatchLen = 0;
CollHeap* exHeap = getExHeap();
unsigned char *headerPattern;
UInt16 headerLength;
NABoolean equalFlag;
NABoolean matchFlag;
NABoolean deallocateNeeded = FALSE;
UInt16 encodedPatternLength = 0;
CharInfo::Collation co = getCollation();
NABoolean systemCollationFlag = CollationInfo::isSystemCollation(co);
UInt16 nPasses;
if (systemCollationFlag)
nPasses = CollationInfo::getCollationNPasses(co);
else
nPasses = 1;
// Check the first partition.
LikePatternHeader* header = this;
const char *patternStr = header->getPattern();
if (header->getType() != LikePatternStringIterator::PERCENT)
{
if (systemCollationFlag)
{
headerPattern = header->getEncodedPattern();
if ((header->getLength()*nPasses) > (endOfText - text))
return FALSE;
}
else
{
headerPattern = (unsigned char *)header->getPattern();
numChrInHeader = Attributes::getCharLengthInBuf
((const char *)headerPattern,
(const char *)headerPattern + header->getLength(),
NULL, cs);
numChrInRecord = Attributes::getCharLengthInBuf
(text, endOfText, NULL, cs);
if (numChrInHeader > numChrInRecord)
return FALSE;
}
matchFlag = header->matches(text, headerMatchLen, cs);
if(header->error() != EXE_OK)
{
error_ = header->error();
return FALSE;
}
if (NOT matchFlag) return FALSE;
// If there is only one partition in the pattern, it must match the whole
// text for there to be a match.
if (header->getNextHeader() == NULL)
return IFX (headerMatchLen == textLen)
THENX TRUE
ELSEX FALSE;
text += headerMatchLen;
patternStr += header->getLength();
}
// Check the last partition.
header = header->getNextHeader();
headerLength = header->getLength();
if (headerLength > 0)
{
NABoolean matchLastHeader = header->matchesR(text, endOfText, cs);
if(header->error() != EXE_OK)
{
error_ = header->error();
return FALSE;
}
if (NOT matchLastHeader)
return FALSE;
}
// Check the remaining partitions.
header = header->getNextHeader();
while (header != NULL) // check all headers in pattern
{
headerLength = header->getLength();
if (systemCollationFlag)
{
headerPattern = header->getEncodedPattern();
if (header->getLength() > (endOfText - text))
return FALSE;
}
else
{
headerPattern = (unsigned char *)header->getPattern();
numChrInHeader = Attributes::getCharLengthInBuf
((const char *)headerPattern,
(const char *)headerPattern + header->getLength(),
NULL, cs);
numChrInRecord = Attributes::getCharLengthInBuf
(text, endOfText, NULL, cs);
if (numChrInHeader > numChrInRecord)
return FALSE;
}
while (endOfText - text > 0)
{
// check text with the pattern header. If they do not match, move to
// the next character in text, compare again. Otherwise, work on the
// next header.
if(header->matches(text, headerMatchLen, cs)) break;
if(header->error() != EXE_OK)
{
error_ = header->error();
return FALSE;
}
if(systemCollationFlag)
{
text += nPasses;
}
else
{
// If the text does not match the pattern, move to next character.
number_bytes = Attributes::getFirstCharLength(text, strlen(text), cs);
if(number_bytes <= 0)
{
error_ = EXE_INVALID_CHARACTER;
return FALSE;
}
text += number_bytes;
}
if (header->getType() == LikePatternStringIterator::NON_WILDCARD)
{
while (text < endOfText)
{
if(systemCollationFlag)
{
equalFlag = TRUE;
for(short i = 0; i < nPasses; i++)
{
if(*(text+i) != *(header->getEncodedPattern()+i))
{
equalFlag = FALSE;
break;
}
}
if(equalFlag) break;
else
text += nPasses;
}
else
{
number_bytes = Attributes::getFirstCharLength(text, strlen(text), cs);
if(number_bytes <= 0)
{
error_ = EXE_INVALID_CHARACTER;
return FALSE;
}
equalFlag = TRUE;
for(short i = 0; i < number_bytes; i++)
{
if( *(text+i) != *(header->getPattern()+i))
{
equalFlag = FALSE;
break;
}
}
if(equalFlag) break;
else
text += number_bytes;
}
}
}
if (header->getLength() > (endOfText - text))
{
return FALSE;
}
}
// move the pointers to next pattern header and the remaining text
patternStr += header->getLength();
text += headerMatchLen;
header = header->getNextHeader();
}
return TRUE;
}
///////////////////////////////////////////////////
// class ExRegexpClauseBase
///////////////////////////////////////////////////
ex_expr::exp_return_type
ExRegexpClauseBase::processNulls(char *op_data[], CollHeap *heap,
ComDiagsArea **diagsArea
)
{
//
// If an operand is missing(its a null value), set the result to UNKNOWN.
//
for (short i = 1; i < getNumOperands(); i++) {
if (getOperand(i)->getNullFlag() && (NOT op_data[i])) {
*(Lng32*)op_data[2 * MAX_OPERANDS] = -1;
return ex_expr::EXPR_NULL;
}
}
return ex_expr::EXPR_OK;
}
///////////////////////////////////////////////////
// class ex_like_clause_base
///////////////////////////////////////////////////
ex_expr::exp_return_type
ex_like_clause_base::processNulls(char *op_data[], CollHeap *heap,
ComDiagsArea **diagsArea
)
{
//
// If an operand is missing(its a null value), set the result to UNKNOWN.
//
for (short i = 1; i < getNumOperands(); i++) {
if (getOperand(i)->getNullFlag() && (NOT op_data[i])) {
*(Lng32*)op_data[2 * MAX_OPERANDS] = -1;
return ex_expr::EXPR_NULL;
}
}
return ex_expr::EXPR_OK;
}
ex_expr::exp_return_type ExRegexpClauseChar::eval(char *op_data[],
CollHeap* exHeap,
ComDiagsArea** diagsArea)
{
NABoolean matchFlag = true;
Lng32 len1 = getOperand(1)->getLength(op_data[-MAX_OPERANDS+1]);
Lng32 len2 = getOperand(2)->getLength(op_data[-MAX_OPERANDS+2]);
regex_t reg;
regmatch_t pm[1];
const size_t nmatch = 1;
Lng32 cflags, z;
char * pattern;
char *srcStr= new (exHeap) char[len1+1];
char ebuf[128];
cflags = REG_EXTENDED|REG_NEWLINE;
pattern = new (exHeap) char[len2+1];
pattern[len2]=0;
srcStr[len1]=0;
str_cpy_all(pattern, op_data[2], len2);
str_cpy_all(srcStr, op_data[1], len1);
z = regcomp(&reg, pattern, cflags);
if (z != 0){
//ERROR
regerror(z, &reg,ebuf, sizeof(ebuf));
ExRaiseSqlError(exHeap, diagsArea, (ExeErrorCode)8452);
**diagsArea << DgString0(ebuf);
return ex_expr::EXPR_ERROR;
}
z = regexec(&reg,srcStr , nmatch, pm, 0);
if (z == REG_NOMATCH)
{
matchFlag = false;
}
else if (z != 0) {
regerror(z, &reg,ebuf, sizeof(ebuf));
ExRaiseSqlError(exHeap, diagsArea, (ExeErrorCode)8452);
**diagsArea << DgString0(ebuf);
return ex_expr::EXPR_ERROR;
}
*(Lng32 *)op_data[0] = (Lng32)matchFlag;
regfree(&reg);
NADELETEBASIC(pattern, exHeap);
NADELETEBASIC(srcStr, exHeap);
return ex_expr::EXPR_OK;
}
ex_expr::exp_return_type ex_like_clause_char::eval(char *op_data[],
CollHeap* exHeap,
ComDiagsArea** diagsArea)
{
CharInfo::CharSet cs = ((SimpleType *)getOperand(1))->getCharSet();
if(cs == CharInfo::ISO88591)
cs = ((SimpleType *)getOperand(1))->getIsoMapping();
// get length of operands
Lng32 len1 = getOperand(1)->getLength(op_data[-MAX_OPERANDS+1]);
Lng32 len2 = getOperand(2)->getLength(op_data[-MAX_OPERANDS+2]);
Lng32 len3 = 0;
if ( cs == CharInfo::UTF8 )
{
Int32 prec1 = ((SimpleType *)getOperand(1))->getPrecision();
len1 = Attributes::trimFillerSpaces( op_data[1], prec1, len1, cs );
Int32 prec2 = ((SimpleType *)getOperand(2))->getPrecision();
len2 = Attributes::trimFillerSpaces( op_data[2], prec2, len2, cs );
}
const char *csname = CharInfo::getCharSetName(cs);
const Int32 smallBufSize = 128;
unsigned char smallBuf[smallBufSize];
const char* escapeChar;
if (getNumOperands() < 4)
escapeChar = NULL;
else {
// get length of escape character
len3 = getOperand(3)->getLength(op_data[-MAX_OPERANDS+3]);
if ( cs == CharInfo::UTF8 )
{
Int32 prec3 = ((SimpleType *)getOperand(3))->getPrecision();
len3 = Attributes::trimFillerSpaces( op_data[3], prec3, len3, cs );
}
if (len3 != 1) {
ExRaiseSqlError(exHeap, diagsArea, EXE_INVALID_ESCAPE_CHARACTER);
return ex_expr::EXPR_ERROR;
}
escapeChar = op_data[3];
}
CharInfo::Collation co = ((SimpleType *)getOperand(1))->getCollation();
LikePatternString patternString(op_data[2], (UInt16)len2, cs, escapeChar, len3 );
LikePattern pattern(patternString, exHeap, cs, co);
if (pattern.error())
{
if(pattern.error() == EXE_INVALID_ESCAPE_SEQUENCE)
ExRaiseSqlError(exHeap, diagsArea, EXE_INVALID_ESCAPE_SEQUENCE);
else
{
ExRaiseSqlError(exHeap, diagsArea, pattern.error());
*(*diagsArea) << DgString0(csname) << DgString1("LIKE PATTERN");
}
return ex_expr::EXPR_ERROR;
}
unsigned char *textStr = (unsigned char *)op_data[1];
unsigned char *encodedText = NULL;
Int32 encodedPatternLength = 0;
NABoolean systemCollationFlag = CollationInfo::isSystemCollation(co);
NABoolean deallocateNeeded = FALSE;
if (systemCollationFlag)
{
pattern.setCollation (co);
short nPasses = CollationInfo::getCollationNPasses(co);
Int32 effEncodedKeyLength;
encodedPatternLength = len1 * nPasses;
if(encodedPatternLength <= smallBufSize)
encodedText = smallBuf;
else
{
encodedText = new (exHeap) unsigned char[encodedPatternLength];
deallocateNeeded = TRUE;
}
ex_function_encode::encodeCollationSearchKey
(
(unsigned char *) op_data[1],
len1,
encodedText,
nPasses*len1,
effEncodedKeyLength,
nPasses,
co,
TRUE
);
textStr = encodedText;
// len1 = effEncodedKeyLength; the length without trading space.
len1 *= nPasses;
}
if (cs == CharInfo::UTF8)
{
Int32 Prec = ((SimpleType *)getOperand(1))->getPrecision();
if ( Prec > 0 )
{
Int32 endOff = Attributes::convertCharToOffset ((const char *)textStr,
Prec+1, len1, cs);
if (endOff >= 0) // If no error
len1 = endOff;
// else bad UTF8 chars will get detected later by existing code (below).
}
}
NABoolean matchFlag = pattern.matches((char *)textStr, (UInt16)len1, cs);
if(deallocateNeeded)
NADELETEBASIC(encodedText, exHeap);
if (pattern.error())
{
ExRaiseSqlError(exHeap, diagsArea, pattern.error());
*(*diagsArea) << DgString0(csname) << DgString1("LIKE CLAUSE");
return ex_expr::EXPR_ERROR;
}
*(Lng32 *)op_data[0] = (Lng32)matchFlag;
return ex_expr::EXPR_OK;
}
ex_expr::exp_return_type ex_like_clause_doublebyte::eval(char *op_data[],
CollHeap* exHeap,
ComDiagsArea** diagsArea)
{
// get length of operands
Lng32 len1 = getOperand(1)->getLength(op_data[-MAX_OPERANDS+1]);
Lng32 len2 = getOperand(2)->getLength(op_data[-MAX_OPERANDS+2]);
NAWchar wPercentChar = 0;
NAWchar wUnderScoreChar = 0;
short bpcs;
switch ( getOperand(1)->getCharSet() )
{
case CharInfo::UNICODE:
wPercentChar = unicode_char_set::percent_char();
wUnderScoreChar = unicode_char_set::underscore_char();
bpcs = unicode_char_set::bytesPerChar();
break;
case CharInfo::KANJI_MP:
wPercentChar = kanji_char_set::percent_char();
wUnderScoreChar = kanji_char_set::underscore_char();
bpcs = kanji_char_set::bytesPerChar();
break;
case CharInfo::KSC5601_MP:
default:
wPercentChar = ksc5601_char_set::percent_char();
wUnderScoreChar = ksc5601_char_set::underscore_char();
bpcs = ksc5601_char_set::bytesPerChar();
break;
}
const char* escapeChar;
if (getNumOperands() < 4)
escapeChar = NULL;
else {
// get length of escape character
ULng32 len3 = getOperand(3)->getLength(op_data[-MAX_OPERANDS+3]);
escapeChar = op_data[3];
if ( len3 != (ULng32)bpcs ) {
ExRaiseSqlError(exHeap, diagsArea, EXE_INVALID_ESCAPE_CHARACTER);
return ex_expr::EXPR_ERROR;
}
}
LikePatternString patternString(op_data[2], (UInt16)len2,
getOperand(1)->getCharSet(), escapeChar, BYTES_PER_NAWCHAR,
(char*)&wUnderScoreChar, BYTES_PER_NAWCHAR,
(char*)&wPercentChar, BYTES_PER_NAWCHAR
);
LikePattern pattern(patternString, exHeap, CharInfo::UNICODE);
if (pattern.error()) {
ExRaiseSqlError(exHeap, diagsArea, EXE_INVALID_ESCAPE_SEQUENCE);
return ex_expr::EXPR_ERROR;
}
NABoolean matchFlag = pattern.matches(op_data[1], (UInt16)len1,
CharInfo::UCS2);
if (pattern.error())
{
ExRaiseSqlError(exHeap, diagsArea, pattern.error());
const char *csname = CharInfo::getCharSetName(CharInfo::UCS2);
*(*diagsArea) << DgString0(csname) << DgString1("LIKE CLAUSE");
return ex_expr::EXPR_ERROR;
}
*(Lng32 *)op_data[0] = (Lng32)matchFlag;
return ex_expr::EXPR_OK;
}
NABoolean LikePatternHeader::matches(const char* text,
Int32 &headerMatchLen,
CharInfo::CharSet cs)
{
headerMatchLen = 0;
Int32 clauseLen;
LikePatternClause* clause = this;
Lng32 lenEncoded = getLength();
char *pattern = getPattern();
unsigned char *encodedPattern = NULL;
CharInfo::Collation co = getCollation();
UInt16 nPasses = 1;
NABoolean systemCollationFlag = CollationInfo::isSystemCollation(co);
if (systemCollationFlag)
{
nPasses = CollationInfo::getCollationNPasses(co);
encodedPattern = getEncodedPattern();
}
do {
if (systemCollationFlag)
{
clause->setEncodedPattern(encodedPattern);
clause->setCollation(this->getCollation());
}
if (NOT clause->matches(text))
return FALSE;
clauseLen = clause->getLength();
if(clause->getType() == LikePatternStringIterator::UNDERSCORE)
{
// underscore match character, not byte
if (systemCollationFlag)
{
Int32 len = clause->getLength()*nPasses;
text += len;
encodedPattern += len;
headerMatchLen += len;
}
else
{
Int32 number_bytes = 1;
for(Int32 k = 0; k < clause->getLength(); k++)
{
number_bytes = Attributes::getFirstCharLength(text, strlen(text), cs);
if(number_bytes < 0)
{
setError(EXE_INVALID_CHARACTER);
return FALSE;
}
text += number_bytes;
headerMatchLen += number_bytes;
}
}
}
else
{
if (systemCollationFlag)
{
Int32 len = clauseLen*nPasses;
text += len;
encodedPattern += len;
headerMatchLen += len;
}
else
{
text += clauseLen;
headerMatchLen += clauseLen;
}
}
clause = clause->getNextClause();
} while (clause != NULL);
return TRUE;
}
NABoolean LikePatternHeader::matchesR(const char * text,
const char * &endText,
CharInfo::CharSet cs
)
{
LikePatternClause* clause = this;
LikePatternClause* clauseR = this;
const char *p, *p1;
Int32 firstCharLen;
CollHeap *heap = getExHeap();
Int32 bufferLength = endText - text;
Int32 headerLength = this->getLength();
char *charLengthInBuf = NULL;
Int32 numberOfCharInBuf;
const Int32 smallBufSize = 128;
char smallBuf[smallBufSize];
CharInfo::Collation co = getCollation();
NABoolean systemCollationFlag = CollationInfo::isSystemCollation(co);
NABoolean deallocateNeeded = FALSE;
UInt16 nPasses = 1;
unsigned char *headerPattern;
if (systemCollationFlag)
{
headerPattern = getEncodedPattern();
nPasses = CollationInfo::getCollationNPasses(co);
headerLength *= nPasses;
}
else
{
if(bufferLength <= smallBufSize)
charLengthInBuf = smallBuf;
else
{
charLengthInBuf = new(heap) char[bufferLength];
deallocateNeeded = TRUE;
}
headerPattern = (unsigned char *)this->getPattern();
}
// Find the last clause in the header
while (clauseR->getNextClause() != NULL)
clauseR = clauseR->getNextClause();
do
{
// clauseR->getLength() = number of byte of the character in pattern
if(clauseR->getType() == LikePatternStringIterator::UNDERSCORE)
{
// One underscore match character, not byte. One clause may have more
// than one underscore.
Int32 numOfUnderscore = clauseR->getLength();
if(systemCollationFlag)
{
endText -= (numOfUnderscore * nPasses);
headerLength -= (clauseR->getLength() * nPasses);
if(endText < text) // String left is shorter than the pattern
{
if(deallocateNeeded)
NADELETEBASIC(charLengthInBuf, heap);
return FALSE;
}
}
else
{
numberOfCharInBuf =
Attributes::getCharLengthInBuf(text, endText, charLengthInBuf, cs);
if(numberOfCharInBuf < numOfUnderscore)
{
if(deallocateNeeded)
NADELETEBASIC(charLengthInBuf, heap);
if(numberOfCharInBuf < 0)
setError(EXE_INVALID_CHARACTER);
return FALSE;
}
for( Int32 k = 1; k <= numOfUnderscore; k++)
endText -= charLengthInBuf[numberOfCharInBuf - k];
}
}
else
{
p = endText - clauseR->getLength()*nPasses;
p1 = text;
// p1 point to the beginning of each character
if(systemCollationFlag)
{
if(p < p1) // String left is shorter than the pattern
{
if(deallocateNeeded)
NADELETEBASIC(charLengthInBuf, heap);
return FALSE;
}
else
{
clauseR->setCollation(this->getCollation());
clauseR->setEncodedPattern
(getEncodedPattern()+(headerLength - (clauseR->getLength()*nPasses)));
}
}
else
{
while (p1 < p)
{
firstCharLen = Attributes::getFirstCharLength(p1, endText - p1, cs);
p1 += firstCharLen;
}
if(p1 != p)
{
if(deallocateNeeded)
NADELETEBASIC(charLengthInBuf, heap);
return FALSE;
}
}
if(NOT clauseR->matches(p))
{
if(deallocateNeeded)
NADELETEBASIC(charLengthInBuf, heap);
return FALSE;
}
endText = p;
headerLength -= (clauseR->getLength()*nPasses);
}
clauseR = clauseR->getPreviousClause();
} while (clauseR);
if(deallocateNeeded)
NADELETEBASIC(charLengthInBuf, heap);
return TRUE;
}
NABoolean LikePatternClause::matches(const char* text)
{
if (getType() == LikePatternStringIterator::NON_WILDCARD)
{
CharInfo::Collation co = getCollation();
Lng32 clauseLength = getLength();
unsigned char *pattern;
UInt16 nPasses;
if (CollationInfo::isSystemCollation(co))
{
pattern = encodedPattern_;
nPasses = CollationInfo::getCollationNPasses(co);
clauseLength *= nPasses;
}
else
pattern = (unsigned char *)pattern_;
for (UInt16 i = 0; i < clauseLength; i++)
if (pattern[i] != (unsigned char)text[i])
return FALSE;
}
return TRUE;
}