/* * 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_like.h" #include "../jrd/evl_string.h" #include "../jrd/intl_classes.h" #include "../jrd/lck_proto.h" using namespace Jrd; namespace { // 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