8
0
mirror of https://github.com/FirebirdSQL/firebird.git synced 2025-01-26 06:43:04 +01:00
firebird-mirror/src/jrd/Collation.cpp
2006-12-04 17:55:25 +00:00

893 lines
27 KiB
C++

/*
* PROGRAM: JRD Intl
* MODULE: Collation.cpp
* DESCRIPTION: International text support routines
*
* copyright (c) 1992, 1993 by Borland International
*/
/************* history ************
*
* COMPONENT: JRD MODULE: INTL.CPP
* generated by Marion V2.5 2/6/90
* from dev db on 4-JAN-1995
*****************************************************************
*
* PR 2002-06-02 Added ugly c hack in
* intl_back_compat_alloc_func_lookup.
* When someone has time we need to change the references to
* return (void*) function to something more C++ like
*
* 42 4711 3 11 17 tamlin 2001
* Added silly numbers before my name, and converted it to C++.
*
* 18850 daves 4-JAN-1995
* Fix gds__alloc usage
*
* 18837 deej 31-DEC-1994
* fixing up HARBOR_MERGE
*
* 18821 deej 27-DEC-1994
* HARBOR MERGE
*
* 18789 jdavid 19-DEC-1994
* Cast some functions
*
* 17508 jdavid 15-JUL-1994
* Bring it up to date
*
* 17500 daves 13-JUL-1994
* Bug 6645: Different calculation of partial keys
*
* 17202 katz 24-MAY-1994
* PC_PLATFORM requires the .dll extension
*
* 17191 katz 23-MAY-1994
* OS/2 requires the .dll extension
*
* 17180 katz 23-MAY-1994
* Define location of DLL on OS/2
*
* 17149 katz 20-MAY-1994
* In JRD, isc_arg_number arguments are SLONG's not int's
*
* 16633 daves 19-APR-1994
* Bug 6202: International licensing uses INTERNATIONAL product code
*
* 16555 katz 17-APR-1994
* The last argument of calls to ERR_post should be 0
*
* 16521 katz 14-APR-1994
* Borland C needs a decorated symbol to lookup
*
* 16403 daves 8-APR-1994
* Bug 6441: Emit an error whenever transliteration from ttype_binary attempted
*
* 16141 katz 28-MAR-1994
* Don't declare return value from ISC_lookup_entrypoint as API_ROUTINE
*
* The contents of this file are subject to the Interbase Public
* License Version 1.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.Inprise.com/IPL.html
*
* Software distributed under the License is distributed on an
* "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express
* or implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code was created by Inprise Corporation
* and its predecessors. Portions created by Inprise Corporation are
* Copyright (C) Inprise Corporation.
*
* All Rights Reserved.
* Contributor(s): ______________________________________.
*
* 2002.10.29 Sean Leyne - Removed obsolete "Netware" port
*
* 2002.10.30 Sean Leyne - Removed support for obsolete "PC_PLATFORM" define
*
* 2006.10.10 Adriano dos Santos Fernandes - refactored from intl.cpp
*
*/
#include "firebird.h"
#include "gen/iberror.h"
#include "../jrd/jrd.h"
#include "../jrd/err_proto.h"
#include "../jrd/evl_string.h"
#include "../jrd/intl_classes.h"
#include "../jrd/lck_proto.h"
#include "../jrd/intl_classes.h"
#include "../jrd/TextType.h"
using namespace Jrd;
namespace {
// Below is former evl_like_h file
// It was not used except Collation.cpp
#define SLEUTH_insensitive 1
static const UCHAR special[256] = {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 1, 0, 1, 0, 0, /* $%*+- (dollar, percent, star, plus, minus) */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, /* ? (question) */
1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* @ (at-sign) */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, /* [ (open square) */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, /* ~ (tilde) */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
};
template <class MATCHESTYPE>
bool MATCHESNAME(Jrd::thread_db* tdbb, Jrd::TextType* obj,
const MATCHESTYPE* p1, SLONG l1_bytes,
const MATCHESTYPE* p2, SLONG l2_bytes)
{
/**************************************
*
* E V L _ ? ? _ m a t c h e s
* E V L _ w c _ m a t c h e s
* E V L _ n c _ m a t c h e s
*
**************************************
*
* Functional description
* Return true if a string (p1, l1) matches a given pattern (p2, l2).
* The character '?' in the pattern may match any single character
* in the the string, and the character '*' may match any sequence
* of characters.
*
* Wide SCHAR version operates on short-based buffer,
* instead of SCHAR-based.
*
* Matches is not a case-sensitive operation, thus it has no
* 8-bit international impact.
*
**************************************/
fb_assert(p1 != NULL);
fb_assert(p2 != NULL);
fb_assert((l1_bytes % sizeof(MATCHESTYPE)) == 0);
fb_assert((l2_bytes % sizeof(MATCHESTYPE)) == 0);
fb_assert((obj->getCanonicalWidth() == sizeof(MATCHESTYPE)));
SLONG l1 = l1_bytes / sizeof(MATCHESTYPE);
SLONG l2 = l2_bytes / sizeof(MATCHESTYPE);
while (l2-- > 0) {
const MATCHESTYPE c = *p2++;
if (c == *(MATCHESTYPE*)obj->getGdmlMatchAnyCanonic()) {
while ((l2 > 0) && (*p2 == *(MATCHESTYPE*)obj->getGdmlMatchAnyCanonic())) {
l2--;
p2++;
}
if (l2 == 0)
return true;
while (l1)
{
if (MATCHESNAME(tdbb, obj, p1++,
l1-- * sizeof(MATCHESTYPE), p2,
l2 * sizeof(MATCHESTYPE)))
{
return true;
}
}
return false;
}
if (l1-- == 0)
return false;
if (c != *(MATCHESTYPE*)obj->getGdmlMatchOneCanonic() && c != *p1)
return false;
p1++;
}
return !l1;
}
template <class SLEUTHTYPE>
bool SLEUTHNAME(Jrd::thread_db* tdbb_dummy, Jrd::TextType* obj, USHORT flags,
const SLEUTHTYPE* search, SLONG search_len,
const SLEUTHTYPE* match, SLONG match_len)
{
/**************************************
*
* E V L _ ? ? _ s l e u t h _ c h e c k
*
**************************************
*
* Functional description
* Evaluate the "sleuth" search operator.
*
* Turn the (pointer, byte length) input parameters into
* (pointer, end_pointer) for use in SLEUTH_AUX
*
**************************************/
fb_assert((match_len % sizeof(SLEUTHTYPE)) == 0);
fb_assert((search_len % sizeof(SLEUTHTYPE)) == 0);
fb_assert(obj->getCanonicalWidth() == sizeof(SLEUTHTYPE));
const SLEUTHTYPE* const end_match = match + (match_len / sizeof(SLEUTHTYPE));
const SLEUTHTYPE* const end_search = search + (search_len / sizeof(SLEUTHTYPE));
return SLEUTH_AUX(obj, flags, search, end_search, match, end_match);
}
template <class SLEUTHTYPE>
ULONG SLEUTH_MERGE_NAME(Jrd::thread_db* tdbb_dummy, Jrd::TextType* obj,
const SLEUTHTYPE* match, SLONG match_bytes,
const SLEUTHTYPE* control, SLONG control_bytes,
SLEUTHTYPE* combined, SLONG combined_bytes)
{
/**************************************
*
* E V L _ ? ? _ s l e u t h _ m e r g e
*
**************************************
*
* Functional description
* Merge the matching pattern and control strings to give a cannonical
* matching pattern. Return the length of the combined string.
*
* What this routine does is to take the language template, strip off
* the prefix and put it in the output string, then parse the definitions
* into an array of character pointers. The index array is the defined
* character. The routine then takes the actual match pattern and uses
* the characters in it to index into the definitions to produce an equivalent
* pattern in the cannonical language.
*
* The silly loop setting *v++ to zero initializes the array up to the
* highest character defined (also max_op). Believe it or not, that part
* is not a bug.
*
**************************************/
fb_assert(match != NULL);
fb_assert(control != NULL);
fb_assert(combined != NULL);
fb_assert((match_bytes % sizeof(SLEUTHTYPE)) == 0);
fb_assert((control_bytes % sizeof(SLEUTHTYPE)) == 0);
fb_assert(obj->getCanonicalWidth() == sizeof(SLEUTHTYPE));
const SLEUTHTYPE* const end_match = match + (match_bytes / sizeof(SLEUTHTYPE));
const SLEUTHTYPE* const end_control = control + (control_bytes / sizeof(SLEUTHTYPE));
SLEUTHTYPE max_op = 0;
SLEUTHTYPE* comb = combined;
SLEUTHTYPE* vector[256];
SLEUTHTYPE** v = vector;
SLEUTHTYPE temp[256];
SLEUTHTYPE* t = temp;
/* Parse control string into substitution strings and initializing string */
while (control < end_control) {
SLEUTHTYPE c = *control++;
if (*control == *(SLEUTHTYPE*)obj->getGdmlSubstituteCanonic()) {
/* Note: don't allow substitution characters larger than vector */
SLEUTHTYPE** const end_vector =
vector + (((int)c < FB_NELEM(vector)) ? c : 0);
while (v <= end_vector)
*v++ = 0;
*end_vector = t;
++control;
while (control < end_control) {
c = *control++;
if ((t > temp && t[-1] == *(SLEUTHTYPE*)obj->getGdmlQuoteCanonic())
|| ((c != *(SLEUTHTYPE*)obj->getGdmlCommaCanonic()) && (c != *(SLEUTHTYPE*)obj->getGdmlRParenCanonic())))
{
*t++ = c;
}
else
break;
}
*t++ = 0;
}
else if (c == *(SLEUTHTYPE*)obj->getGdmlQuoteCanonic() && control < end_control)
*comb++ = *control++;
else if (c == *(SLEUTHTYPE*)obj->getGdmlRParenCanonic())
break;
else if (c != *(SLEUTHTYPE*)obj->getGdmlLParenCanonic())
*comb++ = c;
}
max_op = v - vector;
/* Interpret matching string, substituting where appropriate */
while (match < end_match) {
const SLEUTHTYPE c = *match++;
/* if we've got a defined character, slurp the definition */
SLEUTHTYPE* p;
if (c <= max_op && (p = vector[c])) {
while (*p)
*comb++ = *p++;
/* if we've got the definition of a quote character,
slurp the next character too */
if (comb > combined && comb[-1] == *(SLEUTHTYPE*)obj->getGdmlQuoteCanonic() && *match)
*comb++ = *match++;
}
/* at this point we've got a non-match, but as it might be one of ours,
quote it. */
else {
if ((((size_t) c) < sizeof(special)) && special[c] &&
comb > combined && comb[-1] != *(SLEUTHTYPE*)obj->getGdmlQuoteCanonic())
{
*comb++ = *(SLEUTHTYPE*)obj->getGdmlQuoteCanonic();
}
*comb++ = c;
}
}
/* Put in trailing stuff */
while (control < end_control)
*comb++ = *control++;
/* YYY - need to add code watching for overflow of combined */
return (comb - combined) * sizeof(SLEUTHTYPE);
}
template <class SLEUTHTYPE>
static bool SLEUTH_AUX(
Jrd::TextType* obj,
USHORT flags,
const SLEUTHTYPE* search,
const SLEUTHTYPE* end_search,
const SLEUTHTYPE* match, const SLEUTHTYPE* end_match)
{
/**************************************
*
* s l e u t h _ a u x
*
**************************************
*
* Functional description
* Evaluate the "sleuth" search operator.
*
**************************************/
fb_assert(search != NULL);
fb_assert(end_search != NULL);
fb_assert(match != NULL);
fb_assert(end_match != NULL);
fb_assert(search <= end_search);
fb_assert(match <= end_match);
fb_assert(obj->getCanonicalWidth() == sizeof(SLEUTHTYPE));
while (match < end_match) {
SLEUTHTYPE c = *match++;
if ((c == *(SLEUTHTYPE*)obj->getGdmlQuoteCanonic() && (c = *match++)) ||
((((size_t) c) < sizeof(special)) && !special[c]))
{
if (match >= end_match || *match != *(SLEUTHTYPE*)obj->getGdmlMatchAnyCanonic()) {
if (search >= end_search)
return false;
const SLEUTHTYPE d = *search++;
if (c != d)
return false;
}
else {
++match;
for (;;)
if (SLEUTH_AUX
(obj, flags, search, end_search, match, end_match))
{
return true;
}
else if (search < end_search) {
const SLEUTHTYPE d = *search++;
if (c != d)
return false;
}
else
return false;
}
}
else if (c == *(SLEUTHTYPE*)obj->getGdmlMatchOneCanonic())
if (match >= end_match || *match != *(SLEUTHTYPE*)obj->getGdmlMatchAnyCanonic()) {
if (search >= end_search)
return false;
search++;
}
else {
if (++match >= end_match)
return true;
for (;;)
if (SLEUTH_AUX
(obj, flags, search, end_search, match,
end_match))
{
return true;
}
else if (++search >= end_search)
return false;
}
else if (c == *(SLEUTHTYPE*)obj->getGdmlClassStartCanonic()) {
const SLEUTHTYPE* const char_class = match;
while (*match++ != *(SLEUTHTYPE*)obj->getGdmlClassEndCanonic()) {
if (match >= end_match)
return false;
}
const SLEUTHTYPE* const end_class = match - 1;
if (match >= end_match || *match != *(SLEUTHTYPE*)obj->getGdmlMatchAnyCanonic()) {
if (!SLEUTH_CLASS_NAME
(obj, flags, char_class, end_class, *search++))
{
return false;
}
}
else {
++match;
for (;;)
if (SLEUTH_AUX
(obj, flags, search, end_search, match,
end_match))
{
return true;
}
else if (search < end_search) {
if (!SLEUTH_CLASS_NAME
(obj, flags, char_class, end_class, *search++))
{
return false;
}
}
else
return false;
}
}
else if (c == *(SLEUTHTYPE*)obj->getGdmlFlagSetCanonic()) {
c = *match++;
if (c == *(SLEUTHTYPE*)obj->getGdmlLowerSCanonic() || c == *(SLEUTHTYPE*)obj->getGdmlUpperSCanonic())
flags &= ~SLEUTH_insensitive;
}
else if (c == *(SLEUTHTYPE*)obj->getGdmlFlagClearCanonic()) {
c = *match++;
if (c == *(SLEUTHTYPE*)obj->getGdmlLowerSCanonic() || c == *(SLEUTHTYPE*)obj->getGdmlUpperSCanonic())
flags |= SLEUTH_insensitive;
}
}
if (search < end_search)
return false;
return true;
}
template <class SLEUTHTYPE>
static bool SLEUTH_CLASS_NAME(
Jrd::TextType* obj,
USHORT flags,
const SLEUTHTYPE* char_class,
const SLEUTHTYPE* const end_class,
SLEUTHTYPE character)
{
/**************************************
*
* s l e u t h _ c l a s s
*
**************************************
*
* Functional description
* See if a character is a member of a class.
* Japanese version operates on short-based buffer,
* instead of SCHAR-based.
*
**************************************/
fb_assert(char_class != NULL);
fb_assert(end_class != NULL);
fb_assert(char_class <= end_class);
fb_assert(obj->getCanonicalWidth() == sizeof(SLEUTHTYPE));
bool result = true;
if (*char_class == *(SLEUTHTYPE*)obj->getGdmlNotCanonic()) {
++char_class;
result = false;
}
while (char_class < end_class) {
const SLEUTHTYPE c = *char_class++;
if (c == *(SLEUTHTYPE*)obj->getGdmlQuoteCanonic()) {
if (*char_class++ == character)
return true;
}
else if (*char_class == *(SLEUTHTYPE*)obj->getGdmlRangeCanonic()) {
char_class += 2;
if (character >= c && character <= char_class[-1])
return result;
}
else if (character == c)
return result;
}
return !result;
}
// Below are templates for functions used in Collation implementation
class NullStrConverter {
public:
NullStrConverter(thread_db* tdbb, const TextType* obj, const UCHAR *str, SLONG len) { }
};
template <typename PrevConverter>
class UpcaseConverter : public PrevConverter {
public:
UpcaseConverter(thread_db* tdbb, TextType* obj, const UCHAR* &str, SLONG &len) :
PrevConverter(tdbb, obj, str, len)
{
if (len > (int) sizeof(tempBuffer))
out_str = FB_NEW(*tdbb->getDefaultPool()) UCHAR[len];
else
out_str = tempBuffer;
obj->str_to_upper(len, str, len, out_str);
str = out_str;
}
~UpcaseConverter() {
if (out_str != tempBuffer)
delete[] out_str;
}
private:
UCHAR tempBuffer[100], *out_str;
};
template <typename PrevConverter>
class CanonicalConverter : public PrevConverter {
public:
CanonicalConverter(thread_db* tdbb, TextType* obj, const UCHAR* &str, SLONG &len) :
PrevConverter(tdbb, obj, str, len)
{
SLONG out_len = len / obj->getCharSet()->minBytesPerChar() * obj->getCanonicalWidth();
if (out_len > (int) sizeof(tempBuffer))
out_str = FB_NEW(*tdbb->getDefaultPool()) UCHAR[out_len];
else
out_str = tempBuffer;
if (str)
{
len = obj->canonical(len, str, out_len, out_str) * obj->getCanonicalWidth();
str = out_str;
}
else
len = 0;
}
~CanonicalConverter() {
if (out_str != tempBuffer)
delete[] out_str;
}
private:
UCHAR tempBuffer[100], *out_str;
};
template <typename StrConverter, typename CharType>
class LikeObjectImpl : public LikeObject {
public:
LikeObjectImpl(MemoryPool& pool, const CharType* str, SLONG str_len,
CharType escape, bool use_escape,
CharType sql_match_any, CharType sql_match_one)
: evaluator(pool, str, str_len, escape, use_escape, sql_match_any, sql_match_one)
{ }
void reset() { evaluator.reset(); }
bool result() { return evaluator.getResult(); }
bool process(thread_db* tdbb, Jrd::TextType* ttype, const UCHAR* str, SLONG length) {
StrConverter cvt(tdbb, ttype, str, length);
fb_assert(length % sizeof(CharType) == 0);
return evaluator.processNextChunk(
reinterpret_cast<const CharType*>(str), length / sizeof(CharType));
}
~LikeObjectImpl() {}
static LikeObject* create(thread_db* tdbb, TextType* ttype, const UCHAR* str, SLONG length,
const UCHAR* escape, SLONG escape_length,
const UCHAR* sql_match_any, SLONG match_any_length,
const UCHAR* sql_match_one, SLONG match_one_length)
{
StrConverter cvt(tdbb, ttype, str, length),
cvt_escape(tdbb, ttype, escape, escape_length),
cvt_match_any(tdbb, ttype, sql_match_any, match_any_length),
cvt_match_one(tdbb, ttype, sql_match_one, match_one_length);
fb_assert(length % sizeof(CharType) == 0);
return FB_NEW(*tdbb->getDefaultPool()) LikeObjectImpl(*tdbb->getDefaultPool(),
reinterpret_cast<const CharType*>(str), length / sizeof(CharType),
(escape ? *reinterpret_cast<const CharType*>(escape) : 0), escape_length != 0,
*reinterpret_cast<const CharType*>(sql_match_any),
*reinterpret_cast<const CharType*>(sql_match_one));
}
static bool evaluate(thread_db* tdbb, TextType* ttype, const UCHAR* s, SLONG sl,
const UCHAR* p, SLONG pl, const UCHAR* escape, SLONG escape_length, const UCHAR* sql_match_any, SLONG match_any_length, const UCHAR* sql_match_one, SLONG match_one_length)
{
StrConverter cvt1(tdbb, ttype, p, pl),
cvt2(tdbb, ttype, s, sl),
cvt_escape(tdbb, ttype, escape, escape_length),
cvt_match_any(tdbb, ttype, sql_match_any, match_any_length),
cvt_match_one(tdbb, ttype, sql_match_one, match_one_length);
fb_assert(pl % sizeof(CharType) == 0);
fb_assert(sl % sizeof(CharType) == 0);
Firebird::LikeEvaluator<CharType> evaluator(*tdbb->getDefaultPool(),
reinterpret_cast<const CharType*>(p), pl / sizeof(CharType),
(escape ? *reinterpret_cast<const CharType*>(escape) : 0), escape_length != 0,
*reinterpret_cast<const CharType*>(sql_match_any),
*reinterpret_cast<const CharType*>(sql_match_one));
evaluator.processNextChunk(reinterpret_cast<const CharType*>(s), sl / sizeof(CharType));
return evaluator.getResult();
}
private:
Firebird::LikeEvaluator<CharType> evaluator;
};
template <typename StrConverter, typename CharType>
class ContainsObjectImpl : public ContainsObject
{
public:
ContainsObjectImpl(MemoryPool& pool, const CharType* str, SLONG str_len)
: evaluator(pool, str, str_len)
{ }
void reset() { evaluator.reset(); }
bool result() { return evaluator.getResult(); }
bool process(thread_db* tdbb, Jrd::TextType* ttype, const UCHAR* str, SLONG length) {
StrConverter cvt(tdbb, ttype, str, length);
fb_assert(length % sizeof(CharType) == 0);
return evaluator.processNextChunk(
reinterpret_cast<const CharType*>(str), length / sizeof(CharType));
}
~ContainsObjectImpl() {}
static ContainsObject* create(thread_db* tdbb, TextType* ttype, const UCHAR* str, SLONG length) {
StrConverter cvt(tdbb, ttype, str, length);
fb_assert(length % sizeof(CharType) == 0);
return FB_NEW(*tdbb->getDefaultPool()) ContainsObjectImpl(*tdbb->getDefaultPool(),
reinterpret_cast<const CharType*>(str), length / sizeof(CharType));
}
static bool evaluate(thread_db* tdbb, TextType* ttype, const UCHAR* s, SLONG sl,
const UCHAR* p, SLONG pl)
{
StrConverter cvt1(tdbb, ttype, p, pl), cvt2(tdbb, ttype, s, sl);
fb_assert(pl % sizeof(CharType) == 0);
fb_assert(sl % sizeof(CharType) == 0);
Firebird::ContainsEvaluator<CharType> evaluator(*tdbb->getDefaultPool(),
reinterpret_cast<const CharType*>(p), pl / sizeof(CharType));
evaluator.processNextChunk(reinterpret_cast<const CharType*>(s), sl / sizeof(CharType));
return evaluator.getResult();
}
private:
Firebird::ContainsEvaluator<CharType> evaluator;
};
template <typename StrConverter, typename CharType>
class MatchesObjectImpl
{
public:
static bool evaluate(thread_db* tdbb, TextType* ttype, const UCHAR* s, SLONG sl,
const UCHAR* p, SLONG pl)
{
StrConverter cvt1(tdbb, ttype, p, pl), cvt2(tdbb, ttype, s, sl);
fb_assert(pl % sizeof(CharType) == 0);
fb_assert(sl % sizeof(CharType) == 0);
return MATCHESNAME(tdbb, ttype, reinterpret_cast<const CharType*>(s), sl,
reinterpret_cast<const CharType*>(p), pl);
}
};
template <typename StrConverter, typename CharType>
class SleuthObjectImpl
{
public:
static bool check(thread_db* tdbb, TextType* ttype, USHORT flags,
const UCHAR* search, SLONG search_len,
const UCHAR* match, SLONG match_len)
{
StrConverter cvt1(tdbb, ttype, search, search_len);//, cvt2(tdbb, ttype, match, match_len);
fb_assert(search_len % sizeof(CharType) == 0);
fb_assert(match_len % sizeof(CharType) == 0);
return SLEUTHNAME(tdbb, ttype, flags,
reinterpret_cast<const CharType*>(search), search_len,
reinterpret_cast<const CharType*>(match), match_len);
}
static ULONG merge(thread_db* tdbb, TextType* ttype,
const UCHAR* match, SLONG match_bytes,
const UCHAR* control, SLONG control_bytes,
UCHAR* combined, SLONG combined_bytes)
{
StrConverter cvt1(tdbb, ttype, match, match_bytes), cvt2(tdbb, ttype, control, control_bytes);
fb_assert(match_bytes % sizeof(CharType) == 0);
fb_assert(control_bytes % sizeof(CharType) == 0);
return SLEUTH_MERGE_NAME(tdbb, ttype,
reinterpret_cast<const CharType*>(match), match_bytes,
reinterpret_cast<const CharType*>(control), control_bytes,
reinterpret_cast<CharType*>(combined), combined_bytes);
}
};
template <typename pContainsObjectImpl, typename pLikeObjectImpl,
typename pMatchesObjectImpl, typename pSleuthObjectImpl>
class CollationImpl : public Collation
{
public:
CollationImpl(TTYPE_ID a_type, texttype* a_tt, CharSet* a_cs) : Collation(a_type, a_tt, a_cs) {}
virtual bool matches(thread_db* tdbb, const UCHAR* a, SLONG b, const UCHAR* c, SLONG d)
{
return pMatchesObjectImpl::evaluate(tdbb, this, a, b, c, d);
}
virtual bool sleuth_check(thread_db* tdbb, USHORT a, const UCHAR* b, SLONG c, const UCHAR* d, SLONG e)
{
return pSleuthObjectImpl::check(tdbb, this, a, b, c, d, e);
}
virtual ULONG sleuth_merge(thread_db* tdbb, const UCHAR* a, SLONG b, const UCHAR* c, SLONG d, UCHAR* e, SLONG f)
{
return pSleuthObjectImpl::merge(tdbb, this, a, b, c, d, e, f);
}
virtual bool like(thread_db* tdbb, const UCHAR* s, SLONG sl, const UCHAR* p, SLONG pl, const UCHAR* escape, SLONG escape_length)
{
return pLikeObjectImpl::evaluate(tdbb, this, s, sl, p, pl, escape, escape_length, getCharSet()->getSqlMatchAny(), getCharSet()->getSqlMatchAnyLength(), getCharSet()->getSqlMatchOne(), getCharSet()->getSqlMatchOneLength());
}
virtual LikeObject *like_create(thread_db* tdbb, const UCHAR* p, SLONG pl, const UCHAR* escape, SLONG escape_length)
{
return pLikeObjectImpl::create(tdbb, this, p, pl, escape, escape_length, getCharSet()->getSqlMatchAny(), getCharSet()->getSqlMatchAnyLength(), getCharSet()->getSqlMatchOne(), getCharSet()->getSqlMatchOneLength());
}
virtual bool contains(thread_db* tdbb, const UCHAR* s, SLONG sl, const UCHAR* p, SLONG pl)
{
return pContainsObjectImpl::evaluate(tdbb, this, s, sl, p, pl);
}
virtual ContainsObject *contains_create(thread_db* tdbb, const UCHAR* p, SLONG pl)
{
return pContainsObjectImpl::create(tdbb, this, p, pl);
}
};
typedef ContainsObjectImpl<UpcaseConverter<NullStrConverter>, UCHAR> uchar_contains_direct;
typedef ContainsObjectImpl<UpcaseConverter<NullStrConverter>, USHORT> ushort_contains_direct;
typedef ContainsObjectImpl<UpcaseConverter<NullStrConverter>, ULONG> ulong_contains_direct;
typedef MatchesObjectImpl<CanonicalConverter<NullStrConverter>, UCHAR> uchar_matches_canonical;
typedef SleuthObjectImpl<CanonicalConverter<NullStrConverter>, UCHAR> uchar_sleuth_canonical;
typedef LikeObjectImpl<CanonicalConverter<NullStrConverter>, UCHAR> uchar_like_canonical;
typedef ContainsObjectImpl<CanonicalConverter<UpcaseConverter<NullStrConverter> >, UCHAR> uchar_contains_canonical;
typedef MatchesObjectImpl<CanonicalConverter<NullStrConverter>, USHORT> ushort_matches_canonical;
typedef SleuthObjectImpl<CanonicalConverter<NullStrConverter>, USHORT> ushort_sleuth_canonical;
typedef LikeObjectImpl<CanonicalConverter<NullStrConverter>, USHORT> ushort_like_canonical;
typedef ContainsObjectImpl<CanonicalConverter<UpcaseConverter<NullStrConverter> >, USHORT> ushort_contains_canonical;
typedef MatchesObjectImpl<CanonicalConverter<NullStrConverter>, ULONG> ulong_matches_canonical;
typedef SleuthObjectImpl<CanonicalConverter<NullStrConverter>, ULONG> ulong_sleuth_canonical;
typedef LikeObjectImpl<CanonicalConverter<NullStrConverter>, ULONG> ulong_like_canonical;
typedef ContainsObjectImpl<CanonicalConverter<UpcaseConverter<NullStrConverter> >, ULONG> ulong_contains_canonical;
} // namespace
//-------------
namespace Jrd {
Collation* Collation::createInstance(MemoryPool& pool, TTYPE_ID id, texttype* tt, CharSet* cs)
{
fb_assert(tt->texttype_canonical_width == 1 ||
tt->texttype_canonical_width == 2 ||
tt->texttype_canonical_width == 4);
switch (tt->texttype_canonical_width)
{
case 1:
if (tt->texttype_flags & TEXTTYPE_DIRECT_MATCH)
{
return FB_NEW(pool) CollationImpl<uchar_contains_direct, uchar_like_canonical,
uchar_matches_canonical, uchar_sleuth_canonical>(id, tt, cs);
}
else
{
return FB_NEW(pool) CollationImpl<uchar_contains_canonical, uchar_like_canonical,
uchar_matches_canonical, uchar_sleuth_canonical>(id, tt, cs);
}
break;
case 2:
if (tt->texttype_flags & TEXTTYPE_DIRECT_MATCH)
{
return FB_NEW(pool) CollationImpl<uchar_contains_direct, ushort_like_canonical,
ushort_matches_canonical, ushort_sleuth_canonical>(id, tt, cs);
}
else
{
return FB_NEW(pool) CollationImpl<ushort_contains_canonical, ushort_like_canonical,
ushort_matches_canonical, ushort_sleuth_canonical>(id, tt, cs);
}
break;
case 4:
if (tt->texttype_flags & TEXTTYPE_DIRECT_MATCH)
{
return FB_NEW(pool) CollationImpl<uchar_contains_direct, ulong_like_canonical,
ulong_matches_canonical, ulong_sleuth_canonical>(id, tt, cs);
}
else
{
return FB_NEW(pool) CollationImpl<ulong_contains_canonical, ulong_like_canonical,
ulong_matches_canonical, ulong_sleuth_canonical>(id, tt, cs);
}
break;
}
fb_assert(false);
return NULL; // compiler silencer
}
void Collation::destroy()
{
if (tt->texttype_fn_destroy)
tt->texttype_fn_destroy(tt);
delete tt;
delete existenceLock;
}
void Collation::incUseCount(thread_db* tdbb)
{
++useCount;
}
void Collation::decUseCount(thread_db* tdbb)
{
if (--useCount == 0)
{
if (existenceLock)
LCK_re_post(existenceLock);
}
}
} // namespace Jrd