// Probably file arrived on the disk bool notifyDatabaseName(const Firebird::PathName& file) { #ifdef HAVE_ID_BY_NAME // notifyDatabaseName typically causes changes in aliasesConf() // cause it's called only from Config created for missing database. // Therefore always take write lock at once. WriteLockGuard guard(aliasesConf().rwLock, "notifyDatabaseName"); DbName* db = aliasesConf().dbHash.lookup(file); if (!db) return true; if (db->id) return true; UCharBuffer id; os_utils::getUniqueFileId(file.c_str(), id); if (id.hasData()) { aliasesConf().linkId(db, id); return true; } #endif return false; }
void PreparedStatement::parseDsqlMessage(const dsql_msg* dsqlMsg, Array<dsc>& values, MsgMetadata* msgMetadata, UCharBuffer& msg) { // hvlad: Parameters in dsqlMsg->msg_parameters almost always linked in descending // order by par_index. The only known exception is EXECUTE BLOCK statement. // To generate correct metadata we must walk params in ascending par_index order. // So store all params in array in an ascending par_index order despite of // order in linked list. // ASF: Input parameters don't come necessarily in ascending or descending order, // so I changed the code to use a SortedArray. // AP: removed assertions for correct parameters order - useless with SortedArray. SortedArray<const dsql_par*, InlineStorage<const dsql_par*, 16>, const dsql_par*, DefaultKeyValue<const dsql_par*>, ParamCmp> params; for (size_t i = 0; i < dsqlMsg->msg_parameters.getCount(); ++i) { dsql_par* par = dsqlMsg->msg_parameters[i]; if (par->par_index) params.add(par); } size_t paramCount = params.getCount(); values.resize(paramCount * 2); msgMetadata->setItemsCount(paramCount); for (size_t i = 0; i < paramCount; ++i) dscToMetaItem(¶ms[i]->par_desc, msgMetadata->getItem(i)); msgMetadata->makeOffsets(); msg.resize(msgMetadata->getMessageLength()); dsc* value = values.begin(); for (size_t i = 0; i < paramCount; ++i) { // value *value = params[i]->par_desc; value->dsc_address = msg.begin() + msgMetadata->getItem(i).offset; ++value; // NULL indicator value->makeShort(0); value->dsc_address = msg.begin() + msgMetadata->getItem(i).nullInd; // set NULL indicator value *((SSHORT*) value->dsc_address) = -1; ++value; } }
void PIO_get_unique_file_id(const Jrd::jrd_file* file, UCharBuffer& id) { /************************************** * * P I O _ g e t _ u n i q u e _ f i l e _ i d * ************************************** * * Functional description * Return a binary string that uniquely identifies the file. * **************************************/ struct stat statistics; if (fstat(file->fil_desc, &statistics) != 0) { unix_error("fstat", file, isc_io_access_err); } const size_t len1 = sizeof(statistics.st_dev); const size_t len2 = sizeof(statistics.st_ino); UCHAR* p = id.getBuffer(len1 + len2); memcpy(p, &statistics.st_dev, len1); p += len1; memcpy(p, &statistics.st_ino, len2); }
string Database::getUniqueFileId() const { const PageSpace* const pageSpace = dbb_page_manager.findPageSpace(DB_PAGE_SPACE); UCharBuffer buffer; os_utils::getUniqueFileId(pageSpace->file->fil_desc, buffer); string file_id; char* s = file_id.getBuffer(2 * buffer.getCount()); for (FB_SIZE_T i = 0; i < buffer.getCount(); i++) { sprintf(s, "%02x", (int) buffer[i]); s += 2; } return file_id; }
void IntlUtil::getDefaultCollationAttributes(UCharBuffer& collAttributes, charset& cs) { string attributes("ICU-VERSION="); attributes += Jrd::UnicodeUtil::getDefaultIcuVersion(); setupIcuAttributes(&cs, attributes, "", attributes); collAttributes.push(reinterpret_cast<const UCHAR*>(attributes.c_str()), attributes.length()); }
// We store in CS_METADATA. void Jrd::Attachment::storeMetaDataBlob(thread_db* tdbb, jrd_tra* transaction, bid* blobId, const string& text, USHORT fromCharSet) { UCharBuffer bpb; if (fromCharSet != CS_METADATA) BLB_gen_bpb(isc_blob_text, isc_blob_text, fromCharSet, CS_METADATA, bpb); blb* blob = blb::create2(tdbb, transaction, blobId, bpb.getCount(), bpb.begin()); try { blob->BLB_put_data(tdbb, (const UCHAR*) text.c_str(), text.length()); } catch (const Exception&) { blob->BLB_close(tdbb); throw; } blob->BLB_close(tdbb); }
static void makeUniqueFileId(const struct stat& statistics, UCharBuffer& id) { const size_t len1 = sizeof(statistics.st_dev); const size_t len2 = sizeof(statistics.st_ino); UCHAR* p = id.getBuffer(len1 + len2); memcpy(p, &statistics.st_dev, len1); p += len1; memcpy(p, &statistics.st_ino, len2); }
void getUniqueFileId(const char* name, UCharBuffer& id) { struct STAT statistics; if (os_utils::stat(name, &statistics) != 0) { id.clear(); return; } makeUniqueFileId(statistics, id); }
UnicodeCollationHolder::UnicodeCollationHolder(MemoryPool& pool) { cs = FB_NEW(pool) charset; tt = FB_NEW(pool) texttype; IntlUtil::initUtf8Charset(cs); string collAttributes("ICU-VERSION="); collAttributes += Jrd::UnicodeUtil::DEFAULT_ICU_VERSION; IntlUtil::setupIcuAttributes(cs, collAttributes, "", collAttributes); UCharBuffer collAttributesBuffer; collAttributesBuffer.push(reinterpret_cast<const UCHAR*>(collAttributes.c_str()), collAttributes.length()); if (!IntlUtil::initUnicodeCollation(tt, cs, "UNICODE", 0, collAttributesBuffer, string())) fatal_exception::raiseFmt("cannot initialize UNICODE collation to use in trace plugin"); charSet = Jrd::CharSet::createInstance(pool, 0, cs); textType = FB_NEW(pool) Jrd::TextType(0, tt, charSet); }
void getUniqueFileId(const char* name, UCharBuffer& id) { struct stat statistics; while (stat(name, &statistics) != 0) { if (errno == EINTR) continue; id.clear(); return; } makeUniqueFileId(statistics, id); }
// Parse routine BLR. void Routine::parseBlr(thread_db* tdbb, CompilerScratch* csb, bid* blob_id) { Jrd::Attachment* attachment = tdbb->getAttachment(); UCharBuffer tmp; if (blob_id) { blb* blob = blb::open(tdbb, attachment->getSysTransaction(), blob_id); ULONG length = blob->blb_length + 10; UCHAR* temp = tmp.getBuffer(length); length = blob->BLB_get_data(tdbb, temp, length); tmp.resize(length); } parseMessages(tdbb, csb, BlrReader(tmp.begin(), (unsigned) tmp.getCount())); JrdStatement* statement = getStatement(); PAR_blr(tdbb, NULL, tmp.begin(), (ULONG) tmp.getCount(), NULL, &csb, &statement, false, 0); setStatement(statement); if (!blob_id) setImplemented(false); }
bool MergeJoin::getRecord(thread_db* tdbb) const { if (--tdbb->tdbb_quantum < 0) JRD_reschedule(tdbb, 0, true); jrd_req* const request = tdbb->getRequest(); Impure* const impure = request->getImpure<Impure>(m_impure); if (!(impure->irsb_flags & irsb_open)) return false; // If there is a record group already formed, fetch the next combination if (fetchRecord(tdbb, m_args.getCount() - 1)) return true; // Assuming we are done with the current value group, advance each // stream one record. If any comes up dry, we're done. const NestConst<SortedStream>* highest_ptr = m_args.begin(); FB_SIZE_T highest_index = 0; for (FB_SIZE_T i = 0; i < m_args.getCount(); i++) { const NestConst<SortedStream>* const ptr = &m_args[i]; const SortedStream* const sort_rsb = *ptr; const NestValueArray* const sort_key = m_keys[i]; Impure::irsb_mrg_repeat* const tail = &impure->irsb_mrg_rpt[i]; MergeFile* const mfb = &tail->irsb_mrg_file; // reset equality group record positions tail->irsb_mrg_equal = 0; tail->irsb_mrg_equal_current = 0; tail->irsb_mrg_equal_end = 0; // If there is a record waiting, use it. Otherwise get another. SLONG record = tail->irsb_mrg_last_fetched; if (record >= 0) { tail->irsb_mrg_last_fetched = -1; const UCHAR* const last_data = getData(tdbb, mfb, record); mfb->mfb_current_block = 0; UCHAR* const first_data = getData(tdbb, mfb, 0); if (first_data != last_data) memcpy(first_data, last_data, sort_rsb->getLength()); mfb->mfb_equal_records = 1; record = 0; } else { mfb->mfb_current_block = 0; mfb->mfb_equal_records = 0; if ((record = getRecord(tdbb, i)) < 0) return false; } // map data into target records and do comparison sort_rsb->mapData(tdbb, request, getData(tdbb, mfb, record)); if (ptr != highest_ptr && compare(tdbb, m_keys[highest_index], sort_key) < 0) { highest_ptr = ptr; highest_index = i; } } // Loop thru the streams advancing each up to the target value. // If any exceeds the target value, start over. while (true) { bool recycle = false; for (FB_SIZE_T i = 0; i < m_args.getCount(); i++) { const NestConst<SortedStream>* const ptr = &m_args[i]; const SortedStream* const sort_rsb = *ptr; const NestValueArray* const sort_key = m_keys[i]; Impure::irsb_mrg_repeat* const tail = &impure->irsb_mrg_rpt[i]; if (highest_ptr != ptr) { int result; while ( (result = compare(tdbb, m_keys[highest_index], sort_key)) ) { if (result < 0) { highest_ptr = ptr; highest_index = i; recycle = true; break; } MergeFile* const mfb = &tail->irsb_mrg_file; mfb->mfb_current_block = 0; mfb->mfb_equal_records = 0; const SLONG record = getRecord(tdbb, i); if (record < 0) return false; sort_rsb->mapData(tdbb, request, getData(tdbb, mfb, record)); } if (recycle) break; } } if (!recycle) break; } // finally compute equality group for each stream in sort/merge for (FB_SIZE_T i = 0; i < m_args.getCount(); i++) { const SortedStream* const sort_rsb = m_args[i]; Impure::irsb_mrg_repeat* const tail = &impure->irsb_mrg_rpt[i]; MergeFile* const mfb = &tail->irsb_mrg_file; UCharBuffer key; const ULONG key_length = sort_rsb->getKeyLength(); UCHAR* const first_data = key.getBuffer(key_length); memcpy(first_data, getData(tdbb, mfb, 0), key_length); SLONG record; while ((record = getRecord(tdbb, i)) >= 0) { const UCHAR* p = first_data; const UCHAR* q = getData(tdbb, mfb, record); if (!sort_rsb->compareKeys(p, q)) { tail->irsb_mrg_last_fetched = record; break; } tail->irsb_mrg_equal_end = record; } if (mfb->mfb_current_block) { if (!mfb->mfb_space) { MemoryPool& pool = *getDefaultMemoryPool(); mfb->mfb_space = FB_NEW_POOL(pool) TempSpace(pool, SCRATCH, false); } Sort::writeBlock(mfb->mfb_space, mfb->mfb_block_size * mfb->mfb_current_block, mfb->mfb_block_data, mfb->mfb_block_size); } } // Optimize cross product of equivalence groups by ordering the streams // from left (outermost) to right (innermost) by descending cardinality // of merge blocks. This ordering will vary for each set of equivalence // groups and cannot be statically assigned by the optimizer. typedef Stack<Impure::irsb_mrg_repeat*> ImrStack; ImrStack best_tails; Impure::irsb_mrg_repeat* tail = impure->irsb_mrg_rpt; for (const Impure::irsb_mrg_repeat* const tail_end = tail + m_args.getCount(); tail < tail_end; tail++) { Impure::irsb_mrg_repeat* best_tail = NULL; ULONG most_blocks = 0; for (Impure::irsb_mrg_repeat* tail2 = impure->irsb_mrg_rpt; tail2 < tail_end; tail2++) { ImrStack::iterator stack(best_tails); for (; stack.hasData(); ++stack) { if (stack.object() == tail2) break; } if (stack.hasData()) continue; MergeFile* const mfb = &tail2->irsb_mrg_file; ULONG blocks = mfb->mfb_equal_records / mfb->mfb_blocking_factor; if (++blocks > most_blocks) { most_blocks = blocks; best_tail = tail2; } } best_tails.push(best_tail); tail->irsb_mrg_order = best_tail - impure->irsb_mrg_rpt; } return true; }
bool IntlUtil::initUnicodeCollation(texttype* tt, charset* cs, const ASCII* name, USHORT attributes, const UCharBuffer& specificAttributes, const string& configInfo) { memset(tt, 0, sizeof(*tt)); // name comes from stack. Copy it. ASCII* nameCopy = FB_NEW ASCII[strlen(name) + 1]; strcpy(nameCopy, name); tt->texttype_name = nameCopy; tt->texttype_version = TEXTTYPE_VERSION_1; tt->texttype_country = CC_INTL; tt->texttype_canonical_width = 4; // UTF-32 tt->texttype_fn_destroy = unicodeDestroy; tt->texttype_fn_compare = unicodeCompare; tt->texttype_fn_key_length = unicodeKeyLength; tt->texttype_fn_string_to_key = unicodeStrToKey; tt->texttype_fn_canonical = unicodeCanonical; IntlUtil::SpecificAttributesMap map; Jrd::CharSet* charSet = NULL; try { charSet = Jrd::CharSet::createInstance(*getDefaultMemoryPool(), 0, cs); IntlUtil::parseSpecificAttributes(charSet, specificAttributes.getCount(), specificAttributes.begin(), &map); delete charSet; } catch (...) { delete charSet; gds__log("initUnicodeCollation failed - unexpected exception caught"); return false; } IntlUtil::SpecificAttributesMap map16; SpecificAttributesMap::Accessor accessor(&map); bool found = accessor.getFirst(); while (found) { UCharBuffer s1, s2; USHORT errCode; ULONG errPosition; s1.resize(cs->charset_to_unicode.csconvert_fn_convert( &cs->charset_to_unicode, accessor.current()->first.length(), NULL, 0, NULL, &errCode, &errPosition)); s1.resize(cs->charset_to_unicode.csconvert_fn_convert( &cs->charset_to_unicode, accessor.current()->first.length(), (UCHAR*) accessor.current()->first.c_str(), s1.getCapacity(), s1.begin(), &errCode, &errPosition)); s2.resize(cs->charset_to_unicode.csconvert_fn_convert( &cs->charset_to_unicode, accessor.current()->second.length(), NULL, 0, NULL, &errCode, &errPosition)); s2.resize(cs->charset_to_unicode.csconvert_fn_convert( &cs->charset_to_unicode, accessor.current()->second.length(), (UCHAR*) accessor.current()->second.c_str(), s2.getCapacity(), s2.begin(), &errCode, &errPosition)); map16.put(string((char*) s1.begin(), s1.getCount()), string((char*) s2.begin(), s2.getCount())); found = accessor.getNext(); } UnicodeUtil::Utf16Collation* collation = UnicodeUtil::Utf16Collation::create(tt, attributes, map16, configInfo); if (!collation) { gds__log("initUnicodeCollation failed - UnicodeUtil::Utf16Collation::create failed"); return false; } tt->texttype_impl = FB_NEW TextTypeImpl(cs, collation); return true; }
// Full processing of database name // Returns true if alias was found in databases.conf bool expandDatabaseName(Firebird::PathName alias, Firebird::PathName& file, Firebird::RefPtr<Config>* config) { try { aliasesConf().checkLoadConfig(); } catch (const fatal_exception& ex) { gds__log("File databases.conf contains bad data: %s", ex.what()); Arg::Gds(isc_server_misconfigured).raise(); } // remove whitespaces from database name alias.trim(); ReadLockGuard guard(aliasesConf().rwLock, "expandDatabaseName"); // First of all check in databases.conf if (resolveAlias(alias, file, config)) { return true; } // Now try ISC_PATH environment variable if (!setPath(alias, file)) { // At this step check DatabaseAccess paths in firebird.conf if (!resolveDatabaseAccess(alias, file)) { // Last chance - regular filename expansion file = alias; ISC_systemToUtf8(file); ISC_unescape(file); ISC_utf8ToSystem(file); ISC_expand_filename(file, true); ISC_systemToUtf8(file); ISC_escape(file); ISC_utf8ToSystem(file); } } // Search for correct config in databases.conf if (config) { DbName* db = aliasesConf().dbHash.lookup(file); #ifdef HAVE_ID_BY_NAME if (!db) { UCharBuffer id; os_utils::getUniqueFileId(file.c_str(), id); if (id.hasData()) { Id* i = aliasesConf().idHash.lookup(id); if (i) db = i->db; } } #endif *config = (db && db->config.hasData()) ? db->config : Config::getDefaultConfig(); } return false; }