diff --git a/src/common/IntlUtil.cpp b/src/common/IntlUtil.cpp index cbe32c5a04..f1207c22fd 100644 --- a/src/common/IntlUtil.cpp +++ b/src/common/IntlUtil.cpp @@ -664,7 +664,7 @@ bool IntlUtil::readOneChar(Jrd::CharSet* cs, const UCHAR** s, const UCHAR* end, } -// Transform ICU-VERSION attribute (given by the user) in COLL-VERSION (to be stored). +// Add COLL-VERSION attribute. bool IntlUtil::setupIcuAttributes(charset* cs, const string& specificAttributes, const string& configInfo, string& newSpecificAttributes) { @@ -681,10 +681,19 @@ bool IntlUtil::setupIcuAttributes(charset* cs, const string& specificAttributes, map.get("ICU-VERSION", icuVersion); string collVersion; - if (!UnicodeUtil::getCollVersion(icuVersion, configInfo, collVersion)) + auto icu = UnicodeUtil::getCollVersion(icuVersion, configInfo, collVersion); + + if (!icu) return false; - map.remove("ICU-VERSION"); + if (icuVersion.isEmpty()) + { + int majorVersion, minorVersion; + UnicodeUtil::getICUVersion(icu, majorVersion, minorVersion); + icuVersion.printf("%d.%d", majorVersion, minorVersion); + map.put("ICU-VERSION", icuVersion); + } + map.remove("COLL-VERSION"); if (collVersion.hasData()) @@ -781,16 +790,6 @@ bool IntlUtil::readAttributeChar(Jrd::CharSet* cs, const UCHAR** s, const UCHAR* } -void IntlUtil::getDefaultCollationAttributes(UCharBuffer& collAttributes, charset& cs) -{ - string attributes("ICU-VERSION="); - attributes += Jrd::UnicodeUtil::getDefaultIcuVersion(); - setupIcuAttributes(&cs, attributes, "", attributes); - - collAttributes.push(reinterpret_cast(attributes.c_str()), attributes.length()); -} - - static void unicodeDestroy(texttype* tt) { delete[] const_cast(tt->texttype_name); diff --git a/src/common/IntlUtil.h b/src/common/IntlUtil.h index d7b010ef01..a8471dc13e 100644 --- a/src/common/IntlUtil.h +++ b/src/common/IntlUtil.h @@ -94,7 +94,6 @@ public: static bool setupIcuAttributes(charset* cs, const string& specificAttributes, const string& configInfo, string& newSpecificAttributes); - static void getDefaultCollationAttributes(UCharBuffer& collAttributes, charset& cs); private: static string escapeAttribute(Jrd::CharSet* cs, const string& s); diff --git a/src/common/intlobj_new.h b/src/common/intlobj_new.h index 8ba33c079a..b2dd4055fb 100644 --- a/src/common/intlobj_new.h +++ b/src/common/intlobj_new.h @@ -354,6 +354,20 @@ typedef INTL_BOOL (*pfn_INTL_lookup_texttype) ( const ASCII* config_info ); +/* typedef for texttype lookup entry-point - with status buffer */ +typedef INTL_BOOL (*pfn_INTL_lookup_texttype_with_status) ( + char* status_buffer, + ULONG status_buffer_length, + texttype* tt, + const ASCII* texttype_name, + const ASCII* charset_name, + USHORT attributes, + const UCHAR* specific_attributes, + ULONG specific_attributes_length, + INTL_BOOL ignore_attributes, + const ASCII* config_info +); + /* typedef for charset lookup entry-point */ typedef INTL_BOOL (*pfn_INTL_lookup_charset) ( charset* cs, @@ -379,6 +393,7 @@ typedef ULONG (*pfn_INTL_setup_attributes) ( #define TEXTTYPE_ENTRYPOINT LD_lookup_texttype +#define TEXTTYPE_WITH_STATUS_ENTRYPOINT LD_lookup_texttype_with_status #define CHARSET_ENTRYPOINT LD_lookup_charset #define INTL_VERSION_ENTRYPOINT LD_version #define INTL_SETUP_ATTRIBUTES_ENTRYPOINT LD_setup_attributes diff --git a/src/common/unicode_util.cpp b/src/common/unicode_util.cpp index 6d3a69252b..646be61068 100644 --- a/src/common/unicode_util.cpp +++ b/src/common/unicode_util.cpp @@ -92,22 +92,24 @@ public: // System-wide ICU have no version number at entries names if (!majorVersion) { + fb_assert(false); // ASF: I don't think this code path is correct. + if (module->findSymbol(NULL, name, ptr)) return; } else { // ICU has several schemas for entries names - const char* patterns[] = + const char* const patterns[] = { - "%s_%d", "%s_%d_%d", "%s_%d%d", "%s", NULL + "%s_%d", "%s_%d_%d", "%s_%d%d", "%s" }; string symbol; - for (const char** p = patterns; *p; ++p) + for (auto pattern : patterns) { - symbol.printf(*p, name, majorVersion, minorVersion); + symbol.printf(pattern, name, majorVersion, minorVersion); if (module->findSymbol(NULL, symbol, ptr)) return; } @@ -323,6 +325,7 @@ private: getEntryPoint("ucnv_open", module, ucnv_open); getEntryPoint("ucnv_close", module, ucnv_close); getEntryPoint("ucnv_fromUChars", module, ucnv_fromUChars); + getEntryPoint("u_getVersion", module, u_getVersion); getEntryPoint("u_tolower", module, u_tolower); getEntryPoint("u_toupper", module, u_toupper); getEntryPoint("u_strCompare", module, u_strCompare); @@ -381,8 +384,11 @@ public: if (o) { - o->vMajor = majorVersion; - o->vMinor = minorVersion; + UVersionInfo versionInfo; + o->u_getVersion(versionInfo); + + o->vMajor = versionInfo[0]; + o->vMinor = versionInfo[1]; } return o; @@ -509,15 +515,15 @@ static ModuleLoader::Module* formatAndLoad(const char* templateName, else { // ICU has several schemas for placing version into file name - const char* patterns[] = + const char* const patterns[] = { - "%d_%d", "%d%d", NULL + "%d_%d", "%d.%d", "%d%d" }; PathName s, filename; - for (const char** p = patterns; *p; ++p) + for (auto pattern : patterns) { - s.printf(*p, majorVersion, minorVersion); + s.printf(pattern, majorVersion, minorVersion); filename.printf(templateName, s.c_str()); module = ModuleLoader::fixAndLoadModule(NULL, filename); @@ -1171,7 +1177,7 @@ UnicodeUtil::ICU* UnicodeUtil::loadICU(const string& icuVersion, const string& c getVersions(configInfo, versions); if (versions.isEmpty()) - gds__log("No versions"); + gds__log("No ICU versions specified"); string version = icuVersion.isEmpty() ? versions[0] : icuVersion; if (version == "default") @@ -1298,6 +1304,13 @@ UnicodeUtil::ICU* UnicodeUtil::loadICU(const string& icuVersion, const string& c } +void UnicodeUtil::getICUVersion(ICU* icu, int& majorVersion, int& minorVersion) +{ + majorVersion = icu->majorVersion; + minorVersion = icu->minorVersion; +} + + UnicodeUtil::ConversionICU& UnicodeUtil::getConversionICU() { if (convIcu) @@ -1411,13 +1424,13 @@ string UnicodeUtil::getDefaultIcuVersion() } -bool UnicodeUtil::getCollVersion(const Firebird::string& icuVersion, +UnicodeUtil::ICU* UnicodeUtil::getCollVersion(const Firebird::string& icuVersion, const Firebird::string& configInfo, Firebird::string& collVersion) { ICU* icu = loadICU(icuVersion, configInfo); if (!icu) - return false; + return nullptr; char version[U_MAX_VERSION_STRING_LENGTH]; icu->uVersionToString(icu->collVersion, version); @@ -1427,7 +1440,7 @@ bool UnicodeUtil::getCollVersion(const Firebird::string& icuVersion, else collVersion = version; - return true; + return icu; } UnicodeUtil::Utf16Collation* UnicodeUtil::Utf16Collation::create( @@ -1502,12 +1515,11 @@ UnicodeUtil::Utf16Collation* UnicodeUtil::Utf16Collation::create( tt->texttype_pad_option = (attributes & TEXTTYPE_ATTR_PAD_SPACE) ? true : false; - ICU* icu = loadICU(collVersion, locale, configInfo); - if (!icu) - { - gds__log("loadICU failed"); - return NULL; - } + string icuVersion; + if (specificAttributes.get(IntlUtil::convertAsciiToUtf16("ICU-VERSION"), icuVersion)) + icuVersion = IntlUtil::convertUtf16ToAscii(icuVersion, &error); + + const auto icu = loadICU(icuVersion, collVersion, locale, configInfo); UErrorCode status = U_ZERO_ERROR; HalfStaticArray rulesBuffer; @@ -2000,8 +2012,8 @@ ULONG UnicodeUtil::Utf16Collation::canonical(ULONG srcLen, const USHORT* src, UL UnicodeUtil::ICU* UnicodeUtil::Utf16Collation::loadICU( - const Firebird::string& collVersion, const Firebird::string& locale, - const Firebird::string& configInfo) + const string& icuVersion, const string& collVersion, + const string& locale, const string& configInfo) { ObjectsArray versions; getVersions(configInfo, versions); @@ -2044,7 +2056,13 @@ UnicodeUtil::ICU* UnicodeUtil::Utf16Collation::loadICU( return icu; } - return NULL; + string errorMsg; + errorMsg.printf( + "An ICU library with collation version %s is required but was not found. " + "You may try to install ICU version %s, used to register the collation in this database " + "or look for 'gfix -icu' in Firebird documentation.", + collVersion.c_str(), icuVersion.c_str()); + (Arg::Gds(isc_random) << errorMsg).raise(); } diff --git a/src/common/unicode_util.h b/src/common/unicode_util.h index c7568a13e0..22c00ba2c1 100644 --- a/src/common/unicode_util.h +++ b/src/common/unicode_util.h @@ -58,6 +58,7 @@ public: const UChar *src, int32_t srcLength, UErrorCode *pErrorCode); + void (U_EXPORT2* u_getVersion) (UVersionInfo versionArray); UChar32 (U_EXPORT2* u_tolower) (UChar32 c); UChar32 (U_EXPORT2* u_toupper) (UChar32 c); int32_t (U_EXPORT2* u_strCompare) (const UChar* s1, int32_t length1, @@ -177,7 +178,8 @@ public: static ConversionICU& getConversionICU(); static ICU* loadICU(const Firebird::string& icuVersion, const Firebird::string& configInfo); - static bool getCollVersion(const Firebird::string& icuVersion, + static void getICUVersion(ICU* icu, int& majorVersion, int& minorVersion); + static ICU* getCollVersion(const Firebird::string& icuVersion, const Firebird::string& configInfo, Firebird::string& collVersion); class Utf16Collation @@ -241,8 +243,8 @@ public: ArrayComparator > ContractionsPrefixMap; - static ICU* loadICU(const Firebird::string& collVersion, const Firebird::string& locale, - const Firebird::string& configInfo); + static ICU* loadICU(const Firebird::string& icuVersion, const Firebird::string& collVersion, + const Firebird::string& locale, const Firebird::string& configInfo); void normalize(ULONG* strLen, const USHORT** str, bool forNumericSort, Firebird::HalfStaticArray& buffer) const; diff --git a/src/intl/lc_icu.cpp b/src/intl/lc_icu.cpp index e5eced3a14..f3f3d821a7 100644 --- a/src/intl/lc_icu.cpp +++ b/src/intl/lc_icu.cpp @@ -51,15 +51,11 @@ static bool texttype_default_init(texttype* tt, ULONG specificAttributesLength) //const ASCII* configInfo) { - charset cs; + AutoPtr cs(FB_NEW charset); memset(&cs, 0, sizeof(cs)); // test if that ICU charset exist - if (CSICU_charset_init(&cs, charSetName)) - { - IntlUtil::finiCharset(&cs); - } - else + if (!CSICU_charset_init(cs, charSetName)) return false; if ((attributes & ~TEXTTYPE_ATTR_PAD_SPACE) || @@ -72,7 +68,7 @@ static bool texttype_default_init(texttype* tt, } // name comes from stack. Copy it. - ASCII* p = FB_NEW_POOL(*getDefaultMemoryPool()) ASCII[strlen(name) + 1]; + ASCII* p = FB_NEW ASCII[strlen(name) + 1]; strcpy(p, name); tt->texttype_name = p; @@ -93,23 +89,24 @@ static bool texttype_unicode_init(texttype* tt, ULONG specificAttributesLength, const ASCII* configInfo) { - charset* cs = FB_NEW_POOL(*getDefaultMemoryPool()) charset; + AutoPtr cs(FB_NEW charset); memset(cs, 0, sizeof(*cs)); // test if that charset exist if (!LD_lookup_charset(cs, charSetName, configInfo)) - { - Firebird::SimpleDelete::clear(cs); return false; - } Firebird::UCharBuffer specificAttributesBuffer; memcpy(specificAttributesBuffer.getBuffer(specificAttributesLength), specificAttributes, specificAttributesLength); // ASF: Don't free "cs". It'will be used in the collation. - return Firebird::IntlUtil::initUnicodeCollation(tt, cs, name, + auto ret = Firebird::IntlUtil::initUnicodeCollation(tt, cs, name, attributes, specificAttributesBuffer, configInfo); + + cs.release(); + + return ret; } @@ -120,7 +117,7 @@ bool LCICU_setup_attributes(const ASCII* name, const ASCII* charSetName, const A if (len > 8 && strcmp(name + len - 8, "_UNICODE") == 0) { - AutoPtr cs(FB_NEW_POOL(*getDefaultMemoryPool()) charset); + AutoPtr cs(FB_NEW charset); memset(cs, 0, sizeof(*cs)); // test if that charset exist diff --git a/src/intl/ld.cpp b/src/intl/ld.cpp index 151cd3e812..eaf8f0f22e 100644 --- a/src/intl/ld.cpp +++ b/src/intl/ld.cpp @@ -28,6 +28,7 @@ #include "../intl/ld_proto.h" #include "../intl/cs_icu.h" #include "../intl/lc_icu.h" +#include "../common/utils_proto.h" #include "fb_exception.h" #ifdef HAVE_SYS_PARAM_H @@ -491,20 +492,12 @@ FB_DLL_EXPORT INTL_BOOL LD_lookup_charset(charset* cs, const ASCII* name, const } -FB_DLL_EXPORT INTL_BOOL LD_lookup_texttype(texttype* tt, const ASCII* texttype_name, const ASCII* charset_name, - USHORT attributes, const UCHAR* specific_attributes, - ULONG specific_attributes_length, INTL_BOOL ignore_attributes, - const ASCII* config_info) +FB_DLL_EXPORT INTL_BOOL LD_lookup_texttype_with_status(char* status_buffer, ULONG status_buffer_length, + texttype* tt, const ASCII* texttype_name, const ASCII* charset_name, + USHORT attributes, const UCHAR* specific_attributes, + ULONG specific_attributes_length, INTL_BOOL ignore_attributes, + const ASCII* config_info) { - const ASCII* configInfo; - - // ASF: We can't read config_info if version < INTL_VERSION_2, - // since it wasn't pushed in the stack by the engine. - if (version >= INTL_VERSION_2) - configInfo = config_info; - else - configInfo = ""; - if (ignore_attributes) { attributes = TEXTTYPE_ATTR_PAD_SPACE; @@ -512,6 +505,8 @@ FB_DLL_EXPORT INTL_BOOL LD_lookup_texttype(texttype* tt, const ASCII* texttype_n specific_attributes_length = 0; } + string errorMsg; + try { for (int i = 0; collations[i].collationName; ++i) @@ -527,7 +522,7 @@ FB_DLL_EXPORT INTL_BOOL LD_lookup_texttype(texttype* tt, const ASCII* texttype_n { if (strcmp(charSets[j].charSetName, charset_name) == 0) { - if (LD_lookup_charset(&cs, charset_name, configInfo)) + if (LD_lookup_charset(&cs, charset_name, config_info)) break; return false; @@ -547,13 +542,50 @@ FB_DLL_EXPORT INTL_BOOL LD_lookup_texttype(texttype* tt, const ASCII* texttype_n return LCICU_texttype_init( tt, texttype_name, charset_name, attributes, specific_attributes, - specific_attributes_length, configInfo); + specific_attributes_length, config_info); } - catch (const Firebird::BadAlloc&) + catch (const Firebird::status_exception& ex) + { + auto status = ex.value(); + TEXT temp[BUFFER_LARGE]; + + while (fb_interpret(temp, sizeof(temp), &status)) + { + if (errorMsg.hasData()) + errorMsg += "\n-"; + + errorMsg += temp; + } + } + catch (...) { fb_assert(false); - return false; + errorMsg = "Uncaught exception"; } + + if (status_buffer_length) + fb_utils::copy_terminate(status_buffer, errorMsg.c_str(), status_buffer_length); + + return false; +} + + +FB_DLL_EXPORT INTL_BOOL LD_lookup_texttype(texttype* tt, const ASCII* texttype_name, const ASCII* charset_name, + USHORT attributes, const UCHAR* specific_attributes, + ULONG specific_attributes_length, INTL_BOOL ignore_attributes, + const ASCII* config_info) +{ + const ASCII* configInfo; + + // ASF: We can't read config_info if version < INTL_VERSION_2, + // since it wasn't pushed in the stack by the engine. + if (version >= INTL_VERSION_2) + configInfo = config_info; + else + configInfo = ""; + + return LD_lookup_texttype_with_status(nullptr, 0, tt, texttype_name, charset_name, attributes, specific_attributes, + specific_attributes_length, ignore_attributes, configInfo); } diff --git a/src/intl/ld_proto.h b/src/intl/ld_proto.h index f20fdf076a..20f50d193f 100644 --- a/src/intl/ld_proto.h +++ b/src/intl/ld_proto.h @@ -39,10 +39,18 @@ struct CsConvertImpl extern USHORT version; FB_DLL_EXPORT INTL_BOOL LD_lookup_charset(charset* cs, const ASCII* name, const ASCII* config_info); + +FB_DLL_EXPORT INTL_BOOL LD_lookup_texttype_with_status(char* status_buffer, ULONG status_buffer_length, + texttype* tt, const ASCII* texttype_name, const ASCII* charset_name, + USHORT attributes, const UCHAR* specific_attributes, + ULONG specific_attributes_length, INTL_BOOL ignore_attributes, + const ASCII* config_info); + FB_DLL_EXPORT INTL_BOOL LD_lookup_texttype(texttype* tt, const ASCII* texttype_name, const ASCII* charset_name, - USHORT attributes, const UCHAR* specific_attributes, - ULONG specific_attributes_length, INTL_BOOL ignore_attributes, - const ASCII* config_info); + USHORT attributes, const UCHAR* specific_attributes, + ULONG specific_attributes_length, INTL_BOOL ignore_attributes, + const ASCII* config_info); + FB_DLL_EXPORT void LD_version(USHORT* version); FB_DLL_EXPORT ULONG LD_setup_attributes( const ASCII* textTypeName, const ASCII* charSetName, const ASCII* configInfo, diff --git a/src/jrd/IntlManager.cpp b/src/jrd/IntlManager.cpp index ccc9857e1d..9e09e54936 100644 --- a/src/jrd/IntlManager.cpp +++ b/src/jrd/IntlManager.cpp @@ -625,7 +625,7 @@ bool IntlManager::lookupCharSet(const string& charSetName, charset* cs) } -bool IntlManager::lookupCollation(const string& collationName, +void IntlManager::lookupCollation(const string& collationName, const string& charSetName, USHORT attributes, const UCHAR* specificAttributes, ULONG specificAttributesLen, bool ignoreAttributes, @@ -633,32 +633,56 @@ bool IntlManager::lookupCollation(const string& collationName, { ExternalInfo charSetExternalInfo; ExternalInfo collationExternalInfo; + char statusBuffer[BUFFER_LARGE] = ""; if (charSetCollations->get(charSetName + ":" + charSetName, charSetExternalInfo) && charSetCollations->get(charSetName + ":" + collationName, collationExternalInfo)) { - pfn_INTL_lookup_texttype lookupFunction = NULL; + ModuleLoader::Module* module = nullptr; + + if (collationExternalInfo.moduleName.hasData()) + modules->get(collationExternalInfo.moduleName, module); + + pfn_INTL_lookup_texttype_with_status lookupStatusFunction = nullptr; if (collationExternalInfo.moduleName.isEmpty()) - lookupFunction = INTL_builtin_lookup_texttype; - else - { - ModuleLoader::Module* module; + lookupStatusFunction = INTL_builtin_lookup_texttype_status; + else if (module) + module->findSymbol(nullptr, STRINGIZE(TEXTTYPE_WITH_STATUS_ENTRYPOINT), lookupStatusFunction); - if (modules->get(collationExternalInfo.moduleName, module) && module) - module->findSymbol(NULL, STRINGIZE(TEXTTYPE_ENTRYPOINT), lookupFunction); + if (lookupStatusFunction) + { + if ((*lookupStatusFunction)(statusBuffer, sizeof(statusBuffer), + tt, collationExternalInfo.name.c_str(), charSetExternalInfo.name.c_str(), + attributes, specificAttributes, specificAttributesLen, ignoreAttributes, + collationExternalInfo.configInfo.c_str())) + { + return; + } } - - if (lookupFunction && - (*lookupFunction)(tt, collationExternalInfo.name.c_str(), charSetExternalInfo.name.c_str(), - attributes, specificAttributes, specificAttributesLen, ignoreAttributes, - collationExternalInfo.configInfo.c_str())) + else if (module) { - return true; + pfn_INTL_lookup_texttype lookupFunction = nullptr; + module->findSymbol(nullptr, STRINGIZE(TEXTTYPE_ENTRYPOINT), lookupFunction); + + if (lookupFunction && + (*lookupFunction)(tt, collationExternalInfo.name.c_str(), charSetExternalInfo.name.c_str(), + attributes, specificAttributes, specificAttributesLen, ignoreAttributes, + collationExternalInfo.configInfo.c_str())) + { + return; + } } } - return false; + if (statusBuffer[0]) + { + (Arg::Gds(isc_collation_not_installed) << collationName << charSetName << + Arg::Gds(isc_random) << statusBuffer + ).raise(); + } + else + (Arg::Gds(isc_collation_not_installed) << collationName << charSetName).raise(); } diff --git a/src/jrd/IntlManager.h b/src/jrd/IntlManager.h index 26698497ac..c35ecf9705 100644 --- a/src/jrd/IntlManager.h +++ b/src/jrd/IntlManager.h @@ -47,7 +47,7 @@ public: static bool lookupCharSet(const Firebird::string& charSetName, charset* cs); - static bool lookupCollation(const Firebird::string& collationName, + static void lookupCollation(const Firebird::string& collationName, const Firebird::string& charSetName, USHORT attributes, const UCHAR* specificAttributes, ULONG specificAttributesLen, bool ignoreAttributes, diff --git a/src/jrd/intl.cpp b/src/jrd/intl.cpp index d6cdd9aafa..f03f3773e6 100644 --- a/src/jrd/intl.cpp +++ b/src/jrd/intl.cpp @@ -133,7 +133,7 @@ using namespace Firebird; static bool allSpaces(CharSet*, const BYTE*, ULONG, ULONG); static int blocking_ast_collation(void* ast_object); static void pad_spaces(thread_db*, CHARSET_ID, BYTE *, ULONG); -static INTL_BOOL lookup_texttype(texttype* tt, const SubtypeInfo* info); +static void lookup_texttype(texttype* tt, const SubtypeInfo* info); static GlobalPtr createCollationMtx; @@ -387,15 +387,10 @@ Collation* CharSetContainer::lookupCollation(thread_db* tdbb, USHORT tt_id) } Attachment* const att = tdbb->getAttachment(); - texttype* tt = FB_NEW_POOL(*att->att_pool) texttype; + AutoPtr tt(FB_NEW_POOL(*att->att_pool) texttype); memset(tt, 0, sizeof(texttype)); - if (!lookup_texttype(tt, &info)) - { - delete tt; - ERR_post(Arg::Gds(isc_collation_not_installed) << Arg::Str(info.collationName) << - Arg::Str(info.charsetName)); - } + lookup_texttype(tt, &info); if (charset_collations.getCount() <= id) charset_collations.grow(id + 1); @@ -415,9 +410,12 @@ Collation* CharSetContainer::lookupCollation(thread_db* tdbb, USHORT tt_id) } } - charset_collations[id] = Collation::createInstance(*att->att_pool, tt_id, tt, info.attributes, charset); + charset_collations[id] = Collation::createInstance(*att->att_pool, tt_id, + tt, info.attributes, charset); charset_collations[id]->name = info.collationName; + tt.release(); + // we don't need a lock in the charset if (id != 0) { @@ -489,9 +487,9 @@ void CharSetContainer::unloadCollation(thread_db* tdbb, USHORT tt_id) } -static INTL_BOOL lookup_texttype(texttype* tt, const SubtypeInfo* info) +static void lookup_texttype(texttype* tt, const SubtypeInfo* info) { - return IntlManager::lookupCollation(info->baseCollationName.c_str(), info->charsetName.c_str(), + IntlManager::lookupCollation(info->baseCollationName.c_str(), info->charsetName.c_str(), info->attributes, info->specificAttributes.begin(), info->specificAttributes.getCount(), info->ignoreAttributes, tt); } @@ -1170,12 +1168,19 @@ bool INTL_texttype_validate(Jrd::thread_db* tdbb, const SubtypeInfo* info) texttype tt; memset(&tt, 0, sizeof(tt)); - bool ret = lookup_texttype(&tt, info); + try + { + lookup_texttype(&tt, info); - if (ret && tt.texttype_fn_destroy) - tt.texttype_fn_destroy(&tt); + if (tt.texttype_fn_destroy) + tt.texttype_fn_destroy(&tt); - return ret; + return true; + } + catch (const Exception&) + { + return false; + } } diff --git a/src/jrd/intl_builtin.cpp b/src/jrd/intl_builtin.cpp index da94a9ac10..4eefd9943f 100644 --- a/src/jrd/intl_builtin.cpp +++ b/src/jrd/intl_builtin.cpp @@ -1658,10 +1658,12 @@ INTL_BOOL INTL_builtin_lookup_charset(charset* cs, const ASCII* charset_name, co } -INTL_BOOL INTL_builtin_lookup_texttype(texttype* tt, const ASCII* texttype_name, const ASCII* charset_name, - USHORT attributes, const UCHAR* specific_attributes, - ULONG specific_attributes_length, INTL_BOOL ignore_attributes, - const ASCII* config_info) +INTL_BOOL INTL_builtin_lookup_texttype_status( + char* status_buffer, ULONG status_buffer_length, + texttype* tt, const ASCII* texttype_name, const ASCII* charset_name, + USHORT attributes, const UCHAR* specific_attributes, + ULONG specific_attributes_length, INTL_BOOL ignore_attributes, + const ASCII* config_info) { if (ignore_attributes) { @@ -1700,8 +1702,29 @@ INTL_BOOL INTL_builtin_lookup_texttype(texttype* tt, const ASCII* texttype_name, if (func) { - return func(tt, texttype_name, charset_name, attributes, - specific_attributes, specific_attributes_length, ignore_attributes, config_info); + Firebird::string errorMsg; + + try + { + return func(tt, texttype_name, charset_name, attributes, + specific_attributes, specific_attributes_length, ignore_attributes, config_info); + } + catch (const Firebird::status_exception& ex) + { + auto status = ex.value(); + TEXT temp[BUFFER_LARGE]; + + while (fb_interpret(temp, sizeof(temp), &status)) + { + if (errorMsg.hasData()) + errorMsg += "\n-"; + + errorMsg += temp; + } + + if (status_buffer_length) + fb_utils::copy_terminate(status_buffer, errorMsg.c_str(), status_buffer_length); + } } return false; diff --git a/src/jrd/intl_proto.h b/src/jrd/intl_proto.h index 58c3b479f8..add4b4af78 100644 --- a/src/jrd/intl_proto.h +++ b/src/jrd/intl_proto.h @@ -56,10 +56,12 @@ USHORT INTL_string_to_key(Jrd::thread_db*, USHORT, const dsc*, dsc*, USHORT); // Built-in charsets/texttypes interface INTL_BOOL INTL_builtin_lookup_charset(charset* cs, const ASCII* charset_name, const ASCII* config_info); -INTL_BOOL INTL_builtin_lookup_texttype(texttype* tt, const ASCII* texttype_name, const ASCII* charset_name, - USHORT attributes, const UCHAR* specific_attributes, - ULONG specific_attributes_length, INTL_BOOL ignore_attributes, - const ASCII* config_info); +INTL_BOOL INTL_builtin_lookup_texttype_status( + char* status_buffer, ULONG status_buffer_length, + texttype* tt, const ASCII* texttype_name, const ASCII* charset_name, + USHORT attributes, const UCHAR* specific_attributes, + ULONG specific_attributes_length, INTL_BOOL ignore_attributes, + const ASCII* config_info); ULONG INTL_builtin_setup_attributes(const ASCII* textTypeName, const ASCII* charSetName, const ASCII* configInfo, ULONG srcLen, const UCHAR* src, ULONG dstLen, UCHAR* dst);