Exemple #1
0
// 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;
}
Exemple #2
0
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(&params[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;
	}
}
Exemple #3
0
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);
}
Exemple #4
0
	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;
	}
Exemple #5
0
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());
}
Exemple #6
0
// 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);
}
Exemple #7
0
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);
}
Exemple #8
0
void getUniqueFileId(const char* name, UCharBuffer& id)
{
	struct STAT statistics;
	if (os_utils::stat(name, &statistics) != 0)
	{
		id.clear();
		return;
	}

	makeUniqueFileId(statistics, id);
}
Exemple #9
0
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);
}
Exemple #10
0
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);
}
Exemple #11
0
// 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);
}
Exemple #12
0
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;
}
Exemple #13
0
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;
}
Exemple #14
0
// 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;
}