void INTL_adjust_text_descriptor(thread_db* tdbb, dsc* desc) { /************************************** * * I N T L _ a d j u s t _ t e x t _ d e s c r i p t o r * ************************************** * * Functional description * This function receives a text descriptor with * dsc_length = numberOfCharacters * maxBytesPerChar * and change dsc_length to number of bytes used by the string. * **************************************/ if (desc->dsc_dtype == dtype_text) { SET_TDBB(tdbb); USHORT ttype = INTL_TTYPE(desc); CharSet* charSet = INTL_charset_lookup(tdbb, ttype); if (charSet->isMultiByte()) { Firebird::HalfStaticArray<UCHAR, BUFFER_SMALL> buffer; if (charSet->getFlags() & CHARSET_LEGACY_SEMANTICS) { desc->dsc_length = charSet->substring(TEXT_LEN(desc), desc->dsc_address, TEXT_LEN(desc), buffer.getBuffer(TEXT_LEN(desc) * charSet->maxBytesPerChar()), 0, TEXT_LEN(desc)); const ULONG maxLength = TEXT_LEN(desc) / charSet->maxBytesPerChar(); ULONG charLength = charSet->length(desc->dsc_length, desc->dsc_address, true); while (charLength > maxLength) { if (desc->dsc_address[desc->dsc_length - 1] == *charSet->getSpace()) { --desc->dsc_length; --charLength; } else break; } } else { desc->dsc_length = charSet->substring(TEXT_LEN(desc), desc->dsc_address, TEXT_LEN(desc), buffer.getBuffer(TEXT_LEN(desc)), 0, TEXT_LEN(desc) / charSet->maxBytesPerChar()); } } } }
Collation* CharSetContainer::lookupCollation(thread_db* tdbb, USHORT tt_id) { const USHORT id = TTYPE_TO_COLLATION(tt_id); if (id < charset_collations.getCount() && charset_collations[id] != NULL) { if (!charset_collations[id]->obsolete) return charset_collations[id]; } Jrd::Attachment* att = tdbb->getAttachment(); Jrd::Attachment::CheckoutLockGuard guard(att, createCollationMtx, FB_FUNCTION); // do we need it ? Collation* to_delete = NULL; if (id < charset_collations.getCount() && charset_collations[id] != NULL) { if (charset_collations[id]->obsolete) { // if obsolete collation is not used delete it immediately, // else wait until all references are released if (charset_collations[id]->useCount == 0) { charset_collations[id]->destroy(tdbb); delete charset_collations[id]; } else to_delete = charset_collations[id]; charset_collations[id] = NULL; } else return charset_collations[id]; } SubtypeInfo info; if (MET_get_char_coll_subtype_info(tdbb, tt_id, &info)) { CharSet* charset = INTL_charset_lookup(tdbb, TTYPE_TO_CHARSET(tt_id)); if (TTYPE_TO_CHARSET(tt_id) != CS_METADATA) { Firebird::UCharBuffer specificAttributes; ULONG size = info.specificAttributes.getCount() * charset->maxBytesPerChar(); size = INTL_convert_bytes(tdbb, TTYPE_TO_CHARSET(tt_id), specificAttributes.getBuffer(size), size, CS_METADATA, info.specificAttributes.begin(), info.specificAttributes.getCount(), ERR_post); specificAttributes.shrink(size); info.specificAttributes = specificAttributes; } texttype* 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)); } if (charset_collations.getCount() <= id) charset_collations.grow(id + 1); fb_assert((tt->texttype_canonical_width == 0 && tt->texttype_fn_canonical == NULL) || (tt->texttype_canonical_width != 0 && tt->texttype_fn_canonical != NULL)); if (tt->texttype_canonical_width == 0) { if (charset->isMultiByte()) tt->texttype_canonical_width = sizeof(ULONG); // UTF-32 else { tt->texttype_canonical_width = charset->minBytesPerChar(); // canonical is equal to string, then TEXTTYPE_DIRECT_MATCH can be turned on tt->texttype_flags |= TEXTTYPE_DIRECT_MATCH; } } charset_collations[id] = Collation::createInstance(*att->att_pool, tt_id, tt, charset); charset_collations[id]->name = info.collationName; // we don't need a lock in the charset if (id != 0) { Lock* lock = charset_collations[id]->existenceLock = CharSetContainer::createCollationLock(tdbb, tt_id, charset_collations[id]); fb_assert(charset_collations[id]->useCount == 0); fb_assert(!charset_collations[id]->obsolete); LCK_lock(tdbb, lock, LCK_SR, LCK_WAIT); // as we just obtained SR lock for new collation instance // we could safely delete obsolete instance if (to_delete) { to_delete->destroy(tdbb); delete to_delete; } } } else { if (to_delete) { LCK_lock(tdbb, to_delete->existenceLock, LCK_SR, LCK_WAIT); to_delete->destroy(tdbb); delete to_delete; } ERR_post(Arg::Gds(isc_text_subtype) << Arg::Num(tt_id)); } return charset_collations[id]; }