/*

Copyright (c) 2002-2005, Yauheni Akhotnikau
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

- Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.

- Redistributions in binary form must reproduce the above copyright notice, this
list of conditions and the following disclaimer in the documentation and/or
other materials provided with the distribution.

- The name of the author may not be used to endorse or promote products derived
from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
OF SUCH DAMAGE.

*/

/*
	ObjESSty-1
*/

#include <auto_ptr_3/h/obj_ptr.hpp>

#include <oess_1/defs/h/ex.hpp>
#include <oess_1/defs/impl/h/catch_all.hpp>

#include <oess_1/defs/log/h/out.hpp>
#include <oess_1/defs/log/h/err.hpp>

#include <oess_1/io/h/bstring_buf.hpp>

#include <oess_1/stdsn/h/ent_no_markers.hpp>

#include <oess_1/db/site/impl/h/attach_cmd.hpp>
#include <oess_1/db/site/impl/h/detach_cmd.hpp>
#include <oess_1/db/site/impl/h/ent_create_cmd.hpp>
#include <oess_1/db/site/impl/h/ent_destroy_cmd.hpp>
#include <oess_1/db/site/impl/h/ent_destroy_all_cmd.hpp>
#include <oess_1/db/site/impl/h/ent_load_cmd.hpp>
#include <oess_1/db/site/impl/h/ent_update_cmd.hpp>
#include <oess_1/db/site/impl/h/ent_find_next_cmd.hpp>
#include <oess_1/db/site/impl/h/slice_create_cmd.hpp>
#include <oess_1/db/site/impl/h/slice_destroy_cmd.hpp>
#include <oess_1/db/site/impl/h/slice_is_exists_cmd.hpp>
#include <oess_1/db/site/impl/h/slice_names_cmd.hpp>
#include <oess_1/db/site/impl/h/transaction_cmd.hpp>

#include <oess_1/db/cln/h/errno.hpp>
#include <oess_1/db/cln/impl/h/std_db.hpp>

namespace oess_1 {

namespace db {

namespace cln {

//
// create_std_db
//

OESS_1__DB__FUNC(db_t *)
create_std_db(
	oess_1::db::site::abstract_connector_t * connector )
{
	return new impl::std_db_t( connector );
}

namespace impl {

//
// ent_packer_base_t
//

//! Интерфейс объекта, который умеет создавать двоичное
//! представление сущности.
/*!
	\since v.1.4.0
*/
class	ent_packer_base_t
	{
	public :
		//! Этот оператор должен поместить двоичный образ
		//! сущности в указанную строку.
		virtual void
		operator()(
			//! Приемник двоичного значения сущности.
			std::string & to ) const = 0;
	};

//
// ent_packer_serializer_t
//

//! Реализация интерфейса %ent_packer_base_t для случая
//! штатной сериализации объекта.
/*!
	\since v.1.4.0
*/
class	ent_packer_serializer_t
	:	public ent_packer_base_t
	{
	private :
		//! Исходное значение объекта.
		const oess_1::stdsn::serializable_t & m_ent;

	public :
		ent_packer_serializer_t(
			//! Исходное значение объекта.
			const oess_1::stdsn::serializable_t & ent )
			:	m_ent( ent )
			{}

		virtual void
		operator()(
			std::string & to ) const
			{
				oess_1::io::obstring_t ostream( to );
				oess_1::stdsn::oent_std_t oent( ostream );
				oent << m_ent;
			}
	};

//
// ent_packer_raw_t
//

//! Реализация интерфейса %ent_packer_base_t для случая, когда
//! образ объекта уже представлен в двоичном виде.
/*!
	\since v.1.4.0
*/
class	ent_packer_raw_t
	:	public ent_packer_base_t
	{
	private :
		//! Поток, из которого нужно брать исходное
		//! значение объекта.
		oess_1::io::ibinstream_t & m_from;

		//! Размер двоичного представления объекта в байтах.
		oess_1::uint_t m_image_len;

	public :
		ent_packer_raw_t(
			//! Поток, из которого нужно брать исходное
			//! значение объекта.
			oess_1::io::ibinstream_t & from,
			//! Размер двоичного представления объекта в байтах.
			oess_1::uint_t image_len )
			:	m_from( from )
			,	m_image_len( image_len )
			{}

		virtual void
		operator()(
			std::string & to ) const
			{
				to.reserve( m_image_len );

				// Поскольку нельзя в строку записать сразу весь
				// образ объекта, то будем делать это порциями.
				char buf[ 256 ];
				oess_1::uint_t remaining = m_image_len;

				while( remaining )
					{
						oess_1::uint_t l = remaining;
						if( sizeof( buf ) < l )
							l = sizeof( buf );

						m_from.read( buf, l );
						to.append( buf, l );

						remaining -= l;
					}
			}
	};

//
// ent_unpacker_base_t
//

//! Интерфейс объекта, который умеет разбирать двоичное
//! представление сущности.
/*!
	\since v.1.4.0
*/
class	ent_unpacker_base_t
	{
	public :
		//! Этот оператор должен распаковать двоичный образ
		//! сущности из указанной строки.
		virtual void
		operator()(
			//! Двоичное значение.
			const std::string & value ) = 0;
	};

//
// ent_unpacker_deserializer_t
//

//! Реализация интерфейса %ent_unpacker_base_t для случая
//! штатной десериализации объекта.
/*!
	\since v.1.4.0
*/
class	ent_unpacker_deserializer_t
	:	public ent_unpacker_base_t
	{
	private :
		//! Приемник значения объекта.
		oess_1::stdsn::serializable_t & m_ent;

	public :
		ent_unpacker_deserializer_t(
			//! Исходное значение объекта.
			oess_1::stdsn::serializable_t & ent )
			:	m_ent( ent )
			{}

		virtual void
		operator()(
			const std::string & value )
			{
				oess_1::io::ibstring_t istream( value );
				oess_1::stdsn::ient_std_t ient( istream );
				ient >> m_ent;
			}
	};

//
// ent_unpacker_raw_t
//

//! Реализация интерфейса %ent_unpacker_base_t для случая, когда
//! образ объекта должен быть получен в двоичном виде.
/*!
	\since v.1.4.0
*/
class	ent_unpacker_raw_t
	:	public ent_unpacker_base_t
	{
	private :
		//! Приемник двоичного представления объекта.
		oess_1::io::obinstream_t & m_receiver;

		//! Приемник размера двоичного представления объекта в байтах.
		oess_1::uint_t & m_image_len;

		//! Максимально допустимый размер объекта, который может
		//! быть помещен в m_receiver.
		const oess_1::uint_t	m_size_limit;

	public :
		ent_unpacker_raw_t(
			//! Приемник двоичного представления объекта.
			oess_1::io::obinstream_t & receiver,
			//! Приемник размера двоичного представления объекта в байтах.
			oess_1::uint_t & image_len,
			//! Максимально допустимый размер объекта, который может
			//! быть помещен в receiver.
			oess_1::uint_t size_limit )
			:	m_receiver( receiver )
			,	m_image_len( image_len )
			,	m_size_limit( size_limit )
			{}

		virtual void
		operator()(
			const std::string & value )
			{
				m_image_len = value.size();

				oess_1::uint_t bytes_to_copy = m_size_limit;
				if( m_image_len < bytes_to_copy )
					bytes_to_copy = m_image_len;

				m_receiver.write( value.data(), bytes_to_copy );
			}
	};

//
// std_db_t
//

std_db_t::std_db_t(
	oess_1::db::site::abstract_connector_t * connector )
:
	db_t( connector )
,	m_is_attached( false )
{
}

std_db_t::~std_db_t()
{
	__OESS_CATCH_ALL(
		cleanup();
	)
}

void
std_db_t::attach(
	const std::string & logic_name )
{
	if( m_is_attached )
		OESS_THROW_LOGIC(
			oess_1::db::cln::err::c_already_attached,
			"attachment to DB exists" )

	// Отправляем на сервер запрос на подключение к БД.
	oess_1::db::site::impl::resp_wrapper_t resp_wrapper;
	transmit(
		new oess_1::db::site::impl::attach_cmd_t(
			query_connector().query_client_id(), logic_name ),
		resp_wrapper,
		oess_1::db::site::impl::attach_cmd_result_t::e_id );

	// Если мы здесь, значит все прошло успешно.
	const oess_1::db::site::impl::attach_cmd_result_t & result =
		dynamic_cast< const oess_1::db::site::impl::
			attach_cmd_result_t & >( *resp_wrapper );

	m_logic_name = logic_name;
	m_is_attached = true;
}

void
std_db_t::detach()
{
	must_be_attached();

	try {
		// Отправляем на сервер запрос на отключение от БД.
		oess_1::db::site::impl::resp_wrapper_t resp_wrapper;
		transmit(
			new oess_1::db::site::impl::detach_cmd_t(
				query_connector().query_client_id(), m_logic_name ),
			resp_wrapper,
			oess_1::db::site::impl::detach_cmd_result_t::e_id );

		cleanup();
	}
	catch( ... ) {
		cleanup();
		throw;
	}
}

void
std_db_t::slice_create(
	const std::string & slice_name )
{
	must_be_attached();

	try
	{
		oess_1::db::site::impl::slice_create_cmd_t * req =
			new oess_1::db::site::impl::slice_create_cmd_t(
				query_connector().query_client_id(),
				m_logic_name, slice_name );

		// Запрос полностью продготовлен для передачи на сервер.
		oess_1::db::site::impl::resp_wrapper_t resp_wrapper;
		transmit( req, resp_wrapper,
			oess_1::db::site::impl::slice_create_cmd_result_t::e_id );

		// Если мы здесь, значит все прошло успешно.
	}
	catch( oess_1::physic_ex_t & x ) {
		OESS_1_LOG_ERR( x.query_err_code() << std::endl )

		// После физических ошибок продолжение работы
		// невозможно.
		cleanup();
		throw;
	}
}

void
std_db_t::slice_destroy(
	const std::string & slice_name )
{
	must_be_attached();

	try
	{
		oess_1::db::site::impl::slice_destroy_cmd_t * req =
			new oess_1::db::site::impl::slice_destroy_cmd_t(
				query_connector().query_client_id(),
				m_logic_name, slice_name );

		// Запрос полностью продготовлен для передачи на сервер.
		oess_1::db::site::impl::resp_wrapper_t resp_wrapper;
		transmit( req, resp_wrapper,
			oess_1::db::site::impl::slice_destroy_cmd_result_t::e_id );

		// Если мы здесь, значит все прошло успешно.
	}
	catch( oess_1::physic_ex_t & x ) {
		OESS_1_LOG_ERR( x.query_err_code() << std::endl )

		// После физических ошибок продолжение работы
		// невозможно.
		cleanup();
		throw;
	}
}

bool
std_db_t::slice_is_exists(
	const std::string & slice_name )
{
	must_be_attached();

	bool result = false;

	try
	{
		oess_1::db::site::impl::slice_is_exists_cmd_t * req =
			new oess_1::db::site::impl::slice_is_exists_cmd_t(
				query_connector().query_client_id(),
				m_logic_name, slice_name );

		// Запрос полностью продготовлен для передачи на сервер.
		oess_1::db::site::impl::resp_wrapper_t resp_wrapper;
		transmit( req, resp_wrapper,
			oess_1::db::site::impl::slice_is_exists_cmd_result_t::e_id );

		// Если мы здесь, значит все прошло успешно.
		result = ( dynamic_cast<
				const oess_1::db::site::impl::
					slice_is_exists_cmd_result_t & >(
						*resp_wrapper ) ).is_exists();
	}
	catch( oess_1::physic_ex_t & x ) {
		OESS_1_LOG_ERR( x.query_err_code() << std::endl )

		// После физических ошибок продолжение работы
		// невозможно.
		cleanup();
		throw;
	}

	return result;
}

std::set< std::string >
std_db_t::slice_names()
{
	must_be_attached();

	std::set< std::string > result;

	try
	{
		oess_1::db::site::impl::slice_names_cmd_t * req =
			new oess_1::db::site::impl::slice_names_cmd_t(
				query_connector().query_client_id(), m_logic_name );

		// Запрос полностью продготовлен для передачи на сервер.
		oess_1::db::site::impl::resp_wrapper_t resp_wrapper;
		transmit( req, resp_wrapper,
			oess_1::db::site::impl::slice_names_cmd_result_t::e_id );

		// Если мы здесь, значит все прошло успешно.
		result = ( dynamic_cast<
				const oess_1::db::site::impl::
					slice_names_cmd_result_t & >(
						*resp_wrapper ) ).names();
	}
	catch( oess_1::physic_ex_t & x ) {
		OESS_1_LOG_ERR( x.query_err_code() << std::endl )

		// После физических ошибок продолжение работы
		// невозможно.
		cleanup();
		throw;
	}

	return result;
}

oess_1::ent_id_t
std_db_t::ent_create(
	const std::string & slice_name,
	const oess_1::stdsn::serializable_t & ent )
{
	ent_packer_serializer_t packer( ent );
	return do_ent_create_actions( slice_name, packer );
}

void
std_db_t::ent_destroy(
	const oess_1::ent_id_t & ent_id )
{
	must_be_attached();

	try {
		oess_1::db::site::impl::resp_wrapper_t resp_wrapper;
		transmit(
			new oess_1::db::site::impl::ent_destroy_cmd_t(
				query_connector().query_client_id(),
				m_logic_name, ent_id ),
			resp_wrapper,
			oess_1::db::site::impl::ent_destroy_cmd_result_t::e_id );
	}
	catch( oess_1::physic_ex_t & x ) {
		OESS_1_LOG_ERR( x.query_err_code() << std::endl )

		// После физических ошибок продолжение работы
		// невозможно.
		cleanup();
		throw;
	}
}

void
std_db_t::ent_destroy_all(
	const std::string & slice_name )
{
	must_be_attached();

	try {
		oess_1::db::site::impl::resp_wrapper_t resp_wrapper;
		transmit(
			new oess_1::db::site::impl::ent_destroy_all_cmd_t(
				query_connector().query_client_id(),
				m_logic_name, slice_name ),
			resp_wrapper,
			oess_1::db::site::impl::ent_destroy_all_cmd_result_t::e_id );
	}
	catch( oess_1::physic_ex_t & x ) {
		OESS_1_LOG_ERR( x.query_err_code() << std::endl )

		// После физических ошибок продолжение работы
		// невозможно.
		cleanup();
		throw;
	}
}


void
std_db_t::ent_load(
	const oess_1::ent_id_t & ent_id,
	oess_1::stdsn::serializable_t & ent )
	{
		ent_unpacker_deserializer_t unpacker( ent );
		do_ent_load_actions( ent_id, unpacker );
	}

void
std_db_t::ent_update(
	const oess_1::ent_id_t & ent_id,
	const oess_1::stdsn::serializable_t & ent )
	{
		ent_packer_serializer_t packer( ent );
		do_ent_update_actions( ent_id, packer );
	}

oess_1::ent_id_t
std_db_t::ent_find_next(
	const std::string & slice_name,
	const oess_1::ent_id_t & ent_id )
{
	must_be_attached();

	oess_1::ent_id_t next_ent_id;

	try {
		oess_1::db::site::impl::resp_wrapper_t resp_wrapper;
		transmit(
			new oess_1::db::site::impl::ent_find_next_cmd_t(
				query_connector().query_client_id(),
				m_logic_name, slice_name, ent_id ),
			resp_wrapper,
			oess_1::db::site::impl::
				ent_find_next_cmd_result_t::e_id );

		// Если мы здесь, значит все прошло успешно.
		next_ent_id = ( dynamic_cast< const oess_1::db::site::impl::
			ent_find_next_cmd_result_t & >( *resp_wrapper ) ).
			query_ent_id();
	}
	catch( oess_1::physic_ex_t & x ) {
		OESS_1_LOG_ERR( x.query_err_code() << std::endl )

		// После физических ошибок продолжение работы
		// невозможно.
		cleanup();
		throw;
	}

	return next_ent_id;
}

oess_1::ent_id_t
std_db_t::ent_raw_create(
	const std::string & slice_name,
	oess_1::io::ibinstream_t & image,
	oess_1::uint_t image_size )
	{
		ent_packer_raw_t packer( image, image_size );
		return do_ent_create_actions( slice_name, packer );
	}

oess_1::uint_t
std_db_t::ent_raw_load(
	const oess_1::ent_id_t & ent_id,
	oess_1::io::obinstream_t & receiver,
	oess_1::uint_t size_limit )
	{
		oess_1::uint_t ent_length;
		ent_unpacker_raw_t unpacker( receiver, ent_length, size_limit );
		do_ent_load_actions( ent_id, unpacker );

		return ent_length;
	}

void
std_db_t::ent_raw_update(
	const oess_1::ent_id_t & ent_id,
	oess_1::io::ibinstream_t & image,
	oess_1::uint_t image_size )
	{
		ent_packer_raw_t packer( image, image_size );
		do_ent_update_actions( ent_id, packer );
	}

void
std_db_t::transaction_begin()
{
	must_be_attached();

	try {
		oess_1::db::site::impl::resp_wrapper_t resp_wrapper;
		transmit(
			new oess_1::db::site::impl::transaction_cmd_t(
				query_connector().query_client_id(),
				m_logic_name,
				oess_1::db::site::impl::transaction_cmd_t::begin ),
			resp_wrapper,
			oess_1::db::site::impl::transaction_cmd_result_t::e_id );
		// Если мы здесь, значит все прошло успешно.
	}
	catch( oess_1::physic_ex_t & x ) {
		OESS_1_LOG_ERR( x.query_err_code() << std::endl )

		// После физических ошибок продолжение работы
		// невозможно.
		cleanup();
		throw;
	}
}

void
std_db_t::transaction_commit()
{
	must_be_attached();

	try {
		oess_1::db::site::impl::resp_wrapper_t resp_wrapper;
		transmit(
			new oess_1::db::site::impl::transaction_cmd_t(
				query_connector().query_client_id(),
				m_logic_name,
				oess_1::db::site::impl::transaction_cmd_t::commit ),
			resp_wrapper,
			oess_1::db::site::impl::transaction_cmd_result_t::e_id );
		// Если мы здесь, значит все прошло успешно.
	}
	catch( oess_1::physic_ex_t & x ) {
		OESS_1_LOG_ERR( x.query_err_code() << std::endl )

		// После физических ошибок продолжение работы
		// невозможно.
		cleanup();
		throw;
	}
}

void
std_db_t::transaction_rollback()
{
	must_be_attached();

	try {
		oess_1::db::site::impl::resp_wrapper_t resp_wrapper;
		transmit(
			new oess_1::db::site::impl::transaction_cmd_t(
				query_connector().query_client_id(),
				m_logic_name,
				oess_1::db::site::impl::transaction_cmd_t::rollback ),
			resp_wrapper,
			oess_1::db::site::impl::transaction_cmd_result_t::e_id );
		// Если мы здесь, значит все прошло успешно.
	}
	catch( oess_1::physic_ex_t & x ) {
		OESS_1_LOG_ERR( x.query_err_code() << std::endl )

		// После физических ошибок продолжение работы
		// невозможно.
		cleanup();
		throw;
	}
}

void
std_db_t::cleanup()
{
	m_is_attached = false;

	m_logic_name = "";
}

void
std_db_t::must_be_attached() const
{
	if( !m_is_attached )
		OESS_THROW_LOGIC(
			oess_1::db::cln::err::c_not_attached,
			"no attachment to DB" )
}

oess_1::ent_id_t
std_db_t::do_ent_create_actions(
	const std::string & slice_name,
	const ent_packer_base_t & packer )
	{
		must_be_attached();
   
		oess_1::ent_id_t new_ent_id;
   
		try
			{
				using namespace oess_1::db::site::impl;

				// Используем auto_ptr для автоматического уничтожения
				// не заполненого объекта-запроса в случае, если при
				// его упаковке возникнет исключение.
				oess_1::db::site::impl::ent_create_cmd_t * req =
						new ent_create_cmd_t(
								query_connector().query_client_id(),
								m_logic_name, slice_name );
				auto_ptr_3::obj_ptr_t< ent_create_cmd_t > req_ptr( req );
            
				packer( req->query_ent_value() );
				req_ptr.clear();
            
				// Запрос полностью продготовлен для передачи на сервер.
				oess_1::db::site::impl::resp_wrapper_t resp_wrapper;
				transmit( req, resp_wrapper,
						ent_create_cmd_result_t::e_id );
            
				// Если мы здесь, значит все прошло успешно.
				new_ent_id = ( dynamic_cast< const ent_create_cmd_result_t & >(
						*resp_wrapper ) ).query_ent_id();
			}
		catch( oess_1::physic_ex_t & x )
			{
				OESS_1_LOG_ERR( x.query_err_code() << std::endl )
            
				// После физических ошибок продолжение работы
				// невозможно.
				cleanup();
				throw;
			}
   
		return new_ent_id;
	}

void
std_db_t::do_ent_load_actions(
	const oess_1::ent_id_t & ent_id,
	ent_unpacker_base_t & unpacker )
	{
		must_be_attached();
   
		try
			{
				oess_1::db::site::impl::resp_wrapper_t resp_wrapper;
				transmit(
					new oess_1::db::site::impl::ent_load_cmd_t(
						query_connector().query_client_id(),
						m_logic_name, ent_id ),
					resp_wrapper,
					oess_1::db::site::impl::ent_load_cmd_result_t::e_id );
      
				// Если мы здесь, значит все прошло успешно.
				const std::string & ent_value =
					( dynamic_cast< const oess_1::db::site::impl::
						ent_load_cmd_result_t & >( *resp_wrapper ) ).
						query_ent_value();
      
				// Осталось распаковать значение сущности.
				unpacker( ent_value );
			}
		catch( const oess_1::physic_ex_t & x )
			{
				OESS_1_LOG_ERR( x.query_err_code() << std::endl )
      
				// После физических ошибок продолжение работы
				// невозможно.
				cleanup();
				throw;
			}
	}

void
std_db_t::do_ent_update_actions(
	const oess_1::ent_id_t & ent_id,
	const ent_packer_base_t & packer )
	{
		must_be_attached();
   
		try
			{
				// Используем auto_ptr для автоматического уничтожения
				// не заполненого объекта-запроса.
				oess_1::db::site::impl::ent_update_cmd_t * req =
					new oess_1::db::site::impl::ent_update_cmd_t(
						query_connector().query_client_id(),
						m_logic_name, ent_id );
				auto_ptr_3::obj_ptr_t<
					oess_1::db::site::impl::ent_update_cmd_t >
					req_ptr( req );
      
				packer( req->query_ent_value() );
				req_ptr.clear();
      
				// Запрос полностью продготовлен для передачи на сервер.
				oess_1::db::site::impl::resp_wrapper_t resp_wrapper;
				transmit( req, resp_wrapper,
					oess_1::db::site::impl::ent_update_cmd_result_t::e_id );
			}
		catch( oess_1::physic_ex_t & x )
			{
				OESS_1_LOG_ERR( x.query_err_code() << std::endl )
      
				// После физических ошибок продолжение работы
				// невозможно.
				cleanup();
				throw;
			}
	}

void
std_db_t::transmit(
	oess_1::db::site::impl::request_t * req,
	oess_1::db::site::impl::resp_wrapper_t & resp_wrapper,
	oess_1::uint_t awaiting_resp_id )
{
	oess_1::db::site::impl::req_wrapper_t req_wrapper( req );
	query_connector().transmit( req_wrapper, resp_wrapper,
		awaiting_resp_id );

	// Если исключений не возникло, значит ответ сервера получен.
	oess_1::err_code_t err = resp_wrapper->
		query_result().query_err_code();
	if( err )
		// Произошла ошибка на стороне сервера.
		throw oess_1::logic_ex_t( err );
}

} /* namespace impl */

} /* namespace cln */

} /* namespace db */

} /* namespace oess_1 */
