void CharSetContainer::unloadCollation(thread_db* tdbb, USHORT tt_id) { const USHORT id = TTYPE_TO_COLLATION(tt_id); fb_assert(id != 0); if (id < charset_collations.getCount() && charset_collations[id] != NULL) { if (charset_collations[id]->useCount != 0) { ERR_post(Arg::Gds(isc_no_meta_update) << Arg::Gds(isc_obj_in_use) << Arg::Str(charset_collations[id]->name)); } fb_assert(charset_collations[id]->existenceLock); if (!charset_collations[id]->obsolete) { LCK_convert(tdbb, charset_collations[id]->existenceLock, LCK_EX, LCK_WAIT); charset_collations[id]->obsolete = true; LCK_release(tdbb, charset_collations[id]->existenceLock); } } else { // signal other processes collation is gone Lock* lock = CharSetContainer::createCollationLock(tdbb, tt_id); LCK_lock(tdbb, lock, LCK_EX, LCK_WAIT); LCK_release(tdbb, lock); delete lock; } }
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]; }