/* * 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[128] = { 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) */ }; template 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 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 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 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 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 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 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 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(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(str), length / sizeof(CharType), (escape ? *reinterpret_cast(escape) : 0), escape_length != 0, *reinterpret_cast(sql_match_any), *reinterpret_cast(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 evaluator(*tdbb->getDefaultPool(), reinterpret_cast(p), pl / sizeof(CharType), (escape ? *reinterpret_cast(escape) : 0), escape_length != 0, *reinterpret_cast(sql_match_any), *reinterpret_cast(sql_match_one)); evaluator.processNextChunk(reinterpret_cast(s), sl / sizeof(CharType)); return evaluator.getResult(); } private: Firebird::LikeEvaluator evaluator; }; template 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(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(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 evaluator(*tdbb->getDefaultPool(), reinterpret_cast(p), pl / sizeof(CharType)); evaluator.processNextChunk(reinterpret_cast(s), sl / sizeof(CharType)); return evaluator.getResult(); } private: Firebird::ContainsEvaluator evaluator; }; template 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(s), sl, reinterpret_cast(p), pl); } }; template 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(search), search_len, reinterpret_cast(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(match), match_bytes, reinterpret_cast(control), control_bytes, reinterpret_cast(combined), combined_bytes); } }; template 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, UCHAR> uchar_contains_direct; typedef ContainsObjectImpl, USHORT> ushort_contains_direct; typedef ContainsObjectImpl, ULONG> ulong_contains_direct; typedef MatchesObjectImpl, UCHAR> uchar_matches_canonical; typedef SleuthObjectImpl, UCHAR> uchar_sleuth_canonical; typedef LikeObjectImpl, UCHAR> uchar_like_canonical; typedef ContainsObjectImpl >, UCHAR> uchar_contains_canonical; typedef MatchesObjectImpl, USHORT> ushort_matches_canonical; typedef SleuthObjectImpl, USHORT> ushort_sleuth_canonical; typedef LikeObjectImpl, USHORT> ushort_like_canonical; typedef ContainsObjectImpl >, USHORT> ushort_contains_canonical; typedef MatchesObjectImpl, ULONG> ulong_matches_canonical; typedef SleuthObjectImpl, ULONG> ulong_sleuth_canonical; typedef LikeObjectImpl, ULONG> ulong_like_canonical; typedef ContainsObjectImpl >, 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(id, tt, cs); } else { return FB_NEW(pool) CollationImpl(id, tt, cs); } break; case 2: if (tt->texttype_flags & TEXTTYPE_DIRECT_MATCH) { return FB_NEW(pool) CollationImpl(id, tt, cs); } else { return FB_NEW(pool) CollationImpl(id, tt, cs); } break; case 4: if (tt->texttype_flags & TEXTTYPE_DIRECT_MATCH) { return FB_NEW(pool) CollationImpl(id, tt, cs); } else { return FB_NEW(pool) CollationImpl(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