Ejemplo n.º 1
0
void InternalStatement::doClose(thread_db* tdbb, bool drop)
{
	FbLocalStatus status;

	{
		EngineCallbackGuard guard(tdbb, *this, FB_FUNCTION);

		if (m_cursor)
			m_cursor->close(&status);

		m_cursor = NULL;
		if (status->getState() & IStatus::STATE_ERRORS)
		{
			raise(&status, tdbb, "JResultSet::close");
		}

		if (drop)
		{
			if (m_request)
				m_request->free(&status);

			m_allocated = false;
			m_request = NULL;

			if (status->getState() & IStatus::STATE_ERRORS)
			{
				raise(&status, tdbb, "JStatement::free");
			}
		}
	}
}
Ejemplo n.º 2
0
void InternalBlob::create(thread_db* tdbb, Transaction& tran, dsc& desc, const UCharBuffer* bpb)
{
	fb_assert(!m_blob);
	fb_assert(sizeof(m_blob_id) == desc.dsc_length);

	JAttachment* att = m_connection.getJrdAtt();
	JTransaction* transaction = ((InternalTransaction&) tran).getJrdTran();
	memset(&m_blob_id, 0, sizeof(m_blob_id));

	FbLocalStatus status;

	{
		EngineCallbackGuard guard(tdbb, m_connection, FB_FUNCTION);

		const USHORT bpb_len = bpb ? bpb->getCount() : 0;
		const UCHAR* bpb_buff = bpb ? bpb->begin() : NULL;

		m_blob.assignRefNoIncr(
			att->createBlob(&status, transaction, &m_blob_id, bpb_len, bpb_buff));
	}

	if (status->getState() & IStatus::STATE_ERRORS)
		m_connection.raise(&status, tdbb, "JAttachment::createBlob");

	fb_assert(m_blob);
	memcpy(desc.dsc_address, &m_blob_id, sizeof(m_blob_id));
}
Ejemplo n.º 3
0
bool LCK_lock(thread_db* tdbb, Lock* lock, USHORT level, SSHORT wait)
{
/**************************************
 *
 *	L C K _ l o c k
 *
 **************************************
 *
 * Functional description
 *	Lock a block.  There had better not have been a lock there.
 *
 **************************************/
	SET_TDBB(tdbb);
	fb_assert(LCK_CHECK_LOCK(lock));

#ifdef DEBUG_LCK
	LckSync sync(lock, "LCK_lock");
#endif

	Database* dbb = lock->lck_dbb;
    lock->setLockAttachment(tdbb, tdbb->getAttachment());

	WaitCancelGuard guard(tdbb, lock, wait);
	FbLocalStatus statusVector;

	ENQUEUE(tdbb, &statusVector, lock, level, wait);
	fb_assert(LCK_CHECK_LOCK(lock));

	if (!lock->lck_id)
	{
    	lock->setLockAttachment(tdbb, NULL);
		if (!wait)
		{
			statusVector.copyTo(tdbb->tdbb_status_vector);
			return false;
		}

		switch (statusVector[1])
		{
		case isc_deadlock:
		case isc_lock_conflict:
		case isc_lock_timeout:
			statusVector.copyTo(tdbb->tdbb_status_vector);
			tdbb->checkCancelState(true);
			return false;
		case isc_lockmanerr:
			dbb->dbb_flags |= DBB_bugcheck;
			break;
		}

		statusVector.raise();
	}

	if (!lock->lck_compatible)
		lock->lck_physical = lock->lck_logical = level;

	fb_assert(LCK_CHECK_LOCK(lock));
	return true;
}
Ejemplo n.º 4
0
	void Database::Linger::reset()
	{
		if (active)
		{
			FbLocalStatus s;
			TimerInterfacePtr()->stop(&s, this);
			if (!(s->getState() & IStatus::STATE_ERRORS))
				active = false;
		}
	}
Ejemplo n.º 5
0
bool LCK_convert(thread_db* tdbb, Lock* lock, USHORT level, SSHORT wait)
{
/**************************************
 *
 *	L C K _ c o n v e r t
 *
 **************************************
 *
 * Functional description
 *	Convert an existing lock to a new level.
 *
 **************************************/
	SET_TDBB(tdbb);
	fb_assert(LCK_CHECK_LOCK(lock));

#ifdef DEBUG_LCK
	LckSync sync(lock, "LCK_convert");
#endif

	Database* dbb = lock->lck_dbb;

	Jrd::Attachment* const old_attachment = lock->getLockAttachment();
	lock->setLockAttachment(tdbb, tdbb->getAttachment());

	WaitCancelGuard guard(tdbb, lock, wait);
	FbLocalStatus statusVector;

	const bool result = CONVERT(tdbb, &statusVector, lock, level, wait);

	if (!result)
	{
	    lock->setLockAttachment(tdbb, old_attachment);

		switch (statusVector[1])
		{
		case isc_deadlock:
		case isc_lock_conflict:
		case isc_lock_timeout:
			statusVector.copyTo(tdbb->tdbb_status_vector);
			tdbb->checkCancelState(true);
			return false;
		case isc_lockmanerr:
			dbb->dbb_flags |= DBB_bugcheck;
			break;
		}

		statusVector.raise();
	}

	if (!lock->lck_compatible)
		lock->lck_physical = lock->lck_logical = level;

	fb_assert(LCK_CHECK_LOCK(lock));
	return true;
}
Ejemplo n.º 6
0
bool InternalConnection::cancelExecution()
{
	if (!m_attachment->getHandle())
		return false;

	if (m_isCurrent)
		return true;

	FbLocalStatus status;

	m_attachment->cancelOperation(&status, fb_cancel_raise);
	return !(status->getState() & IStatus::STATE_ERRORS);
}
Ejemplo n.º 7
0
void InternalBlob::write(thread_db* tdbb, const UCHAR* buff, USHORT len)
{
	fb_assert(m_blob);

	FbLocalStatus status;

	{
		EngineCallbackGuard guard(tdbb, m_connection, FB_FUNCTION);
		m_blob->putSegment(&status, len, buff);
	}

	if (status->getState() & IStatus::STATE_ERRORS)
		m_connection.raise(&status, tdbb, "JBlob::putSegment");
}
Ejemplo n.º 8
0
inline USHORT DOWNGRADE(thread_db* tdbb, Lock* lock)
{
	Database* const dbb = tdbb->getDatabase();

	FbLocalStatus statusVector;

	USHORT ret = lock->lck_compatible ?
		internal_downgrade(tdbb, &statusVector, lock) :
		dbb->dbb_lock_mgr->downgrade(tdbb, &statusVector, lock->lck_id);

	fb_assert(statusVector.isEmpty());

	return ret;
}
Ejemplo n.º 9
0
void LCK_init(thread_db* tdbb, enum lck_owner_t owner_type)
{
/**************************************
 *
 *	L C K _ i n i t
 *
 **************************************
 *
 * Functional description
 *	Initialize the locking stuff for the given owner.
 *
 **************************************/
	LOCK_OWNER_T owner_id;
	SLONG* owner_handle_ptr = 0;

	SET_TDBB(tdbb);
	Database* const dbb = tdbb->getDatabase();

	switch (owner_type)
	{
	case LCK_OWNER_database:
		owner_id = LCK_OWNER_ID_DBB(tdbb);
		owner_handle_ptr = LCK_OWNER_HANDLE_DBB(tdbb);
		break;

	case LCK_OWNER_attachment:
		owner_id = LCK_OWNER_ID_ATT(tdbb);
		owner_handle_ptr = LCK_OWNER_HANDLE_ATT(tdbb);
		break;

	default:
		bug_lck("Invalid lock owner type in LCK_init ()");
		break;
	}

	FbLocalStatus statusVector;

	if (!dbb->dbb_lock_mgr->initializeOwner(&statusVector, owner_id, owner_type, owner_handle_ptr))
	{
		if (statusVector[1] == isc_lockmanerr)
		{
			statusVector.copyTo(tdbb->tdbb_status_vector);
			tdbb->getDatabase()->dbb_flags |= DBB_bugcheck;
		}

		statusVector.raise();
	}
}
Ejemplo n.º 10
0
void InternalBlob::close(thread_db* tdbb)
{
	fb_assert(m_blob);
	FbLocalStatus status;

	{
		EngineCallbackGuard guard(tdbb, m_connection, FB_FUNCTION);
		m_blob->close(&status);
		m_blob = NULL;
	}

	if (status->getState() & IStatus::STATE_ERRORS)
		m_connection.raise(&status, tdbb, "JBlob::close");

	fb_assert(!m_blob);
}
Ejemplo n.º 11
0
USHORT InternalBlob::read(thread_db* tdbb, UCHAR* buff, USHORT len)
{
	fb_assert(m_blob);

	unsigned result = 0;
	FbLocalStatus status;

	{
		EngineCallbackGuard guard(tdbb, m_connection, FB_FUNCTION);
		m_blob->getSegment(&status, len, buff, &result);
	}

	if (status->getState() & IStatus::STATE_ERRORS)
		m_connection.raise(&status, tdbb, "JBlob::getSegment");

	return result;
}
Ejemplo n.º 12
0
void InternalConnection::attach(thread_db* tdbb, const PathName& dbName,
		const MetaName& user, const string& pwd,
		const MetaName& role)
{
	fb_assert(!m_attachment);
	Database* dbb = tdbb->getDatabase();
	fb_assert(dbName.isEmpty() || dbName == dbb->dbb_database_name.c_str());

	// Don't wrap raised errors. This is needed for backward compatibility.
	setWrapErrors(false);

	Jrd::Attachment* attachment = tdbb->getAttachment();
	if ((user.isEmpty() || user == attachment->att_user->getUserName()) &&
		pwd.isEmpty() &&
		(role.isEmpty() || role == attachment->att_user->getSqlRole()))
	{
		m_isCurrent = true;
		m_attachment = attachment->getInterface();
	}
	else
	{
		m_isCurrent = false;
		m_dbName = dbb->dbb_database_name.c_str();
		generateDPB(tdbb, m_dpb, user, pwd, role);

		// Avoid change of m_dpb by validatePassword() below
		ClumpletWriter newDpb(m_dpb);
		validatePassword(tdbb, m_dbName, newDpb);

		FbLocalStatus status;
		{
			EngineCallbackGuard guard(tdbb, *this, FB_FUNCTION);
			RefPtr<JProvider> jInstance(JProvider::getInstance());
			jInstance->setDbCryptCallback(&status, tdbb->getAttachment()->att_crypt_callback);
			m_attachment.assignRefNoIncr(jInstance->attachDatabase(&status, m_dbName.c_str(),
				newDpb.getBufferLength(), newDpb.getBuffer()));
		}

		if (status->getState() & IStatus::STATE_ERRORS)
			raise(&status, tdbb, "JProvider::attach");
	}

	m_sqlDialect = (m_attachment->getHandle()->att_database->dbb_flags & DBB_DB_SQL_dialect_3) ?
					SQL_DIALECT_V6 : SQL_DIALECT_V5;
}
Ejemplo n.º 13
0
bool InternalStatement::doFetch(thread_db* tdbb)
{
	FbLocalStatus status;

	bool res = true;

	{
		EngineCallbackGuard guard(tdbb, *this, FB_FUNCTION);

		fb_assert(m_outMetadata->getMessageLength() == m_out_buffer.getCount());
		fb_assert(m_cursor);
		res = m_cursor->fetchNext(&status, m_out_buffer.begin()) == IStatus::RESULT_OK;
	}

	if (status->getState() & IStatus::STATE_ERRORS)
		raise(&status, tdbb, "JResultSet::fetchNext");

	return res;
}
Ejemplo n.º 14
0
void InternalStatement::doExecute(thread_db* tdbb)
{
	JTransaction* transaction = getIntTransaction()->getJrdTran();

	FbLocalStatus status;

	{
		EngineCallbackGuard guard(tdbb, *this, FB_FUNCTION);

		fb_assert(m_inMetadata->getMessageLength() == m_in_buffer.getCount());
		fb_assert(m_outMetadata->getMessageLength() == m_out_buffer.getCount());

		m_request->execute(&status, transaction,
			m_inMetadata, m_in_buffer.begin(), m_outMetadata, m_out_buffer.begin());
	}

	if (status->getState() & IStatus::STATE_ERRORS)
		raise(&status, tdbb, "JStatement::execute");
}
Ejemplo n.º 15
0
// Create a Format based on an IMessageMetadata.
Format* Routine::createFormat(MemoryPool& pool, IMessageMetadata* params, bool addEof)
{
	FbLocalStatus status;

	unsigned count = params->getCount(&status);
	status.check();

	Format* format = Format::newFormat(pool, count * 2 + (addEof ? 1 : 0));
	unsigned runOffset = 0;

	dsc* desc = format->fmt_desc.begin();

	for (unsigned i = 0; i < count; ++i)
	{
		unsigned descOffset, nullOffset, descDtype, descLength;

		unsigned type = params->getType(&status, i);
		status.check();
		unsigned len = params->getLength(&status, i);
		status.check();
		runOffset = fb_utils::sqlTypeToDsc(runOffset, type, len, &descDtype, &descLength,
			&descOffset, &nullOffset);

		desc->clear();
		desc->dsc_dtype = descDtype;
		desc->dsc_length = descLength;
		desc->dsc_scale = params->getScale(&status, i);
		status.check();
		desc->dsc_sub_type = params->getSubType(&status, i);
		status.check();
		desc->setTextType(params->getCharSet(&status, i));
		status.check();
		desc->dsc_address = (UCHAR*)(IPTR) descOffset;
		desc->dsc_flags = (params->isNullable(&status, i) ? DSC_nullable : 0);
		status.check();

		++desc;
		desc->makeShort(0, (SSHORT*)(IPTR) nullOffset);

		++desc;
	}

	if (addEof)
	{
		// Next item is aligned on USHORT, so as the previous one.
		desc->makeShort(0, (SSHORT*)(IPTR) runOffset);
		runOffset += sizeof(USHORT);
	}

	format->fmt_length = runOffset;

	return format;
}
Ejemplo n.º 16
0
static void internal_dequeue(thread_db* tdbb, Lock* lock)
{
/**************************************
 *
 *	i n t e r n a l _ d e q u e u e
 *
 **************************************
 *
 * Functional description
 *	Dequeue a lock.  If there are identical
 *	compatible locks, check to see whether
 *	the lock needs to be downgraded.
 *
 **************************************/
	SET_TDBB(tdbb);
	Database* const dbb = tdbb->getDatabase();

	fb_assert(LCK_CHECK_LOCK(lock));
	fb_assert(lock->lck_compatible);

	// if this is the last identical lock in the hash table, release it

	Lock* match;
	if (hash_remove_lock(lock, &match))
	{
		if (!dbb->dbb_lock_mgr->dequeue(lock->lck_id))
		{
			bug_lck("LOCK_deq() failed in Lock:internal_dequeue");
		}

		lock->lck_id = 0;
		lock->lck_physical = lock->lck_logical = LCK_none;
		return;
	}

	// check for a potential downgrade

	FbLocalStatus statusVector;
	internal_downgrade(tdbb, &statusVector, match);
	fb_assert(statusVector.isEmpty());
}
Ejemplo n.º 17
0
void InternalConnection::doDetach(thread_db* tdbb)
{
	fb_assert(m_attachment);
	if (!m_attachment->getHandle())
		return;

	if (m_isCurrent)
	{
		m_attachment = NULL;
	}
	else
	{
		FbLocalStatus status;

		RefPtr<JAttachment> att = m_attachment;
		m_attachment = NULL;

		{	// scope
			EngineCallbackGuard guard(tdbb, *this, FB_FUNCTION);
			att->detach(&status);
		}

		if (status->getErrors()[1] == isc_att_shutdown)
		{
			status->init();
		}

		if (status->getState() & IStatus::STATE_ERRORS)
		{
			m_attachment = att;
			raise(&status, tdbb, "JAttachment::detach");
		}
	}

	fb_assert(!m_attachment);
}
Ejemplo n.º 18
0
void InternalStatement::doOpen(thread_db* tdbb)
{
	JTransaction* transaction = getIntTransaction()->getJrdTran();

	FbLocalStatus status;

	{
		EngineCallbackGuard guard(tdbb, *this, FB_FUNCTION);

		if (m_cursor)
		{
			m_cursor->close(&status);
			m_cursor = NULL;
		}

		fb_assert(m_inMetadata->getMessageLength() == m_in_buffer.getCount());

		m_cursor.assignRefNoIncr(m_request->openCursor(&status, transaction,
			m_inMetadata, m_in_buffer.begin(), m_outMetadata, 0));
	}

	if (status->getState() & IStatus::STATE_ERRORS)
		raise(&status, tdbb, "JStatement::open");
}
Ejemplo n.º 19
0
RecordBuffer* DbCreatorsList::getList(thread_db* tdbb, jrd_rel* relation)
{
	fb_assert(relation);
	fb_assert(relation->rel_id == rel_sec_db_creators);

	RecordBuffer* buffer = getData(relation);
	if (buffer)
	{
		return buffer;
	}

	RefPtr<IAttachment> att;
	RefPtr<ITransaction> tra;
	const char* dbName = tdbb->getDatabase()->dbb_config->getSecurityDatabase();
	if (!openDb(dbName, att, tra))
	{
		// In embedded mode we are not raising any errors - silent return
		if (MasterInterfacePtr()->serverMode(-1) < 0)
			return makeBuffer(tdbb);

		(Arg::Gds(isc_crdb_nodb) << dbName).raise();
	}

	Message gr;
	Field<ISC_SHORT> uType(gr);
	Field<Varying> u(gr, MAX_SQL_IDENTIFIER_LEN);

	FbLocalStatus st;
	RefPtr<IResultSet> curs(att->openCursor(&st, tra, 0,
		"select RDB$USER_TYPE, RDB$USER from RDB$DB_CREATORS",
		SQL_DIALECT_V6, NULL, NULL, gr.getMetadata(), NULL, 0));

	if (st->getState() & IStatus::STATE_ERRORS)
	{
		if (!fb_utils::containsErrorCode(st->getErrors(), isc_dsql_relation_err))
			check("IAttachment::openCursor", &st);

		// isc_dsql_relation_err when opening cursor - i.e. table
		// is missing due to non-FB3 security DB

		// In embedded mode we are not raising any errors - silent return
		if (MasterInterfacePtr()->serverMode(-1) < 0)
			return makeBuffer(tdbb);

		(Arg::Gds(isc_crdb_notable) << dbName).raise();
	}

	try
	{
		buffer = makeBuffer(tdbb);
		while (curs->fetchNext(&st, gr.getBuffer()) == IStatus::RESULT_OK)
		{
			Record* record = buffer->getTempRecord();
			record->nullify();

			putField(tdbb, record,
					 DumpField(f_sec_crt_user, VALUE_STRING, u->len, u->data));

			SINT64 v = uType;
			putField(tdbb, record,
					 DumpField(f_sec_crt_u_type, VALUE_INTEGER, sizeof(v), &v));

			buffer->store(record);
		}
		check("IResultSet::fetchNext", &st);
	}
	catch (const Exception&)
	{
		clearSnapshot();
		throw;
	}

	return getData(relation);
}
Ejemplo n.º 20
0
bool checkCreateDatabaseGrant(const MetaName& userName, const MetaName& trustedRole,
	const MetaName& sqlRole, const char* securityDb)
{
	if (userName == DBA_USER_NAME)
		return true;

	RefPtr<IAttachment> att;
	RefPtr<ITransaction> tra;
	bool hasDb = openDb(securityDb, att, tra);

	FbLocalStatus st;
	MetaName role(sqlRole);
	if (hasDb && role.hasData())
	{
		const UCHAR info[] = { isc_info_db_sql_dialect, isc_info_end };
		UCHAR buffer[BUFFER_TINY];
		att->getInfo(&st, sizeof(info), info, sizeof(buffer), buffer);
		check("IAttachment::getInfo", &st);

		int dialect = SQL_DIALECT_V5;		// reasonable default
		const UCHAR* p = buffer;
		while (*p != isc_info_end && *p != isc_info_truncated && p < buffer + sizeof(buffer))
		{
			const UCHAR item = (UCHAR) *p++;
			const USHORT length = gds__vax_integer(p, sizeof(USHORT));
			p += sizeof(USHORT);

			switch (item)
			{
			case isc_info_db_sql_dialect:
				dialect = gds__vax_integer(p, length);
				break;
			}

			p += length;
		}

		UserId::makeRoleName(role, dialect);

		// We need to check is role granted to userName in security DB
		const char* sql = "select count(*) from RDB$USER_PRIVILEGES "
			"where RDB$USER = ? and RDB$RELATION_NAME = ? and RDB$PRIVILEGE = 'M'";

		Message prm;
		Field<Varying> u(prm, MAX_SQL_IDENTIFIER_LEN);
		Field<Varying> r(prm, MAX_SQL_IDENTIFIER_LEN);
		u = userName.c_str();
		r = role.c_str();

		Message result;
		Field<ISC_INT64> cnt(result);

		att->execute(&st, tra, 0, sql, SQL_DIALECT_V6, prm.getMetadata(), prm.getBuffer(),
			result.getMetadata(), result.getBuffer());

		if (st->getState() & IStatus::STATE_ERRORS)
		{
			// isc_dsql_relation_err when exec SQL - i.e. table RDB$USER_PRIVILEGES
			// is missing due to non-FB security DB
			if (!fb_utils::containsErrorCode(st->getErrors(), isc_dsql_relation_err))
				check("IAttachment::execute", &st);

			role = "";
		}
		else if (cnt == 0)
			role = "";
	}
	else
		role = trustedRole;

	if (role == ADMIN_ROLE)
		return true;

	if (!hasDb)
		return false;

	// check db creators table
	Message gr;
	Field<ISC_SHORT> uType(gr);
	Field<Varying> u(gr, MAX_SQL_IDENTIFIER_LEN);
	Field<ISC_SHORT> rType(gr);
	Field<Varying> r(gr, MAX_SQL_IDENTIFIER_LEN);
	uType = obj_user;
	u = userName.c_str();
	rType = role.hasData() ? obj_sql_role : 255;
	r = role.c_str();

	Message result;
	Field<ISC_INT64> cnt(result);

	att->execute(&st, tra, 0,
		"select count(*) from RDB$DB_CREATORS"
		" where (RDB$USER_TYPE = ? and RDB$USER = ?) or (RDB$USER_TYPE = ? and RDB$USER = ?)",
		SQL_DIALECT_V6, gr.getMetadata(), gr.getBuffer(), result.getMetadata(), result.getBuffer());
	if (st->getState() & IStatus::STATE_ERRORS)
	{
		if (fb_utils::containsErrorCode(st->getErrors(), isc_dsql_relation_err))
		{
			// isc_dsql_relation_err when exec SQL - i.e. table RDB$DB_CREATORS
			// is missing due to non-FB3 security DB
			return false;
		}
		check("IAttachment::execute", &st);
	}

	if (cnt > 0)
		return true;

	if (!role.hasData())
		role = "NONE";

	Message par2;
	Field<ISC_SHORT> uType2(par2);
	Field<Varying> u2(par2, MAX_SQL_IDENTIFIER_LEN);
	Field<Varying> r2(par2, MAX_SQL_IDENTIFIER_LEN);
	uType2 = obj_user;
	u2 = userName.c_str();
	r2 = role.c_str();

	Message res2;
	Field<Text> priv(res2, 8);

	const char* sql =
		"with recursive role_tree as ( "
		"   select rdb$relation_name as nm, 0 as ur from rdb$user_privileges "
		"       where rdb$privilege = 'M' and rdb$field_name = 'D' and rdb$user_type = ? and rdb$user = ? "
		"   union all "
		"   select rdb$role_name as nm, 1 as ur from rdb$roles "
		"       where rdb$role_name = ? "
		"   union all "
		"   select p.rdb$relation_name as nm, t.ur from rdb$user_privileges p "
		"       join role_tree t on t.nm = p.rdb$user "
		"       where p.rdb$privilege = 'M' and (p.rdb$field_name = 'D' or t.ur = 1)) "
		"select r.rdb$system_privileges "
		"   from role_tree t join rdb$roles r on t.nm = r.rdb$role_name ";
	RefPtr<IResultSet> rs(REF_NO_INCR, att->openCursor(&st, tra, 0, sql,
		SQL_DIALECT_V6, par2.getMetadata(), par2.getBuffer(), res2.getMetadata(), NULL, 0));
	check("IAttachment::execute", &st);

	UserId::Privileges privileges, wrk;

	while (rs->fetchNext(&st, res2.getBuffer()) == IStatus::RESULT_OK)
	{
		wrk.load(&priv);
		privileges |= wrk;
	}

	check("IResultSet::fetchNext", &st);

	return wrk.test(CREATE_DATABASE);
}
Ejemplo n.º 21
0
bool checkCreateDatabaseGrant(const MetaName& userName, const MetaName& trustedRole,
	const MetaName& sqlRole, const char* securityDb)
{
	if (userName == SYSDBA_USER_NAME)
		return true;

	RefPtr<IAttachment> att;
	RefPtr<ITransaction> tra;
	if (!openDb(securityDb, att, tra))
		return false;

	FbLocalStatus st;
	MetaName role(sqlRole);
	if (role.hasData())
	{
		const UCHAR info[] = { isc_info_db_sql_dialect, isc_info_end };
		UCHAR buffer[BUFFER_TINY];
		att->getInfo(&st, sizeof(info), info, sizeof(buffer), buffer);
		check("IAttachment::getInfo", &st);

		int dialect = SQL_DIALECT_V5;		// reasonable default
		const UCHAR* p = buffer;
		while (*p != isc_info_end && *p != isc_info_truncated && p < buffer + sizeof(buffer))
		{
			const UCHAR item = (UCHAR) *p++;
			const USHORT length = gds__vax_integer(p, sizeof(USHORT));
			p += sizeof(USHORT);

			switch (item)
			{
			case isc_info_db_sql_dialect:
				dialect = gds__vax_integer(p, length);
				break;
			}

			p += length;
		}

		JRD_make_role_name(role, dialect);

		// We need to check is admin role granted to userName in security DB
		const char* sql = "select count(*) from RDB$USER_PRIVILEGES "
			"where RDB$USER = ? and RDB$RELATION_NAME = ? and RDB$PRIVILEGE = 'M'";

		Message prm;
		Field<Varying> u(prm, MAX_SQL_IDENTIFIER_LEN);
		Field<Varying> r(prm, MAX_SQL_IDENTIFIER_LEN);
		u = userName.c_str();
		r = role.c_str();

		Message result;
		Field<ISC_INT64> cnt(result);

		att->execute(&st, tra, 0, sql, SQL_DIALECT_V6, prm.getMetadata(), prm.getBuffer(),
			result.getMetadata(), result.getBuffer());

		if (st->getState() & IStatus::STATE_ERRORS)
		{
			// isc_dsql_relation_err when exec SQL - i.e. table RDB$USER_PRIVILEGES
			// is missing due to non-FB security DB
			if (!fb_utils::containsErrorCode(st->getErrors(), isc_dsql_relation_err))
				check("IAttachment::execute", &st);

			role = "";
		}
		else if (cnt == 0)
			role = "";
	}
	else
		role = trustedRole;

	if (role == ADMIN_ROLE)
		return true;

	Message gr;
	Field<ISC_SHORT> uType(gr);
	Field<Varying> u(gr, MAX_SQL_IDENTIFIER_LEN);
	Field<ISC_SHORT> rType(gr);
	Field<Varying> r(gr, MAX_SQL_IDENTIFIER_LEN);
	uType = obj_user;
	u = userName.c_str();
	rType = role.hasData() ? obj_sql_role : 255;
	r = role.c_str();

	Message result;
	Field<ISC_INT64> cnt(result);

	att->execute(&st, tra, 0,
		"select count(*) from RDB$DB_CREATORS"
		" where (RDB$USER_TYPE = ? and RDB$USER = ?) or (RDB$USER_TYPE = ? and RDB$USER = ?)",
		SQL_DIALECT_V6, gr.getMetadata(), gr.getBuffer(), result.getMetadata(), result.getBuffer());
	if (st->getState() & IStatus::STATE_ERRORS)
	{
		if (fb_utils::containsErrorCode(st->getErrors(), isc_dsql_relation_err))
		{
			// isc_dsql_relation_err when exec SQL - i.e. table RDB$DB_CREATORS
			// is missing due to non-FB3 security DB
			return false;
		}
		check("IAttachment::execute", &st);
	}

	return cnt > 0;
}
Ejemplo n.º 22
0
void InternalStatement::doPrepare(thread_db* tdbb, const string& sql)
{
	m_inMetadata->reset();
	m_outMetadata->reset();

	JAttachment* att = m_intConnection.getJrdAtt();
	JTransaction* tran = getIntTransaction()->getJrdTran();

	FbLocalStatus status;

	if (m_request)
	{
		doClose(tdbb, true);
		fb_assert(!m_allocated);
	}

	{
		EngineCallbackGuard guard(tdbb, *this, FB_FUNCTION);

		CallerName save_caller_name(tran->getHandle()->tra_caller_name);

		if (m_callerPrivileges)
		{
			jrd_req* request = tdbb->getRequest();
			JrdStatement* statement = request ? request->getStatement() : NULL;
			CallerName callerName;
			const Routine* routine;

			if (statement && statement->parentStatement)
				statement = statement->parentStatement;

			if (statement && statement->triggerName.hasData())
				tran->getHandle()->tra_caller_name = CallerName(obj_trigger, statement->triggerName);
			else if (statement && (routine = statement->getRoutine()) &&
				routine->getName().identifier.hasData())
			{
				if (routine->getName().package.isEmpty())
				{
					tran->getHandle()->tra_caller_name = CallerName(routine->getObjectType(),
						routine->getName().identifier);
				}
				else
				{
					tran->getHandle()->tra_caller_name = CallerName(obj_package_header,
						routine->getName().package);
				}
			}
			else
				tran->getHandle()->tra_caller_name = CallerName();
		}

		m_request.assignRefNoIncr(att->prepare(&status, tran, sql.length(), sql.c_str(),
			m_connection.getSqlDialect(), 0));
		m_allocated = (m_request != NULL);

		tran->getHandle()->tra_caller_name = save_caller_name;
	}

	if (status->getState() & IStatus::STATE_ERRORS)
		raise(&status, tdbb, "JAttachment::prepare", &sql);

	const DsqlCompiledStatement* statement = m_request->getHandle()->getStatement();

	if (statement->getSendMsg())
	{
		try
		{
			PreparedStatement::parseDsqlMessage(statement->getSendMsg(), m_inDescs,
				m_inMetadata, m_in_buffer);
			m_inputs = m_inMetadata->getCount();
		}
		catch (const Exception&)
		{
			raise(tdbb->tdbb_status_vector, tdbb, "parse input message", &sql);
		}
	}
	else
		m_inputs = 0;

	if (statement->getReceiveMsg())
	{
		try
		{
			PreparedStatement::parseDsqlMessage(statement->getReceiveMsg(), m_outDescs,
				m_outMetadata, m_out_buffer);
			m_outputs = m_outMetadata->getCount();
		}
		catch (const Exception&)
		{
			raise(tdbb->tdbb_status_vector, tdbb, "parse output message", &sql);
		}
	}
	else
		m_outputs = 0;

	m_stmt_selectable = false;

	switch (statement->getType())
	{
	case DsqlCompiledStatement::TYPE_SELECT:
	case DsqlCompiledStatement::TYPE_SELECT_UPD:
	case DsqlCompiledStatement::TYPE_SELECT_BLOCK:
		m_stmt_selectable = true;
		break;

	case DsqlCompiledStatement::TYPE_START_TRANS:
	case DsqlCompiledStatement::TYPE_COMMIT:
	case DsqlCompiledStatement::TYPE_ROLLBACK:
	case DsqlCompiledStatement::TYPE_COMMIT_RETAIN:
	case DsqlCompiledStatement::TYPE_ROLLBACK_RETAIN:
	case DsqlCompiledStatement::TYPE_CREATE_DB:
		Arg::Gds(isc_eds_expl_tran_ctrl).copyTo(&status);
		raise(&status, tdbb, "JAttachment::prepare", &sql);
		break;

	case DsqlCompiledStatement::TYPE_INSERT:
	case DsqlCompiledStatement::TYPE_DELETE:
	case DsqlCompiledStatement::TYPE_UPDATE:
	case DsqlCompiledStatement::TYPE_UPDATE_CURSOR:
	case DsqlCompiledStatement::TYPE_DELETE_CURSOR:
	case DsqlCompiledStatement::TYPE_DDL:
	case DsqlCompiledStatement::TYPE_EXEC_PROCEDURE:
	case DsqlCompiledStatement::TYPE_SET_GENERATOR:
	case DsqlCompiledStatement::TYPE_SAVEPOINT:
	case DsqlCompiledStatement::TYPE_EXEC_BLOCK:
		break;
	}
}