/*----- PROTECTED REGION ID(DataBase.cpp) ENABLED START -----*/
//=============================================================================
//
// file :        DataBase.cpp
//
// description : C++ source for the DataBase and its commands.
//               The class is derived from Device. It represents the
//               CORBA servant object which will be accessed from the
//               network. All commands which can be executed on the
//               DataBase are implemented in this file.
//
// project :     TANGO Database server.
//
// Copyright (C) :      2004,2005,2006,2007,2008,2009,2010,2011,2012,2013
//						European Synchrotron Radiation Facility
//                      BP 220, Grenoble 38043
//                      FRANCE
//
// This file is part of Tango.
//
// Tango is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Tango is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Tango.  If not, see <http://www.gnu.org/licenses/>.
//
//=============================================================================
//                This file is generated by POGO
//        (Program Obviously used to Generate tango Object)
//=============================================================================


#include <tango/tango.h>
#include "DataBase.h"
#include "DataBaseClass.h"
#include "Logging.h"
#include <stdio.h>
#include <algorithm>
#include "DatabaseConnectionHandle.h"

/*----- PROTECTED REGION END -----*/	//	DataBase.cpp

/**
 *  DataBase class description:
 *    This class manage the TANGO database.
 */

//================================================================
//  The following table gives the correspondence
//  between command and method names.
//
//  Command name                          |  Method name
//================================================================
//  State                                 |  dev_state
//  Status                                |  Inherited (no method)
//  DbAddDevice                           |  db_add_device
//  DbAddServer                           |  db_add_server
//  DbDeleteAttributeAlias                |  db_delete_attribute_alias
//  DbDeleteClassAttribute                |  db_delete_class_attribute
//  DbDeleteClassAttributeProperty        |  db_delete_class_attribute_property
//  DbDeleteClassProperty                 |  db_delete_class_property
//  DbDeleteDevice                        |  db_delete_device
//  DbDeleteDeviceAlias                   |  db_delete_device_alias
//  DbDeleteDeviceAttribute               |  db_delete_device_attribute
//  DbDeleteDeviceAttributeProperty       |  db_delete_device_attribute_property
//  DbDeleteDeviceProperty                |  db_delete_device_property
//  DbDeleteProperty                      |  db_delete_property
//  DbDeleteServer                        |  db_delete_server
//  DbDeleteServerInfo                    |  db_delete_server_info
//  DbExportDevice                        |  db_export_device
//  DbExportEvent                         |  db_export_event
//  DbGetAliasDevice                      |  db_get_alias_device
//  DbGetAttributeAlias                   |  db_get_attribute_alias
//  DbGetAttributeAliasList               |  db_get_attribute_alias_list
//  DbGetClassAttributeList               |  db_get_class_attribute_list
//  DbGetClassAttributeProperty           |  db_get_class_attribute_property
//  DbGetClassAttributeProperty2          |  db_get_class_attribute_property2
//  DbGetClassAttributePropertyHist       |  db_get_class_attribute_property_hist
//  DbGetClassForDevice                   |  db_get_class_for_device
//  DbGetClassInheritanceForDevice        |  db_get_class_inheritance_for_device
//  DbGetClassList                        |  db_get_class_list
//  DbGetClassProperty                    |  db_get_class_property
//  DbGetClassPropertyHist                |  db_get_class_property_hist
//  DbGetClassPropertyList                |  db_get_class_property_list
//  DbGetDeviceAlias                      |  db_get_device_alias
//  DbGetDeviceAliasList                  |  db_get_device_alias_list
//  DbGetDeviceAttributeList              |  db_get_device_attribute_list
//  DbGetDeviceAttributeProperty          |  db_get_device_attribute_property
//  DbGetDeviceAttributeProperty2         |  db_get_device_attribute_property2
//  DbGetDeviceAttributePropertyHist      |  db_get_device_attribute_property_hist
//  DbGetDeviceClassList                  |  db_get_device_class_list
//  DbGetDeviceDomainList                 |  db_get_device_domain_list
//  DbGetDeviceExportedList               |  db_get_device_exported_list
//  DbGetDeviceFamilyList                 |  db_get_device_family_list
//  DbGetDeviceInfo                       |  db_get_device_info
//  DbGetDeviceList                       |  db_get_device_list
//  DbGetDeviceWideList                   |  db_get_device_wide_list
//  DbGetDeviceMemberList                 |  db_get_device_member_list
//  DbGetDeviceProperty                   |  db_get_device_property
//  DbGetDevicePropertyHist               |  db_get_device_property_hist
//  DbGetDevicePropertyList               |  db_get_device_property_list
//  DbGetDeviceServerClassList            |  db_get_device_server_class_list
//  DbGetExportdDeviceListForClass        |  db_get_exportd_device_list_for_class
//  DbGetHostList                         |  db_get_host_list
//  DbGetHostServerList                   |  db_get_host_server_list
//  DbGetHostServersInfo                  |  db_get_host_servers_info
//  DbGetInstanceNameList                 |  db_get_instance_name_list
//  DbGetObjectList                       |  db_get_object_list
//  DbGetProperty                         |  db_get_property
//  DbGetPropertyHist                     |  db_get_property_hist
//  DbGetPropertyList                     |  db_get_property_list
//  DbGetServerInfo                       |  db_get_server_info
//  DbGetServerList                       |  db_get_server_list
//  DbGetServerNameList                   |  db_get_server_name_list
//  DbImportDevice                        |  db_import_device
//  DbImportEvent                         |  db_import_event
//  DbInfo                                |  db_info
//  DbPutAttributeAlias                   |  db_put_attribute_alias
//  DbPutClassAttributeProperty           |  db_put_class_attribute_property
//  DbPutClassAttributeProperty2          |  db_put_class_attribute_property2
//  DbPutClassProperty                    |  db_put_class_property
//  DbPutDeviceAlias                      |  db_put_device_alias
//  DbPutDeviceAttributeProperty          |  db_put_device_attribute_property
//  DbPutDeviceAttributeProperty2         |  db_put_device_attribute_property2
//  DbPutDeviceProperty                   |  db_put_device_property
//  DbPutProperty                         |  db_put_property
//  DbPutServerInfo                       |  db_put_server_info
//  DbUnExportDevice                      |  db_un_export_device
//  DbUnExportEvent                       |  db_un_export_event
//  DbUnExportServer                      |  db_un_export_server
//  ResetTimingValues                     |  reset_timing_values
//  DbGetDataForServerCache               |  db_get_data_for_server_cache
//  DbDeleteAllDeviceAttributeProperty    |  db_delete_all_device_attribute_property
//  DbMySqlSelect                         |  db_my_sql_select
//  DbGetCSDbServerList                   |  db_get_csdb_server_list
//  DbGetAttributeAlias2                  |  db_get_attribute_alias2
//  DbGetAliasAttribute                   |  db_get_alias_attribute
//  DbRenameServer                        |  db_rename_server
//  DbGetClassPipeProperty                |  db_get_class_pipe_property
//  DbGetDevicePipeProperty               |  db_get_device_pipe_property
//  DbDeleteClassPipe                     |  db_delete_class_pipe
//  DbDeleteDevicePipe                    |  db_delete_device_pipe
//  DbDeleteClassPipeProperty             |  db_delete_class_pipe_property
//  DbDeleteDevicePipeProperty            |  db_delete_device_pipe_property
//  DbGetClassPipeList                    |  db_get_class_pipe_list
//  DbGetDevicePipeList                   |  db_get_device_pipe_list
//  DbDeleteAllDevicePipeProperty         |  db_delete_all_device_pipe_property
//  DbPutClassPipeProperty                |  db_put_class_pipe_property
//  DbPutDevicePipeProperty               |  db_put_device_pipe_property
//  DbGetClassPipePropertyHist            |  db_get_class_pipe_property_hist
//  DbGetDevicePipePropertyHist           |  db_get_device_pipe_property_hist
//  DbGetForwardedAttributeListForDevice  |  db_get_forwarded_attribute_list_for_device
//  DbGetClassPropertyListWildcard        |  db_get_class_property_list_wildcard
//================================================================

//================================================================
//  Attributes managed are:
//================================================================
//  StoredProcedureRelease  |  Tango::DevString	Scalar
//  Timing_average          |  Tango::DevDouble	Spectrum  ( max = 64)
//  Timing_minimum          |  Tango::DevDouble	Spectrum  ( max = 64)
//  Timing_maximum          |  Tango::DevDouble	Spectrum  ( max = 64)
//  Timing_calls            |  Tango::DevDouble	Spectrum  ( max = 64)
//  Timing_index            |  Tango::DevString	Spectrum  ( max = 64)
//  Timing_info             |  Tango::DevString	Spectrum  ( max = 64)
//================================================================

namespace DataBase_ns
{
/*----- PROTECTED REGION ID(DataBase::namespace_starting) ENABLED START -----*/

	//	static initializations
std::string DataBase::db_name("sys/database/1");
bool nocase_compare(char c1, char c2)
{
	return toupper(c1) == toupper(c2);
}

char* to_corba_string(CORBA::ULong val)
{
  auto str = std::to_string(val);
  return Tango::string_dup(str.c_str());
}

	/*----- PROTECTED REGION END -----*/	//	DataBase::namespace_starting

//--------------------------------------------------------
/**
 *	Method      : DataBase::DataBase()
 *	Description : Constructors for a Tango device
 *                implementing the classDataBase
 */
//--------------------------------------------------------
DataBase::DataBase(Tango::DeviceClass *cl, std::string &s)
 : TANGO_BASE_CLASS(cl, s.c_str())
{
	/*----- PROTECTED REGION ID(DataBase::constructor_1) ENABLED START -----*/

	init_device();

	/*----- PROTECTED REGION END -----*/	//	DataBase::constructor_1
}
//--------------------------------------------------------
DataBase::DataBase(Tango::DeviceClass *cl, const char *s)
 : TANGO_BASE_CLASS(cl, s)
{
	/*----- PROTECTED REGION ID(DataBase::constructor_2) ENABLED START -----*/

	init_device();

	/*----- PROTECTED REGION END -----*/	//	DataBase::constructor_2
}
//--------------------------------------------------------
DataBase::DataBase(Tango::DeviceClass *cl, const char *s, const char *d)
 : TANGO_BASE_CLASS(cl, s, d)
{
	/*----- PROTECTED REGION ID(DataBase::constructor_3) ENABLED START -----*/

	init_device();

	/*----- PROTECTED REGION END -----*/	//	DataBase::constructor_3
}

//--------------------------------------------------------
/**
 *	Method      : DataBase::delete_device()
 *	Description : will be called at device destruction or at init command
 */
//--------------------------------------------------------
void DataBase::delete_device()
{
	DEBUG_STREAM << "DataBase::delete_device() " << device_name << std::endl;
	/*----- PROTECTED REGION ID(DataBase::delete_device) ENABLED START -----*/

	// Mark the server as non-exported in db

	if (get_state() == Tango::ON)
	{
		Tango::Util *tg = Tango::Util::instance();
		std::string &ds_name = tg->get_ds_name();
		char *tmp_ds_name = const_cast<char *>(ds_name.c_str());
		db_un_export_server(tmp_ds_name);
	}

	//	Delete device allocated objects
	//	Delete device's allocated object

	delete [] timing_stats_average;
	delete [] timing_stats_minimum;
	delete [] timing_stats_maximum;
	delete [] timing_stats_calls;

	for (unsigned int i = 0;i < timing_stats_map.size();i++)
		free(timing_stats_index[i]);
	delete [] timing_stats_index;

	std::map<std::string,TimingStatsStruct*>::iterator iter;
	for (iter = timing_stats_map.begin(); iter != timing_stats_map.end(); iter++)
		delete iter->second;

	dcp.reset();

	/*----- PROTECTED REGION END -----*/	//	DataBase::delete_device
}

//--------------------------------------------------------
/**
 *	Method      : DataBase::init_device()
 *	Description : will be called at device initialization.
 */
//--------------------------------------------------------
void DataBase::init_device()
{
	DEBUG_STREAM << "DataBase::init_device() create device " << device_name << std::endl;
	/*----- PROTECTED REGION ID(DataBase::init_device_before) ENABLED START -----*/

	//	Initialization before get_device_property() call

	/*----- PROTECTED REGION END -----*/	//	DataBase::init_device_before
	
	//	No device property to be read from database
	
	/*----- PROTECTED REGION ID(DataBase::init_device) ENABLED START -----*/

//
//	Initialize device
//

	const char *mysql_user     = NULL;
	const char *mysql_password = NULL;
	const char *mysql_host = NULL;

	WARN_STREAM << "DataBase::DataBase() create database device " << device_name << std::endl;

//
// Check if we are using the thread safe release of the MySQL library
//

	if (mysql_thread_safe() == 0)
	{
		ERROR_STREAM << "MySQL library used by this process is not tread safe. Please, use libmysqlclient_r" << std::endl;

		Tango::Except::throw_exception(DB_MySQLLibNotThreadSafe,
	   				  "MySQL library used by this process is not thread safe. Please, use libmysqlclient_r or use DataBase release < 4.x",
					  "DataBase::DataBase()");
	}

//
// Get user environment variables if defined
//

	DummyDev d;
	std::string my_user,my_password,my_host,my_name;

	if (d.get_env_var("MYSQL_USER",my_user) != -1)
	{
		mysql_user = my_user.c_str();
	}
	if (d.get_env_var("MYSQL_PASSWORD",my_password) != -1)
	{
		mysql_password = my_password.c_str();
	}
	if (d.get_env_var("MYSQL_HOST",my_host) != -1)
	{
		mysql_host = my_host.c_str();
	}
	if (d.get_env_var("MYSQL_DATABASE",my_name) != -1)
	{
		// override the compile time default
		mysql_db_name = my_name;
	}

	dcp = std::make_shared<DatabaseConnectionPool>(this, mysql_user, mysql_password, mysql_host, mysql_db_name.c_str());

//
// Do we need to propagate info to Starter
//

	try
	{
		//	Check if controlled server list modification must be fired to starter
		Tango::DevVarStringArray *argin = new Tango::DevVarStringArray();
		argin->length(2);
		(*argin)[0] = CORBA::string_dup("Default");
		(*argin)[1] = CORBA::string_dup("FireToStarter");
		Tango::DevVarStringArray *argout = db_get_property(argin);

		if ((*argout)[3] == 0)	//	Not defined
			fireToStarter = true;
		else
		{
			//	Get property value
			std::string	value((*argout)[4]);
			transform(value.begin(), value.end(), value.begin(), ::tolower);
			if (value=="false")
				fireToStarter = false;
			else
				fireToStarter = true;
		}
		delete argin;
		delete argout;
	}
	catch(Tango::DevFailed &)
	{
		fireToStarter = true;
	}

	WARN_STREAM << "fireToStarter = " << fireToStarter << std::endl;

	//	If fire to starter is true
	if (fireToStarter==true)
	{
        std::string starter_domain = STARTER_DEVNAME_DOMAIN;
    	//	Get starter domain if not the default one
	    Tango::DevVarStringArray	*array = new Tango::DevVarStringArray();
	    array->length(2);
    	(*array)[0] = CORBA::string_dup("Starter");
	    (*array)[1] = CORBA::string_dup("Domain");
    	Tango::DevVarStringArray	*props = db_get_class_property(array);

        if (props->length()>0)
        {
            int nb = atoi((*props)[1]); // nb proeprties
            if (nb==1)
            {
                nb = atoi((*props)[3]); // nb values
                if (nb==1)
                {
                    std::string domain((*props)[4]);
                    if (!domain.empty())
                        starter_domain = domain;
                }
            }
        }
        //TANGO_LOG << "-----------> Starter domain = " << starter_domain << std::endl;

    	delete array;
	    delete props;

        //	Build shared data and thread to update Starter in case of
		//	change of controlled servers conditions
		starter_shared = new UpdStarterData(starter_domain);
		upd_starter_thread = new UpdateStarter(starter_shared);
		upd_starter_thread->start();
	}

	// Load history depth property
	historyDepth = 10;
	try
	{
		Tango::DevVarStringArray *argin = new Tango::DevVarStringArray();
		argin->length(2);
		(*argin)[0] = CORBA::string_dup(get_name().c_str());
		(*argin)[1] = CORBA::string_dup("historyDepth");
		Tango::DevVarStringArray *argout = db_get_device_property(argin);

		if ((*argout)[3] != 0)
		{
		  if(strcmp((*argout)[4]," ")!=0) {

			std::stringstream ss;
		    ss << (*argout)[4];
		    ss >> historyDepth;

		    if( historyDepth == 0 ) {
		      TANGO_LOG << "Warning, Invalid historyDepth property, resetting to default value (10)" << std::endl;
		      historyDepth = 10;
		    }
		  }
		}
		delete argin;
		delete argout;
	}
	catch(Tango::DevFailed &)
	{}

	// Check history tables
	check_history_tables();

	init_timing_stats();
	stored_release_ptr = &(stored_release[0]);
	attr_StoredProcedureRelease_read = &stored_release_ptr;
	set_state(Tango::ON);
	set_status("Device is OK");

	/*----- PROTECTED REGION END -----*/	//	DataBase::init_device
}


//--------------------------------------------------------
/**
 *	Method      : DataBase::always_executed_hook()
 *	Description : method always executed before any command is executed
 */
//--------------------------------------------------------
void DataBase::always_executed_hook()
{
	DEBUG_STREAM << "DataBase::always_executed_hook()  " << device_name << std::endl;
	/*----- PROTECTED REGION ID(DataBase::always_executed_hook) ENABLED START -----*/

	//	code always executed before all requests

	/*----- PROTECTED REGION END -----*/	//	DataBase::always_executed_hook
}

//--------------------------------------------------------
/**
 *	Method      : DataBase::read_attr_hardware()
 *	Description : Hardware acquisition for attributes
 */
//--------------------------------------------------------
void DataBase::read_attr_hardware(TANGO_UNUSED(std::vector<long> &attr_list))
{
	DEBUG_STREAM << "DataBase::read_attr_hardware(std::vector<long> &attr_list) entering... " << std::endl;
	/*----- PROTECTED REGION ID(DataBase::read_attr_hardware) ENABLED START -----*/

	//	Add your own code
	//	Add your own code here

	/*----- PROTECTED REGION END -----*/	//	DataBase::read_attr_hardware
}

//--------------------------------------------------------
/**
 *	Read attribute StoredProcedureRelease related method
 *	Description: 
 *
 *	Data type:	Tango::DevString
 *	Attr type:	Scalar
 */
//--------------------------------------------------------
void DataBase::read_StoredProcedureRelease(Tango::Attribute &attr)
{
	DEBUG_STREAM << "DataBase::read_StoredProcedureRelease(Tango::Attribute &attr) entering... " << std::endl;
	/*----- PROTECTED REGION ID(DataBase::read_StoredProcedureRelease) ENABLED START -----*/
	TangoSys_MemStream	sql_query_stream;
	MYSQL_RES *result;
	MYSQL_ROW row;
	int n_fields;

	sql_query_stream << "SHOW PROCEDURE STATUS WHERE Db LIKE \"";
	sql_query_stream << mysql_db_name;
	sql_query_stream << "\" AND Name LIKE \"ds_start\"";

	DEBUG_STREAM << "DataBase::read_StoredProcedureRelease(): sql_query " << sql_query_stream.str() << std::endl;

	result = query(sql_query_stream.str(),"read_StoredProcedureRelease()");

	n_fields = mysql_num_fields(result);
	DEBUG_STREAM << "DataBase::read_StoreProcedureRelease(): mysql_num_fields() " << n_fields << std::endl;

	if (n_fields > 7)
	{
		unsigned long *lengths;
		if ((row = mysql_fetch_row(result)) != NULL)
		{
			lengths = mysql_fetch_lengths(result);
			strcpy(stored_release,row[7]);
			stored_release[lengths[7]] = '\0';
		}
		else
		{
			mysql_free_result(result);
	   		Tango::Except::throw_exception(DB_IncorrectArguments,
	   				  "Can't fetch row from the returned result",
					  "DataBase::read_StoredProcedureRelease()");
		}
	}
	else
	{
		mysql_free_result(result);
	   	Tango::Except::throw_exception(DB_IncorrectArguments,
	   				  "Wrong fields number in the data returned by the query",
					  "DataBase::read_StoredProcedureRelease()");
	}

	mysql_free_result(result);

	attr.set_value(attr_StoredProcedureRelease_read);

	/*----- PROTECTED REGION END -----*/	//	DataBase::read_StoredProcedureRelease
}
//--------------------------------------------------------
/**
 *	Read attribute Timing_average related method
 *	Description: 
 *
 *	Data type:	Tango::DevDouble
 *	Attr type:	Spectrum max = 64
 */
//--------------------------------------------------------
void DataBase::read_Timing_average(Tango::Attribute &attr)
{
	DEBUG_STREAM << "DataBase::read_Timing_average(Tango::Attribute &attr) entering... " << std::endl;
	/*----- PROTECTED REGION ID(DataBase::read_Timing_average) ENABLED START -----*/
	std::map<std::string,TimingStatsStruct*>::iterator iter;

	{
		omni_mutex_lock guard(timing_stats_mutex);

		int i = 0;
		for (iter = timing_stats_map.begin(); iter != timing_stats_map.end(); iter++)
		{
			timing_stats_average[i] = iter->second->average;
			i++;
		}
	}

	attr.set_value(timing_stats_average, timing_stats_size);

	/*----- PROTECTED REGION END -----*/	//	DataBase::read_Timing_average
}
//--------------------------------------------------------
/**
 *	Read attribute Timing_minimum related method
 *	Description: 
 *
 *	Data type:	Tango::DevDouble
 *	Attr type:	Spectrum max = 64
 */
//--------------------------------------------------------
void DataBase::read_Timing_minimum(Tango::Attribute &attr)
{
	DEBUG_STREAM << "DataBase::read_Timing_minimum(Tango::Attribute &attr) entering... " << std::endl;
	/*----- PROTECTED REGION ID(DataBase::read_Timing_minimum) ENABLED START -----*/
	std::map<std::string,TimingStatsStruct*>::iterator iter;

	{
		omni_mutex_lock guard(timing_stats_mutex);

		int i = 0;
		for (iter = timing_stats_map.begin(); iter != timing_stats_map.end(); iter++)
		{
			timing_stats_minimum[i] = iter->second->minimum;
			i++;
		}
	}

	attr.set_value(timing_stats_minimum, timing_stats_size);

	/*----- PROTECTED REGION END -----*/	//	DataBase::read_Timing_minimum
}
//--------------------------------------------------------
/**
 *	Read attribute Timing_maximum related method
 *	Description: 
 *
 *	Data type:	Tango::DevDouble
 *	Attr type:	Spectrum max = 64
 */
//--------------------------------------------------------
void DataBase::read_Timing_maximum(Tango::Attribute &attr)
{
	DEBUG_STREAM << "DataBase::read_Timing_maximum(Tango::Attribute &attr) entering... " << std::endl;
	/*----- PROTECTED REGION ID(DataBase::read_Timing_maximum) ENABLED START -----*/
	std::map<std::string,TimingStatsStruct*>::iterator iter;

	{
		omni_mutex_lock guard(timing_stats_mutex);

		int i = 0;
		for (iter = timing_stats_map.begin(); iter != timing_stats_map.end(); iter++)
		{
			timing_stats_maximum[i] = iter->second->maximum;
			i++;
		}
	}

	attr.set_value(timing_stats_maximum, timing_stats_size);

	/*----- PROTECTED REGION END -----*/	//	DataBase::read_Timing_maximum
}
//--------------------------------------------------------
/**
 *	Read attribute Timing_calls related method
 *	Description: 
 *
 *	Data type:	Tango::DevDouble
 *	Attr type:	Spectrum max = 64
 */
//--------------------------------------------------------
void DataBase::read_Timing_calls(Tango::Attribute &attr)
{
	DEBUG_STREAM << "DataBase::read_Timing_calls(Tango::Attribute &attr) entering... " << std::endl;
	/*----- PROTECTED REGION ID(DataBase::read_Timing_calls) ENABLED START -----*/
	std::map<std::string,TimingStatsStruct*>::iterator iter;

	{
		omni_mutex_lock guard(timing_stats_mutex);

		int i = 0;
		for (iter = timing_stats_map.begin(); iter != timing_stats_map.end(); iter++)
		{
			timing_stats_calls[i] = iter->second->calls;
			i++;
		}
	}

	attr.set_value(timing_stats_calls, timing_stats_size);

	/*----- PROTECTED REGION END -----*/	//	DataBase::read_Timing_calls
}
//--------------------------------------------------------
/**
 *	Read attribute Timing_index related method
 *	Description: 
 *
 *	Data type:	Tango::DevString
 *	Attr type:	Spectrum max = 64
 */
//--------------------------------------------------------
void DataBase::read_Timing_index(Tango::Attribute &attr)
{
	DEBUG_STREAM << "DataBase::read_Timing_index(Tango::Attribute &attr) entering... " << std::endl;
	/*----- PROTECTED REGION ID(DataBase::read_Timing_index) ENABLED START -----*/
	attr.set_value(timing_stats_index, timing_stats_size);

	/*----- PROTECTED REGION END -----*/	//	DataBase::read_Timing_index
}
//--------------------------------------------------------
/**
 *	Read attribute Timing_info related method
 *	Description: 
 *
 *	Data type:	Tango::DevString
 *	Attr type:	Spectrum max = 64
 */
//--------------------------------------------------------
void DataBase::read_Timing_info(Tango::Attribute &attr)
{
	DEBUG_STREAM << "DataBase::read_Timing_info(Tango::Attribute &attr) entering... " << std::endl;
	/*----- PROTECTED REGION ID(DataBase::read_Timing_info) ENABLED START -----*/
	char info_str[512];
	char hostname[256];
	Tango::DevString *timing_info = new Tango::DevString[timing_stats_size+4];

	gethostname(hostname, sizeof(hostname));
	snprintf(info_str,sizeof(info_str), "TANGO Database Timing info on host %s",hostname);
	timing_info[0] = CORBA::string_dup(info_str);
// newline
	timing_info[1] = CORBA::string_dup(" ");
	timing_info[2] = CORBA::string_dup("command	average	minimum	maximum	calls");
 	timing_info[3] = CORBA::string_dup(" ");

    std::map<std::string,TimingStatsStruct*>::iterator iter;

	{
		omni_mutex_lock guard(timing_stats_mutex);
		int i = 0;
	    for (iter = timing_stats_map.begin(); iter != timing_stats_map.end(); iter++)
	    {
	    	sprintf(info_str,"%s\t%6.3f\t%6.3f\t%6.3f\t%.0f",
					iter->first.c_str(), iter->second->average,
	    			iter->second->minimum, iter->second->maximum,
					iter->second->calls);
	        timing_info[i+4] = CORBA::string_dup(info_str);
	        i++;
	    }
	}

	attr.set_value(timing_info,timing_stats_size+4,0,true);

	/*----- PROTECTED REGION END -----*/	//	DataBase::read_Timing_info
}

//--------------------------------------------------------
/**
 *	Method      : DataBase::add_dynamic_attributes()
 *	Description : Create the dynamic attributes if any
 *                for specified device.
 */
//--------------------------------------------------------
void DataBase::add_dynamic_attributes()
{
	/*----- PROTECTED REGION ID(DataBase::add_dynamic_attributes) ENABLED START -----*/

	//	Add your own code to create and add dynamic attributes if any

	/*----- PROTECTED REGION END -----*/	//	DataBase::add_dynamic_attributes
}

//--------------------------------------------------------
/**
 *	Command State related method
 *	Description: This command gets the device state (stored in its <i>device_state</i> data member) and returns it to the caller.
 *
 *	@returns State Code
 */
//--------------------------------------------------------
Tango::DevState DataBase::dev_state()
{
	DEBUG_STREAM << "DataBase::State()  - " << device_name << std::endl;
	/*----- PROTECTED REGION ID(DataBase::dev_state) ENABLED START -----*/

	Tango::DevState	argout = DeviceImpl::dev_state();
		//	Add your own state management
	return device_state;

	/*----- PROTECTED REGION END -----*/	//	DataBase::dev_state
	set_state(argout);    // Give the state to Tango.
	if (argout!=Tango::ALARM)
		Tango::DeviceImpl::dev_state();
	return get_state();  // Return it after Tango management.
}
//--------------------------------------------------------
/**
 *	Command DbAddDevice related method
 *	Description: Add a Tango class device to a specific device server
 *
 *	@param argin Str[0] = Full device server process name
 *               Str[1] = Device name
 *               Str[2] = Tango class name
 */
//--------------------------------------------------------
void DataBase::db_add_device(const Tango::DevVarStringArray *argin)
{
	DEBUG_STREAM << "DataBase::DbAddDevice()  - " << device_name << std::endl;
	/*----- PROTECTED REGION ID(DataBase::db_add_device) ENABLED START -----*/

	const Tango::DevVarStringArray  *server_device = argin;
	TangoSys_MemStream sql_query_stream;
 	char domain[256], family[256], member[256];
	const char *tmp_server, *tmp_class, *tmp_alias = NULL;
	std::string tmp_device;
	std::string dserver_name;
	MYSQL_RES *result;


	if (server_device->length() < 3)
	{
	   WARN_STREAM << "DataBase::AddDevice(): incorrect number of input arguments " << std::endl;
	   Tango::Except::throw_exception(DB_IncorrectArguments,
	   				  "incorrect no. of input arguments, needs at least 3 (server,device,class)",
					  "DataBase::AddDevice()");
	}

	INFO_STREAM << "DataBase::AddDevice(): insert " << (*server_device)[0] << " server with device " << (*server_device)[1] << std::endl;
	tmp_server = (*server_device)[0];
	tmp_device = (*server_device)[1];
	tmp_class = (*server_device)[2];
	if (server_device->length() > 3)
	{
		tmp_alias = (*server_device)[3];
	}
	if (!check_device_name(tmp_device))
	{
       TangoSys_OMemStream o;
	   o << "device name (" << tmp_device << ") syntax error (should be [tango:][//instance/]domain/family/member)";
	   Tango::Except::throw_exception(DB_IncorrectDeviceName,
	   				                  o.str(),
					                  "DataBase::AddDevice()");
	}
	device_name_to_dfm(tmp_device, domain, family, member);

	{
		AutoLock al(this);
		int n_rows=0;

// first delete the tuple (device,name) from the device table

		sql_query_stream << "DELETE FROM device WHERE name LIKE \"" << tmp_device << "\"";
		DEBUG_STREAM << "DataBase::AddDevice(): sql_query " << sql_query_stream.str() << std::endl;
		simple_query(sql_query_stream.str(),"db_add_device()",al.get_dch());

// then insert the new value for this tuple

    	sql_query_stream.str("");
		if (server_device->length() < 4)
		{
			sql_query_stream << "INSERT INTO device SET name=\"" << tmp_device
		                	 << "\",domain=\"" << domain << "\",family=\"" << family
							 << "\",member=\"" << member
							 << "\",exported=0,ior=\"nada\",host=\"nada\",server=\""
							 << tmp_server << "\",pid=0,class=\"" << tmp_class
							 << "\",version=\"0\",started=NULL,stopped=NULL";
		}
		else
		{
			sql_query_stream << "INSERT INTO device SET name=\"" << tmp_device
		                	 << "\",domain=\"" << domain << "\",family=\"" << family
							 << "\",member=\"" << member
							 << "\",exported=0,ior=\"nada\",host=\"nada\",server=\""
							 << tmp_server << "\",pid=0,class=\"" << tmp_class
							 << "\",alias=\"" << tmp_alias
							 << "\",version=\"0\",started=NULL,stopped=NULL";
		}
		DEBUG_STREAM << "DataBase::AddDevice(): sql_query " << sql_query_stream.str() << std::endl;
		simple_query(sql_query_stream.str(),"db_add_device()",al.get_dch());

//
// Check if a DServer device entry for the process already exists
//
    	sql_query_stream.str("");
		sql_query_stream << "SELECT name FROM device WHERE server LIKE \"" << tmp_server
	                	 << "\" AND class LIKE \"DServer\"";
		DEBUG_STREAM << "DataBase::AddDevice(): sql_query " << sql_query_stream.str() << std::endl;
		result = query(sql_query_stream.str(),"db_add_device()",al.get_dch());

		n_rows = mysql_num_rows(result);
		DEBUG_STREAM << "DataBase::AddDevice(): mysql_num_rows() " << n_rows << std::endl;

//
// If there is no admin device for the device's server, create one
//

		if (n_rows == 0)
		{
			dserver_name = "dserver/";
			dserver_name = dserver_name + std::string(tmp_server);
			device_name_to_dfm(dserver_name, domain, family, member);
        	sql_query_stream.str("");
			sql_query_stream << "INSERT INTO device SET name=\"dserver/" << tmp_server
		                	 << "\",domain=\"" << domain << "\",family=\"" << family
							 << "\",member=\"" << member
							 << "\",exported=0,ior=\"nada\",host=\"nada\",server=\"" << tmp_server
							 << "\",pid=0,class=\"DServer\",version=\"0\",started=NULL,stopped=NULL";
			DEBUG_STREAM << "DataBase::AddDevice(): sql_query " << sql_query_stream.str() << std::endl;
  	    	simple_query(sql_query_stream.str(),"db_add_device()",al.get_dch());

		}

		mysql_free_result(result);
	}

	return;

	/*----- PROTECTED REGION END -----*/	//	DataBase::db_add_device
}
//--------------------------------------------------------
/**
 *	Command DbAddServer related method
 *	Description: Create a device server process entry in database
 *
 *	@param argin Str[0] = Full device server name
 *               Str[1] = Device(s) name
 *               Str[2] = Tango class name
 *               Str[n] = Device name
 *               Str[n + 1] = Tango class name
 */
//--------------------------------------------------------
void DataBase::db_add_server(const Tango::DevVarStringArray *argin)
{
	DEBUG_STREAM << "DataBase::DbAddServer()  - " << device_name << std::endl;
	/*----- PROTECTED REGION ID(DataBase::db_add_server) ENABLED START -----*/

	const Tango::DevVarStringArray  *server_device_list = argin;
	TangoSys_MemStream sql_query_stream;
	char domain[256], family[256], member[256];
	const char *tmp_server, *tmp_class;

	if (server_device_list->length() < 3)
	{
	   WARN_STREAM << "DataBase::AddServer(): incorrect number of input arguments " << std::endl;
	   Tango::Except::throw_exception(DB_IncorrectArguments,
	   				  "incorrect no. of input arguments, needs at least 3 (server,device,class)",
					  "DataBase::AddServer()");
	}

	INFO_STREAM << "DataBase::AddServer(): insert " << (*server_device_list)[0] << " server with device " << (*server_device_list)[1] << std::endl;
	tmp_server = (*server_device_list)[0];

	{
		AutoLock al(this);

		for (unsigned int i=0; i<(server_device_list->length()-1)/2; i++)
		{
			std::string tmp_device((*server_device_list)[i*2+1].in());
			tmp_class = (*server_device_list)[i*2+2];
			if (!check_device_name(tmp_device))
			{
  	 	    	TangoSys_OMemStream o;
	   			o << "device name (" << tmp_device << ") syntax error (should be [tango:][//instance/]domain/family/member)";
	   			Tango::Except::throw_exception(DB_IncorrectDeviceName,
						                	   o.str(),
						                	   "DataBase::AddServer()");
			}
			device_name_to_dfm(tmp_device, domain, family, member);

// first delete the tuple (device,name,count) from the device table

        	sql_query_stream.str("");
        	sql_query_stream << "DELETE FROM device WHERE server=\"" << tmp_server
		                	 << "\" AND name=\"" << tmp_device << "\" ";
			DEBUG_STREAM << "DataBase::AddServer(): sql_query " << sql_query_stream.str() << std::endl;
			simple_query(sql_query_stream.str(),"db_add_server()",al.get_dch());

// then insert the new value for this tuple

        	sql_query_stream.str("");
        	sql_query_stream << "INSERT INTO device SET name=\"" << tmp_device
		                	 << "\",domain=\"" << domain << "\",family=\"" << family
							 << "\",member=\"" << member
							 << "\",exported=0,ior=\"nada\",host=\"nada\",server=\"" << tmp_server
							 << "\",pid=0,class=\"" << tmp_class
							 << "\",version=0,started=NULL,stopped=NULL";
			DEBUG_STREAM << "DataBase::AddServer(): sql_query " << sql_query_stream.str() << std::endl;
			simple_query(sql_query_stream.str(),"db_add_server()",al.get_dch());

		}

// Finally, add the admin device

        std::string tmp_device("dserver/");
        tmp_device = tmp_device + tmp_server;

        device_name_to_dfm(tmp_device,domain,family,member);

        sql_query_stream.str("");
        sql_query_stream << "DELETE FROM device WHERE server=\"" << tmp_server
		                	 << "\" AND name=\"" << tmp_device << "\" ";
        DEBUG_STREAM << "DataBase::AddServer(): sql_query " << sql_query_stream.str() << std::endl;
        simple_query(sql_query_stream.str(),"db_add_server()",al.get_dch());

        tmp_class = "DServer";
        sql_query_stream.str("");
        sql_query_stream << "INSERT INTO device SET name =\"" << tmp_device
		                	 << "\",domain=\"" << domain << "\",family=\"" << family
							 << "\",member=\"" << member
							 << "\",exported=0,ior=\"nada\",host=\"nada\",server=\"" << tmp_server
							 << "\",pid=0,class=\"" << tmp_class
							 << "\",version=0,started=NULL,stopped=NULL";
        DEBUG_STREAM << "DataBase::AddServer(): sql_query " << sql_query_stream.str() << std::endl;
        simple_query(sql_query_stream.str(),"db_add_server()",al.get_dch());
	}

	return;

	/*----- PROTECTED REGION END -----*/	//	DataBase::db_add_server
}
//--------------------------------------------------------
/**
 *	Command DbDeleteAttributeAlias related method
 *	Description: Delete an attribute alias.
 *
 *	@param argin Attriibute alias name.
 */
//--------------------------------------------------------
void DataBase::db_delete_attribute_alias(Tango::DevString argin)
{
	DEBUG_STREAM << "DataBase::DbDeleteAttributeAlias()  - " << device_name << std::endl;
	/*----- PROTECTED REGION ID(DataBase::db_delete_attribute_alias) ENABLED START -----*/

	TangoSys_MemStream sql_query_stream;

	// first check to see if this alias exists
	sql_query_stream << "DELETE  FROM attribute_alias WHERE alias=\'" << argin << "\' ";
	DEBUG_STREAM << "DataBase::db_delete_attribute_alias(): sql_query " << sql_query_stream.str() << std::endl;
	simple_query(sql_query_stream.str(),"db_delete_attribute_alias()");

	/*----- PROTECTED REGION END -----*/	//	DataBase::db_delete_attribute_alias
}
//--------------------------------------------------------
/**
 *	Command DbDeleteClassAttribute related method
 *	Description: delete a class attribute and all its properties from database
 *
 *	@param argin Str[0] = Tango class name
 *               Str[1] = Attribute name
 */
//--------------------------------------------------------
void DataBase::db_delete_class_attribute(const Tango::DevVarStringArray *argin)
{
	DEBUG_STREAM << "DataBase::DbDeleteClassAttribute()  - " << device_name << std::endl;
	/*----- PROTECTED REGION ID(DataBase::db_delete_class_attribute) ENABLED START -----*/

	TangoSys_MemStream sql_query_stream;
	const char *attribute;
	std::string tmp_class;

	if (argin->length() < 2) {
   		WARN_STREAM << "DataBase::db_delete_class_attribute(): insufficient number of arguments ";
   		WARN_STREAM << std::endl;
   		Tango::Except::throw_exception(DB_IncorrectArguments,
					       "insufficient number of arguments to delete class attribute",
					       "DataBase::db_delete_class_attribute()");
	}

	tmp_class = (*argin)[0];
	attribute = (*argin)[1];

	INFO_STREAM << "DataBase::db_delete_class_attribute(): delete " << tmp_class << " from database" << std::endl;

// then delete class from the property_attribute_class table

    sql_query_stream << "DELETE FROM property_attribute_class WHERE class LIKE \"" << tmp_class
	                 << "\" AND attribute LIKE \"" << attribute << "\" ";
    DEBUG_STREAM << "DataBase::db_delete_class_attribute(): sql_query " << sql_query_stream.str() << std::endl;
	simple_query(sql_query_stream.str(),"db_delete_class_attribute()");

    return;

	/*----- PROTECTED REGION END -----*/	//	DataBase::db_delete_class_attribute
}
//--------------------------------------------------------
/**
 *	Command DbDeleteClassAttributeProperty related method
 *	Description: delete class attribute properties from database
 *
 *	@param argin Str[0] = Tango class name
 *               Str[1] = Attribute name
 *               Str[2] = Property name
 *               Str[n] = Property name
 */
//--------------------------------------------------------
void DataBase::db_delete_class_attribute_property(const Tango::DevVarStringArray *argin)
{
	DEBUG_STREAM << "DataBase::DbDeleteClassAttributeProperty()  - " << device_name << std::endl;
	/*----- PROTECTED REGION ID(DataBase::db_delete_class_attribute_property) ENABLED START -----*/

	TangoSys_MemStream sql_query_stream;
	const char *attribute, *property;
	std::string tmp_class;
	MYSQL_RES *result;
	MYSQL_ROW row;

	if (argin->length() < 3) {
   		WARN_STREAM << "DataBase::db_delete_class_attribute_property(): insufficient number of arguments ";
   		WARN_STREAM << std::endl;
   		Tango::Except::throw_exception(DB_IncorrectArguments,
					       "insufficient number of arguments to delete class attribute property",
					       "DataBase::db_delete_class_attribute_property()");
	}

	tmp_class = (*argin)[0];
	attribute = (*argin)[1];

	{
		AutoLock al(this);

		for (unsigned  int i=0; i<argin->length()-2; i++)
		{
			property = (*argin)[i+2];

			INFO_STREAM << "DataBase::db_delete_class_attribute_property(): delete class " << tmp_class ;
			INFO_STREAM << " attribute " << attribute << " property[" << i <<"] " << property << " from database" << std::endl;

// Is there something to delete ?

        	sql_query_stream.str("");
			sql_query_stream << "SELECT count(*) FROM property_attribute_class WHERE class = \"" << tmp_class
		                	 << "\" AND attribute = \"" << attribute << "\" AND name = \"" << property
							 << "\" ";
   			DEBUG_STREAM << "DataBase::db_delete_class_attribute_property(): sql_query " << sql_query_stream.str() << std::endl;
			result = query(sql_query_stream.str(),"db_delete_class_attribute_property()",al.get_dch());
 	    	row = mysql_fetch_row(result);
			int count;
			std::stringstream ss;
			ss << row[0];
			ss >> count;
  	    	mysql_free_result(result);

			if(count) {

// then delete property from the property_attribute_class table

        	  sql_query_stream.str("");
			  sql_query_stream << "DELETE FROM property_attribute_class WHERE class = \"" << tmp_class
		                	   << "\" AND attribute = \"" << attribute << "\" AND name = \"" << property
							   << "\" ";
   			  DEBUG_STREAM << "DataBase::db_delete_class_attribute_property(): sql_query " << sql_query_stream.str() << std::endl;
			  simple_query(sql_query_stream.str(),"db_delete_class_attribute_property()",al.get_dch());

// Mark this property as deleted

        	  Tango::DevULong64 class_attribute_property_hist_id = get_id("class_attribute",al.get_dch());
        	  sql_query_stream.str("");
			  sql_query_stream << "INSERT INTO property_attribute_class_hist SET class='" << tmp_class \
													 << "',attribute='" << attribute \
													 << "',name='" << property \
													 << "',id='" << class_attribute_property_hist_id \
													 << "',count='0',value='DELETED'";
	    	  DEBUG_STREAM << "DataBase::db_delete_class_attribute_property(): sql_query " << sql_query_stream.str() << std::endl;
			  simple_query(sql_query_stream.str(),"db_delete_class_attribute_property()",al.get_dch());

			}
			purge_att_property("property_attribute_class_hist","class",tmp_class.c_str(),attribute,property,al.get_dch());
		}
	}

  	return;

	/*----- PROTECTED REGION END -----*/	//	DataBase::db_delete_class_attribute_property
}
//--------------------------------------------------------
/**
 *	Command DbDeleteClassProperty related method
 *	Description: Delete class properties from database
 *
 *	@param argin Str[0] = Tango class name
 *               Str[1] = Property name
 *               Str[n] = Property name
 */
//--------------------------------------------------------
void DataBase::db_delete_class_property(const Tango::DevVarStringArray *argin)
{
	DEBUG_STREAM << "DataBase::DbDeleteClassProperty()  - " << device_name << std::endl;
	/*----- PROTECTED REGION ID(DataBase::db_delete_class_property) ENABLED START -----*/

	const Tango::DevVarStringArray  *property_list = argin;
	TangoSys_MemStream sql_query_stream;
	int n_properties=0;
	const char *tmp_class;
	std::string tmp_name;
	MYSQL_RES *result;
	MYSQL_ROW row;

	n_properties = property_list->length() - 1;
	INFO_STREAM << "DataBase::DeleteClassProperty(): delete " << n_properties << " properties for class " << (*property_list)[0] << std::endl;

	{
		AutoLock al(this);

		int i,j;
		for (i=0; i<n_properties; i++)
		{
	    	  tmp_class = (*property_list)[0];
	    	  tmp_name =  replace_wildcard((*property_list)[i+1]);

        	  // Is there something to delete ?

        	  sql_query_stream.str("");
	    	  sql_query_stream << "SELECT DISTINCT name FROM property_class WHERE class=\"" << tmp_class
		                	   << "\" AND name LIKE \"" << tmp_name << "\"";
			  result = query(sql_query_stream.str(),"db_delete_class_property()",al.get_dch());
			  int count = mysql_num_rows(result);

			  for(j=0;j<count;j++) {

		    	row = mysql_fetch_row(result);

            	// delete the tuple (device,name,count) from the property table
		    	sql_query_stream.str("");
		    	sql_query_stream << "DELETE FROM property_class WHERE class=\"" << tmp_class
		                	   << "\" AND name=\"" << row[0] << "\"";
	        	DEBUG_STREAM << "DataBase::DeleteClassProperty(): sql_query " << sql_query_stream.str() << std::endl;
		    	simple_query(sql_query_stream.str(),"db_delete_class_property()",al.get_dch());

				// Mark this property as deleted
				Tango::DevULong64 class_property_hist_id = get_id("class",al.get_dch());
				sql_query_stream.str("");
				sql_query_stream << "INSERT INTO property_class_hist SET class='" << tmp_class \
													 << "',name='" << row[0] \
													 << "',id='" << class_property_hist_id \
													 << "',count='0',value='DELETED'";
	        	DEBUG_STREAM << "DataBase::PutClassProperty(): sql_query " << sql_query_stream.str() << std::endl;
  	        	simple_query(sql_query_stream.str(),"db_delete_class_property()",al.get_dch());

   	        	purge_property("property_class_hist","class",tmp_class,row[0],al.get_dch());

			  }
  	    	  mysql_free_result(result);

		}
	}

	return;

	/*----- PROTECTED REGION END -----*/	//	DataBase::db_delete_class_property
}
//--------------------------------------------------------
/**
 *	Command DbDeleteDevice related method
 *	Description: Delete a device from database
 *
 *	@param argin device name
 */
//--------------------------------------------------------
void DataBase::db_delete_device(Tango::DevString argin)
{
	DEBUG_STREAM << "DataBase::DbDeleteDevice()  - " << device_name << std::endl;
	/*----- PROTECTED REGION ID(DataBase::db_delete_device) ENABLED START -----*/

	Tango::DevString  device = argin;
	TangoSys_MemStream sql_query_stream;
	std::string tmp_device;

	INFO_STREAM << "DataBase::db_delete_device(): delete " << device << " from database" << std::endl;

// first check the device name

	tmp_device = device;
	if (!check_device_name(tmp_device))
	{
         	WARN_STREAM << "DataBase::db_delete_device(): device name  " << device << " incorrect ";
         	WARN_STREAM << std::endl;
         	Tango::Except::throw_exception(DB_IncorrectDeviceName,
					       "failed to delete device, device name incorrect",
					       "DataBase::db_delete_device()");
	}

// replace database wildcards (% and _)

	std::string tmp_wildcard = replace_wildcard(tmp_device.c_str());

	{
		AutoLock al(this);

// then delete the device from the device table

    	sql_query_stream << "DELETE FROM device WHERE name LIKE \"" << tmp_wildcard << "\"";
    	DEBUG_STREAM << "DataBase::db_delete_device(): sql_query " << sql_query_stream.str() << std::endl;
		simple_query(sql_query_stream.str(),"db_delete_device()",al.get_dch());

// then delete device from the property_device table

    	sql_query_stream.str("");
		sql_query_stream << "DELETE FROM property_device WHERE device LIKE \"" << tmp_wildcard << "\"";
    	DEBUG_STREAM << "DataBase::db_delete_device(): sql_query " << sql_query_stream.str() << std::endl;
		simple_query(sql_query_stream.str(),"db_delete_device()",al.get_dch());

// then delete device from the property_attribute_device table

    	sql_query_stream.str("");
		sql_query_stream << "DELETE FROM property_attribute_device WHERE device LIKE \"" << tmp_wildcard << "\"";
    	DEBUG_STREAM << "DataBase::db_delete_device(): sql_query " << sql_query_stream.str() << std::endl;
		simple_query(sql_query_stream.str(),"db_delete_device()",al.get_dch());

// then delete device from the property_pipe_device table

    	sql_query_stream.str("");
		sql_query_stream << "DELETE FROM property_pipe_device WHERE device LIKE \"" << tmp_wildcard << "\"";
    	DEBUG_STREAM << "DataBase::db_delete_device(): sql_query " << sql_query_stream.str() << std::endl;
		simple_query(sql_query_stream.str(),"db_delete_device()",al.get_dch());

// then delete device from attribute_alias table

		sql_query_stream.str("");
		sql_query_stream << "DELETE FROM attribute_alias WHERE device LIKE \"" << tmp_wildcard << "\"";
		DEBUG_STREAM << "DataBase::db_delete_device(): sql_query " << sql_query_stream.str() << std::endl;
		simple_query(sql_query_stream.str(),"db_delete_device()",al.get_dch());
	}

    return;

	/*----- PROTECTED REGION END -----*/	//	DataBase::db_delete_device
}
//--------------------------------------------------------
/**
 *	Command DbDeleteDeviceAlias related method
 *	Description: Delete a device alias.
 *
 *	@param argin device alias name
 */
//--------------------------------------------------------
void DataBase::db_delete_device_alias(Tango::DevString argin)
{
	DEBUG_STREAM << "DataBase::DbDeleteDeviceAlias()  - " << device_name << std::endl;
	/*----- PROTECTED REGION ID(DataBase::db_delete_device_alias) ENABLED START -----*/

	TangoSys_MemStream sql_query_stream;

	// first check to see if this alias exists
	sql_query_stream << "UPDATE device SET alias=null WHERE alias=\'" << argin << "\' ";
	DEBUG_STREAM  << "DataBase::db_delete_device_alias(): sql_query " << sql_query_stream.str() << std::endl;
	simple_query(sql_query_stream.str(),"db_delete_device_alias()");

	/*----- PROTECTED REGION END -----*/	//	DataBase::db_delete_device_alias
}
//--------------------------------------------------------
/**
 *	Command DbDeleteDeviceAttribute related method
 *	Description: Delete  device attribute properties from database
 *
 *	@param argin Str[0] = Device name
 *               Str[1] = Attribute name
 */
//--------------------------------------------------------
void DataBase::db_delete_device_attribute(const Tango::DevVarStringArray *argin)
{
	DEBUG_STREAM << "DataBase::DbDeleteDeviceAttribute()  - " << device_name << std::endl;
	/*----- PROTECTED REGION ID(DataBase::db_delete_device_attribute) ENABLED START -----*/

	TangoSys_MemStream sql_query_stream;
	const char *attribute;
	std::string tmp_device;

	if (argin->length() < 2) {
   		WARN_STREAM << "DataBase::db_delete_device_attribute(): insufficient number of arguments ";
   		WARN_STREAM << std::endl;
   		Tango::Except::throw_exception(DB_IncorrectArguments,
					       "insufficient number of arguments to delete device attribute",
					       "DataBase::db_delete_device_attribute()");
	}

	tmp_device = (*argin)[0].in();
	attribute = (*argin)[1];

	INFO_STREAM << "DataBase::db_delete_device(): delete " << tmp_device << " from database" << std::endl;

// first check the device name

	if (!check_device_name(tmp_device))
	{
         	WARN_STREAM << "DataBase::db_delete_device_attribute(): device name  " << tmp_device << " incorrect ";
         	WARN_STREAM << std::endl;
         	Tango::Except::throw_exception(DB_IncorrectDeviceName,
					       "failed to delete device attribute, device name incorrect",
					       "DataBase::db_delete_device_attribute()");
	}

// replace database wildcards (% and _)

	std::string tmp_wildcard = replace_wildcard(tmp_device.c_str());

// then delete device from the property_attribute_device table

    sql_query_stream << "DELETE FROM property_attribute_device WHERE device LIKE \""
	                 << tmp_wildcard << "\" AND attribute LIKE \"" << attribute << "\" ";
    DEBUG_STREAM << "DataBase::db_delete_device_attribute(): sql_query " << sql_query_stream.str() << std::endl;
	simple_query(sql_query_stream.str(),"db_delete_device_attribute()");

    return;

	/*----- PROTECTED REGION END -----*/	//	DataBase::db_delete_device_attribute
}
//--------------------------------------------------------
/**
 *	Command DbDeleteDeviceAttributeProperty related method
 *	Description: delete a device attribute property from the database
 *
 *	@param argin Str[0] = Device name
 *               Str[1] = Attribute name
 *               Str[2] = Property name
 *               Str[n] = Property name
 */
//--------------------------------------------------------
void DataBase::db_delete_device_attribute_property(const Tango::DevVarStringArray *argin)
{
	DEBUG_STREAM << "DataBase::DbDeleteDeviceAttributeProperty()  - " << device_name << std::endl;
	/*----- PROTECTED REGION ID(DataBase::db_delete_device_attribute_property) ENABLED START -----*/

	TangoSys_MemStream sql_query_stream;
	const char *attribute, *property;
	std::string tmp_device;
	MYSQL_RES *result;
	MYSQL_ROW row;

	if (argin->length() < 3) {
   		WARN_STREAM << "DataBase::db_delete_device_attribute_property(): insufficient number of arguments ";
   		WARN_STREAM << std::endl;
   		Tango::Except::throw_exception(DB_IncorrectArguments,
					       "insufficient number of arguments to delete device attribute property",
					       "DataBase::db_delete_device_attribute_property()");
	}

	tmp_device = (*argin)[0];
	if (!check_device_name(tmp_device))
	{
        	WARN_STREAM << "DataBase::db_delete_device_attribute(): device name  " << tmp_device << " incorrect ";
         	WARN_STREAM << std::endl;
         	Tango::Except::throw_exception(DB_IncorrectDeviceName,
				       	"failed to delete device attribute, device name incorrect",
				       	"DataBase::db_delete_device_attribute()");
	}
	attribute = (*argin)[1];

	{
		AutoLock al(this);

		unsigned int i;
		for (i=0; i<argin->length()-2; i++)
		{
			property = (*argin)[i+2];

			INFO_STREAM << "DataBase::db_delete_device_attribute_property(): delete device " << tmp_device ;
			INFO_STREAM << " attribute " << attribute << " property[" << i <<"] " << property << " from database" << std::endl;

// Is there something to delete ?

			sql_query_stream.str("");
			sql_query_stream << "SELECT count(*) FROM property_attribute_device WHERE device = \"" << tmp_device
		                	 <<"\" AND attribute = \"" << attribute << "\" AND name = \"" << property << "\" ";
			result = query(sql_query_stream.str(),"db_delete_device_attribute_property()",al.get_dch());
 	    	row = mysql_fetch_row(result);
			int count;
			std::stringstream ss;
			ss << row[0];
			ss >> count;
  	    	mysql_free_result(result);

			if(count) {

// then delete property from the property_attribute_device table

			  sql_query_stream.str("");
			  sql_query_stream << "DELETE FROM property_attribute_device WHERE device = \"" << tmp_device
		                	   <<"\" AND attribute = \"" << attribute << "\" AND name = \"" << property << "\" ";
   			  DEBUG_STREAM << "DataBase::db_delete_device_attribute_property(): sql_query " << sql_query_stream.str() << std::endl;
			  simple_query(sql_query_stream.str(),"db_delete_device_attribute_property()",al.get_dch());

// Mark this property as deleted

        	  Tango::DevULong64 device_attribute_property_hist_id = get_id("device_attribute",al.get_dch());
			  sql_query_stream.str("");
			  sql_query_stream << "INSERT INTO property_attribute_device_hist SET device='" << tmp_device
							   << "',attribute='" << attribute
							   << "',name='" << property
							   << "',id='" << device_attribute_property_hist_id
							   << "',count='0',value='DELETED'";
	    	  DEBUG_STREAM << "DataBase::PutAttributeProperty(): sql_query " << sql_query_stream.str() << std::endl;
			  simple_query(sql_query_stream.str(),"db_delete_device_attribute_property()",al.get_dch());

			}
			purge_att_property("property_attribute_device_hist","device",tmp_device.c_str(),attribute,property,al.get_dch());
		}
	}

	return;

	/*----- PROTECTED REGION END -----*/	//	DataBase::db_delete_device_attribute_property
}
//--------------------------------------------------------
/**
 *	Command DbDeleteDeviceProperty related method
 *	Description: Delete device property(ies)
 *
 *	@param argin Str[0] = Device name
 *               Str[1] = Property name
 *               Str[n] = Property name
 */
//--------------------------------------------------------
void DataBase::db_delete_device_property(const Tango::DevVarStringArray *argin)
{
	DEBUG_STREAM << "DataBase::DbDeleteDeviceProperty()  - " << device_name << std::endl;
	/*----- PROTECTED REGION ID(DataBase::db_delete_device_property) ENABLED START -----*/

	const Tango::DevVarStringArray  *property_list = argin;
	TangoSys_MemStream	sql_query_stream;
	int n_properties=0;
	const char *tmp_device;
	std::string tmp_name;
	MYSQL_RES *result;
	MYSQL_ROW row;

	TimeVal	before, after;
	GetTime(before);

	n_properties = property_list->length() - 1;
	INFO_STREAM << "DataBase::DeleteDeviceProperty(): delete " << n_properties << " properties for device " << (*property_list)[0] << std::endl;

	{
		AutoLock al(this);

		int i,j;
		for (i=0; i<n_properties; i++)
		{
	    	  tmp_device = (*property_list)[0];
	    	  tmp_name =   replace_wildcard((*property_list)[i+1]);

			  // Is there something to delete ?

        	  sql_query_stream.str("");
	    	  sql_query_stream << "SELECT DISTINCT name FROM property_device WHERE device=\""
		                	   << tmp_device << "\" AND name LIKE \"" << tmp_name << "\"";
			  result = query(sql_query_stream.str(),"db_delete_device_property()",al.get_dch());
			  int count = mysql_num_rows(result);

			  for(j=0;j<count;j++) {

  		    	row = mysql_fetch_row(result);

				// delete the tuple (device,name,count) from the property table

            	sql_query_stream.str("");
	        	sql_query_stream << "DELETE FROM property_device WHERE device=\""
		                    	 << tmp_device << "\" AND name=\"" << row[0] << "\"";
	        	DEBUG_STREAM << "DataBase::DeleteDeviceProperty(): sql_query " << sql_query_stream.str() << std::endl;
		    	simple_query(sql_query_stream.str(),"db_delete_device_property()",al.get_dch());

				// Mark this property as deleted

	        	Tango::DevULong64 device_property_hist_id = get_id("device",al.get_dch());
		    	sql_query_stream.str("");
		    	sql_query_stream << "INSERT INTO property_device_hist SET device='"
		                	   << tmp_device << "',id='" << device_property_hist_id << "',name='"
							   << row[0] << "',count='0',value='DELETED'";
		    	simple_query(sql_query_stream.str(),"db_delete_device_property()",al.get_dch());

            	purge_property("property_device_hist","device",tmp_device,row[0],al.get_dch());

        	  }

  	    	  mysql_free_result(result);

		}
	}

	GetTime(after);
	update_timing_stats(before, after, "DbDeleteDeviceProperty");
	return;

	/*----- PROTECTED REGION END -----*/	//	DataBase::db_delete_device_property
}
//--------------------------------------------------------
/**
 *	Command DbDeleteProperty related method
 *	Description: Delete free property from database
 *
 *	@param argin Str[0]  = Object name
 *               Str[1] = Property name
 *               Str[n] = Property name
 */
//--------------------------------------------------------
void DataBase::db_delete_property(const Tango::DevVarStringArray *argin)
{
	DEBUG_STREAM << "DataBase::DbDeleteProperty()  - " << device_name << std::endl;
	/*----- PROTECTED REGION ID(DataBase::db_delete_property) ENABLED START -----*/

	const Tango::DevVarStringArray  *property_list = argin;
	TangoSys_MemStream	sql_query_stream;
	int n_properties=0;
	const char *tmp_object;
	std::string tmp_name;
	MYSQL_RES *result;
	MYSQL_ROW row;

	n_properties = property_list->length() - 1;
	INFO_STREAM << "DataBase::db_delete_property(): put " << n_properties << " properties for device " << (*property_list)[0] << std::endl;

	{
		AutoLock al(this);

		int i,j;
		for (i=0; i<n_properties; i++)
		{
	    	  tmp_object = (*property_list)[0];
	    	  tmp_name = replace_wildcard((*property_list)[i+1]);

			  // Is there something to delete ?

        	  sql_query_stream.str("");
	    	  sql_query_stream << "SELECT DISTINCT name FROM property WHERE object=\"" << tmp_object
		                	   << "\" AND name LIKE \"" << tmp_name << "\"";
			  result = query(sql_query_stream.str(),"db_delete_property()",al.get_dch());
			  int count = mysql_num_rows(result);

			  for (j=0;j<count;j++) {

				row = mysql_fetch_row(result);

				// delete the tuple (object,name,count) from the property table

		    	sql_query_stream.str("");
		    	sql_query_stream << "DELETE FROM property WHERE object=\"" << tmp_object
		                	   << "\" AND name = \"" << row[0] << "\"";
	        	DEBUG_STREAM << "DataBase::db_delete_property(): sql_query " << sql_query_stream.str() << std::endl;
		    	simple_query(sql_query_stream.str(),"db_delete_property()",al.get_dch());

				// Mark this property as deleted

		    	Tango::DevULong64 object_property_hist_id = get_id("object",al.get_dch());
		    	sql_query_stream.str("");
		    	sql_query_stream << "INSERT INTO property_hist SET object='" << tmp_object
											 << "',name='" << row[0]
											 << "',id='" << object_property_hist_id
											 << "',count='0',value='DELETED'";
	        	DEBUG_STREAM << "DataBase::db_put_property(): sql_query " << sql_query_stream.str() << std::endl;
		    	simple_query(sql_query_stream.str(),"db_delete_property()",al.get_dch());

            	purge_property("property_hist","object",tmp_object,row[0],al.get_dch());

			  }

  	    	  mysql_free_result(result);

		}
	}

	return;

	/*----- PROTECTED REGION END -----*/	//	DataBase::db_delete_property
}
//--------------------------------------------------------
/**
 *	Command DbDeleteServer related method
 *	Description: Delete server from the database but dont delete device properties
 *
 *	@param argin Device server name
 */
//--------------------------------------------------------
void DataBase::db_delete_server(Tango::DevString argin)
{
	DEBUG_STREAM << "DataBase::DbDeleteServer()  - " << device_name << std::endl;
	/*----- PROTECTED REGION ID(DataBase::db_delete_server) ENABLED START -----*/

	Tango::DevString  server = argin;
	TangoSys_MemStream sql_query_stream;
	MYSQL_RES *result;
	MYSQL_ROW row;
	int n_rows;

	INFO_STREAM << "DataBase::db_delete_server(): delete server " << server << " from database" << std::endl;

// first check the server name that it has no wildcard '*' and
// that it has at least one slash in it

	std::string tmp_server = std::string(server);

	if ((tmp_server.find('*') != std::string::npos) ||
	    (tmp_server.find('%') != std::string::npos) ||
	    (tmp_server.find('/') == std::string::npos))
	{
         	WARN_STREAM << "DataBase::db_delete_server(): server name  " << server << "incorrect ";
         	WARN_STREAM << std::endl;
         	Tango::Except::throw_exception(DB_IncorrectServerName,
					       "failed to delete server, server name incorrect",
					       "DataBase::db_delete_server()");
	}

	tmp_server = replace_wildcard(server);

//
//	get  host where running
//

	std::string	previous_host("");
	if (fireToStarter==true)
	{
		omni_mutex_lock oml(starter_mutex);

		std::string	adm_dev("dserver/");
		adm_dev += tmp_server;
		try
		{
			char *tmp_ptr = db_get_device_host((Tango::DevString)adm_dev.c_str());
			previous_host = tmp_ptr;
			DEBUG_STREAM << tmp_server << " was running on " << previous_host << std::endl;
			CORBA::string_free(tmp_ptr);
		}
		catch (Tango::DevFailed &e)
		{
			std::string reason(e.errors[0].reason.in());
			if (reason == DB_DeviceNotDefined)
			{
				DEBUG_STREAM << "DataBase::db_delete_server(): server " << tmp_server << " not defined in DB" << std::endl;
				TangoSys_OMemStream o;
				o << "Server " << tmp_server << " not defined in database !";
				Tango::Except::throw_exception(DB_IncorrectServerName,o.str(),
							   "DataBase::db_delete_server()");
			}
		}

	}

//
// Get list of devices for this server
//

	sql_query_stream << "SELECT name FROM device WHERE server LIKE \"" << tmp_server << "\" ORDER BY name";
	DEBUG_STREAM << "DataBase::db_delete_server_info(): sql_query " << sql_query_stream.str() << std::endl;

	result = query(sql_query_stream.str(),"db_delete_server()");

	n_rows = mysql_num_rows(result);
	DEBUG_STREAM << "DataBase::db_delete_server(): mysql_num_rows() " << n_rows << std::endl;

//
// Delete device(s) and associated properties
//

	if (n_rows > 0)
	{
		for (int loop = 0;loop < n_rows;loop++)
		{
			if ((row = mysql_fetch_row(result)) != NULL)
			{
				DEBUG_STREAM << "Database::db_deleet_server(): Deleting device " << row[0] << std::endl;
				db_delete_device(row[0]);
			}
		}
	}
	mysql_free_result(result);

//
//	Update host's starter to update controlled servers list
//

	if (fireToStarter==true)
	{
		omni_mutex_lock oml(starter_mutex);

		std::vector<std::string>	hosts;
		if (previous_host!="")
		{
			hosts.push_back(previous_host);
			starter_shared->send_starter_cmd(hosts);
		}
	}

	/*----- PROTECTED REGION END -----*/	//	DataBase::db_delete_server
}
//--------------------------------------------------------
/**
 *	Command DbDeleteServerInfo related method
 *	Description: delete info related to a Tango devvice server process
 *
 *	@param argin Device server name
 */
//--------------------------------------------------------
void DataBase::db_delete_server_info(Tango::DevString argin)
{
	DEBUG_STREAM << "DataBase::DbDeleteServerInfo()  - " << device_name << std::endl;
	/*----- PROTECTED REGION ID(DataBase::db_delete_server_info) ENABLED START -----*/

	Tango::DevString  server_name = argin;
	TangoSys_MemStream sql_query_stream;

	INFO_STREAM << "DataBase::db_delete_server_info(): delete " << server_name << " from database" << std::endl;

// replace database wildcards (% and _)

//	std::string tmp_wildcard = replace_wildcard(server_name);

// then delete the device from the device table
    sql_query_stream << "DELETE FROM server WHERE name = \"" << server_name << "\"";
    DEBUG_STREAM << "DataBase::db_delete_server_info(): sql_query " << sql_query_stream.str() << std::endl;
	simple_query(sql_query_stream.str(),"db_delete_server_info()");

	/*----- PROTECTED REGION END -----*/	//	DataBase::db_delete_server_info
}
//--------------------------------------------------------
/**
 *	Command DbExportDevice related method
 *	Description: Export a device to the database
 *
 *	@param argin Str[0] = Device name
 *               Str[1] = CORBA IOR
 *               Str[2] = Device server process host name
 *               Str[3] = Device server process PID or string ``null``
 *               Str[4] = Device server process version
 */
//--------------------------------------------------------
void DataBase::db_export_device(const Tango::DevVarStringArray *argin)
{
	DEBUG_STREAM << "DataBase::DbExportDevice()  - " << device_name << std::endl;
	/*----- PROTECTED REGION ID(DataBase::db_export_device) ENABLED START -----*/

	const Tango::DevVarStringArray  *export_info = argin;
	TangoSys_MemStream sql_query_stream;
	MYSQL_RES *result;
	MYSQL_ROW row;
	const char *tmp_ior, *tmp_host, *tmp_pid, *tmp_version;
	std::string tmp_device, tmp_server;

	TimeVal	before, after;
	GetTime(before);


	if (export_info->length() < 5) {
   		WARN_STREAM << "DataBase::DbExportDevice(): insufficient export info for device ";
   		WARN_STREAM << tmp_device << std::endl;
   		Tango::Except::throw_exception(DB_IncorrectArguments,
					       "Insufficient export info for device",
					       "DataBase::DbExportDevice()");
	}

	INFO_STREAM << "DataBase::ExportDevice(): put " << export_info->length()-1 << " export info for device " << (*export_info)[0] << std::endl;

	tmp_device = (*export_info)[0];
	for (unsigned  int i=0; i<tmp_device.length(); i++) {
		tmp_device[i] = tolower(tmp_device[i]);
	}
	tmp_ior = (*export_info)[1];
	tmp_host = (*export_info)[2];
	tmp_pid = (*export_info)[3];
	if (strcmp(tmp_pid, "null")==0)
		tmp_pid = "-1";
	tmp_version = (*export_info)[4];
//
//	If it is a server stating -> get previous host where running
//
	bool	do_fire = false;
	std::string	previous_host;
	{
		AutoLock al(this);

		if (fireToStarter==true)
		{
			if (tmp_device.substr(0,8) == "dserver/")
			{
				omni_mutex_lock oml(starter_mutex);

				//	Get database server name
				//--------------------------------------
				Tango::Util *tg = Tango::Util::instance();
				std::string	db_serv = tg->get_ds_name();
				transform(db_serv.begin(), db_serv.end(), db_serv.begin(), ::tolower);
				std::string	adm_dev("dserver/");
				adm_dev += db_serv;

				//	Check if not database or starter servers
				if (tmp_device !=  adm_dev &&
					tmp_device.substr(0,16) != "dserver/starter/" )
				{
					do_fire = true;
					char *tmp_ptr = db_get_device_host((Tango::DevString)tmp_device.c_str(),al.get_dch());
					previous_host = tmp_ptr;
					DEBUG_STREAM << tmp_device << " was running on " << previous_host << std::endl;
					CORBA::string_free(tmp_ptr);
				}
			}
		}

//
// check if device is defined and if so get server name in order to
// update server table
//
		sql_query_stream << "SELECT server FROM device WHERE name LIKE \"" << tmp_device << "\" ";
		DEBUG_STREAM << "DataBase::ExportDevice(): sql_query " << sql_query_stream.str() << std::endl;

		result = query(sql_query_stream.str(),"db_export_device()",al.get_dch());

		long n_rows=0;
		n_rows = mysql_num_rows(result);
		DEBUG_STREAM << "DataBase::ExportDevice(): mysql_num_rows() " << n_rows << std::endl;

		if (n_rows > 0)
		{
		   if ((row = mysql_fetch_row(result)) != NULL)
		   {
	    	  DEBUG_STREAM << "DataBase::ExportDevice(): device "<< tmp_device << " server name " << row[0] << std::endl;
	    	  tmp_server = row[0];
		   }
		}
		else
		{
	    	 INFO_STREAM << "DataBase::ExportDevice(): device not defined !" << std::endl;
  	 		 TangoSys_OMemStream o;
			 o << "device " << tmp_device << " not defined in the database !";
	    	 mysql_free_result(result);
	    	 Tango::Except::throw_exception(DB_DeviceNotDefined,
	     				                	o.str(),
					                    	"DataBase::ExportDevice()");
		}
		mysql_free_result(result);

// update the new value for this tuple
   		sql_query_stream.str("");
		sql_query_stream << "UPDATE device set exported=1,ior=\'" << tmp_ior
	                 << "\',host=\'" << tmp_host << "\',pid=\'" << tmp_pid
					 << "\',version=\'" << tmp_version
					 << "\',started=NOW() where name LIKE \'" << tmp_device << "\'";
		DEBUG_STREAM << "DataBase::ExportDevice(): sql_query " << sql_query_stream.str() << std::endl;

		simple_query(sql_query_stream.str(),"db_export_device()",al.get_dch());

// update host name in server table

    	sql_query_stream.str("");
		sql_query_stream << "UPDATE server set host=\'" << tmp_host << "\' where name LIKE \'"
	                 << tmp_server << "\'";
    	DEBUG_STREAM << "DataBase::ExportDevice(): sql_query " << sql_query_stream.str() << std::endl;

		simple_query(sql_query_stream.str(),"db_export_device()",al.get_dch());
	}

	//	Check if a server has been started.
	if (do_fire)
	{
		//	Update host's starter to update controlled servers list
		std::vector<std::string>	hosts;
		hosts.push_back(tmp_host);
		DEBUG_STREAM << "New Host is " << tmp_host << std::endl;

		if (previous_host!=""      &&
			previous_host!="nada"  &&
			previous_host!=tmp_host)
				hosts.push_back(previous_host);

		starter_shared->send_starter_cmd(hosts);
	}
	GetTime(after);
	update_timing_stats(before, after, "DbExportDevice");
	return;

	/*----- PROTECTED REGION END -----*/	//	DataBase::db_export_device
}
//--------------------------------------------------------
/**
 *	Command DbExportEvent related method
 *	Description: Export Event channel to database
 *
 *	@param argin Str[0] = event channel name (or factory name)
 *               Str[1] = CORBA IOR
 *               Str[2] = Notifd host name
 *               Str[3] = Notifd pid
 *               Str[4] = Notifd version
 */
//--------------------------------------------------------
void DataBase::db_export_event(const Tango::DevVarStringArray *argin)
{
	DEBUG_STREAM << "DataBase::DbExportEvent()  - " << device_name << std::endl;
	/*----- PROTECTED REGION ID(DataBase::db_export_event) ENABLED START -----*/

	const Tango::DevVarStringArray  *export_info = argin;
	TangoSys_MemStream sql_query_stream;
	const char *tmp_ior, *tmp_host, *tmp_pid, *tmp_version;
	std::string tmp_event, tmp_server;

	TimeVal	before, after;
	GetTime(before);

	if (export_info->length() < 5) {
   		WARN_STREAM << "DataBase::db_export_event(): insufficient export info for event ";
   		Tango::Except::throw_exception(DB_IncorrectArguments,
					       "insufficient export info for event",
					       "DataBase::db_export_event()");
	}

	INFO_STREAM << "DataBase::db_export_event(): put " << export_info->length()-1 << " export info for event " << (*export_info)[0] << std::endl;

	tmp_event = (*export_info)[0];
	for (unsigned  int i=0; i<tmp_event.length(); i++) {
		tmp_event[i] = tolower(tmp_event[i]);
	}
	tmp_event   = replace_wildcard(tmp_event.c_str());
	tmp_ior     = (*export_info)[1];
	tmp_host    = (*export_info)[2];
	tmp_pid     = (*export_info)[3];
	tmp_version = (*export_info)[4];

// first delete existing information from database

	{
		AutoLock al(this);

		sql_query_stream << "DELETE FROM event WHERE name=\"" << tmp_event << "\"";
   		DEBUG_STREAM << "DataBase::db_export_event(): sql_query " << sql_query_stream.str() << std::endl;
		simple_query(sql_query_stream.str(),"db_export_event()",al.get_dch());

// update the new value for this tuple

		sql_query_stream.str("");
		sql_query_stream << "INSERT event set name=\'" << tmp_event
	                 << "\',exported=1,ior=\'" << tmp_ior << "\',host=\'" << tmp_host
					 << "\',server=\'" << tmp_event << "\',pid=\'" << tmp_pid
					 << "\',version=\'" << tmp_version << "\',started=NOW();";
		DEBUG_STREAM << "DataBase::export_event(): sql_query " << sql_query_stream.str() << std::endl;
		simple_query(sql_query_stream.str(),"db_export_event()",al.get_dch());
	}

	GetTime(after);
	update_timing_stats(before, after, "DbExportEvent");

	/*----- PROTECTED REGION END -----*/	//	DataBase::db_export_event
}
//--------------------------------------------------------
/**
 *	Command DbGetAliasDevice related method
 *	Description: Get device name from its alias.
 *
 *	@param argin Alias name
 *	@returns Device name
 */
//--------------------------------------------------------
Tango::DevString DataBase::db_get_alias_device(Tango::DevString argin)
{
	Tango::DevString argout;
	DEBUG_STREAM << "DataBase::DbGetAliasDevice()  - " << device_name << std::endl;
	/*----- PROTECTED REGION ID(DataBase::db_get_alias_device) ENABLED START -----*/

	TangoSys_MemStream sql_query_stream;
	std::string tmp_argin;
	MYSQL_RES *result;
	MYSQL_ROW row;
	int n_rows;

	argout = NULL;

	if (argin == NULL)
	{
		sql_query_stream << "SELECT name FROM device WHERE alias LIKE \"%\"";
	}
	else
	{
		tmp_argin = replace_wildcard(argin);
		sql_query_stream << "SELECT name FROM device WHERE alias LIKE \"" << tmp_argin << "\"";
	}
	DEBUG_STREAM << "DataBase::db_get_alias_device(): sql_query " << sql_query_stream.str() << std::endl;

	result = query(sql_query_stream.str(),"db_get_alias_device()");

	n_rows = mysql_num_rows(result);
	DEBUG_STREAM << "DataBase::db_get_alias_device(): mysql_num_rows() " << n_rows << std::endl;
	if (n_rows > 0)
	{
		if ((row = mysql_fetch_row(result)) != NULL)
		{
			argout = CORBA::string_dup(row[0]);
		}
		mysql_free_result(result);
	}
	else
	{
		mysql_free_result(result);
        TangoSys_OMemStream o;
	    o << "No device found for alias \'" << argin << "\'";
		std::string msg = o.str();
		WARN_STREAM << msg << std::endl;
		Tango::Except::throw_exception(DB_DeviceNotDefined,
	   				                   msg,
					                   "DataBase::db_get_alias_device()");
	}

	/*----- PROTECTED REGION END -----*/	//	DataBase::db_get_alias_device
	return argout;
}
//--------------------------------------------------------
/**
 *	Command DbGetAttributeAlias related method
 *	Description: Get the attribute name for the given alias.
 *               If alias not found in database, returns an empty string.
 *
 *	@param argin The attribute alias name
 *	@returns The attribute name (device/attribute)
 */
//--------------------------------------------------------
Tango::DevString DataBase::db_get_attribute_alias(Tango::DevString argin)
{
	Tango::DevString argout;
	DEBUG_STREAM << "DataBase::DbGetAttributeAlias()  - " << device_name << std::endl;
	/*----- PROTECTED REGION ID(DataBase::db_get_attribute_alias) ENABLED START -----*/

	TangoSys_MemStream sql_query_stream;
	MYSQL_RES *result;
	MYSQL_ROW row;
	long n_rows=0;
	argout  = new char[256];

	INFO_STREAM << "DataBase::db_get_attribute_alias(): put " << argin << std::endl;

// first check to see if this alias exists

	sql_query_stream << "SELECT name from attribute_alias WHERE alias LIKE \'" << argin << "\' ";
	DEBUG_STREAM << "DataBase::db_get_attribute_alias(): sql_query " << sql_query_stream.str() << std::endl;

	result = query(sql_query_stream.str(),"db_get_attribute_alias()");

	n_rows = mysql_num_rows(result);
	DEBUG_STREAM << "DataBase::db_get_attribute_alias(): mysql_num_rows() " << n_rows << std::endl;

	if (n_rows > 0)
	{
        if ((row = mysql_fetch_row(result)) != NULL)
        {
            DEBUG_STREAM << "DataBase::db_get_attribute_alias(): attribute name "<< row[0] << std::endl;
            strcpy(argout,row[0]);
		}
	}
	else
	{
		//strcpy(argout,"");
        TangoSys_OMemStream o;
	   	o << "No attribute found for alias  \'" << argin << "\'";
		mysql_free_result(result);
		delete [] argout;
	   	Tango::Except::throw_exception(DB_SQLError,
	   				  	               o.str(),
					  	               "DataBase::db_get_attribute_alias()");
	}

	mysql_free_result(result);

	/*----- PROTECTED REGION END -----*/	//	DataBase::db_get_attribute_alias
	return argout;
}
//--------------------------------------------------------
/**
 *	Command DbGetAttributeAliasList related method
 *	Description: Get attribute alias list for a specified filter
 *
 *	@param argin attribute alias filter string (eg: att*)
 *	@returns attribute aliases
 */
//--------------------------------------------------------
Tango::DevVarStringArray *DataBase::db_get_attribute_alias_list(Tango::DevString argin)
{
	Tango::DevVarStringArray *argout;
	DEBUG_STREAM << "DataBase::DbGetAttributeAliasList()  - " << device_name << std::endl;
	/*----- PROTECTED REGION ID(DataBase::db_get_attribute_alias_list) ENABLED START -----*/

	TangoSys_MemStream sql_query_stream;
	std::string tmp_wildcard;
	MYSQL_RES *result;
	MYSQL_ROW row;
	int n_rows;

	INFO_STREAM << "DataBase::db_get_attribute_alias_list(): alias " << argin;
	WARN_STREAM << " wildcard " << argin << std::endl;

	if (argin == NULL)
	{
		sql_query_stream << "SELECT DISTINCT alias,attribute FROM attribute_alias WHERE alias LIKE \"%\" ORDER BY attribute";
	}
	else
	{
		tmp_wildcard = replace_wildcard (argin);
		sql_query_stream << "SELECT DISTINCT alias,attribute FROM attribute_alias WHERE alias LIKE \""
		                 << tmp_wildcard << "\" ORDER BY attribute";
	}
	DEBUG_STREAM << "DataBase::db_get_attribute_alias_list(): sql_query " << sql_query_stream.str() << std::endl;

	result = query(sql_query_stream.str(),"db_get_attribute_alias_list()");

	n_rows = mysql_num_rows(result);
	DEBUG_STREAM << "DataBase::db_get_attribute_alias_list(): mysql_num_rows() " << n_rows << std::endl;
	argout = new Tango::DevVarStringArray;

	if (n_rows > 0)
	{
	   argout->length(n_rows);

	   for (int i=0; i<n_rows; i++)
	   {
	      if ((row = mysql_fetch_row(result)) != NULL)
	      {
	         DEBUG_STREAM << "DataBase::db_get_attribute_alias_list(): attribute[ "<< i << "] attribute " << row[0] << std::endl;
	         (*argout)[i]   = CORBA::string_dup(row[0]);
	      }
	   }
	}
	else
		argout->length(0);
	mysql_free_result(result);

	/*----- PROTECTED REGION END -----*/	//	DataBase::db_get_attribute_alias_list
	return argout;
}
//--------------------------------------------------------
/**
 *	Command DbGetClassAttributeList related method
 *	Description: Get attrilute list for a given Tango class with a specified filter
 *
 *	@param argin Str[0] = Tango class name
 *               Str[1] = Attribute name filter (eg: att*)
 *	@returns Str[0] = Class attribute name
 *           Str[n] = Class attribute name
 */
//--------------------------------------------------------
Tango::DevVarStringArray *DataBase::db_get_class_attribute_list(const Tango::DevVarStringArray *argin)
{
	Tango::DevVarStringArray *argout;
	DEBUG_STREAM << "DataBase::DbGetClassAttributeList()  - " << device_name << std::endl;
	/*----- PROTECTED REGION ID(DataBase::db_get_class_attribute_list) ENABLED START -----*/

	const Tango::DevVarStringArray  *class_wildcard = argin;
	TangoSys_MemStream sql_query_stream;
	MYSQL_RES *result;
	MYSQL_ROW row;
	int n_rows=0;
	argout = new Tango::DevVarStringArray;
	const char *class_name, *wildcard;
	std::string tmp_wildcard;

	class_name = (*class_wildcard)[0];
	INFO_STREAM << "DataBase::db_get_class_attribute(): get attributes for class " << class_name << std::endl;

	wildcard = (*class_wildcard)[1];
	if (wildcard == NULL)
	{
#ifdef WIN32
		sql_query_stream << "SELECT DISTINCT attribute FROM property_attribute_class WHERE class = \"" << class_name << "\"  AND attribute like \"\\%\"";
#else
		sql_query_stream << "SELECT DISTINCT attribute FROM property_attribute_class WHERE class = \"" << class_name << "\"  AND attribute like \"%%\"";
#endif /* WIN32 */
	}
	else
	{
		tmp_wildcard = replace_wildcard(wildcard);
		sql_query_stream << "SELECT DISTINCT attribute FROM property_attribute_class WHERE class = \""
		                 << class_name << "\"  AND attribute like \"" << tmp_wildcard << "\"";
	}
	DEBUG_STREAM << "DataBase::GetClassAttributeList(): sql_query " << sql_query_stream.str() << std::endl;

	result = query(sql_query_stream.str(),"db_get_class_attribute_list()");

	n_rows = mysql_num_rows(result);
	DEBUG_STREAM << "DataBase::GetClassAttributeList(): num_rows() " << n_rows << std::endl;
	if (n_rows > 0)
	{
		  int n_attrs=0;
	      for (int j=0; j<n_rows; j++)
	      {
	         if ((row = mysql_fetch_row(result)) != NULL)
	         {
	            DEBUG_STREAM << "DataBase::GetClassAttributeList(): attribute[ "<< j << "] " << row[0] << std::endl;
		    	n_attrs++;
		    	argout->length(n_attrs);
	            (*argout)[n_attrs-1] = CORBA::string_dup(row[0]);
	         }
	      }
	}
	mysql_free_result(result);

	DEBUG_STREAM << "DataBase::GetClassAttributeList(): argout->length() "<< argout->length() << std::endl;

	/*----- PROTECTED REGION END -----*/	//	DataBase::db_get_class_attribute_list
	return argout;
}
//--------------------------------------------------------
/**
 *	Command DbGetClassAttributeProperty related method
 *	Description: Get Tango class property(ies) value
 *
 *	@param argin Str[0] = Tango class name
 *               Str[1] = Attribute name
 *               Str[n] = Attribute name
 *	@returns Str[0] = Tango class name
 *           Str[1] = Attribute property  number
 *           Str[2] = Attribute property 1 name
 *           Str[3] = Attribute property 1 value
 *           Str[n + 1] = Attribute property 2 name
 *           Str[n + 2] = Attribute property 2 value
 */
//--------------------------------------------------------
Tango::DevVarStringArray *DataBase::db_get_class_attribute_property(const Tango::DevVarStringArray *argin)
{
	Tango::DevVarStringArray *argout;
	DEBUG_STREAM << "DataBase::DbGetClassAttributeProperty()  - " << device_name << std::endl;
	/*----- PROTECTED REGION ID(DataBase::db_get_class_attribute_property) ENABLED START -----*/

	const Tango::DevVarStringArray  *property_names = argin;
	TangoSys_MemStream sql_query_stream;
	char n_rows_str[256];
	MYSQL_RES *result;
	MYSQL_ROW row;
	int n_rows=0, n_props=0;
	argout = new Tango::DevVarStringArray;
	const char *tmp_class, *tmp_attribute;

	INFO_STREAM << "DataBase::GetAttributeProperty(): get " << property_names->length()-1 << " attributes for class " << (*property_names)[0] << std::endl;

	tmp_class = (*property_names)[0];
	n_props = 2;
	argout->length(n_props);
	(*argout)[n_props-2] = CORBA::string_dup(tmp_class);
	(*argout)[n_props-1] = to_corba_string(property_names->length() - 1);

	for (unsigned int i=1; i<property_names->length(); i++)
	{
	   tmp_attribute = (*property_names)[i];
	   sql_query_stream.str("");
	   sql_query_stream << "SELECT name,value FROM property_attribute_class WHERE class = \""
	                    << tmp_class << "\" AND attribute LIKE \"" << tmp_attribute << "\" ";
	   DEBUG_STREAM << "DataBase::GetAttributeProperty(): sql_query " << sql_query_stream.str() << std::endl;

	   result = query(sql_query_stream.str(),"db_get_class_attribute_property()");

	   n_rows = mysql_num_rows(result);
	   DEBUG_STREAM << "DataBase::GetAttributeProperty(): mysql_num_rows() " << n_rows << std::endl;
	   sprintf(n_rows_str,"%d",n_rows);
	   n_props = n_props+2;
	   argout->length(n_props);
	   (*argout)[n_props-2] = CORBA::string_dup(tmp_attribute);
	   (*argout)[n_props-1] = CORBA::string_dup(n_rows_str);
	   if (n_rows > 0)
	   {

	      for (int j=0; j<n_rows; j++)
	      {
	         if ((row = mysql_fetch_row(result)) != NULL)
	         {
	            DEBUG_STREAM << "DataBase::GetAttributeProperty(): property[ "<< i << "] count " << row[0] << " value " << row[1] << std::endl;
	            n_props = n_props+2;
	            argout->length(n_props);
	            (*argout)[n_props-2] = CORBA::string_dup(row[0]);
	            (*argout)[n_props-1] = CORBA::string_dup(row[1]);
	         }
	      }
	   }
	   mysql_free_result(result);
	}

	DEBUG_STREAM << "DataBase::GetClassProperty(): argout->length() "<< argout->length() << std::endl;

	/*----- PROTECTED REGION END -----*/	//	DataBase::db_get_class_attribute_property
	return argout;
}
//--------------------------------------------------------
/**
 *	Command DbGetClassAttributeProperty2 related method
 *	Description: This command supports array property compared to the old command called
 *               DbGetClassAttributeProperty. The old command has not been deleted from the
 *               server for compatibility reasons.
 *
 *	@param argin Str[0] = Tango class name
 *               Str[1] = Attribute name
 *               Str[n] = Attribute name
 *	@returns Str[0] = Tango class name
 *           Str[1] = Attribute property  number
 *           Str[2] = Attribute property 1 name
 *           Str[3] = Attribute property 1 value number (array case)
 *           Str[4] = Attribute property 1 value
 *           Str[n] = Attribute property 1 value (array case)
 *           Str[n + 1] = Attribute property 2 name
 *           Str[n + 2] = Attribute property 2 value number (array case)
 *           Str[n + 3] = Attribute property 2 value
 *           Str[n + m] = Attribute property 2 value (array case)
 */
//--------------------------------------------------------
Tango::DevVarStringArray *DataBase::db_get_class_attribute_property2(const Tango::DevVarStringArray *argin)
{
	Tango::DevVarStringArray *argout;
	DEBUG_STREAM << "DataBase::DbGetClassAttributeProperty2()  - " << device_name << std::endl;
	/*----- PROTECTED REGION ID(DataBase::db_get_class_attribute_property2) ENABLED START -----*/

	const Tango::DevVarStringArray  *property_names = argin;
	//	POGO has generated a method core with argout allocation.
	//	If you would like to use a static reference without copying,
	//	See "TANGO Device Server Programmer's Manual"
	//		(chapter : Writing a TANGO DS / Exchanging data)
	//------------------------------------------------------------
	DEBUG_STREAM << "DataBase::db_get_class_attribute_property2(): entering... !" << std::endl;


	TangoSys_MemStream sql_query_stream;
	char n_rows_str[256];
	char prop_size_str[256];
	MYSQL_RES *result;
	MYSQL_ROW row;
	int n_rows=0, n_props=0;
	argout = new Tango::DevVarStringArray;
	const char *tmp_class, *tmp_attribute;

	INFO_STREAM << "DataBase::GetClassAttributeProperty2(): get " << property_names->length()-1 << " properties for device " << (*property_names)[0] << std::endl;

	tmp_class = (*property_names)[0];
	n_props = 2;
	argout->length(n_props);
	(*argout)[n_props-2] = CORBA::string_dup(tmp_class);
	(*argout)[n_props-1] = to_corba_string(property_names->length() - 1);

	for (unsigned int i=1; i<property_names->length(); i++)
	{
	   	tmp_attribute = (*property_names)[i];
		sql_query_stream.str("");
		sql_query_stream << "SELECT name,value FROM property_attribute_class WHERE class = \""
		                 << tmp_class << "\" AND attribute LIKE \"" << tmp_attribute
						 << "\" ORDER BY name,count";
	   	DEBUG_STREAM << "DataBase::GetClassAttributeProperty2(): sql_query " << sql_query_stream.str() << std::endl;

		result = query(sql_query_stream.str(),"db_get_class_attribute_property2()");

	   	n_rows = mysql_num_rows(result);
	   	DEBUG_STREAM << "DataBase::GetClassAttributeProperty2(): mysql_num_rows() " << n_rows << std::endl;
	   	n_props = n_props+2;
	   	argout->length(n_props);
	   	(*argout)[n_props-2] = CORBA::string_dup(tmp_attribute);
		int prop_number_idx = n_props-1;
		int prop_number = 0;
	   	if (n_rows > 0)
	   	{
			std::string name, old_name;
			bool new_prop = true;
			int prop_size_idx = 0;
			int prop_size = 0;
	      	for (int j=0; j<n_rows; j++)
	      	{
	        	if ((row = mysql_fetch_row(result)) != NULL)
	         	{
					name = row[0];
					if (j == 0)
						old_name = name;
					else
					{
						name = row[0];
						if (name != old_name)
						{
							new_prop = true;
							old_name = name;
						}
						else
							new_prop = false;
					}
//	            			DEBUG_STREAM << "DataBase::GetClassAttributeProperty2(): property[ "<< i << "] count " << row[0] << " value " << row[1] << std::endl;
					if (new_prop == true)
					{
						n_props = n_props + 3;
						argout->length(n_props);
	            		(*argout)[n_props-3] = CORBA::string_dup(row[0]);
	            		(*argout)[n_props-1] = CORBA::string_dup(row[1]);
						if (prop_size != 0)
						{
							sprintf(prop_size_str,"%d",prop_size);
							(*argout)[prop_size_idx] = CORBA::string_dup(prop_size_str);
							prop_number++;
						}
						prop_size_idx = n_props - 2;
						prop_size = 1;
					}
					else
					{
						n_props = n_props + 1;
						argout->length(n_props);
						(*argout)[n_props-1] = CORBA::string_dup(row[1]);
						prop_size++;
					}
	         	}
	      	}
			if (prop_size != 0)
			{
				sprintf(prop_size_str,"%d",prop_size);
				(*argout)[prop_size_idx] = CORBA::string_dup(prop_size_str);
				prop_number++;
			}
	   	}
	   	sprintf(n_rows_str,"%d",prop_number);
		(*argout)[prop_number_idx] = CORBA::string_dup(n_rows_str);
	   	mysql_free_result(result);
	}

	DEBUG_STREAM << "DataBase::GetClassAttributeProperty2(): argout->length() "<< argout->length() << std::endl;

	/*----- PROTECTED REGION END -----*/	//	DataBase::db_get_class_attribute_property2
	return argout;
}
//--------------------------------------------------------
/**
 *	Command DbGetClassAttributePropertyHist related method
 *	Description: Retrieve Tango class attribute property history
 *
 *	@param argin Str[0] = Tango class
 *               Str[1] = Attribute name
 *               Str[2] = Property name
 *	@returns Str[0] = Attribute name
 *           Str[1] = Property name
 *           Str[2] = date
 *           Str[3] = Property value number (array case)
 *           Str[4] = Property value 1
 *           Str[n] = Property value n
 */
//--------------------------------------------------------
Tango::DevVarStringArray *DataBase::db_get_class_attribute_property_hist(const Tango::DevVarStringArray *argin)
{
	Tango::DevVarStringArray *argout;
	DEBUG_STREAM << "DataBase::DbGetClassAttributePropertyHist()  - " << device_name << std::endl;
	/*----- PROTECTED REGION ID(DataBase::db_get_class_attribute_property_hist) ENABLED START -----*/

	TangoSys_MemStream	sql_query_stream;
	MYSQL_RES *ids;
	MYSQL_RES *result;
	MYSQL_ROW row;
	const char *tmp_class;
	std::string      tmp_attribute;
	std::string      tmp_name;

	if (argin->length() != 3)
	{
	   WARN_STREAM << "DataBase::DbGetClassAttributePropertyHist(): incorrect number of input arguments " << std::endl;
	   Tango::Except::throw_exception(DB_IncorrectArguments,
	   				  "incorrect no. of input arguments, needs 3 (class,attribute,property)",
					  "DataBase::DbGetClassAttributePropertyHist()");
	}

	argout = new Tango::DevVarStringArray;

	tmp_class     = (*argin)[0];
	tmp_attribute = replace_wildcard((*argin)[1]);
	tmp_name      = replace_wildcard((*argin)[2]);

	// Get id list

    sql_query_stream << "SELECT DISTINCT id,date FROM property_attribute_class_hist WHERE class = \""
                     << tmp_class << "\" AND attribute LIKE \"" << tmp_attribute
				     << "\" AND name LIKE \"" << tmp_name << "\" ORDER by date ASC";

	{
		AutoLock al(this);

		ids = query(sql_query_stream.str(),"db_get_class_attribute_property_hist()",al.get_dch());

		// Retreive history
		int nb_item = 0;
		argout->length(0);

		for (unsigned int i=0; i<mysql_num_rows(ids); i++)
		{
		   row = mysql_fetch_row(ids);
		   Tango::DevULong64 id;
		   std::stringstream ss;
		   ss << row[0];
		   ss >> id;
		   sql_query_stream.str("");
		   sql_query_stream << "SELECT DATE_FORMAT(date,'%Y-%m-%d %H:%i:%s'),value,attribute,name,count FROM property_attribute_class_hist WHERE id = \""
	                    	<< id << "\" AND class = \"" << tmp_class << "\" ORDER BY count ASC";

		   result = query(sql_query_stream.str(),"db_get_class_attribute_property_hist()",al.get_dch());

		   int count = mysql_num_rows(result);

    	   row = mysql_fetch_row(result);
  		   int deleted = (atoi(row[4]) == 0); // count=0 for deleted property
  		   if(deleted) count = 0;
		   char n_rows_str[256];
		   sprintf(n_rows_str,"%d",count);

    	   argout->length(nb_item+4+count);
		   (*argout)[nb_item+0] = CORBA::string_dup(row[2]);
    	   (*argout)[nb_item+1] = CORBA::string_dup(row[3]);
    	   (*argout)[nb_item+2] = CORBA::string_dup(row[0]);
    	   (*argout)[nb_item+3] = CORBA::string_dup(n_rows_str);

		   for(int j=0;j<count;j++) {
            	 (*argout)[nb_item+4+j] = CORBA::string_dup(row[1]);
            	 row = mysql_fetch_row(result);
		   }

		   nb_item += 4+count;
		   mysql_free_result(result);
		}
	}

	mysql_free_result(ids);

	/*----- PROTECTED REGION END -----*/	//	DataBase::db_get_class_attribute_property_hist
	return argout;
}
//--------------------------------------------------------
/**
 *	Command DbGetClassForDevice related method
 *	Description: Get Tango class for the specified device.
 *
 *	@param argin Device name
 *	@returns Device Tango class
 */
//--------------------------------------------------------
Tango::DevString DataBase::db_get_class_for_device(Tango::DevString argin)
{
	Tango::DevString argout;
	DEBUG_STREAM << "DataBase::DbGetClassForDevice()  - " << device_name << std::endl;
	/*----- PROTECTED REGION ID(DataBase::db_get_class_for_device) ENABLED START -----*/

	//	Get class for device
	argout = NULL;

	TangoSys_MemStream	tms;
	tms << "SELECT DISTINCT class FROM device WHERE name=\""
				<< argin <<  "\"";
	DEBUG_STREAM << "DataBase::db_get_class_for_device(): sql_query " << tms.str() << std::endl;

	MYSQL_RES *result = query(tms.str(), "db_get_class_for_device()");
	int	n_rows = mysql_num_rows(result);
	if (n_rows==0)
	{
		mysql_free_result(result);
		TangoSys_MemStream	tms;
		tms << "Class not found for " << argin;
		Tango::Except::throw_exception(DB_IncorrectArguments,
	   				  tms.str().c_str(),
					  "DataBase::db_get_class_for_device()");
	}

	if (n_rows > 0)
		for (int i=0; i<n_rows; i++)
		{
			MYSQL_ROW	row = mysql_fetch_row(result);
			if (row != NULL)
			{
				argout = CORBA::string_dup(row[0]);
			}
		}
	mysql_free_result(result);

	DEBUG_STREAM << "Class " << argout << " found for " << argin << std::endl;

	/*----- PROTECTED REGION END -----*/	//	DataBase::db_get_class_for_device
	return argout;
}
//--------------------------------------------------------
/**
 *	Command DbGetClassInheritanceForDevice related method
 *	Description: Get class inheritance for the specified device.
 *
 *	@param argin Device name
 *	@returns Classes off the specified device.
 *           [0] - is the class of the device.
 *           [1] - is the class from the device class is inherited.
 *           ........and so on
 */
//--------------------------------------------------------
Tango::DevVarStringArray *DataBase::db_get_class_inheritance_for_device(Tango::DevString argin)
{
	Tango::DevVarStringArray *argout;
	DEBUG_STREAM << "DataBase::DbGetClassInheritanceForDevice()  - " << device_name << std::endl;
	/*----- PROTECTED REGION ID(DataBase::db_get_class_inheritance_for_device) ENABLED START -----*/

	//	Get class for the specified device
	std::string	classname = db_get_class_for_device(argin);

	//	Get its inheritance
	Tango::DevVarStringArray	*array = new Tango::DevVarStringArray();
	array->length(2);
	(*array)[0] = CORBA::string_dup(classname.c_str());
	(*array)[1] = CORBA::string_dup("InheritedFrom");
	Tango::DevVarStringArray	*props = db_get_class_property(array);

	//	Put in argout
	argout = new Tango::DevVarStringArray();
	argout->length(props->length()-3);
	(*argout)[0] = CORBA::string_dup(classname.c_str());
	for (unsigned int i=4 ; i<props->length() ; i++)
		(*argout)[i-3] = CORBA::string_dup((*props)[i]);

	delete array;
	delete props;

	/*----- PROTECTED REGION END -----*/	//	DataBase::db_get_class_inheritance_for_device
	return argout;
}
//--------------------------------------------------------
/**
 *	Command DbGetClassList related method
 *	Description: Get Tango class list with a specified filter
 *
 *	@param argin Filter
 *	@returns Class list
 */
//--------------------------------------------------------
Tango::DevVarStringArray *DataBase::db_get_class_list(Tango::DevString argin)
{
	Tango::DevVarStringArray *argout;
	DEBUG_STREAM << "DataBase::DbGetClassList()  - " << device_name << std::endl;
	/*----- PROTECTED REGION ID(DataBase::db_get_class_list) ENABLED START -----*/

	Tango::DevString  server = argin;
	TangoSys_MemStream	sql_query_stream;
	MYSQL_RES *result;
	MYSQL_ROW row;
	int n_rows;
	std::string tmp_server;

	INFO_STREAM << "DataBase::db_get_class_list(): server " << server << std::endl;

	tmp_server = replace_wildcard(server);
	sql_query_stream << "SELECT DISTINCT class FROM device WHERE class LIKE \""
	                 << tmp_server << "\" ORDER BY class";
	DEBUG_STREAM << "DataBase::db_get_class_list(): sql_query " << sql_query_stream.str() << std::endl;

	result = query(sql_query_stream.str(),"db_get_class_list()");

	n_rows = mysql_num_rows(result);
	DEBUG_STREAM << "DataBase::db_get_class_list(): mysql_num_rows() " << n_rows << std::endl;
	argout = new Tango::DevVarStringArray;

	if (n_rows > 0)
	{
	   argout->length(n_rows);

	   for (int i=0; i<n_rows; i++)
	   {
	      if ((row = mysql_fetch_row(result)) != NULL)
	      {
//	         DEBUG_STREAM << "DataBase::db_get_class_list(): row[ "<< i << "] class " << row[0] << std::endl;
	         (*argout)[i]   = CORBA::string_dup(row[0]);
	      }
	   }
	}
	else
		argout->length(0);
	mysql_free_result(result);

	/*----- PROTECTED REGION END -----*/	//	DataBase::db_get_class_list
	return argout;
}
//--------------------------------------------------------
/**
 *	Command DbGetClassProperty related method
 *	Description: 
 *
 *	@param argin Str[0] = Tango class
 *               Str[1] = Property name
 *               Str[2] = Property name
 *	@returns Str[0] = Tango class
 *           Str[1] = Property number
 *           Str[2] = Property name
 *           Str[3] = Property value number (array case)
 *           Str[4] = Property value
 *           Str[n] = Property value (array case)
 *           ....
 */
//--------------------------------------------------------
Tango::DevVarStringArray *DataBase::db_get_class_property(const Tango::DevVarStringArray *argin)
{
	Tango::DevVarStringArray *argout;
	DEBUG_STREAM << "DataBase::DbGetClassProperty()  - " << device_name << std::endl;
	/*----- PROTECTED REGION ID(DataBase::db_get_class_property) ENABLED START -----*/

	const Tango::DevVarStringArray  *property_names = argin;
	TangoSys_MemStream sql_query_stream;
	char n_rows_str[256];
	MYSQL_RES *result;
	MYSQL_ROW row;
	int n_rows=0, n_props=0;
	argout = new Tango::DevVarStringArray;
	const char *tmp_class, *tmp_name;

	INFO_STREAM << "DataBase::GetClassProperty(): get " << property_names->length()-1 << " properties for device " << (*property_names)[0] << std::endl;

	tmp_class = (*property_names)[0];
	n_props = 2;
	argout->length(n_props);
	(*argout)[0] = CORBA::string_dup(tmp_class);
	(*argout)[1] = to_corba_string(property_names->length() - 1);

	for (unsigned int i=1; i<property_names->length(); i++)
	{
	   tmp_name = (*property_names)[i];
	   sql_query_stream.str("");
	   sql_query_stream << "SELECT count,value FROM property_class WHERE class = \""
	                    << tmp_class << "\" AND name LIKE \"" << tmp_name << "\" ORDER BY count";
	   DEBUG_STREAM << "DataBase::GetClassProperty(): sql_query " << sql_query_stream.str() << std::endl;

	   result = query(sql_query_stream.str(),"db_get_class_property()");

	   n_rows = mysql_num_rows(result);
	   DEBUG_STREAM << "DataBase::GetClassProperty(): mysql_num_rows() " << n_rows << std::endl;
	   sprintf(n_rows_str,"%d",n_rows);
	   n_props = n_props+2;
	   argout->length(n_props);
	   (*argout)[n_props-2] = CORBA::string_dup(tmp_name);
	   (*argout)[n_props-1] = CORBA::string_dup(n_rows_str);
	   if (n_rows > 0)
	   {

	      for (int j=0; j<n_rows; j++)
	      {
	         if ((row = mysql_fetch_row(result)) != NULL)
	         {
	            DEBUG_STREAM << "DataBase::GetClassProperty(): property[ "<< i << "] count " << row[0] << " value " << row[1] << std::endl;
		    	n_props++;
		    	argout->length(n_props);
	            (*argout)[n_props-1] = CORBA::string_dup(row[1]);
	         }
	      }
	   }
	   mysql_free_result(result);
	}

	DEBUG_STREAM << "DataBase::GetClassProperty(): argout->length() "<< argout->length() << std::endl;

	/*----- PROTECTED REGION END -----*/	//	DataBase::db_get_class_property
	return argout;
}
//--------------------------------------------------------
/**
 *	Command DbGetClassPropertyHist related method
 *	Description: Retrieve Tango class property history
 *
 *	@param argin Str[0] = Tango class
 *               Str[1] = Property name
 *	@returns Str[0] = Property name
 *           Str[1] = date
 *           Str[2] = Property value number (array case)
 *           Str[3] = Property value 1
 *           Str[n] = Property value n
 */
//--------------------------------------------------------
Tango::DevVarStringArray *DataBase::db_get_class_property_hist(const Tango::DevVarStringArray *argin)
{
	Tango::DevVarStringArray *argout;
	DEBUG_STREAM << "DataBase::DbGetClassPropertyHist()  - " << device_name << std::endl;
	/*----- PROTECTED REGION ID(DataBase::db_get_class_property_hist) ENABLED START -----*/

	TangoSys_MemStream	sql_query_stream;
	MYSQL_RES *ids;
	MYSQL_RES *result;
	MYSQL_ROW row;
	const char *tmp_class;
	std::string      tmp_name;

	if (argin->length() != 2)
	{
	   WARN_STREAM << "DataBase::DbGetClassPropertyHist(): incorrect number of input arguments " << std::endl;
	   Tango::Except::throw_exception(DB_IncorrectArguments,
	   				  "incorrect no. of input arguments, needs 2 (class,property)",
					  "DataBase::DbGetClassPropertyHist()");
	}

	argout = new Tango::DevVarStringArray;

	tmp_class  = (*argin)[0];
	tmp_name   = replace_wildcard((*argin)[1]);

	// Get id list

    sql_query_stream << "SELECT DISTINCT id,date FROM property_class_hist WHERE class = \""
	                 << tmp_class << "\" AND name LIKE \"" << tmp_name << "\" ORDER by date ASC";

	{
		AutoLock al(this);

		ids = query(sql_query_stream.str(),"db_get_class_property_hist()",al.get_dch());

		// Retreive history
		int nb_item = 0;
		argout->length(0);

		for (unsigned int i=0; i<mysql_num_rows(ids); i++)
		{
		   row = mysql_fetch_row(ids);
		   Tango::DevULong64 id;
		   std::stringstream ss;
		   ss << row[0];
		   ss >> id;
		   sql_query_stream.str("");
		   sql_query_stream << "SELECT DATE_FORMAT(date,'%Y-%m-%d %H:%i:%s'),value,name,count FROM property_class_hist WHERE id = \""
	                    	<< id << "\" AND class = \"" << tmp_class << "\" ORDER BY count ASC";

		   result = query(sql_query_stream.str(),"db_get_class_property_hist()",al.get_dch());

		   int count = mysql_num_rows(result);

    	   row = mysql_fetch_row(result);
  		   int deleted = (atoi(row[3]) == 0); // count=0 for deleted property
  		   if(deleted) count = 0;
		   char n_rows_str[256];
		   sprintf(n_rows_str,"%d",count);

    	   argout->length(nb_item+3+count);
		   (*argout)[nb_item+0] = CORBA::string_dup(row[2]);
    	   (*argout)[nb_item+1] = CORBA::string_dup(row[0]);
    	   (*argout)[nb_item+2] = CORBA::string_dup(n_rows_str);

		   for(int j=0;j<count;j++) {
        	 (*argout)[nb_item+3+j] = CORBA::string_dup(row[1]);
        	 row = mysql_fetch_row(result);
		   }

		   nb_item += 3+count;
		   mysql_free_result(result);
		}
	}

	mysql_free_result(ids);

	/*----- PROTECTED REGION END -----*/	//	DataBase::db_get_class_property_hist
	return argout;
}
//--------------------------------------------------------
/**
 *	Command DbGetClassPropertyList related method
 *	Description: Get property list for a given Tango class
 *
 *	@param argin The class
 *	@returns Property name list
 */
//--------------------------------------------------------
Tango::DevVarStringArray *DataBase::db_get_class_property_list(Tango::DevString argin)
{
	Tango::DevVarStringArray *argout;
	DEBUG_STREAM << "DataBase::DbGetClassPropertyList()  - " << device_name << std::endl;
	/*----- PROTECTED REGION ID(DataBase::db_get_class_property_list) ENABLED START -----*/

	Tango::DevString  class_name = argin;
	TangoSys_MemStream	sql_query_stream;
	MYSQL_RES *result;
	MYSQL_ROW row;
	int n_rows;

	TimeVal	before, after;
	GetTime(before);


	INFO_STREAM << "DataBase::db_get_class_property_list(): class " << class_name << std::endl;

	if (class_name == NULL)
	{
		sql_query_stream << "SELECT DISTINCT name FROM property_class WHERE class LIKE \"%\" ORDER BY name";
	}
	else
	{
		sql_query_stream << "SELECT DISTINCT name FROM property_class WHERE class LIKE \""
		                 << class_name << "\" ORDER BY name";
	}
	DEBUG_STREAM << "DataBase::db_get_class_property_list(): sql_query " << sql_query_stream.str() << std::endl;

	result = query(sql_query_stream.str(),"db_get_class_property_list()");

	n_rows = mysql_num_rows(result);
	DEBUG_STREAM << "DataBase::db_get_class_property_list(): mysql_num_rows() " << n_rows << std::endl;
	argout = new Tango::DevVarStringArray;

	if (n_rows > 0)
	{
	   argout->length(n_rows);

	   for (int i=0; i<n_rows; i++)
	   {
	      if ((row = mysql_fetch_row(result)) != NULL)
	      {
	         DEBUG_STREAM << "DataBase::db_get_class_property_list(): property[ "<< i << "] alias " << row[0] << std::endl;
	         (*argout)[i]   = CORBA::string_dup(row[0]);
	      }
	   }
	}
	else
		argout->length(0);
	mysql_free_result(result);

	GetTime(after);
	update_timing_stats(before, after, "DbGetClassPropertyList");

	/*----- PROTECTED REGION END -----*/	//	DataBase::db_get_class_property_list
	return argout;
}
//--------------------------------------------------------
/**
 *	Command DbGetDeviceAlias related method
 *	Description: Return alias for device name if found.
 *
 *	@param argin The device name
 *	@returns The alias found
 */
//--------------------------------------------------------
Tango::DevString DataBase::db_get_device_alias(Tango::DevString argin)
{
	Tango::DevString argout;
	DEBUG_STREAM << "DataBase::DbGetDeviceAlias()  - " << device_name << std::endl;
	/*----- PROTECTED REGION ID(DataBase::db_get_device_alias) ENABLED START -----*/

	TangoSys_MemStream sql_query_stream;
	std::string		devname(argin);
	std::string		tmp_devname;
	MYSQL_RES	*result;
	MYSQL_ROW	row;
	int			n_rows;

	argout = NULL;

	INFO_STREAM << "DataBase::db_get_device_alias(): devname " << devname << std::endl;
	if (!check_device_name(devname))
	{
         	WARN_STREAM << "DataBase::db_get_device_alias(): device name  " << devname << " incorrect ";
         	WARN_STREAM << std::endl;
         	Tango::Except::throw_exception(DB_IncorrectDeviceName,
					       "failed to find alias, device name incorrect",
					       "DataBase::db_get_device_alias()");
	}

	tmp_devname = replace_wildcard(devname.c_str());
	sql_query_stream << "SELECT DISTINCT alias FROM device WHERE name LIKE \"" << tmp_devname
	                 << "\" ORDER BY alias";
	DEBUG_STREAM << "DataBase::db_get_device_alias(): sql_query " << sql_query_stream.str() << std::endl;

	result = query(sql_query_stream.str(),"db_get_device_alias()");

	n_rows = mysql_num_rows(result);
	DEBUG_STREAM << "DataBase::db_get_device_alias_(): mysql_num_rows() " << n_rows << std::endl;

	if (n_rows > 0)
	{
		if ((row = mysql_fetch_row(result)) != NULL)
		{
			if (row[0]==NULL)
			{
				mysql_free_result(result);
  	            TangoSys_OMemStream o;
				o << "No alias found for device \'" << devname << "\'";
				std::string msg = o.str();
				WARN_STREAM << msg << std::endl;
				Tango::Except::throw_exception(DB_AliasNotDefined,
	   						                   msg,
							                   "DataBase::db_get_device_alias()");
			}
			else
				argout = CORBA::string_dup(row[0]);
		}
	}
	else
	{
		mysql_free_result(result);
        TangoSys_OMemStream o;
		o << "No alias found for device \'" << devname << "\'";
		std::string msg = o.str();
		WARN_STREAM << msg << std::endl;
		Tango::Except::throw_exception(DB_AliasNotDefined,
	   				                   msg,
					                   "DataBase::db_get_device_alias()");
	}
	mysql_free_result(result);

	/*----- PROTECTED REGION END -----*/	//	DataBase::db_get_device_alias
	return argout;
}
//--------------------------------------------------------
/**
 *	Command DbGetDeviceAliasList related method
 *	Description: Get device alias name with a specific filter
 *
 *	@param argin The filter
 *	@returns Device alias list
 */
//--------------------------------------------------------
Tango::DevVarStringArray *DataBase::db_get_device_alias_list(Tango::DevString argin)
{
	Tango::DevVarStringArray *argout;
	DEBUG_STREAM << "DataBase::DbGetDeviceAliasList()  - " << device_name << std::endl;
	/*----- PROTECTED REGION ID(DataBase::db_get_device_alias_list) ENABLED START -----*/

	Tango::DevString  wildcard = argin;
	TangoSys_MemStream sql_query_stream;
	std::string tmp_wildcard;
	MYSQL_RES *result;
	MYSQL_ROW row;
	int n_rows;

	INFO_STREAM << "DataBase::db_get_device_alias_list(): wild card " << wildcard << std::endl;

	if (wildcard == NULL)
	{
		sql_query_stream << "SELECT DISTINCT alias FROM device WHERE alias LIKE \"%\" ORDER BY alias";
	}
	else
	{
		tmp_wildcard = replace_wildcard(wildcard);
		sql_query_stream << "SELECT DISTINCT alias FROM device WHERE alias LIKE \"" << tmp_wildcard
		                 << "\" ORDER BY alias";
	}
	DEBUG_STREAM << "DataBase::db_get_device_alias_list(): sql_query " << sql_query_stream.str() << std::endl;

	result = query(sql_query_stream.str(),"db_get_device_alias_list()");

	n_rows = mysql_num_rows(result);
	DEBUG_STREAM << "DataBase::db_get_device_alias_list(): mysql_num_rows() " << n_rows << std::endl;
	argout = new Tango::DevVarStringArray;

	if (n_rows > 0)
	{
	   argout->length(n_rows);

	   for (int i=0; i<n_rows; i++)
	   {
	      if ((row = mysql_fetch_row(result)) != NULL)
	      {
//	         DEBUG_STREAM << "DataBase::db_get_device_alias_list(): row[ "<< i << "] alias " << row[0] << std::endl;
	         (*argout)[i]   = CORBA::string_dup(row[0]);
	      }
	   }
	}
	else
		argout->length(0);
	mysql_free_result(result);

	/*----- PROTECTED REGION END -----*/	//	DataBase::db_get_device_alias_list
	return argout;
}
//--------------------------------------------------------
/**
 *	Command DbGetDeviceAttributeList related method
 *	Description: Return list of attributes matching the wildcard
 *                for the specified device
 *
 *	@param argin Str[0] = Device name
 *               Str[1] = Wildcard
 *	@returns attribute name list
 */
//--------------------------------------------------------
Tango::DevVarStringArray *DataBase::db_get_device_attribute_list(const Tango::DevVarStringArray *argin)
{
	Tango::DevVarStringArray *argout;
	DEBUG_STREAM << "DataBase::DbGetDeviceAttributeList()  - " << device_name << std::endl;
	/*----- PROTECTED REGION ID(DataBase::db_get_device_attribute_list) ENABLED START -----*/

	const Tango::DevVarStringArray  *device_wildcard = argin;
	TangoSys_MemStream sql_query_stream;
	std::string tmp_wildcard;
	MYSQL_RES *result;
	MYSQL_ROW row;
	int n_rows;
	const char *device, *wildcard;

	device = (*device_wildcard)[0];
	wildcard = (*device_wildcard)[1];
	INFO_STREAM << "DataBase::db_get_device_attribute_list(): device " << device;
	WARN_STREAM << " wildcard " << wildcard << std::endl;

	if (wildcard == NULL)
	{
		sql_query_stream << "SELECT DISTINCT attribute FROM property_attribute_device WHERE device=\""
		                 << device << "\" AND attribute LIKE \"%\" ORDER BY attribute";
	}
	else
	{
		tmp_wildcard = replace_wildcard (wildcard);
		sql_query_stream << "SELECT DISTINCT attribute FROM property_attribute_device WHERE device=\""
		                 << device << "\" AND attribute LIKE \"" << tmp_wildcard << "\" ORDER BY attribute";
	}
	DEBUG_STREAM << "DataBase::db_get_device_attrribute_list(): sql_query " << sql_query_stream.str() << std::endl;

	result = query(sql_query_stream.str(),"db_get_device_attribute_list()");

	n_rows = mysql_num_rows(result);
	DEBUG_STREAM << "DataBase::db_get_device_attribute_list(): mysql_num_rows() " << n_rows << std::endl;
	argout = new Tango::DevVarStringArray;

	if (n_rows > 0)
	{
	   argout->length(n_rows);

	   for (int i=0; i<n_rows; i++)
	   {
	      if ((row = mysql_fetch_row(result)) != NULL)
	      {
	         DEBUG_STREAM << "DataBase::db_get_device_attribute_list(): attribute[ "<< i << "] attribute " << row[0] << std::endl;
	         (*argout)[i]   = CORBA::string_dup(row[0]);
	      }
	   }
	}
	else
		argout->length(0);
	mysql_free_result(result);

	/*----- PROTECTED REGION END -----*/	//	DataBase::db_get_device_attribute_list
	return argout;
}
//--------------------------------------------------------
/**
 *	Command DbGetDeviceAttributeProperty related method
 *	Description: Get device attribute property(ies) value
 *
 *	@param argin Str[0] = Device name
 *               Str[1] = Attribute name
 *               Str[n] = Attribute name
 *	@returns Str[0] = Device name
 *           Str[1] = Attribute property  number
 *           Str[2] = Attribute property 1 name
 *           Str[3] = Attribute property 1 value
 *           Str[n + 1] = Attribute property 2 name
 *           Str[n + 2] = Attribute property 2 value
 */
//--------------------------------------------------------
Tango::DevVarStringArray *DataBase::db_get_device_attribute_property(const Tango::DevVarStringArray *argin)
{
	Tango::DevVarStringArray *argout;
	DEBUG_STREAM << "DataBase::DbGetDeviceAttributeProperty()  - " << device_name << std::endl;
	/*----- PROTECTED REGION ID(DataBase::db_get_device_attribute_property) ENABLED START -----*/

	const Tango::DevVarStringArray  *property_names = argin;
	TangoSys_MemStream	sql_query_stream;
	char n_rows_str[256];
	MYSQL_RES *result;
	MYSQL_ROW row;
	int n_rows=0, n_props=0;
	argout = new Tango::DevVarStringArray;
	const char *tmp_device, *tmp_attribute;

	TimeVal	before, after;
	GetTime(before);


	INFO_STREAM << "DataBase::GetAttributeProperty(): get " << property_names->length()-1 << " properties for device " << (*property_names)[0] << std::endl;

	tmp_device = (*property_names)[0];
	n_props = 2;
	argout->length(n_props);
	(*argout)[n_props-2] = CORBA::string_dup(tmp_device);
	(*argout)[n_props-1] = to_corba_string(property_names->length() - 1);

	for (unsigned int i=1; i<property_names->length(); i++)
	{
	   tmp_attribute = (*property_names)[i];
	   sql_query_stream.str("");
	   sql_query_stream << "SELECT name,value FROM property_attribute_device WHERE device = \""
	                    << tmp_device << "\" AND attribute LIKE \"" << tmp_attribute << "\" ";
	   DEBUG_STREAM << "DataBase::GetAttributeProperty(): sql_query " << sql_query_stream.str() << std::endl;

	   result = query(sql_query_stream.str(),"db_get_device_attribute_property()");

	   n_rows = mysql_num_rows(result);
	   DEBUG_STREAM << "DataBase::GetAttributeProperty(): mysql_num_rows() " << n_rows << std::endl;
	   sprintf(n_rows_str,"%d",n_rows);
	   n_props = n_props+2;
	   argout->length(n_props);
	   (*argout)[n_props-2] = CORBA::string_dup(tmp_attribute);
           (*argout)[n_props-1] = CORBA::string_dup(n_rows_str);
	   if (n_rows > 0)
	   {

	      for (int j=0; j<n_rows; j++)
	      {
	         if ((row = mysql_fetch_row(result)) != NULL)
	         {
	            DEBUG_STREAM << "DataBase::GetAttributeProperty(): property[ "<< i << "] count " << row[0] << " value " << row[1] << std::endl;
	   	    	n_props = n_props+2;
	   	    	argout->length(n_props);
	            (*argout)[n_props-2] = CORBA::string_dup(row[0]);
	            (*argout)[n_props-1] = CORBA::string_dup(row[1]);
	         }
	      }
	   }
	   mysql_free_result(result);
	}

	DEBUG_STREAM << "DataBase::GetDeviceProperty(): argout->length() "<< argout->length() << std::endl;

	GetTime(after);
	update_timing_stats(before, after, "DbGetDeviceAttributeProperty");

	/*----- PROTECTED REGION END -----*/	//	DataBase::db_get_device_attribute_property
	return argout;
}
//--------------------------------------------------------
/**
 *	Command DbGetDeviceAttributeProperty2 related method
 *	Description: Retrieve device attribute properties. This command has the possibility to retrieve
 *               device attribute properties which are arrays. It is not possible with the old
 *               DbGetDeviceAttributeProperty command. Nevertheless, the old command has not been
 *               deleted for compatibility reason
 *
 *	@param argin Str[0] = Device name
 *               Str[1] = Attribute name
 *               Str[n] = Attribute name
 *	@returns Str[0] = Device name
 *           Str[1] = Attribute property  number
 *           Str[2] = Attribute property 1 name
 *           Str[3] = Attribute property 1 value number (array case)
 *           Str[4] = Attribute property 1 value
 *           Str[n] = Attribute property 1 value (array case)
 *           Str[n + 1] = Attribute property 2 name
 *           Str[n + 2] = Attribute property 2 value number (array case)
 *           Str[n + 3] = Attribute property 2 value
 *           Str[n + m] = Attribute property 2 value (array case)
 */
//--------------------------------------------------------
Tango::DevVarStringArray *DataBase::db_get_device_attribute_property2(const Tango::DevVarStringArray *argin)
{
	Tango::DevVarStringArray *argout;
	DEBUG_STREAM << "DataBase::DbGetDeviceAttributeProperty2()  - " << device_name << std::endl;
	/*----- PROTECTED REGION ID(DataBase::db_get_device_attribute_property2) ENABLED START -----*/

	const Tango::DevVarStringArray  *property_names = argin;
	TangoSys_MemStream sql_query_stream;
	char n_rows_str[256];
	char prop_size_str[256];
	MYSQL_RES *result;
	MYSQL_ROW row;
	int n_rows=0, n_props=0;
	argout = new Tango::DevVarStringArray;
	const char *tmp_device, *tmp_attribute;

	TimeVal	before, after;
	GetTime(before);

	INFO_STREAM << "DataBase::GetDeviceAttributeProperty2(): get " << property_names->length()-1 << " properties for device " << (*property_names)[0] << std::endl;

	tmp_device = (*property_names)[0];
	n_props = 2;
	argout->length(n_props);
	(*argout)[n_props-2] = CORBA::string_dup(tmp_device);
	(*argout)[n_props-1] = to_corba_string(property_names->length() - 1);

//
// First, get how many attributes belonging to the device have
// properties defined in the db
//

	bool all_attr = false;
	sql_query_stream << "SELECT COUNT(DISTINCT attribute) FROM property_attribute_device WHERE device = \"" << tmp_device << "\"";
	DEBUG_STREAM << "Database::GetDeviceAttributeProperty2(): sql_query " << sql_query_stream.str() << std::endl;

	result = query(sql_query_stream.str(),"db_get_device_attribute_property2()");
	n_rows = mysql_num_rows(result);
	DEBUG_STREAM << "DataBase::GetDeviceAttributeProperty2(): mysql_num_rows() " << n_rows << std::endl;

	if (n_rows != 0)
	{
		if ((row = mysql_fetch_row(result)) != NULL)
		{
			std::stringstream tmp_str;
			std::string nb_attr_str = row[0];
		 	tmp_str << nb_attr_str;
			unsigned int nb_attr = 0;
			tmp_str >> nb_attr;
			if (property_names->length()-1 >= nb_attr)
				all_attr = true;
	   		mysql_free_result(result);
		}
	}

	if (all_attr == true)
	{
		DEBUG_STREAM << "DataBase::GetDeviceAttributeProperty2(): Get attribute properties for all attribute(s)" << std::endl;
	}

	if (all_attr == false)
	{
		for (unsigned int i=1; i<property_names->length(); i++)
		{
	   		tmp_attribute = (*property_names)[i];
			sql_query_stream.str("");
			sql_query_stream << "SELECT name,value FROM property_attribute_device WHERE device = \""
		                 << tmp_device << "\" AND attribute LIKE \"" << tmp_attribute
						 << "\" ORDER BY name,count";
	   		DEBUG_STREAM << "DataBase::GetDeviceAttributeProperty2(): sql_query " << sql_query_stream.str() << std::endl;

			result = query(sql_query_stream.str(),"db_get_device_attribute_property2()");

	   		n_rows = mysql_num_rows(result);
	   		DEBUG_STREAM << "DataBase::GetDeviceAttributeProperty2(): mysql_num_rows() " << n_rows << std::endl;
	   		n_props = n_props+2;
	   		argout->length(n_props);
	   		(*argout)[n_props-2] = CORBA::string_dup(tmp_attribute);
			int prop_number_idx = n_props-1;
			int prop_number = 0;
	   		if (n_rows > 0)
	   		{
				std::string name, old_name;
				bool new_prop = true;
				int prop_size_idx = 0;
				int prop_size = 0;
	      		for (int j=0; j<n_rows; j++)
	      		{
	        		if ((row = mysql_fetch_row(result)) != NULL)
	         		{
						name = row[0];
						if (j == 0)
							old_name = name;
						else
						{
							name = row[0];
							if (name != old_name)
							{
								new_prop = true;
								old_name = name;
							}
							else
								new_prop = false;
						}
//	            			DEBUG_STREAM << "DataBase::GetDeviceAttributeProperty2(): property[ "<< i << "] count " << row[0] << " value " << row[1] << std::endl;
						if (new_prop == true)
						{
							n_props = n_props + 3;
							argout->length(n_props);
	            			(*argout)[n_props-3] = CORBA::string_dup(row[0]);
	            			(*argout)[n_props-1] = CORBA::string_dup(row[1]);
							if (prop_size != 0)
							{
								sprintf(prop_size_str,"%d",prop_size);
								(*argout)[prop_size_idx] = CORBA::string_dup(prop_size_str);
								prop_number++;
							}
							prop_size_idx = n_props - 2;
							prop_size = 1;
						}
						else
						{
							n_props = n_props + 1;
							argout->length(n_props);
							(*argout)[n_props-1] = CORBA::string_dup(row[1]);
							prop_size++;
						}
	         		}
	      		}
				if (prop_size != 0)
				{
					sprintf(prop_size_str,"%d",prop_size);
					(*argout)[prop_size_idx] = CORBA::string_dup(prop_size_str);
					prop_number++;
				}
	   		}
	   		sprintf(n_rows_str,"%d",prop_number);
			(*argout)[prop_number_idx] = CORBA::string_dup(n_rows_str);
	   		mysql_free_result(result);
		}
	}
	else
	{
		sql_query_stream.str("");
		sql_query_stream << "SELECT attribute,name,value FROM property_attribute_device WHERE device = \""
		                 << tmp_device << "\" ORDER BY attribute,name,count";
	   	DEBUG_STREAM << "DataBase::GetDeviceAttributeProperty2(): sql_query " << sql_query_stream.str() << std::endl;

		result = query(sql_query_stream.str(),"db_get_device_attribute_property2()");
		n_rows = mysql_num_rows(result);
		DEBUG_STREAM << "DataBase::GetDeviceAttributeProperty2(): mysql_num_rows() " << n_rows << std::endl;

		std::map<std::string,std::vector<PropDef> > db_data;

		std::string att,prev_att;
		std::string p_name,prev_p_name;
		std::string value;
		PropDef prop;
		std::vector<PropDef> att_props;

//
// Create a map with data coming from db
//

		for (int j = 0;j < n_rows;j++)
		{
			if ((row = mysql_fetch_row(result)) != NULL)
			{
				att = row[0];
				transform(att.begin(),att.end(),att.begin(),::tolower);

				if (att != prev_att)
				{
					if (j != 0)
					{
						att_props.push_back(prop);
						db_data.insert(make_pair(prev_att,att_props));
						prop.prop_val.clear();
						att_props.clear();
					}
					p_name = row[1];
					prop.prop_name_cd = p_name;
					transform(p_name.begin(),p_name.end(),p_name.begin(),::tolower);

					prop.prop_name = p_name;
					value = row[2];
					prop.prop_val.push_back(value);

					prev_p_name = p_name;
					prev_att = att;
				}
				else
				{
					p_name = row[1];
					transform(p_name.begin(),p_name.end(),p_name.begin(),::tolower);

					if (p_name != prev_p_name)
					{
						att_props.push_back(prop);
						prop.prop_val.clear();

						prop.prop_name = p_name;
						prop.prop_name_cd = row[1];
						value = row[2];
						prop.prop_val.push_back(value);

						prev_p_name = p_name;
					}
					else
					{
						value = row[2];
						prop.prop_val.push_back(value);
					}
				}
			}
		}
	   	mysql_free_result(result);

		if (n_rows != 0)
		{
			att_props.push_back(prop);
			db_data.insert(make_pair(att,att_props));
		}

//
// Initialized data returned to caller
//

		for (unsigned int i=1; i<property_names->length(); i++)
		{
	   		std::string tmp_attribute((*property_names)[i]);
			std::string tmp_att_lower(tmp_attribute);
			transform(tmp_att_lower.begin(),tmp_att_lower.end(),tmp_att_lower.begin(),::tolower);

			std::map<std::string,std::vector<PropDef> >::iterator pos = db_data.find(tmp_att_lower);

//
// Data for this attribute in map?
//

			if (pos == db_data.end())
			{
	   			n_props = n_props+2;
	   			argout->length(n_props);
	   			(*argout)[n_props-2] = CORBA::string_dup(tmp_attribute.c_str());
				(*argout)[n_props-1] = CORBA::string_dup("0");
			}
			else
			{
				int prop_nb = pos->second.size();

	   			n_props = n_props + 2;
	   			argout->length(n_props);
	   			(*argout)[n_props - 2] = CORBA::string_dup(tmp_attribute.c_str());
	   			sprintf(n_rows_str,"%d",prop_nb);
				(*argout)[n_props - 1] = CORBA::string_dup(n_rows_str);

				for (int i = 0;i < prop_nb;i++)
				{
					PropDef &pd = (pos->second)[i];
					int prop_size = pd.prop_val.size();
					int old_n_props = n_props;
					n_props = n_props + 2 + prop_size;

					argout->length(n_props);
					(*argout)[old_n_props++] = CORBA::string_dup(pd.prop_name_cd.c_str());
	   				sprintf(n_rows_str,"%d",prop_size);
					(*argout)[old_n_props++] = CORBA::string_dup(n_rows_str);

					for (int j = 0;j < prop_size;j++)
					{
						(*argout)[old_n_props++] = CORBA::string_dup(pd.prop_val[j].c_str());
					}
				}
			}
		}
	}

	DEBUG_STREAM << "DataBase::GetDeviceAttributeProperty2(): argout->length() "<< argout->length() << std::endl;

	GetTime(after);
	update_timing_stats(before, after, "DbGetDeviceAttributeProperty2");

	/*----- PROTECTED REGION END -----*/	//	DataBase::db_get_device_attribute_property2
	return argout;
}
//--------------------------------------------------------
/**
 *	Command DbGetDeviceAttributePropertyHist related method
 *	Description: Retrieve device attribute property history
 *
 *	@param argin Str[0] = Device name
 *               Str[1] = Attribute name
 *               Str[2] = Property name
 *	@returns Str[0] = Attribute name
 *           Str[1] = Property name
 *           Str[2] = date
 *           Str[3] = Property value number (array case)
 *           Str[4] = Property value 1
 *           Str[n] = Property value n
 */
//--------------------------------------------------------
Tango::DevVarStringArray *DataBase::db_get_device_attribute_property_hist(const Tango::DevVarStringArray *argin)
{
	Tango::DevVarStringArray *argout;
	DEBUG_STREAM << "DataBase::DbGetDeviceAttributePropertyHist()  - " << device_name << std::endl;
	/*----- PROTECTED REGION ID(DataBase::db_get_device_attribute_property_hist) ENABLED START -----*/

	TangoSys_MemStream	sql_query_stream;
	MYSQL_RES *ids;
	MYSQL_RES *result;
	MYSQL_ROW row;
	const char *tmp_device;
	std::string      tmp_attribute;
	std::string      tmp_name;

	if (argin->length() != 3)
	{
	   WARN_STREAM << "DataBase::DbGetDeviceAttributePropertyHist(): incorrect number of input arguments " << std::endl;
	   Tango::Except::throw_exception(DB_IncorrectArguments,
	   				  "incorrect no. of input arguments, needs 3 (device,attribute,property)",
					  "DataBase::DbGetDeviceAttributePropertyHist()");
	}

	argout = new Tango::DevVarStringArray;

	tmp_device    = (*argin)[0];
	tmp_attribute = replace_wildcard((*argin)[1]);
	tmp_name      = replace_wildcard((*argin)[2]);

	// Get id list

    sql_query_stream << "SELECT DISTINCT id,date FROM property_attribute_device_hist WHERE device = \""
	                 << tmp_device << "\" AND attribute LIKE \"" << tmp_attribute
 			         << "\" AND name LIKE \"" << tmp_name << "\" ORDER by date ASC";

	{
		AutoLock al(this);

		ids = query(sql_query_stream.str(),"db_get_device_attribute_property_hist()",al.get_dch());

		// Retreive history
		int nb_item = 0;
		argout->length(0);

		for (unsigned int i=0; i<mysql_num_rows(ids); i++)
		{
		   row = mysql_fetch_row(ids);
		   Tango::DevULong64 id;
		   std::stringstream ss;
		   ss << row[0];
		   ss >> id;
		   sql_query_stream.str("");
		   sql_query_stream << "SELECT DATE_FORMAT(date,'%Y-%m-%d %H:%i:%s'),value,attribute,name,count FROM property_attribute_device_hist WHERE id = \""
	                    	<< id << "\" AND device = \"" << tmp_device << "\" ORDER BY count ASC";

		   result = query(sql_query_stream.str(),"db_get_device_attribute_property_hist()",al.get_dch());

		   int count = mysql_num_rows(result);

    	   row = mysql_fetch_row(result);
  		   int deleted = (atoi(row[4]) == 0); // count=0 for deleted property
  		   if(deleted) count = 0;
		   char n_rows_str[256];
		   sprintf(n_rows_str,"%d",count);

    	   argout->length(nb_item+4+count);
		   (*argout)[nb_item+0] = CORBA::string_dup(row[2]);
    	   (*argout)[nb_item+1] = CORBA::string_dup(row[3]);
    	   (*argout)[nb_item+2] = CORBA::string_dup(row[0]);
    	   (*argout)[nb_item+3] = CORBA::string_dup(n_rows_str);

		   for(int j=0;j<count;j++) {
        	 (*argout)[nb_item+4+j] = CORBA::string_dup(row[1]);
        	 row = mysql_fetch_row(result);
		   }

		   nb_item += 4+count;
		   mysql_free_result(result);
		}
	}

	mysql_free_result(ids);

	/*----- PROTECTED REGION END -----*/	//	DataBase::db_get_device_attribute_property_hist
	return argout;
}
//--------------------------------------------------------
/**
 *	Command DbGetDeviceClassList related method
 *	Description: Get Tango classes/device list embedded in a specific device server
 *
 *	@param argin Device server process name
 *	@returns Str[0] = Device name
 *           Str[1] = Tango class
 *           Str[n] = Device name
 *           Str[n + 1] = Tango class
 */
//--------------------------------------------------------
Tango::DevVarStringArray *DataBase::db_get_device_class_list(Tango::DevString argin)
{
	Tango::DevVarStringArray *argout;
	DEBUG_STREAM << "DataBase::DbGetDeviceClassList()  - " << device_name << std::endl;
	/*----- PROTECTED REGION ID(DataBase::db_get_device_class_list) ENABLED START -----*/

	Tango::DevString  server = argin;
	TangoSys_MemStream	sql_query_stream;
	MYSQL_RES *result;
	MYSQL_ROW row;
	int n_rows;

	TimeVal	before, after;
	GetTime(before);


	INFO_STREAM << "DataBase::GetDeviceClassList(): server " << server << std::endl;

	sql_query_stream << "SELECT name,class FROM device WHERE server = \""
	                 << server << "\" ORDER BY name";
	DEBUG_STREAM << "DataBase::GetDeviceClassList(): sql_query " << sql_query_stream.str() << std::endl;

	result = query(sql_query_stream.str(),"db_get_device_class_list()");

	n_rows = mysql_num_rows(result);
	INFO_STREAM << "DataBase::GetDeviceClassList(): mysql_num_rows() " << n_rows << std::endl;
	argout = new Tango::DevVarStringArray;

	if (n_rows > 0)
	{
	   argout->length(n_rows*2);

	   for (int i=0; i<n_rows; i++)
	   {
	      if ((row = mysql_fetch_row(result)) != NULL)
	      {
	         DEBUG_STREAM << "DataBase::GetDeviceClassList(): row[ "<< i << "] name " << row[0] << " class " << row[1] << std::endl;
	         (*argout)[i*2]   = CORBA::string_dup(row[0]);
	         (*argout)[i*2+1] = CORBA::string_dup(row[1]);
	      }
	   }
	}
	else
		argout->length(0);
	mysql_free_result(result);

	GetTime(after);
	update_timing_stats(before, after, "DbGetDeviceClassList");

	/*----- PROTECTED REGION END -----*/	//	DataBase::db_get_device_class_list
	return argout;
}
//--------------------------------------------------------
/**
 *	Command DbGetDeviceDomainList related method
 *	Description: Get list of device domain name matching the specified
 *
 *	@param argin The wildcard
 *	@returns Device name domain list
 */
//--------------------------------------------------------
Tango::DevVarStringArray *DataBase::db_get_device_domain_list(Tango::DevString argin)
{
	Tango::DevVarStringArray *argout;
	DEBUG_STREAM << "DataBase::DbGetDeviceDomainList()  - " << device_name << std::endl;
	/*----- PROTECTED REGION ID(DataBase::db_get_device_domain_list) ENABLED START -----*/

	Tango::DevString  wildcard = argin;
	TangoSys_MemStream	sql_query_stream;
	std::string tmp_wildcard;
	MYSQL_RES *result;
	MYSQL_ROW row;
	int n_rows;

	TimeVal	before, after;
	GetTime(before);

	INFO_STREAM << "DataBase::db_get_device_domain_list(): wild card " << wildcard << std::endl;

	if (wildcard == NULL)
	{
		sql_query_stream << "SELECT DISTINCT domain FROM device WHERE name LIKE \"%\" ORDER BY domain";
	}
	else
	{
		tmp_wildcard = replace_wildcard(wildcard);
		sql_query_stream << "SELECT DISTINCT domain FROM device WHERE name LIKE \""
		                 << tmp_wildcard << "\" OR alias LIKE \"" << tmp_wildcard
						 << "\" ORDER BY domain";
	}
	DEBUG_STREAM << "DataBase::db_get_device_domain_list(): sql_query " << sql_query_stream.str() << std::endl;

	result = query(sql_query_stream.str(),"db_get_device_domain_list()");

	n_rows = mysql_num_rows(result);
	DEBUG_STREAM << "DataBase::db_get_device_domain_list(): mysql_num_rows() " << n_rows << std::endl;
	argout = new Tango::DevVarStringArray;

	if (n_rows > 0)
	{
	   argout->length(n_rows);
	   for (int i=0; i<n_rows; i++)
	   {
	      if ((row = mysql_fetch_row(result)) != NULL)
	      {
//	         DEBUG_STREAM << "DataBase::db_get_device_domain_list(): domain[ "<< i << "] " << row[0] << std::endl;
	         (*argout)[i] = CORBA::string_dup(row[0]);
	      }
	   }
	}
	else
		argout->length(0);
	mysql_free_result(result);

	GetTime(after);
	update_timing_stats(before, after, "DbGetDeviceDomainList");

	/*----- PROTECTED REGION END -----*/	//	DataBase::db_get_device_domain_list
	return argout;
}
//--------------------------------------------------------
/**
 *	Command DbGetDeviceExportedList related method
 *	Description: Get a list of exported devices whose names satisfy the filter (wildcard is
 *
 *	@param argin filter
 *	@returns list of exported devices
 */
//--------------------------------------------------------
Tango::DevVarStringArray *DataBase::db_get_device_exported_list(Tango::DevString argin)
{
	Tango::DevVarStringArray *argout;
	DEBUG_STREAM << "DataBase::DbGetDeviceExportedList()  - " << device_name << std::endl;
	/*----- PROTECTED REGION ID(DataBase::db_get_device_exported_list) ENABLED START -----*/

	Tango::DevString  filter = argin;
	TangoSys_MemStream sql_query_stream;
	std::string tmp_filter;
	MYSQL_RES *result;
	MYSQL_ROW row;
	int n_rows;

	TimeVal	before, after;
	GetTime(before);

	INFO_STREAM << "DataBase::db_get_device_exported_list(): filter " << filter << std::endl;

	if (filter == NULL)
	{
		sql_query_stream << "SELECT DISTINCT name FROM device WHERE name LIKE \"%\" AND exported=1 ORDER BY name";
	}
	else
	{
		tmp_filter = replace_wildcard(filter);
		sql_query_stream << "SELECT DISTINCT name FROM device WHERE (name LIKE \""
		                 << tmp_filter << "\" OR alias LIKE \"" << tmp_filter
						 << "\") AND exported=1 ORDER BY name";
	}
	DEBUG_STREAM << "DataBase::db_get_device_exported_list(): sql_query " << sql_query_stream.str() << std::endl;

	result = query(sql_query_stream.str(),"db_get_device_exported_list()");

	n_rows = mysql_num_rows(result);
	DEBUG_STREAM << "DataBase::db_get_device_exported_list(): mysql_num_rows() " << n_rows << std::endl;
	argout = new Tango::DevVarStringArray;

	if (n_rows > 0)
	{
	   argout->length(n_rows);

	   for (int i=0; i<n_rows; i++)
	   {
	      if ((row = mysql_fetch_row(result)) != NULL)
	      {
	         DEBUG_STREAM << "DataBase::db_get_device_exported_list(): device_list[ "<< i << "] alias " << row[0] << std::endl;
	         (*argout)[i]   = CORBA::string_dup(row[0]);
	      }
	   }
	}
	else
		argout->length(0);
	mysql_free_result(result);

	GetTime(after);
	update_timing_stats(before, after, "DbGetDeviceExportedList");

	/*----- PROTECTED REGION END -----*/	//	DataBase::db_get_device_exported_list
	return argout;
}
//--------------------------------------------------------
/**
 *	Command DbGetDeviceFamilyList related method
 *	Description: Get a list of device name families for device name matching the
 *               specified wildcard
 *
 *	@param argin The wildcard
 *	@returns Family list
 */
//--------------------------------------------------------
Tango::DevVarStringArray *DataBase::db_get_device_family_list(Tango::DevString argin)
{
	Tango::DevVarStringArray *argout;
	DEBUG_STREAM << "DataBase::DbGetDeviceFamilyList()  - " << device_name << std::endl;
	/*----- PROTECTED REGION ID(DataBase::db_get_device_family_list) ENABLED START -----*/

	Tango::DevString  wildcard = argin;
	TangoSys_MemStream	sql_query_stream;
	std::string tmp_wildcard;
	MYSQL_RES *result;
	MYSQL_ROW row;
	int n_rows;

	TimeVal	before, after;
	GetTime(before);


	INFO_STREAM << "DataBase::db_get_device_family_list(): wild card " << wildcard << std::endl;

	if (wildcard == NULL)
	{
		sql_query_stream << "SELECT DISTINCT family FROM device WHERE name LIKE \"%\" ORDER BY family";
	}
	else
	{
		tmp_wildcard = replace_wildcard(wildcard);
		sql_query_stream << "SELECT DISTINCT family FROM device WHERE name LIKE \""
		                 << tmp_wildcard << "\" OR alias LIKE \"" << tmp_wildcard
						 << "\" ORDER BY family";
	}
	DEBUG_STREAM << "DataBase::db_get_device_family_list(): sql_query " << sql_query_stream.str() << std::endl;

	result = query(sql_query_stream.str(),"db_get_device_family_list()");

	n_rows = mysql_num_rows(result);
	DEBUG_STREAM << "DataBase::db_get_device_family_list(): mysql_num_rows() " << n_rows << std::endl;
	argout = new Tango::DevVarStringArray;

	if (n_rows > 0)
	{
	   argout->length(n_rows);
	   for (int i=0; i<n_rows; i++)
	   {
	      if ((row = mysql_fetch_row(result)) != NULL)
	      {
	         DEBUG_STREAM << "DataBase::db_get_device_family_list(): family[ "<< i << "] " << row[0] << std::endl;
	         (*argout)[i] = CORBA::string_dup(row[0]);
	      }
	   }
	}
	else
		argout->length(0);
	mysql_free_result(result);

	GetTime(after);
	update_timing_stats(before, after, "DbGetDeviceFamilyList");

	/*----- PROTECTED REGION END -----*/	//	DataBase::db_get_device_family_list
	return argout;
}
//--------------------------------------------------------
/**
 *	Command DbGetDeviceInfo related method
 *	Description: Returns info from DbImportDevice and started/stopped dates.
 *
 *	@param argin Device name
 *	@returns Str[0] = Device name
 *           Str[1] = CORBA IOR
 *           Str[2] = Device version
 *           Str[3] = Device Server name
 *           Str[4] = Device Server process host name
 *           Str[5] = Started date (or ? if not set)
 *           Str[6] = Stopped date (or ? if not set)
 *           Str[7] = Device class
 *           
 *           Lg[0] = Device exported flag
 *           Lg[1] = Device Server process PID (or -1 if not set)
 */
//--------------------------------------------------------
Tango::DevVarLongStringArray *DataBase::db_get_device_info(Tango::DevString argin)
{
	Tango::DevVarLongStringArray *argout;
	DEBUG_STREAM << "DataBase::DbGetDeviceInfo()  - " << device_name << std::endl;
	/*----- PROTECTED REGION ID(DataBase::db_get_device_info) ENABLED START -----*/

	TangoSys_MemStream sql_query_stream;
	MYSQL_RES *result;
	MYSQL_ROW row;
	int n_rows=0;
	int exported, pid;
	std::string tmp_device;

	INFO_STREAM << "DataBase::ImportDevice(): get import info for " << argin << " device " << std::endl;

	tmp_device = argin;
	for (unsigned int i=0; i<tmp_device.size(); i++) {
		tmp_device[i] = tolower(tmp_device[i]);
	}

	sql_query_stream << "SELECT exported,ior,version,pid,server,host,started,stopped,class FROM device WHERE name = '"
	                 << tmp_device << "' or alias = '" << tmp_device << "';";
	DEBUG_STREAM << "DataBase::ImportDevice(): sql_query " << sql_query_stream.str() << std::endl;

	result = query(sql_query_stream.str(),"db_get_device_info()");

	n_rows = mysql_num_rows(result);
	DEBUG_STREAM << "DataBase::ImportDeviceList(): mysql_num_rows() " << n_rows << std::endl;

	argout = new Tango::DevVarLongStringArray;
	if (n_rows > 0)
	{

	   if ((row = mysql_fetch_row(result)) != NULL)
	   {
	      DEBUG_STREAM << "DataBase::ImportDeviceList():  exported " << row[0] << " version " << row[2] << " server " << row[4] << " host " << row[5] << std::endl;
	   	  int n_svalues=0, n_lvalues=0;
	      n_svalues = 8;
		  if ((row[4] == NULL) || (row[5] == NULL))
		  {
	         TangoSys_OMemStream o;
			 o << "Wrong info in database for device " << tmp_device;
			 o << "Database entry seems corrupted (server or host column NULL)" << std::ends;
	    	 mysql_free_result(result);
			 delete argout;
	    	 Tango::Except::throw_exception(DB_DeviceNotDefined,
								            o.str(),
								            "DataBase::GetDeviceInfo()");
		  }
	      (argout->svalue).length(n_svalues);
	      (argout->svalue)[0] = CORBA::string_dup(tmp_device.c_str());
	      (argout->svalue)[2] = CORBA::string_dup(row[2]);
	      (argout->svalue)[3] = CORBA::string_dup(row[4]);
	      (argout->svalue)[4] = CORBA::string_dup(row[5]);
		  (argout->svalue)[7] = CORBA::string_dup(row[8]);
			//	IOR Check
		  if (row[1]!=NULL)
	      	(argout->svalue)[1] = CORBA::string_dup(row[1]);
		  else
	      	(argout->svalue)[1] = CORBA::string_dup("");

		//	Convert date format
		char	*format = (char *)"%D %M %Y at %H:%i:%s";
		MYSQL_RES *result2;
		MYSQL_ROW row2;
		for (int x=0 ; x<2 ; x++)
		{
			if (row[x+6]!=NULL)
			{
				sql_query_stream.str("");
				sql_query_stream << "SELECT DATE_FORMAT(\'" << row[x+6] << "\',\'" << format << "\')";
				result2 = query(sql_query_stream.str(),"db_get_device_info()");
				int nb = mysql_num_rows(result2);
				if (nb > 0)
				{
					if ((row2 = mysql_fetch_row(result2)) != NULL && row2[0] != NULL) //add extra check for MySQL 5
						(argout->svalue)[5+x] = CORBA::string_dup(row2[0]);
					else (argout->svalue)[5+x] = CORBA::string_dup("?"); // empty date-> row2[0]==NULL !!!
				}
				else
					(argout->svalue)[5+x] = CORBA::string_dup("?");
             	mysql_free_result(result2);
			}
			else
				(argout->svalue)[5+x] = CORBA::string_dup("?");
		}



	      exported = -1;
	      if (row[0] != NULL)
	      {
	        exported = ParseString<int>(row[0]);
	      }
	      n_lvalues++;
	      (argout->lvalue).length(n_lvalues);
	      (argout->lvalue)[n_lvalues-1] = exported;
	      pid = -1;
	      if (row[3] != NULL)
	      {
	        pid = ParseString<int>(row[3]);
	      }
	      n_lvalues++;
	      (argout->lvalue).length(n_lvalues);
	      (argout->lvalue)[n_lvalues-1] = pid;
	   }
		else {
	    	 INFO_STREAM << "DataBase::ImportDevice(): info not defined !" << std::endl;
	         TangoSys_OMemStream o;
			 o << "device " << tmp_device << " import info not found in the database !";
	    	 mysql_free_result(result);
			 delete argout;
	    	 Tango::Except::throw_exception(DB_DeviceNotDefined,
								            o.str(),
								            "DataBase::GetDeviceInfo()");
		}
	}
	else {
	     INFO_STREAM << "DataBase::ImportDevice(): device not defined !" << std::endl;
         TangoSys_OMemStream o;
		 o << "device " << tmp_device << " not defined in the database !";
	     mysql_free_result(result);
		 delete argout;
	     Tango::Except::throw_exception(DB_DeviceNotDefined,
							            o.str(),
							            "DataBase::GetDeviceInfo()");
	}
	mysql_free_result(result);

	/*----- PROTECTED REGION END -----*/	//	DataBase::db_get_device_info
	return argout;
}
//--------------------------------------------------------
/**
 *	Command DbGetDeviceList related method
 *	Description: Get a list of devices for specified server and class.
 *
 *	@param argin argin[0] : server name
 *               argin[1] : class name
 *	@returns The list of devices for specified server and class.
 */
//--------------------------------------------------------
Tango::DevVarStringArray *DataBase::db_get_device_list(const Tango::DevVarStringArray *argin)
{
	Tango::DevVarStringArray *argout;
	DEBUG_STREAM << "DataBase::DbGetDeviceList()  - " << device_name << std::endl;
	/*----- PROTECTED REGION ID(DataBase::db_get_device_list) ENABLED START -----*/

	const Tango::DevVarStringArray  *server_class = argin;
	TangoSys_MemStream	sql_query_stream;
	MYSQL_RES *result;
	MYSQL_ROW row;
	int n_rows;
	std::string tmp_server;
	std::string tmp_class;

	if (server_class->length() != 2)
	{
	   WARN_STREAM << "DataBase::db_get_device_list(): incorrect number of input arguments " << std::endl;
	   Tango::Except::throw_exception(DB_IncorrectArguments,
	   				  "incorrect no. of input arguments, needs 2 (server,class)",
					  "DataBase::GetDeviceList()");
	}

	tmp_server = replace_wildcard((*server_class)[0]);
	tmp_class = replace_wildcard((*server_class)[1]);

	INFO_STREAM << "DataBase::GetClassList(): server " << tmp_server << std::endl;

	sql_query_stream << "SELECT DISTINCT name FROM device WHERE server LIKE \""
	                 << tmp_server << "\" AND class LIKE \"" << tmp_class << "\" ORDER BY name";
	DEBUG_STREAM << "DataBase::GetDeviceList(): sql_query " << sql_query_stream.str() << std::endl;

	result = query(sql_query_stream.str(),"db_get_device_list()");

	n_rows = mysql_num_rows(result);
	DEBUG_STREAM << "DataBase::GetDeviceList(): mysql_num_rows() " << n_rows << std::endl;
	argout = new Tango::DevVarStringArray;

	if (n_rows > 0)
	{
	   argout->length(n_rows);

	   for (int i=0; i<n_rows; i++)
	   {
	      if ((row = mysql_fetch_row(result)) != NULL)
	      {
	         DEBUG_STREAM << "DataBase::GetdeviceList(): row[ "<< i << "] name " << row[0] << std::endl;
	         (*argout)[i]   = CORBA::string_dup(row[0]);
	      }
	   }
	}
	else
		argout->length(0);
	mysql_free_result(result);

	/*----- PROTECTED REGION END -----*/	//	DataBase::db_get_device_list
	return argout;
}
//--------------------------------------------------------
/**
 *	Command DbGetDeviceWideList related method
 *	Description: Get a list of devices whose names satisfy the filter.
 *
 *	@param argin filter
 *	@returns list of exported devices
 */
//--------------------------------------------------------
Tango::DevVarStringArray *DataBase::db_get_device_wide_list(Tango::DevString argin)
{
	Tango::DevVarStringArray *argout;
	DEBUG_STREAM << "DataBase::DbGetDeviceWideList()  - " << device_name << std::endl;
	/*----- PROTECTED REGION ID(DataBase::db_get_device_wide_list) ENABLED START -----*/

	Tango::DevString  filter = argin;
	TangoSys_MemStream sql_query_stream;
	std::string tmp_filter;
	MYSQL_RES *result;
	MYSQL_ROW row;
	int n_rows;

	TimeVal	before, after;
	GetTime(before);

	INFO_STREAM << "DataBase::db_get_device_wide_list(): filter " << filter << std::endl;

	if (filter == NULL)
	{
		sql_query_stream << "SELECT DISTINCT name FROM device WHERE name LIKE \"%\" ORDER BY name";
	}
	else
	{
		tmp_filter = replace_wildcard(filter);
		sql_query_stream << "SELECT DISTINCT name FROM device WHERE name LIKE \""
		                 << tmp_filter << "\"  ORDER BY name";
	}
	DEBUG_STREAM << "DataBase::db_get_device_wide_list(): sql_query " << sql_query_stream.str() << std::endl;

	result = query(sql_query_stream.str(),"db_get_device_wide_list()");

	n_rows = mysql_num_rows(result);
	DEBUG_STREAM << "DataBase::db_get_device_wide_list(): mysql_num_rows() " << n_rows << std::endl;
	argout = new Tango::DevVarStringArray;

	if (n_rows > 0)
	{
	   argout->length(n_rows);

	   for (int i=0; i<n_rows; i++)
	   {
	      if ((row = mysql_fetch_row(result)) != NULL)
	      {
	         DEBUG_STREAM << "DataBase::db_get_device_wide_list(): device_list[ "<< i << "] alias " << row[0] << std::endl;
	         (*argout)[i]   = CORBA::string_dup(row[0]);
	      }
	   }
	}
	else
		argout->length(0);
	mysql_free_result(result);

	GetTime(after);

	/*----- PROTECTED REGION END -----*/	//	DataBase::db_get_device_wide_list
	return argout;
}
//--------------------------------------------------------
/**
 *	Command DbGetDeviceMemberList related method
 *	Description: Get a list of device name members for device name matching the
 *               specified filter
 *
 *	@param argin The filter
 *	@returns Device names member list
 */
//--------------------------------------------------------
Tango::DevVarStringArray *DataBase::db_get_device_member_list(Tango::DevString argin)
{
	Tango::DevVarStringArray *argout;
	DEBUG_STREAM << "DataBase::DbGetDeviceMemberList()  - " << device_name << std::endl;
	/*----- PROTECTED REGION ID(DataBase::db_get_device_member_list) ENABLED START -----*/

	Tango::DevString  wildcard = argin;
	TangoSys_MemStream	sql_query_stream;
	std::string tmp_wildcard;
	MYSQL_RES *result;
	MYSQL_ROW row;
	int n_rows;

	TimeVal	before, after;
	GetTime(before);


	INFO_STREAM << "DataBase::db_get_device_member_list(): wild card " << wildcard << std::endl;

	if (wildcard == NULL)
	{
		sql_query_stream << "SELECT DISTINCT member FROM device WHERE name LIKE \"%\" ORDER BY member";
	}
	else
	{
		tmp_wildcard = replace_wildcard(wildcard);
		sql_query_stream << "SELECT DISTINCT member FROM device WHERE name LIKE \""
		                 << tmp_wildcard << "\" OR alias LIKE \"" << tmp_wildcard
						 << "\" ORDER BY member";
	}
	DEBUG_STREAM << "DataBase::db_get_device_member_list(): sql_query " << sql_query_stream.str() << std::endl;

	result = query(sql_query_stream.str(),"db_get_device_member_list()");

	n_rows = mysql_num_rows(result);
	DEBUG_STREAM << "DataBase::db_get_device_member_list(): mysql_num_rows() " << n_rows << std::endl;
	argout = new Tango::DevVarStringArray;

	if (n_rows > 0)
	{
	   argout->length(n_rows);
	   for (int i=0; i<n_rows; i++)
	   {
	      if ((row = mysql_fetch_row(result)) != NULL)
	      {
	         DEBUG_STREAM << "DataBase::db_get_device_member_list(): member[ "<< i << "] " << row[0] << std::endl;
	         (*argout)[i] = CORBA::string_dup(row[0]);
	      }
	   }
	}
	else
		argout->length(0);
	mysql_free_result(result);

	GetTime(after);
	update_timing_stats(before, after, "DbGetDeviceMemberList");

	/*----- PROTECTED REGION END -----*/	//	DataBase::db_get_device_member_list
	return argout;
}
//--------------------------------------------------------
/**
 *	Command DbGetDeviceProperty related method
 *	Description: 
 *
 *	@param argin Str[0] = Device name
 *               Str[1] = Property name
 *               Str[n] = Property name
 *	@returns Str[0] = Device name
 *           Str[1] = Property number
 *           Str[2] = Property name
 *           Str[3] = Property value number (array case)
 *           Str[4] = Property value 1
 *           Str[n] = Property value n (array case)
 *           Str[n + 1] = Property name
 *           Str[n + 2] = Property value number (array case)
 *           Str[n + 3] = Property value 1
 *           Str[n + m] = Property value m
 */
//--------------------------------------------------------
Tango::DevVarStringArray *DataBase::db_get_device_property(const Tango::DevVarStringArray *argin)
{
	Tango::DevVarStringArray *argout;
	DEBUG_STREAM << "DataBase::DbGetDeviceProperty()  - " << device_name << std::endl;
	/*----- PROTECTED REGION ID(DataBase::db_get_device_property) ENABLED START -----*/

	const Tango::DevVarStringArray  *property_names = argin;
	TangoSys_MemStream	sql_query_stream;
	char n_rows_str[256];
	MYSQL_RES *result;
	MYSQL_ROW row;
	int n_rows=0, n_props=0;
	const char *tmp_device;
	std::string	tmp_name;
	std::string	prop_name;

	TimeVal	before, after;
	GetTime(before);

	if (property_names->length() < 2)
	{
	   WARN_STREAM << "DataBase::GetDeviceProperty(): incorrect number of input arguments " << std::endl;
	   Tango::Except::throw_exception(DB_IncorrectArguments,
	   				  "incorrect no. of input arguments, needs at least 2 (device,property)",
					  "DataBase::GetDeviceProperty()");
	}

	INFO_STREAM << "DataBase::GetDeviceProperty(): get " << property_names->length()-1 << " properties for device " << (*property_names)[0] << std::endl;

	argout = new Tango::DevVarStringArray;

	tmp_device = (*property_names)[0];
	n_props = 2;
	argout->length(n_props);
	(*argout)[0] = CORBA::string_dup(tmp_device);
	(*argout)[1] = to_corba_string(property_names->length() - 1);

	for (unsigned int i=1; i<property_names->length(); i++)
	{
	   prop_name = (*property_names)[i];
	   tmp_name = replace_wildcard((*property_names)[i]);
	   sql_query_stream.str("");
	   sql_query_stream << "SELECT count,value,name FROM property_device WHERE device = \""
	                    << tmp_device << "\" AND name LIKE \"" << tmp_name << "\" ORDER BY count";
	   DEBUG_STREAM << "DataBase::GetDeviceProperty(): sql_query " << sql_query_stream.str() << std::endl;

	   result = query(sql_query_stream.str(),"db_get_device_property()");

	   n_rows = mysql_num_rows(result);
	   DEBUG_STREAM << "DataBase::GetDeviceProperty(): mysql_num_rows() " << n_rows << std::endl;
	   sprintf(n_rows_str,"%d",n_rows);
	   n_props = n_props+2;
	   argout->length(n_props);
	   (*argout)[n_props-2] = CORBA::string_dup(prop_name.c_str());
       (*argout)[n_props-1] = CORBA::string_dup(n_rows_str);
	   if (n_rows > 0)
	   {

	      for (int j=0; j<n_rows; j++)
	      {
	         if ((row = mysql_fetch_row(result)) != NULL)
	         {
	            DEBUG_STREAM << "DataBase::GetDeviceProperty(): property[ "<< i << "] count " << row[0] << " value " << row[1] << std::endl;
		    	n_props++;
		    	argout->length(n_props);
	            (*argout)[n_props-1] = CORBA::string_dup(row[1]);
	         }
	      }
	   }
	   else
	   {
	      n_props++;
	      argout->length(n_props);
	      (*argout)[n_props-1] = CORBA::string_dup(" ");
	   }
	   mysql_free_result(result);
	}

	DEBUG_STREAM << "DataBase::GetDeviceProperty(): argout->length() "<< argout->length() << std::endl;

	GetTime(after);
	update_timing_stats(before, after, "DbGetDeviceProperty");

	/*----- PROTECTED REGION END -----*/	//	DataBase::db_get_device_property
	return argout;
}
//--------------------------------------------------------
/**
 *	Command DbGetDevicePropertyHist related method
 *	Description: Retrieve device  property history
 *
 *	@param argin Str[0] = Device name
 *               Str[2] = Property name
 *	@returns Str[0] = Property name
 *           Str[1] = date
 *           Str[2] = Property value number (array case)
 *           Str[3] = Property value 1
 *           Str[n] = Property value n
 */
//--------------------------------------------------------
Tango::DevVarStringArray *DataBase::db_get_device_property_hist(const Tango::DevVarStringArray *argin)
{
	Tango::DevVarStringArray *argout;
	DEBUG_STREAM << "DataBase::DbGetDevicePropertyHist()  - " << device_name << std::endl;
	/*----- PROTECTED REGION ID(DataBase::db_get_device_property_hist) ENABLED START -----*/

	TangoSys_MemStream	sql_query_stream;
	MYSQL_RES *ids;
	MYSQL_RES *result;
	MYSQL_ROW row;
	const char *tmp_device;
	std::string      tmp_name;

	if (argin->length() != 2)
	{
	   WARN_STREAM << "DataBase::GetDevicePropertyHist(): incorrect number of input arguments " << std::endl;
	   Tango::Except::throw_exception(DB_IncorrectArguments,
	   				  "incorrect no. of input arguments, needs 2 (device,property)",
					  "DataBase::GetDevicePropertyHist()");
	}

	argout = new Tango::DevVarStringArray;

	tmp_device = (*argin)[0];
	tmp_name   = replace_wildcard((*argin)[1]);

	// Get id list

    sql_query_stream << "SELECT DISTINCT id,date FROM property_device_hist WHERE device = \""
	                 << tmp_device << "\" AND name LIKE \"" << tmp_name << "\" ORDER by date ASC";

	{
		AutoLock al(this);

		ids = query(sql_query_stream.str(),"db_get_device_property_hist()",al.get_dch());

		// Retreive history
		int nb_item = 0;
		argout->length(0);

		for (unsigned int i=0; i<mysql_num_rows(ids); i++)
		{
		   row = mysql_fetch_row(ids);
		   Tango::DevULong64 id;
		   std::stringstream ss;
		   ss << row[0];
		   ss >> id;
		   sql_query_stream.str("");
		   sql_query_stream << "SELECT DATE_FORMAT(date,'%Y-%m-%d %H:%i:%s'),value,name,count FROM property_device_hist WHERE id = \""
	                    	<< id << "\" AND device = \"" << tmp_device << "\" ORDER BY count ASC";

		   result = query(sql_query_stream.str(),"db_get_device_property_hist()",al.get_dch());

		   int count = mysql_num_rows(result);

    	   row = mysql_fetch_row(result);
  		   int deleted = (atoi(row[3]) == 0); // count=0 for deleted property
  		   if(deleted) count = 0;
		   char n_rows_str[256];
		   sprintf(n_rows_str,"%d",count);

    	   argout->length(nb_item+3+count);
		   (*argout)[nb_item+0] = CORBA::string_dup(row[2]);
    	   (*argout)[nb_item+1] = CORBA::string_dup(row[0]);
    	   (*argout)[nb_item+2] = CORBA::string_dup(n_rows_str);

		   for(int j=0;j<count;j++) {
        	 (*argout)[nb_item+3+j] = CORBA::string_dup(row[1]);
        	 row = mysql_fetch_row(result);
		   }

		   nb_item += 3+count;
		   mysql_free_result(result);
		}
	}

	mysql_free_result(ids);

	/*----- PROTECTED REGION END -----*/	//	DataBase::db_get_device_property_hist
	return argout;
}
//--------------------------------------------------------
/**
 *	Command DbGetDevicePropertyList related method
 *	Description: Get property list belonging to the specified device and with
 *               name matching the specified filter
 *
 *	@param argin Str[0] = device name
 *               Str[1] = Filter
 *	@returns Property name list
 */
//--------------------------------------------------------
Tango::DevVarStringArray *DataBase::db_get_device_property_list(const Tango::DevVarStringArray *argin)
{
	Tango::DevVarStringArray *argout;
	DEBUG_STREAM << "DataBase::DbGetDevicePropertyList()  - " << device_name << std::endl;
	/*----- PROTECTED REGION ID(DataBase::db_get_device_property_list) ENABLED START -----*/

	const Tango::DevVarStringArray  *device_wildcard = argin;
	TangoSys_MemStream	sql_query_stream;
	MYSQL_RES *result;
	MYSQL_ROW row;
	int n_rows;
	const char *device,*wildcard;
	std::string tmp_wildcard;

	TimeVal	before, after;
	GetTime(before);


	device = (*device_wildcard)[0];
	wildcard = (*device_wildcard)[1];
	INFO_STREAM << "DataBase::db_get_device_property_list(): device " << device ;
	INFO_STREAM << " wildcard " << wildcard << std::endl;

	if (wildcard == NULL)
	{
		sql_query_stream << "SELECT name FROM property_device WHERE device=\"" << device
		                 << "\" AND name LIKE \"%\" AND count=1 ORDER BY name";
	}
	else
	{
		tmp_wildcard = replace_wildcard(wildcard);
		sql_query_stream << "SELECT name FROM property_device WHERE device=\"" << device
		                 << "\" AND name LIKE \"" << tmp_wildcard << "\" AND count=1 ORDER BY name";
	}
	DEBUG_STREAM << "DataBase::db_get_device_property_list(): sql_query " << sql_query_stream.str() << std::endl;

	result = query(sql_query_stream.str(),"db_get_device_property_list()");

	n_rows = mysql_num_rows(result);
	DEBUG_STREAM << "DataBase::db_get_device_property_list(): mysql_num_rows() " << n_rows << std::endl;
	argout = new Tango::DevVarStringArray;

	if (n_rows > 0)
	{
	   argout->length(n_rows);

	   for (int i=0; i<n_rows; i++)
	   {
	      if ((row = mysql_fetch_row(result)) != NULL)
	      {
	         DEBUG_STREAM << "DataBase::db_get_device_property_list(): property[ "<< i << "] alias " << row[0] << std::endl;
	         (*argout)[i]   = CORBA::string_dup(row[0]);
	      }
	   }
	}
	else
		argout->length(0);
	mysql_free_result(result);

	GetTime(after);
	update_timing_stats(before, after, "DbGetDevicePropertyList");

	/*----- PROTECTED REGION END -----*/	//	DataBase::db_get_device_property_list
	return argout;
}
//--------------------------------------------------------
/**
 *	Command DbGetDeviceServerClassList related method
 *	Description: Get list of Tango classes for a device server
 *
 *	@param argin device server process name
 *	@returns list of classes for this device server
 */
//--------------------------------------------------------
Tango::DevVarStringArray *DataBase::db_get_device_server_class_list(Tango::DevString argin)
{
	Tango::DevVarStringArray *argout;
	DEBUG_STREAM << "DataBase::DbGetDeviceServerClassList()  - " << device_name << std::endl;
	/*----- PROTECTED REGION ID(DataBase::db_get_device_server_class_list) ENABLED START -----*/

	Tango::DevString  server = argin;
	TangoSys_MemStream sql_query_stream;
	MYSQL_RES *result;
	MYSQL_ROW row;
	int n_rows;
	std::string tmp_server;

	INFO_STREAM << "DataBase::db_get_device_server_class_list(): server " << server << std::endl;

	tmp_server = replace_wildcard(server);
	sql_query_stream << "SELECT DISTINCT class FROM device WHERE server LIKE \"" << tmp_server
	                 << "\" ORDER BY class";
	DEBUG_STREAM << "DataBase::db_get_device_server_class_list(): sql_query " << sql_query_stream.str() << std::endl;

	result = query(sql_query_stream.str(),"db_get_device_server_class_list()");

	n_rows = mysql_num_rows(result);
	DEBUG_STREAM << "DataBase::db_get_device_server_class_list(): mysql_num_rows() " << n_rows << std::endl;
	argout = new Tango::DevVarStringArray;

	if (n_rows > 0)
	{
	   argout->length(n_rows);

	   for (int i=0; i<n_rows; i++)
	   {
	      if ((row = mysql_fetch_row(result)) != NULL)
	      {
	         DEBUG_STREAM << "DataBase::db_get_device_server_class_list(): row[ "<< i << "] class " << row[0] << std::endl;
	         (*argout)[i]   = CORBA::string_dup(row[0]);
	      }
	   }
	}
	else
		argout->length(0);
	mysql_free_result(result);

	/*----- PROTECTED REGION END -----*/	//	DataBase::db_get_device_server_class_list
	return argout;
}
//--------------------------------------------------------
/**
 *	Command DbGetExportdDeviceListForClass related method
 *	Description: Query the database for device exported for the specified class.
 *
 *	@param argin Class name
 *	@returns Device exported list
 */
//--------------------------------------------------------
Tango::DevVarStringArray *DataBase::db_get_exportd_device_list_for_class(Tango::DevString argin)
{
	Tango::DevVarStringArray *argout;
	DEBUG_STREAM << "DataBase::DbGetExportdDeviceListForClass()  - " << device_name << std::endl;
	/*----- PROTECTED REGION ID(DataBase::db_get_exportd_device_list_for_class) ENABLED START -----*/

	Tango::DevString  classname = argin;
	TangoSys_MemStream sql_query_stream;
	std::string tmp_classname;
	MYSQL_RES *result;
	MYSQL_ROW row;
	int n_rows;

	INFO_STREAM << "DataBase::db_get_device_exported_list(): classname " << classname << std::endl;

	if (classname == NULL)
	{
		sql_query_stream << "SELECT DISTINCT name FROM device WHERE class LIKE \"%\" AND exported=1 ORDER BY name";
	}
	else
	{
		tmp_classname = replace_wildcard(classname);
		sql_query_stream << "SELECT DISTINCT name FROM device WHERE class LIKE \"" << tmp_classname
		                 << "\" AND exported=1 ORDER BY name";
	}
	DEBUG_STREAM << "DataBase::db_get_device_exported_list(): sql_query " << sql_query_stream.str() << std::endl;

	result = query(sql_query_stream.str(),"db_get_exportd_device_list_for_class()");

	n_rows = mysql_num_rows(result);
	DEBUG_STREAM << "DataBase::db_get_device_exported_list(): mysql_num_rows() " << n_rows << std::endl;
	argout = new Tango::DevVarStringArray;

	if (n_rows > 0)
	{
	   argout->length(n_rows);

	   for (int i=0; i<n_rows; i++)
	   {
	      if ((row = mysql_fetch_row(result)) != NULL)
	      {
	         DEBUG_STREAM << "DataBase::db_get_device_exported_list(): device_list[ "<< i << "] alias " << row[0] << std::endl;
	         (*argout)[i]   = CORBA::string_dup(row[0]);
	      }
	   }
	}
	else
		argout->length(0);
	mysql_free_result(result);

	/*----- PROTECTED REGION END -----*/	//	DataBase::db_get_exportd_device_list_for_class
	return argout;
}
//--------------------------------------------------------
/**
 *	Command DbGetHostList related method
 *	Description: Get host list with name matching the specified filter
 *
 *	@param argin The filter
 *	@returns Host name list
 */
//--------------------------------------------------------
Tango::DevVarStringArray *DataBase::db_get_host_list(Tango::DevString argin)
{
	Tango::DevVarStringArray *argout;
	DEBUG_STREAM << "DataBase::DbGetHostList()  - " << device_name << std::endl;
	/*----- PROTECTED REGION ID(DataBase::db_get_host_list) ENABLED START -----*/

	Tango::DevString  wildcard = argin;
	TangoSys_MemStream	sql_query_stream;
	std::string tmp_wildcard;
	MYSQL_RES *result;
	MYSQL_ROW row;
	int n_rows;

	TimeVal	before, after;
	GetTime(before);


	INFO_STREAM << "DataBase::db_get_host_list(): wild card " << wildcard << std::endl;

	if (wildcard == NULL)
	{
		sql_query_stream << "SELECT DISTINCT host FROM device WHERE host LIKE \"%\" ORDER BY host";
	}
	else
	{
		tmp_wildcard = replace_wildcard(wildcard);
		sql_query_stream << "SELECT DISTINCT host FROM device WHERE host LIKE \"" << tmp_wildcard
		                 << "\" ORDER BY host";
	}
	DEBUG_STREAM << "DataBase::db_get_host_list(): sql_query " << sql_query_stream.str() << std::endl;

	result = query(sql_query_stream.str(),"db_get_host_list()");

	n_rows = mysql_num_rows(result);
	DEBUG_STREAM << "DataBase::db_get_host_list(): mysql_num_rows() " << n_rows << std::endl;
	argout = new Tango::DevVarStringArray;

	if (n_rows > 0)
	{
	   argout->length(n_rows);

	   for (int i=0; i<n_rows; i++)
	   {
	      if ((row = mysql_fetch_row(result)) != NULL)
	      {
	         DEBUG_STREAM << "DataBase::db_get_host_list(): host[ "<< i << "] alias " << row[0] << std::endl;
	         (*argout)[i]   = CORBA::string_dup(row[0]);
	      }
	   }
	}
	else
		argout->length(0);
	mysql_free_result(result);

	GetTime(after);
	update_timing_stats(before, after, "DbGetHostList");

	/*----- PROTECTED REGION END -----*/	//	DataBase::db_get_host_list
	return argout;
}
//--------------------------------------------------------
/**
 *	Command DbGetHostServerList related method
 *	Description: Get list of device server process name running on host with name matching
 *               the specified filter
 *
 *	@param argin The filter
 *	@returns Device server process name list
 */
//--------------------------------------------------------
Tango::DevVarStringArray *DataBase::db_get_host_server_list(Tango::DevString argin)
{
	Tango::DevVarStringArray *argout;
	DEBUG_STREAM << "DataBase::DbGetHostServerList()  - " << device_name << std::endl;
	/*----- PROTECTED REGION ID(DataBase::db_get_host_server_list) ENABLED START -----*/

	Tango::DevString  wildcard = argin;
	TangoSys_MemStream	sql_query_stream;
	std::string tmp_wildcard;
	MYSQL_RES *result;
	MYSQL_ROW row;
	int n_rows;

	TimeVal	before, after;
	GetTime(before);

	INFO_STREAM << "DataBase::db_get_host_server_list(): wild card " << wildcard << std::endl;

	if (wildcard == NULL)
	{
		sql_query_stream << "SELECT DISTINCT server FROM device WHERE host LIKE \"%\" ORDER BY server";
	}
	else
	{
		tmp_wildcard = replace_wildcard(wildcard);
		//	For compatibility reason between before and after Tang-5.2
		//	Will check with and without Fully Qualify Domain Name.
		sql_query_stream << "SELECT DISTINCT server FROM device WHERE (host LIKE \"" << tmp_wildcard
		                 << "\" or host LIKE \"" << tmp_wildcard << ".%%\") AND name LIKE \"dserver/%%\" ORDER BY server";
	}
	DEBUG_STREAM << "DataBase::db_get_host_server_list(): sql_query " << sql_query_stream.str() << std::endl;

	result = query(sql_query_stream.str(),"db_get_host_server_list()");

	n_rows = mysql_num_rows(result);
	DEBUG_STREAM << "DataBase::db_get_host_server_list(): mysql_num_rows() " << n_rows << std::endl;
	argout = new Tango::DevVarStringArray;

	if (n_rows > 0)
	{
	   argout->length(n_rows);

	   for (int i=0; i<n_rows; i++)
	   {
	      if ((row = mysql_fetch_row(result)) != NULL)
	      {
	         DEBUG_STREAM << "DataBase::db_get_host_server_list(): row[ "<< i << "] alias " << row[0] << std::endl;
	         (*argout)[i]   = CORBA::string_dup(row[0]);
	      }
	   }
	}
	else
		argout->length(0);
	mysql_free_result(result);

	GetTime(after);
	update_timing_stats(before, after, "DbGetHostServerList");

	/*----- PROTECTED REGION END -----*/	//	DataBase::db_get_host_server_list
	return argout;
}
//--------------------------------------------------------
/**
 *	Command DbGetHostServersInfo related method
 *	Description: Get info about all servers running on specified host, name, mode and level
 *
 *	@param argin Host name
 *	@returns Server info for all servers running on specified host
 */
//--------------------------------------------------------
Tango::DevVarStringArray *DataBase::db_get_host_servers_info(Tango::DevString argin)
{
	Tango::DevVarStringArray *argout;
	DEBUG_STREAM << "DataBase::DbGetHostServersInfo()  - " << device_name << std::endl;
	/*----- PROTECTED REGION ID(DataBase::db_get_host_servers_info) ENABLED START -----*/

	//- struct timeval	t0, t;
	//- gettimeofday(&t0, NULL);
	INFO_STREAM << "DataBase::db_get_host_servers_info(): entering... !" << std::endl;
	//	Get server list
	Tango::DevVarStringArray	*servers = db_get_host_server_list(argin);
	argout  = new Tango::DevVarStringArray();
	argout->length(servers->length()*3);
	int		idx = 0;
	for (unsigned int i=0 ; i<servers->length() ; i++)
	{
		//	Get info for each server
		Tango::DevVarStringArray	*info = db_get_server_info((*servers)[i]);
		(*argout)[idx++] = CORBA::string_dup((*servers)[i]);//	Server name
		(*argout)[idx++] = CORBA::string_dup((*info)[2]);	//	Controlled ?
		(*argout)[idx++] = CORBA::string_dup((*info)[3]);	//	Startup level
		delete info;
	}
	delete servers;

	//	Check execution duration
	//- gettimeofday(&t, NULL);
	//- WARN_STREAM << argin << "; " << 1000.0*(t.tv_sec - t0.tv_sec) +
	//-	((double)t.tv_usec - t0.tv_usec) / 1000 << " ms" << std::endl;

	/*----- PROTECTED REGION END -----*/	//	DataBase::db_get_host_servers_info
	return argout;
}
//--------------------------------------------------------
/**
 *	Command DbGetInstanceNameList related method
 *	Description: Returns the instance names found for specified server.
 *
 *	@param argin Server name
 *	@returns The instance names found for specified server.
 */
//--------------------------------------------------------
Tango::DevVarStringArray *DataBase::db_get_instance_name_list(Tango::DevString argin)
{
	Tango::DevVarStringArray *argout;
	DEBUG_STREAM << "DataBase::DbGetInstanceNameList()  - " << device_name << std::endl;
	/*----- PROTECTED REGION ID(DataBase::db_get_instance_name_list) ENABLED START -----*/

	//	Build a wildcard wing arg in
	char	*wildcard = new char[strlen(argin) + 3];
	strcpy(wildcard, argin);
	strcat(wildcard, "/*");
	Tango::DevVarStringArray *server_list = db_get_server_list(wildcard);

	std::vector<std::string>	instance_names;

	for (unsigned  int i=0 ; i<server_list->length() ; i++)
	{
		//	Take only server name
		std::string	str((*server_list)[i]);
		std::string::size_type	idx;
		if ((idx=str.find("/"))!= std::string::npos)
		{
			str = str.substr(idx+1);
			instance_names.push_back(str);
		}
	}
	delete server_list;
	//	copy result vector to arg out.
	argout = new Tango::DevVarStringArray;
	argout->length(instance_names.size());
	for (unsigned int i = 0 ; i<instance_names.size() ; i++)
	{
		std::string	name(instance_names[i]);
		(*argout)[i] = CORBA::string_dup(name.c_str());
	}
	delete [] wildcard;

	/*----- PROTECTED REGION END -----*/	//	DataBase::db_get_instance_name_list
	return argout;
}
//--------------------------------------------------------
/**
 *	Command DbGetObjectList related method
 *	Description: Get list of free object defined in database with name
 *               matching the specified filter
 *
 *	@param argin The filter
 *	@returns Object name list
 */
//--------------------------------------------------------
Tango::DevVarStringArray *DataBase::db_get_object_list(Tango::DevString argin)
{
	Tango::DevVarStringArray *argout;
	DEBUG_STREAM << "DataBase::DbGetObjectList()  - " << device_name << std::endl;
	/*----- PROTECTED REGION ID(DataBase::db_get_object_list) ENABLED START -----*/

	Tango::DevString  wildcard = argin;
	TangoSys_MemStream	sql_query_stream;
	MYSQL_RES *result;
	MYSQL_ROW row;
	int n_rows;
	std::string tmp_wildcard;

	INFO_STREAM << "DataBase::db_get_object_list(): object " << wildcard << std::endl;

	tmp_wildcard = replace_wildcard(wildcard);
	sql_query_stream << "SELECT DISTINCT object FROM property WHERE object LIKE \""
	                 << tmp_wildcard << "\" ORDER BY object";

	DEBUG_STREAM << "DataBase::db_get_object_list(): sql_query " << sql_query_stream.str() << std::endl;

	result = query(sql_query_stream.str(),"db_get_object_list()");

	n_rows = mysql_num_rows(result);
	DEBUG_STREAM << "DataBase::db_get_object_list(): mysql_num_rows() " << n_rows << std::endl;
	argout = new Tango::DevVarStringArray;

	if (n_rows > 0)
	{
	   argout->length(n_rows);

	   for (int i=0; i<n_rows; i++)
	   {
	      if ((row = mysql_fetch_row(result)) != NULL)
	      {
//	         DEBUG_STREAM << "DataBase::db_get_object_list(): object[ "<< i << "] object " << row[0] << std::endl;
	         (*argout)[i]   = CORBA::string_dup(row[0]);
	      }
	   }
	}
	else
		argout->length(0);
	mysql_free_result(result);

	/*----- PROTECTED REGION END -----*/	//	DataBase::db_get_object_list
	return argout;
}
//--------------------------------------------------------
/**
 *	Command DbGetProperty related method
 *	Description: Get free object property
 *
 *	@param argin Str[0] = Object name
 *               Str[1] = Property name
 *               Str[n] = Property name
 *	@returns Str[0] = Object name
 *           Str[1] = Property number
 *           Str[2] = Property name
 *           Str[3] = Property value number (array case)
 *           Str[4] = Property value 1
 *           Str[n] = Property value n (array case)
 *           Str[n + 1] = Property name
 *           Str[n + 2] = Property value number (array case)
 *           Str[n + 3] = Property value 1
 *           Str[n + m] = Property value m
 */
//--------------------------------------------------------
Tango::DevVarStringArray *DataBase::db_get_property(const Tango::DevVarStringArray *argin)
{
	Tango::DevVarStringArray *argout;
	DEBUG_STREAM << "DataBase::DbGetProperty()  - " << device_name << std::endl;
	/*----- PROTECTED REGION ID(DataBase::db_get_property) ENABLED START -----*/

	const Tango::DevVarStringArray  *property_names = argin;
	TangoSys_MemStream	sql_query_stream;
	char n_rows_str[256];
	MYSQL_RES *result;
	MYSQL_ROW row;
	int n_rows=0, n_props=0;
	argout = new Tango::DevVarStringArray;
	const char *tmp_object;
	std::string tmp_name;

	INFO_STREAM << "DataBase::db_get_property(): get " << property_names->length()-1 << " properties for object " << (*property_names)[0] << std::endl;

	tmp_object = (*property_names)[0];
	argout->length(2);
	(*argout)[0] = CORBA::string_dup(tmp_object);
	(*argout)[1] = to_corba_string(property_names->length() - 1);
	n_props = 2;

	for (unsigned int i=1; i<property_names->length(); i++)
	{
	   tmp_name = replace_wildcard((*property_names)[i]);
	   sql_query_stream.str("");
	   sql_query_stream << "SELECT count,value,name FROM property WHERE object = \"" << tmp_object <<
	                       "\" AND name LIKE \"" << tmp_name << "\" ORDER BY count";
	   DEBUG_STREAM << "DataBase::db_get_property(): sql_query " << sql_query_stream.str() << std::endl;

	   result = query(sql_query_stream.str(),"db_get_property()");

	   n_rows = mysql_num_rows(result);
	   DEBUG_STREAM << "DataBase::db_get_property(): mysql_num_rows() " << n_rows << std::endl;
	   sprintf(n_rows_str,"%d",n_rows);
	   n_props = n_props+2;
	   argout->length(n_props);
	   (*argout)[n_props-2] = CORBA::string_dup((*property_names)[i]);
           (*argout)[n_props-1] = CORBA::string_dup(n_rows_str);
	   if (n_rows > 0)
	   {
	      for (int j=0; j<n_rows; j++)
	      {
	         if ((row = mysql_fetch_row(result)) != NULL)
	         {
	            DEBUG_STREAM << "DataBase::db_get_property(): property[ "<< i << "] count " << row[0] << " value " << row[1] << std::endl;
		    	n_props++;
	   	    	argout->length(n_props);
	            (*argout)[n_props-1] = CORBA::string_dup(row[1]);
	         }
	      }
	   }
	   else
	   {
	      n_props++;
	      argout->length(n_props);
	      (*argout)[n_props-1] = CORBA::string_dup(" ");
	   }
	   mysql_free_result(result);
	}

	DEBUG_STREAM << "DataBase::db_get_property(): argout->length() "<< argout->length() << std::endl;

	/*----- PROTECTED REGION END -----*/	//	DataBase::db_get_property
	return argout;
}
//--------------------------------------------------------
/**
 *	Command DbGetPropertyHist related method
 *	Description: Retrieve object  property history
 *
 *	@param argin Str[0] = Object name
 *               Str[2] = Property name
 *	@returns Str[0] = Property name
 *           Str[1] = date
 *           Str[2] = Property value number (array case)
 *           Str[3] = Property value 1
 *           Str[n] = Property value n
 */
//--------------------------------------------------------
Tango::DevVarStringArray *DataBase::db_get_property_hist(const Tango::DevVarStringArray *argin)
{
	Tango::DevVarStringArray *argout;
	DEBUG_STREAM << "DataBase::DbGetPropertyHist()  - " << device_name << std::endl;
	/*----- PROTECTED REGION ID(DataBase::db_get_property_hist) ENABLED START -----*/

	TangoSys_MemStream	sql_query_stream;
	MYSQL_RES *ids;
	MYSQL_RES *result;
	MYSQL_ROW row;
	const char *tmp_object;
	std::string      tmp_name;

	if (argin->length() != 2)
	{
	   WARN_STREAM << "DataBase::DbGetPropertyHist(): incorrect number of input arguments " << std::endl;
	   Tango::Except::throw_exception(DB_IncorrectArguments,
	   				  "incorrect no. of input arguments, needs 2 (object,property)",
					  "DataBase::DbGetPropertyHist()");
	}

	argout = new Tango::DevVarStringArray;

	tmp_object  = (*argin)[0];
	tmp_name   = replace_wildcard((*argin)[1]);

	// Get id list

    sql_query_stream << "SELECT DISTINCT id,date FROM property_hist WHERE object = \""
	                 << tmp_object << "\" AND name LIKE \"" << tmp_name << "\" ORDER by date";

	{
		AutoLock al(this);

		ids = query(sql_query_stream.str(),"db_get_property_hist()",al.get_dch());

		// Retreive history
		int nb_item = 0;
		argout->length(0);

		for (unsigned int i=0; i<mysql_num_rows(ids); i++)
		{
		   row = mysql_fetch_row(ids);
		   Tango::DevULong64 id;
		   std::stringstream ss;
		   ss << row[0];
		   ss >> id;
		   sql_query_stream.str("");
		   sql_query_stream << "SELECT DATE_FORMAT(date,'%Y-%m-%d %H:%i:%s'),value,name,count FROM property_hist WHERE id = \""
	                    	<< id << "\" AND object = \"" << tmp_object << "\" ORDER BY count";

		   result = query(sql_query_stream.str(),"db_get_property_hist()",al.get_dch());

		   int count = mysql_num_rows(result);

    	   row = mysql_fetch_row(result);
  		   int deleted = (atoi(row[3]) == 0); // count=0 for deleted property
  		   if(deleted) count = 0;
		   char n_rows_str[256];
		   sprintf(n_rows_str,"%d",count);

    	   argout->length(nb_item+3+count);
		   (*argout)[nb_item+0] = CORBA::string_dup(row[2]);
    	   (*argout)[nb_item+1] = CORBA::string_dup(row[0]);
    	   (*argout)[nb_item+2] = CORBA::string_dup(n_rows_str);

		   for(int j=0;j<count;j++) {
        	 (*argout)[nb_item+3+j] = CORBA::string_dup(row[1]);
        	 row = mysql_fetch_row(result);
		   }

		   nb_item += 3+count;
		   mysql_free_result(result);
		}
	}

	mysql_free_result(ids);

	/*----- PROTECTED REGION END -----*/	//	DataBase::db_get_property_hist
	return argout;
}
//--------------------------------------------------------
/**
 *	Command DbGetPropertyList related method
 *	Description: Get list of property defined for a free object and matching the
 *               specified filter
 *
 *	@param argin Str[0] = Object name
 *               Str[1] = filter
 *	@returns Property name list
 */
//--------------------------------------------------------
Tango::DevVarStringArray *DataBase::db_get_property_list(const Tango::DevVarStringArray *argin)
{
	Tango::DevVarStringArray *argout;
	DEBUG_STREAM << "DataBase::DbGetPropertyList()  - " << device_name << std::endl;
	/*----- PROTECTED REGION ID(DataBase::db_get_property_list) ENABLED START -----*/

	const Tango::DevVarStringArray  *object_wildcard = argin;
	TangoSys_MemStream	sql_query_stream;
	MYSQL_RES *result;
	MYSQL_ROW row;
	int n_rows;
	const char *object, *wildcard;
	std::string tmp_wildcard;

	if (object_wildcard->length() != 2)
	{
	   WARN_STREAM << "DataBase::db_get_property_list(): incorrect number of input arguments " << std::endl;
	   Tango::Except::throw_exception(DB_IncorrectArguments,
	   				  "incorrect no. of input arguments, needs 2 (object,wildcard)",
					  "DataBase::GetPropertyList()");
	}
	object = (*object_wildcard)[0];
	wildcard = (*object_wildcard)[1];

	INFO_STREAM << "DataBase::db_get_property_list(): object " << object << std::endl;

	if (object == NULL)
	{
		sql_query_stream << "SELECT DISTINCT name FROM property WHERE object LIKE \"%\" ORDER BY name";
	}
	else
	{
		tmp_wildcard = replace_wildcard(wildcard);
		sql_query_stream << "SELECT DISTINCT name FROM property WHERE object LIKE \"" << object <<
		                    "\" AND name LIKE \"" << tmp_wildcard << "\" ORDER BY name";
	}
	DEBUG_STREAM << "DataBase::db_get_property_list(): sql_query " << sql_query_stream.str() << std::endl;

    result = query( sql_query_stream.str() , "db_get_property_list()");

	n_rows = mysql_num_rows(result);
	DEBUG_STREAM << "DataBase::db_get_property_list(): mysql_num_rows() " << n_rows << std::endl;
	argout = new Tango::DevVarStringArray;

	if (n_rows > 0)
	{
	   argout->length(n_rows);

	   for (int i=0; i<n_rows; i++)
	   {
	      if ((row = mysql_fetch_row(result)) != NULL)
	      {
	         DEBUG_STREAM << "DataBase::db_get_property_list(): property[ "<< i << "] property " << row[0] << std::endl;
	         (*argout)[i]   = CORBA::string_dup(row[0]);
	      }
	   }
	}
	else
		argout->length(0);
	mysql_free_result(result);

	/*----- PROTECTED REGION END -----*/	//	DataBase::db_get_property_list
	return argout;
}
//--------------------------------------------------------
/**
 *	Command DbGetServerInfo related method
 *	Description: Get info about host, mode and level for specified server
 *
 *	@param argin server name
 *	@returns server info
 */
//--------------------------------------------------------
Tango::DevVarStringArray *DataBase::db_get_server_info(Tango::DevString argin)
{
	Tango::DevVarStringArray *argout;
	DEBUG_STREAM << "DataBase::DbGetServerInfo()  - " << device_name << std::endl;
	/*----- PROTECTED REGION ID(DataBase::db_get_server_info) ENABLED START -----*/

	Tango::DevString  server_name = argin;
	TangoSys_MemStream sql_query_stream;
	MYSQL_RES *result;
	MYSQL_ROW row;
	int n_rows=0;
	argout = new Tango::DevVarStringArray;
	std::string tmp_name;

	INFO_STREAM << "DataBase::db_get_server_info(): server " << server_name << std::endl;

	argout->length(4);
	(*argout)[0] = CORBA::string_dup(server_name);

//	tmp_name = replace_wildcard(server_name);
    sql_query_stream << "SELECT host,mode,level FROM server WHERE name = '" << server_name << "';";
	DEBUG_STREAM << "DataBase::db_get_server_info(): sql_query " << sql_query_stream.str() << std::endl;

	result = query(sql_query_stream.str(),"db_get_server_info()");

	n_rows = mysql_num_rows(result);
	DEBUG_STREAM << "DataBase::db_get_server_info(): mysql_num_rows() " << n_rows << std::endl;
	if (n_rows > 0)
	{
	   if ((row = mysql_fetch_row(result)) != NULL)
	   {
	      DEBUG_STREAM << "DataBase::db_get_server_info(): host "<< row[0] << " mode " << row[1] << " level " << row[2] << std::endl;
	      (*argout)[1] = CORBA::string_dup(row[0]);
	      (*argout)[2] = CORBA::string_dup(row[1]);
	      (*argout)[3] = CORBA::string_dup(row[2]);
	   }
	}
	else
	{
	   (*argout)[1] = CORBA::string_dup(" ");
	   (*argout)[2] = CORBA::string_dup(" ");
	   (*argout)[3] = CORBA::string_dup(" ");
	}
	mysql_free_result(result);

	/*----- PROTECTED REGION END -----*/	//	DataBase::db_get_server_info
	return argout;
}
//--------------------------------------------------------
/**
 *	Command DbGetServerList related method
 *	Description: Get list of device server process defined in database
 *               with name matching the specified filter
 *
 *	@param argin The filter
 *	@returns Device server process name list
 */
//--------------------------------------------------------
Tango::DevVarStringArray *DataBase::db_get_server_list(Tango::DevString argin)
{
	Tango::DevVarStringArray *argout;
	DEBUG_STREAM << "DataBase::DbGetServerList()  - " << device_name << std::endl;
	/*----- PROTECTED REGION ID(DataBase::db_get_server_list) ENABLED START -----*/

	Tango::DevString  wildcard = argin;
	TangoSys_MemStream	sql_query_stream;
	std::string tmp_wildcard;
	MYSQL_RES *result;
	MYSQL_ROW row;
	int n_rows;

	TimeVal	before, after;
	GetTime(before);


	INFO_STREAM << "DataBase::db_get_server_list(): wild card " << wildcard << std::endl;

	if (wildcard == NULL)
	{
		sql_query_stream << "SELECT DISTINCT server FROM device WHERE server LIKE \"%\" ORDER BY server";
	}
	else
	{
		tmp_wildcard = replace_wildcard(wildcard);
		sql_query_stream << "SELECT DISTINCT server FROM device WHERE server LIKE \""
		                 << tmp_wildcard << "\" ORDER BY server";
	}
	DEBUG_STREAM << "DataBase::db_get_server_list(): sql_query " << sql_query_stream.str() << std::endl;

	result = query(sql_query_stream.str(),"db_get_server_list()");

	n_rows = mysql_num_rows(result);
	DEBUG_STREAM << "DataBase::db_get_server_list(): mysql_num_rows() " << n_rows << std::endl;
	argout = new Tango::DevVarStringArray;

	if (n_rows > 0)
	{
	   argout->length(n_rows);

	   for (int i=0; i<n_rows; i++)
	   {
	      if ((row = mysql_fetch_row(result)) != NULL)
	      {
//	         DEBUG_STREAM << "DataBase::db_get_server_list(): server[ "<< i << "] alias " << row[0] << std::endl;
	         (*argout)[i]   = CORBA::string_dup(row[0]);
	      }
	   }
	}
	else
		argout->length(0);
	mysql_free_result(result);

	GetTime(after);
	update_timing_stats(before, after, "DbGetServerList");

	/*----- PROTECTED REGION END -----*/	//	DataBase::db_get_server_list
	return argout;
}
//--------------------------------------------------------
/**
 *	Command DbGetServerNameList related method
 *	Description: Returns the list of server names found for the wildcard specified.
 *               It returns only the server executable name without instance name as DbGetServerList.
 *
 *	@param argin wildcard for server names.
 *	@returns server names found.
 */
//--------------------------------------------------------
Tango::DevVarStringArray *DataBase::db_get_server_name_list(Tango::DevString argin)
{
	Tango::DevVarStringArray *argout;
	DEBUG_STREAM << "DataBase::DbGetServerNameList()  - " << device_name << std::endl;
	/*----- PROTECTED REGION ID(DataBase::db_get_server_name_list) ENABLED START -----*/

	Tango::DevString  wildcard = argin;
	Tango::DevVarStringArray *server_list = db_get_server_list(wildcard);

	std::vector<std::string>	server_names;
	for (unsigned int i = 0 ; i<server_list->length() ; i++)
	{
		//	Take only server name
		std::string	str((*server_list)[i]);
		std::string::size_type	idx;
		if ((idx=str.find("/"))!= std::string::npos)
		{
			str = str.substr(0, idx);
			//	Search if already in vector
			bool	found = false;
			for(unsigned int j=0 ; j<server_names.size() && !found ; j++)
			{
				std::string	name(server_names[j]);
				//	compare without case sensitive
				found = (name.size() ==  str.size()  &&   //	ensure same size
						equal (name.begin(), name.end(),  //	server name from vector
								str.begin(),              //	server name from db
								nocase_compare));         //	case insensitive
			}
			//	if not already in vector, put in
			if (!found)
				server_names.push_back(str);
		}
	}

	//	copy result vector to arg out.
	argout = new Tango::DevVarStringArray;
	argout->length(server_names.size());
	for (unsigned int i = 0 ; i<server_names.size() ; i++)
	{
		std::string	name(server_names[i]);
		(*argout)[i] = CORBA::string_dup(name.c_str());
	}

	delete server_list;

	/*----- PROTECTED REGION END -----*/	//	DataBase::db_get_server_name_list
	return argout;
}
//--------------------------------------------------------
/**
 *	Command DbImportDevice related method
 *	Description: Import a device from the database
 *
 *	@param argin Device name (or alias)
 *	@returns Str[0] = device name
 *           Str[1] = CORBA IOR
 *           Str[2] = device version
 *           Str[3] = device server process name
 *           Str[4] = host name
 *           Str[5] = Tango class name
 *           
 *           Lg[0] = Exported flag
 *           Lg[1] = Device server process PID
 */
//--------------------------------------------------------
Tango::DevVarLongStringArray *DataBase::db_import_device(Tango::DevString argin)
{
	Tango::DevVarLongStringArray *argout;
	DEBUG_STREAM << "DataBase::DbImportDevice()  - " << device_name << std::endl;
	/*----- PROTECTED REGION ID(DataBase::db_import_device) ENABLED START -----*/

	Tango::DevString  devname = argin;
	/*
	static TimeVal	t0;
	TimeVal	t1;
	GetTime(t1);
	TANGO_LOG << Elapsed(t0, t1) << "   " ;
	GetTime(t0);
	*/
	TangoSys_MemStream sql_query_stream;
	MYSQL_RES *result;
	MYSQL_ROW row;
	int n_rows=0;
	int exported, pid;
	std::string tmp_device;

	TimeVal	before, after;
	GetTime(before);

	INFO_STREAM << "DataBase::ImportDevice(): get import info for " << devname << " device " << std::endl;

	tmp_device = devname;
	for (unsigned int i=0; i<tmp_device.size(); i++) {
		tmp_device[i] = tolower(tmp_device[i]);
	}
//	tmp_device = replace_wildcard(tmp_device.c_str());

// the following query takes too long because the use of OR in the SELECT means the
// indices cannot be used by mysql. therefore do the SELECT in two stages - andy 31may05

//	sprintf(sql_query,"SELECT exported,ior,version,pid,server,host FROM device WHERE name = '%s' or alias = '%s';",
//	        tmp_device.c_str(),tmp_device.c_str());

	{
		AutoLock al(this);

		sql_query_stream << "SELECT exported,ior,version,pid,server,host,class FROM device WHERE name = '"
	                 	<< tmp_device << "';";
		DEBUG_STREAM << "DataBase::ImportDevice(): sql_query " << sql_query_stream.str() << std::endl;

		result = query(sql_query_stream.str(),"db_import_device()",al.get_dch());

		n_rows = mysql_num_rows(result);
		DEBUG_STREAM << "DataBase::ImportDevice(): mysql_num_rows() " << n_rows << std::endl;

		if (n_rows <= 0)
		{
//
// could not find device by name, try to look for by alias
//
   			INFO_STREAM << "DataBase::ImportDevice(): could not find device by name, look for alias !" << std::endl;
			mysql_free_result(result);
			sql_query_stream.str("");
			sql_query_stream << "SELECT exported,ior,version,pid,server,host,class FROM device WHERE alias = '"
		                	 << tmp_device << "';";
			DEBUG_STREAM << "DataBase::ImportDevice(): sql_query " << sql_query_stream.str() << std::endl;

 	    	result = query(sql_query_stream.str(),"db_import_device()",al.get_dch());

			n_rows = mysql_num_rows(result);
			DEBUG_STREAM << "DataBase::ImportDevice(): mysql_num_rows() " << n_rows << std::endl;
		}
	}


	argout = new Tango::DevVarLongStringArray;
	if (n_rows > 0)
	{

	   if ((row = mysql_fetch_row(result)) != NULL)
	   {
		  int n_svalues=0, n_lvalues=0;
	      DEBUG_STREAM << "DataBase::ImportDevice(): device exported " << row[0] << " version " << row[2] << " server " << row[4] << " host " << row[5] << std::endl;
	      n_svalues = n_svalues+6;
	      (argout->svalue).length(n_svalues);
	      (argout->svalue)[n_svalues-6] = CORBA::string_dup(tmp_device.c_str());
	      (argout->svalue)[n_svalues-4] = CORBA::string_dup(row[2]);
	      (argout->svalue)[n_svalues-3] = CORBA::string_dup(row[4]);
	      (argout->svalue)[n_svalues-2] = CORBA::string_dup(row[5]);
		  (argout->svalue)[n_svalues-1] = CORBA::string_dup(row[6]);
			//	IOR Check
		  if (row[1]!=NULL)
	     	(argout->svalue)[n_svalues-5] = CORBA::string_dup(row[1]);
		  else
		  	(argout->svalue)[n_svalues-5] = CORBA::string_dup("");
	      exported = -1;
	      if (row[0] != NULL)
	      {
	        exported = ParseString<int>(row[0]);
	      }
	      n_lvalues++;
	      (argout->lvalue).length(n_lvalues);
	      (argout->lvalue)[n_lvalues-1] = exported;
	      pid = -1;
	      if (row[3] != NULL)
	      {
	        pid = ParseString<int>(row[3]);
	      }
	      n_lvalues++;
	      (argout->lvalue).length(n_lvalues);
	      (argout->lvalue)[n_lvalues-1] = pid;
	   }
		else {
	    	 INFO_STREAM << "DataBase::ImportDevice(" << tmp_device << "): info not defined !" << std::endl;
	    	 mysql_free_result(result);
		     delete argout;
	    	 Tango::Except::throw_exception(DB_DeviceNotDefined,
								"Device import info not found in the database !",
								"DataBase::ImportDevice()");
		}
	}
	else {
	     INFO_STREAM << "DataBase::ImportDevice(" << tmp_device << "): device not defined !" << std::endl;
 	 	 TangoSys_OMemStream o;
		 o << "device " << tmp_device << " not defined in the database !";
	     mysql_free_result(result);
	     delete argout;
	     Tango::Except::throw_exception(DB_DeviceNotDefined,
							            o.str(),
							            "DataBase::ImportDevice()");
	}
	mysql_free_result(result);
	/*
	 * calculate elapsed time and update timing variables
	 */
	GetTime(after);
	update_timing_stats(before, after, "DbImportDevice");

	/*----- PROTECTED REGION END -----*/	//	DataBase::db_import_device
	return argout;
}
//--------------------------------------------------------
/**
 *	Command DbImportEvent related method
 *	Description: Get event channel info from database
 *
 *	@param argin name of event channel or factory
 *	@returns export information e.g. IOR
 */
//--------------------------------------------------------
Tango::DevVarLongStringArray *DataBase::db_import_event(Tango::DevString argin)
{
	Tango::DevVarLongStringArray *argout;
	DEBUG_STREAM << "DataBase::DbImportEvent()  - " << device_name << std::endl;
	/*----- PROTECTED REGION ID(DataBase::db_import_event) ENABLED START -----*/

	Tango::DevString  event_name = argin;
	TangoSys_MemStream sql_query_stream;
	MYSQL_RES *result;
	MYSQL_ROW row;
	int n_rows=0;
	int exported, pid;
	std::string tmp_event;

	TimeVal	before, after;
	GetTime(before);

	INFO_STREAM << "DataBase::db_import_event(): get import info for " << event_name << std::endl;

	tmp_event = event_name;
	for (unsigned int i=0; i<tmp_event.size(); i++) {
		tmp_event[i] = tolower(tmp_event[i]);
	}
	tmp_event = replace_wildcard(tmp_event.c_str());

    sql_query_stream << "SELECT exported,ior,version,pid,host FROM event WHERE name = '" << tmp_event << "';";
	DEBUG_STREAM  << "DataBase::db_import_event(): sql_query " << sql_query_stream.str() << std::endl;

	result = query(sql_query_stream.str(),"db_import_event()");

	n_rows = mysql_num_rows(result);
	DEBUG_STREAM << "DataBase::db_import_event(): mysql_num_rows() " << n_rows << std::endl;

	argout = new Tango::DevVarLongStringArray;
	if (n_rows > 0)
	{

	   if ((row = mysql_fetch_row(result)) != NULL)
	   {
		  int n_svalues=0, n_lvalues=0;
	      DEBUG_STREAM << "DataBase::db_import_event(): device exported " << row[0] << " IOR  " << row[1] << " version " << row[2] << std::endl;
	      n_svalues = n_svalues+4;
	      (argout->svalue).length(n_svalues);
	      (argout->svalue)[n_svalues-4] = CORBA::string_dup(tmp_event.c_str());
	      (argout->svalue)[n_svalues-3] = CORBA::string_dup(row[1]);
	      (argout->svalue)[n_svalues-2] = CORBA::string_dup(row[2]);
	      (argout->svalue)[n_svalues-1] = CORBA::string_dup(row[4]);
	      exported = -1;
	      if (row[0] != NULL)
	      {
	        exported = ParseString<int>(row[0]);
	      }
	      n_lvalues++;
	      (argout->lvalue).length(n_lvalues);
	      (argout->lvalue)[n_lvalues-1] = exported;
	      pid = -1;
	      if (row[3] != NULL)
	      {
	        pid = ParseString<int>(row[3]);
	      }
	      n_lvalues++;
	      (argout->lvalue).length(n_lvalues);
	      (argout->lvalue)[n_lvalues-1] = pid;
	   }
	}
	else {
	     INFO_STREAM << "DataBase::db_import_event(): event not defined !" << std::endl;
   	 	 TangoSys_OMemStream o;
		 o << "event " << tmp_event << " not defined in the database !";
	     mysql_free_result(result);
		 delete argout;
	     Tango::Except::throw_exception(DB_DeviceNotDefined,
	     				                o.str(),
					                    "DataBase::db_import_event()");
	}
	mysql_free_result(result);

	GetTime(after);
	update_timing_stats(before, after, "DbImportEvent");

	/*----- PROTECTED REGION END -----*/	//	DataBase::db_import_event
	return argout;
}
//--------------------------------------------------------
/**
 *	Command DbInfo related method
 *	Description: Get miscellaneous numbers on information
 *               stored in database
 *
 *	@returns Miscellaneous info like:
 *           - Device defined in database
 *           - Device marked as exported in database
 *           - Device server process defined in database
 *           - Device server process marked as exported in database
 *           - Device properties defined in database
 *           - Class properties defined in database
 *           - Device attribute properties defined in database
 *           - Class attribute properties defined in database
 *           - Object properties defined in database
 */
//--------------------------------------------------------
Tango::DevVarStringArray *DataBase::db_info()
{
	Tango::DevVarStringArray *argout;
	DEBUG_STREAM << "DataBase::DbInfo()  - " << device_name << std::endl;
	/*----- PROTECTED REGION ID(DataBase::db_info) ENABLED START -----*/

	TangoSys_MemStream	sql_query_stream;
	char info_str[256];
	char info2_str[256];
	MYSQL_RES *result;
	MYSQL_ROW row;
	int n_rows=0, n_infos=0;
	argout = new Tango::DevVarStringArray;

	TimeVal	before, after;
	GetTime(before);


	INFO_STREAM << "DataBase::db_info(): get general database infos" << std::endl;

	sprintf(info_str,"TANGO Database %s",DataBase::db_name.c_str());
	n_infos = 1;
	argout->length(n_infos);
	(*argout)[n_infos-1] = CORBA::string_dup(info_str);

// newline

	n_infos++;
	argout->length(n_infos);
	(*argout)[n_infos-1] = CORBA::string_dup(" ");

// get start time of database

	sql_query_stream << "SELECT started FROM device WHERE name = \"" << DataBase::db_name << "\" ";
//	DEBUG_STREAM << "DataBase::db_info(): sql_query " << sql_query_stream.str() << std::endl;

    result = query(sql_query_stream.str(),"db_info()");

	sprintf(info_str,"Running since ...");
	n_rows = mysql_num_rows(result);
	if (n_rows > 0)
	{
	   if ((row = mysql_fetch_row(result)) != NULL)
	   {
	      DEBUG_STREAM << "DataBase::db_info(): database started " << row[0] << std::endl;
	      sprintf(info_str,"Running since %s",row[0]);
	   }
	}
	mysql_free_result(result);
	n_infos++;
	argout->length(n_infos);
	(*argout)[n_infos-1] = CORBA::string_dup(info_str);

// newline

	n_infos++;
	argout->length(n_infos);
	(*argout)[n_infos-1] = CORBA::string_dup(" ");

// get number of devices defined
	sql_query_stream.str("");
	sql_query_stream << "SELECT COUNT(*) FROM device ";
//	DEBUG_STREAM << "DataBase::db_info(): sql_query " << sql_query_stream.str() << std::endl;

    result = query(sql_query_stream.str(),"db_info()");

	sprintf(info_str,"Devices defined ...");
	n_rows = mysql_num_rows(result);
	if (n_rows > 0)
	{
	   if ((row = mysql_fetch_row(result)) != NULL)
	   {
	      DEBUG_STREAM << "DataBase::db_info(): no. of devices " << row[0] << std::endl;
	      sprintf(info_str,"Devices defined  = %s",row[0]);
	   }
	}
	mysql_free_result(result);
	n_infos++;
	argout->length(n_infos);
	(*argout)[n_infos-1] = CORBA::string_dup(info_str);

// get number of devices exported

	sql_query_stream.str("");
	sql_query_stream << "SELECT COUNT(*) FROM device WHERE exported = 1 ";
//	DEBUG_STREAM << "DataBase::db_info(): sql_query " << sql_query_stream.str() << std::endl;

    result = query(sql_query_stream.str(),"db_info()");

	sprintf(info_str,"Devices exported ...");
	n_rows = mysql_num_rows(result);
	if (n_rows > 0)
	{
	   if ((row = mysql_fetch_row(result)) != NULL)
	   {
	      DEBUG_STREAM << "DataBase::db_info(): no. of devices exported " << row[0] << std::endl;
	      sprintf(info_str,"Devices exported  = %s",row[0]);
	   }
	}
	mysql_free_result(result);
	n_infos++;
	argout->length(n_infos);
	(*argout)[n_infos-1] = CORBA::string_dup(info_str);

// get number of devices servers defined

	sql_query_stream.str("");
	sql_query_stream << "SELECT COUNT(*) FROM device WHERE class = \"DServer\" ";
//	DEBUG_STREAM << "DataBase::db_info(): sql_query " << sql_query_stream.str() << std::endl;

    result = query(sql_query_stream.str(),"db_info()");

	sprintf(info_str,"Device servers defined ...");
	n_rows = mysql_num_rows(result);
	if (n_rows > 0)
	{
	   if ((row = mysql_fetch_row(result)) != NULL)
	   {
	      DEBUG_STREAM << "DataBase::db_info(): no. of device servers defined " << row[0] << std::endl;
	      sprintf(info_str,"Device servers defined  = %s",row[0]);
	   }
	}
	mysql_free_result(result);
	n_infos++;
	argout->length(n_infos);
	(*argout)[n_infos-1] = CORBA::string_dup(info_str);

// get number of devices servers exported

	sql_query_stream.str("");
	sql_query_stream << "SELECT COUNT(*) FROM device WHERE class = \"DServer\" AND exported = 1 ";
//	DEBUG_STREAM << "DataBase::db_info(): sql_query " << sql_query_stream.str() << std::endl;

    result = query(sql_query_stream.str(),"db_info()");

	sprintf(info_str,"Device servers exported ...");
	n_rows = mysql_num_rows(result);
	if (n_rows > 0)
	{
	   if ((row = mysql_fetch_row(result)) != NULL)
	   {
	      DEBUG_STREAM << "DataBase::db_info(): no. of device servers exported " << row[0] << std::endl;
	      sprintf(info_str,"Device servers exported  = %s",row[0]);
	   }
	}
	mysql_free_result(result);
	n_infos++;
	argout->length(n_infos);
	(*argout)[n_infos-1] = CORBA::string_dup(info_str);

// newline

	n_infos++;
	argout->length(n_infos);
	(*argout)[n_infos-1] = CORBA::string_dup(" ");

// -------------------------------------------------------------------------------------

// get number of device properties

	sql_query_stream.str("");
	sql_query_stream << "SELECT COUNT(*) FROM property_device ";
    result = query(sql_query_stream.str(),"db_info()");
    row = mysql_fetch_row(result);
    sprintf(info_str,"Device properties defined  = %s",row[0]);
	mysql_free_result(result);
	sql_query_stream.str("");
	sql_query_stream << "SELECT COUNT(*) FROM property_device_hist ";
    result = query(sql_query_stream.str(),"db_info()");
    row = mysql_fetch_row(result);
    sprintf(info2_str," [History lgth = %s]",row[0]);
	strcat(info_str,info2_str);
	mysql_free_result(result);
	n_infos++;
	argout->length(n_infos);
	(*argout)[n_infos-1] = CORBA::string_dup(info_str);

// get number of class properties

	sql_query_stream.str("");
	sql_query_stream << "SELECT COUNT(*) FROM property_class ";
    result = query(sql_query_stream.str(),"db_info()");
    row = mysql_fetch_row(result);
    sprintf(info_str,"Class properties defined  = %s",row[0]);
	mysql_free_result(result);
	sql_query_stream.str("");
	sql_query_stream << "SELECT COUNT(*) FROM property_class_hist ";
    result = query(sql_query_stream.str(),"db_info()");
    row = mysql_fetch_row(result);
    sprintf(info2_str," [History lgth = %s]",row[0]);
	strcat(info_str,info2_str);
	mysql_free_result(result);
	n_infos++;
	argout->length(n_infos);
	(*argout)[n_infos-1] = CORBA::string_dup(info_str);

// get number of device attribute properties

	sql_query_stream.str("");
	sql_query_stream << "SELECT COUNT(*) FROM property_attribute_device ";
    result = query(sql_query_stream.str(),"db_info()");
    row = mysql_fetch_row(result);
    sprintf(info_str,"Device attribute properties defined  = %s",row[0]);
	mysql_free_result(result);
	sql_query_stream.str("");
	sql_query_stream << "SELECT COUNT(*) FROM property_attribute_device_hist ";
    result = query(sql_query_stream.str(),"db_info()");
    row = mysql_fetch_row(result);
    sprintf(info2_str," [History lgth = %s]",row[0]);
	strcat(info_str,info2_str);
	mysql_free_result(result);
	n_infos++;
	argout->length(n_infos);
	(*argout)[n_infos-1] = CORBA::string_dup(info_str);

// get number of class attribute properties

	sql_query_stream.str("");
	sql_query_stream << "SELECT COUNT(*) FROM property_attribute_class ";
    result = query(sql_query_stream.str(),"db_info()");
    row = mysql_fetch_row(result);
    sprintf(info_str,"Class attribute properties defined  = %s",row[0]);
	mysql_free_result(result);
	sql_query_stream.str("");
	sql_query_stream << "SELECT COUNT(*) FROM property_attribute_class_hist ";
    result = query(sql_query_stream.str(),"db_info()");
    row = mysql_fetch_row(result);
    sprintf(info2_str," [History lgth = %s]",row[0]);
	strcat(info_str,info2_str);
	mysql_free_result(result);
	n_infos++;
	argout->length(n_infos);
	(*argout)[n_infos-1] = CORBA::string_dup(info_str);

// get number of object properties

	sql_query_stream.str("");
	sql_query_stream << "SELECT COUNT(*) FROM property ";
    result = query(sql_query_stream.str(),"db_info()");
    row = mysql_fetch_row(result);
    sprintf(info_str,"Object properties defined  = %s",row[0]);
	mysql_free_result(result);
	sql_query_stream.str("");
	sql_query_stream << "SELECT COUNT(*) FROM property_hist ";
    result = query(sql_query_stream.str(),"db_info()");
    row = mysql_fetch_row(result);
    sprintf(info2_str," [History lgth = %s]",row[0]);
	strcat(info_str,info2_str);
	mysql_free_result(result);
	n_infos++;
	argout->length(n_infos);
	(*argout)[n_infos-1] = CORBA::string_dup(info_str);

	DEBUG_STREAM << "DataBase::db_info(): argout->length() "<< argout->length() << std::endl;

	GetTime(after);
	update_timing_stats(before, after, "DbInfo");

	/*----- PROTECTED REGION END -----*/	//	DataBase::db_info
	return argout;
}
//--------------------------------------------------------
/**
 *	Command DbPutAttributeAlias related method
 *	Description: Define an alias for an attribute
 *
 *	@param argin Str[0] = attribute name
 *               Str[1] = attribute alias
 */
//--------------------------------------------------------
void DataBase::db_put_attribute_alias(const Tango::DevVarStringArray *argin)
{
	DEBUG_STREAM << "DataBase::DbPutAttributeAlias()  - " << device_name << std::endl;
	/*----- PROTECTED REGION ID(DataBase::db_put_attribute_alias) ENABLED START -----*/

	TangoSys_MemStream sql_query_stream;
	MYSQL_RES *result;
	std::string tmp_alias;
	std::string tmp_name, tmp_attribute, tmp_device;


	if (argin->length() < 2) {
   		WARN_STREAM << "DataBase::db_put_attribute_alias(): insufficient alias info for attribute ";
   		Tango::Except::throw_exception(DB_IncorrectArguments,
					       "insufficient alias info for attribute",
					       "DataBase::db_put_attribute_alias()");
	}

	tmp_name = (*argin)[0];
	tmp_alias = (*argin)[1];
	for (unsigned int i=0; i<tmp_alias.length(); i++) {
		char tmp_char = tmp_alias[i];
		if (tmp_char == '/' || tmp_char == ' ')
		{
   			WARN_STREAM << "DataBase::db_put_attribute_alias(): Wrong alias for attribute ";
   			Tango::Except::throw_exception(DB_IncorrectArguments,
					       "Wrong alias for attribute!. Characters '/',' ' forbidden in alias",
					       "DataBase::db_put_attribute_alias()");
		}
	}
	INFO_STREAM << "DataBase::db_put_attribute_alias(): put " << tmp_alias << " for attribute " << tmp_name << std::endl;

// first check to see if this alias exists

	{
		AutoLock al(this);

		long n_rows=0;
    	sql_query_stream << "SELECT alias from attribute_alias WHERE alias=\'" << tmp_alias
	                	 << "\' AND name <> \'" << tmp_name << "\'";
		DEBUG_STREAM << "DataBase::db_put_attribute_alias(): sql_query " << sql_query_stream.str() << std::endl;

		result = query(sql_query_stream.str(),"db_put_attribute_alias()",al.get_dch());

		n_rows = mysql_num_rows(result);
		DEBUG_STREAM << "DataBase::db_put_attribute_alias(): mysql_num_rows() " << n_rows << std::endl;

		mysql_free_result(result);
		if (n_rows > 0)
		{
		   WARN_STREAM << "DataBase::db_put_attribute_alias(): this alias exists already !" << std::endl;
    	   TangoSys_OMemStream o;
		   o << "alias " << tmp_alias << " already exists !";
		   Tango::Except::throw_exception(DB_SQLError,
	   				                	  o.str(),
					                	  "DataBase::db_put_attribute_alias()");
		}

		std::string::size_type pos=0;
		int nsep=0;
		do
		{
			if (pos != 0) pos++;
			pos = tmp_name.find("/",pos);
			if (pos != std::string::npos) nsep++;
			WARN_STREAM << "DataBase::db_put_attribute_alias(): found " << nsep << " separators , remaining string " << tmp_name.substr(pos+1) << std::endl;
		}
		while (pos != std::string::npos);
		if (nsep != 3)
		{
		   WARN_STREAM << "DataBase::db_put_attribute_alias(): attribute name has bad syntax, must have 3 / in it" << std::endl;
    	   TangoSys_OMemStream o;
		   o << "attribute name " << tmp_name << " has bad syntax, must have 3 / in it";
		   Tango::Except::throw_exception(DB_SQLError,
	   				                	  o.str(),
					                	  "DataBase::db_put_attribute_alias()");
		}
		tmp_device = tmp_name.substr(0,tmp_name.rfind("/"));
		tmp_attribute = tmp_name.substr(tmp_name.rfind("/")+1);
// first delete the current entry (if any)

    	sql_query_stream.str("");
		sql_query_stream << "DELETE FROM attribute_alias WHERE name=\'" << tmp_name << "\'";
		DEBUG_STREAM << "DataBase::db_put_attribute_alias(): sql_query " << sql_query_stream.str() << std::endl;
		simple_query(sql_query_stream.str(),"db_put_attribute_alias()",al.get_dch());

// update the new value for this tuple

    	sql_query_stream.str("");
		sql_query_stream << "INSERT attribute_alias SET alias=\'" << tmp_alias
	                	 << "\',name=\'" << tmp_name << "\',device=\'" << tmp_device
						 << "\',attribute=\'" << tmp_attribute << "\',updated=NOW()";
		DEBUG_STREAM << "DataBase::db_put_attribute_alias(): sql_query " << sql_query_stream.str() << std::endl;
		simple_query(sql_query_stream.str(),"db_put_attribute_alias()",al.get_dch());
	}

	/*----- PROTECTED REGION END -----*/	//	DataBase::db_put_attribute_alias
}
//--------------------------------------------------------
/**
 *	Command DbPutClassAttributeProperty related method
 *	Description: Create/Update class attribute property(ies) in database
 *
 *	@param argin Str[0] = Tango class name
 *               Str[1] = Attribute number
 *               Str[2] = Attribute name
 *               Str[3] = Property number
 *               Str[4] = Property name
 *               Str[5] = Property value
 *               .....
 */
//--------------------------------------------------------
void DataBase::db_put_class_attribute_property(const Tango::DevVarStringArray *argin)
{
	DEBUG_STREAM << "DataBase::DbPutClassAttributeProperty()  - " << device_name << std::endl;
	/*----- PROTECTED REGION ID(DataBase::db_put_class_attribute_property) ENABLED START -----*/

	const Tango::DevVarStringArray  *property_list = argin;
	TangoSys_MemStream sql_query_stream;
	const char *tmp_class, *tmp_attribute, *tmp_name;

	const int n_attributes = ParseString<int>((*property_list)[1]);
	INFO_STREAM << "DataBase::PutAttributeProperty(): put " << n_attributes << " attributes for device " << (*property_list)[0] << std::endl;

	{
		AutoLock al(this);

		int i, j, k;
		k = 2;
		for (i=0; i<n_attributes; i++)
		{
		   tmp_class = (*property_list)[0];
		   tmp_attribute = (*property_list)[k];
		   const int n_properties = ParseString<int>((*property_list)[k+1]);
		   for (j=k+2; j<k+n_properties*2+2; j=j+2)
		   {
	    	  tmp_name = (*property_list)[j];
        	  std::string tmp_escaped_string = escape_string((*property_list)[j+1]);

// first delete the tuple (device,name,count) from the property table
			  sql_query_stream.str("");
			  sql_query_stream << "DELETE FROM property_attribute_class WHERE class LIKE \"" \
													 << tmp_class << "\" AND attribute LIKE \"" << tmp_attribute \
													 << "\" AND name LIKE \"" << tmp_name << "\"";
	    	  DEBUG_STREAM << "DataBase::PutAttributeProperty(): sql_query " << sql_query_stream.str() << std::endl;
			  simple_query(sql_query_stream.str(),"db_put_class_attribute_property()",al.get_dch());

// then insert the new value for this tuple
        	  sql_query_stream.str("");
			  sql_query_stream << "INSERT INTO property_attribute_class SET class='" << tmp_class \
													 << "',attribute='" << tmp_attribute \
													 << "',name='" << tmp_name \
													 << "',count='1',value='" << tmp_escaped_string \
													 << "',updated=NOW(),accessed=NOW()";
	    	  DEBUG_STREAM << "DataBase::PutAttributeProperty(): sql_query " << sql_query_stream.str() << std::endl;
			  simple_query(sql_query_stream.str(),"db_put_class_attribute_property()",al.get_dch());

// then insert the new value into the history table

			  Tango::DevULong64 class_attribute_property_hist_id = get_id("class_attribute",al.get_dch());
        	  sql_query_stream.str("");
			  sql_query_stream << "INSERT INTO property_attribute_class_hist SET class='" << tmp_class \
													 << "',attribute='" << tmp_attribute \
													 << "',name='" << tmp_name \
													 << "',id='" << class_attribute_property_hist_id \
													 << "',count='1',value='" << tmp_escaped_string << "'";
	    	  DEBUG_STREAM << "DataBase::PutAttributeProperty(): sql_query " << sql_query_stream.str() << std::endl;
			  simple_query(sql_query_stream.str(),"db_put_class_attribute_property()",al.get_dch());

	    	  purge_att_property("property_attribute_class_hist","class",tmp_class,tmp_attribute,tmp_name,al.get_dch());
		   }
		   k = k+n_properties*2+2;
		}
	}

	return;

	/*----- PROTECTED REGION END -----*/	//	DataBase::db_put_class_attribute_property
}
//--------------------------------------------------------
/**
 *	Command DbPutClassAttributeProperty2 related method
 *	Description: This command adds support for array properties compared to the previous one
 *               called DbPutClassAttributeProperty. The old comman is still there for compatibility reason
 *
 *	@param argin Str[0] = Tango class name
 *               Str[1] = Attribute number
 *               Str[2] = Attribute name
 *               Str[3] = Property number
 *               Str[4] = Property name
 *               Str[5] = Property value number (array case)
 *               Str[5] = Property value 1
 *               Str[n] = Property value n (array case)
 *               .....
 */
//--------------------------------------------------------
void DataBase::db_put_class_attribute_property2(const Tango::DevVarStringArray *argin)
{
	DEBUG_STREAM << "DataBase::DbPutClassAttributeProperty2()  - " << device_name << std::endl;
	/*----- PROTECTED REGION ID(DataBase::db_put_class_attribute_property2) ENABLED START -----*/

	TangoSys_MemStream sql_query_stream;
	char tmp_count_str[256];
	const char *tmp_class, *tmp_attribute, *tmp_name;

	const int n_attributes = ParseString<int>((*argin)[1]);
	INFO_STREAM << "DataBase::PutClassAttributeProperty2(): put " << n_attributes << " attributes for device " << (*argin)[0] << std::endl;

	{
		AutoLock al(this);

		int tmp_count, i, j, k, l, jj;
		k = 2;
		for (i=0; i<n_attributes; i++)
		{
	   		tmp_class = (*argin)[0];
	   		tmp_attribute = (*argin)[k];
	   		const int n_properties = ParseString<int>((*argin)[k+1]);
	   		for (jj=0; jj<n_properties; jj++)
	   		{
				j = k + 2;
	      		tmp_name = (*argin)[j];

// first delete the tuple (device,name,count) from the property table

				sql_query_stream.str("");
				sql_query_stream << "DELETE FROM property_attribute_class WHERE class LIKE \""
			                	 << tmp_class << "\" AND attribute LIKE \"" << tmp_attribute
								 << "\" AND name LIKE \"" << tmp_name << "\" ";
	      		DEBUG_STREAM << "DataBase::PutClassAttributeProperty2(): sql_query " << sql_query_stream.str() << std::endl;
				simple_query(sql_query_stream.str(),"db_put_class_attribute_property2()",al.get_dch());

				const int n_rows = ParseString<int>((*argin)[j+1]);
				tmp_count = 0;
				Tango::DevULong64 class_attribute_property_hist_id = get_id("class_attribute",al.get_dch());
	   			for (l=j+1; l<j+n_rows+1; l++)
	   			{
          				std::string tmp_escaped_string = escape_string((*argin)[l+1]);
	      				tmp_count++; sprintf(tmp_count_str, "%d", tmp_count);

// then insert the new value for this tuple

 			        sql_query_stream.str("");
					sql_query_stream << "INSERT INTO property_attribute_class SET class=\'"
					                 << tmp_class << "\',attribute=\'" << tmp_attribute
									 << "\',name=\'" << tmp_name << "\',count=\'" << tmp_count_str
									 << "\',value=\'" << tmp_escaped_string
									 << "\',updated=NOW(),accessed=NOW()";
	      			DEBUG_STREAM << "DataBase::PutClassAttributeProperty2(): sql_query " << sql_query_stream.str() << std::endl;
			        simple_query(sql_query_stream.str(),"db_put_class_attribute_property2()",al.get_dch());

// then insert the new value into the history table

 			        sql_query_stream.str("");
					sql_query_stream << "INSERT INTO property_attribute_class_hist SET class=\'"
					                 << tmp_class << "\',attribute=\'" << tmp_attribute
									 << "\',name=\'" << tmp_name << "\',count=\'" << tmp_count_str
									 << "\',id=\'" << class_attribute_property_hist_id
									 << "\',value=\'" << tmp_escaped_string << "\'";
	      			DEBUG_STREAM << "DataBase::PutClassAttributeProperty2(): sql_query " << sql_query_stream.str() << std::endl;
			        simple_query(sql_query_stream.str(),"db_put_class_attribute_property2()",al.get_dch());

				}
		        purge_att_property("property_attribute_class_hist","class",tmp_class,tmp_attribute,tmp_name,al.get_dch());
				k = k + n_rows + 2;
	   		}
	   		k = k+2;
		}
	}

	return;

	/*----- PROTECTED REGION END -----*/	//	DataBase::db_put_class_attribute_property2
}
//--------------------------------------------------------
/**
 *	Command DbPutClassProperty related method
 *	Description: Create / Update class property(ies)
 *
 *	@param argin Str[0] = Tango class name
 *               Str[1] = Property number
 *               Str[2] = Property name
 *               Str[3] = Property value number
 *               Str[4] = Property value 1
 *               Str[n] = Property value n
 *               ....
 */
//--------------------------------------------------------
void DataBase::db_put_class_property(const Tango::DevVarStringArray *argin)
{
	DEBUG_STREAM << "DataBase::DbPutClassProperty()  - " << device_name << std::endl;
	/*----- PROTECTED REGION ID(DataBase::db_put_class_property) ENABLED START -----*/

	const Tango::DevVarStringArray  *property_list = argin;
	TangoSys_MemStream sql_query_stream;
    char tmp_count_str[256];
	const char *tmp_class, *tmp_name;

	TimeVal	before, after;
	GetTime(before);

	const int n_properties = ParseString<int>((*property_list)[1]);
	INFO_STREAM << "DataBase::PutClassProperty(): put " << n_properties << " properties for device " << (*property_list)[0] << std::endl;

	{
		AutoLock al(this);

		int i, j, k;
		int tmp_count;

		k = 2;
		tmp_class = (*property_list)[0];
		for (i=0; i<n_properties; i++)
		{
			tmp_count = 0;
		   	tmp_name = (*property_list)[k];

// first delete all tuples (device,name) from the property table
			sql_query_stream.str("");
			sql_query_stream << "DELETE FROM property_class WHERE class LIKE \"" << tmp_class \
												<< "\" AND name LIKE \"" << tmp_name << "\"";

			DEBUG_STREAM << "DataBase::PutClassProperty(): sql_query " << sql_query_stream.str() << std::endl;
		   	simple_query(sql_query_stream.str(),"db_put_class_property()",al.get_dch());
		   	const int n_rows = ParseString<int>((*property_list)[k+1]);
		   	Tango::DevULong64 class_property_hist_id = get_id("class",al.get_dch());
		   	for (j=k+2; j<k+n_rows+2; j++)
		   	{
        	  	std::string tmp_escaped_string = escape_string((*property_list)[j]);
	    	  	tmp_count++; sprintf(tmp_count_str, "%d", tmp_count);

// then insert the new value for this tuple
				sql_query_stream.str("");
				sql_query_stream << "INSERT INTO property_class SET class='" << tmp_class \
													 << "',name='" << tmp_name \
													 << "',count='" << tmp_count_str \
													 << "',value='" << tmp_escaped_string \
													 << "',updated=NOW(),accessed=NOW()";
	    	  	DEBUG_STREAM << "DataBase::PutClassProperty(): sql_query " << sql_query_stream.str() << std::endl;
  	    	  	simple_query(sql_query_stream.str(),"db_put_class_property()",al.get_dch());

// then insert the new value into the history table
				sql_query_stream.str("");
				sql_query_stream << "INSERT INTO property_class_hist SET class='" << tmp_class \
													 << "',name='" << tmp_name \
													 << "',count='" << tmp_count_str \
													 << "',id='" << class_property_hist_id \
													 << "',value='" << tmp_escaped_string << "'";
	    	  	DEBUG_STREAM << "DataBase::PutClassProperty(): sql_query " << sql_query_stream.str() << std::endl;
  	    	  	simple_query(sql_query_stream.str(),"db_put_class_property()",al.get_dch());
		   	}
		   	purge_property("property_class_hist","class",tmp_class,tmp_name,al.get_dch());
		   	k = k+n_rows+2;
		}
	}

	GetTime(after);
	update_timing_stats(before, after, "DbPutClassProperty");
	return;

	/*----- PROTECTED REGION END -----*/	//	DataBase::db_put_class_property
}
//--------------------------------------------------------
/**
 *	Command DbPutDeviceAlias related method
 *	Description: Define alias for  a given device name
 *
 *	@param argin Str[0] = device name
 *               Str[1] = alias name
 */
//--------------------------------------------------------
void DataBase::db_put_device_alias(const Tango::DevVarStringArray *argin)
{
	DEBUG_STREAM << "DataBase::DbPutDeviceAlias()  - " << device_name << std::endl;
	/*----- PROTECTED REGION ID(DataBase::db_put_device_alias) ENABLED START -----*/

	const Tango::DevVarStringArray  *device_alias = argin;
	TangoSys_MemStream sql_query_stream;
	MYSQL_RES *result;
	std::string tmp_alias;
	std::string tmp_device;


	if (device_alias->length() < 2) {
   		WARN_STREAM << "DataBase::db_put_device_alias(): insufficient alias info for device ";
   		Tango::Except::throw_exception(DB_IncorrectArguments,
					       "insufficient alias info for device",
					       "DataBase::db_put_device_alias()");
	}

	tmp_device = (*device_alias)[0];
	tmp_alias = (*device_alias)[1];
	for (unsigned int i=0; i<tmp_alias.length(); i++) {
		char tmp_char = tmp_alias[i];
		if (tmp_char == '/' || tmp_char == ' ')
		{
   			WARN_STREAM << "DataBase::db_put_device_alias(): Wrong alias info for device ";
   			Tango::Except::throw_exception(DB_IncorrectArguments,
					       "Wrong alias info for device!. Characters '/',' ' forbidden in alias",
					       "DataBase::db_put_device_alias()");
		}
	}
	INFO_STREAM << "DataBase::db_put_device_alias(): put " << tmp_alias << " for device " << tmp_device << std::endl;

// first check to see if this alias exists

	{
		AutoLock al(this);

    	sql_query_stream << "SELECT alias from device WHERE alias=\'" << tmp_alias
	                	 << "\' AND name <> \'" << tmp_device << "\'";
		DEBUG_STREAM << "DataBase::db_put_device_alias(): sql_query " << sql_query_stream.str() << std::endl;

		result = query(sql_query_stream.str(),"db_put_device_alias()",al.get_dch());

		long n_rows=0;
		n_rows = mysql_num_rows(result);
		DEBUG_STREAM << "DataBase::db_put_device_alias(): mysql_num_rows() " << n_rows << std::endl;

		mysql_free_result(result);
		if (n_rows > 0)
		{
		   WARN_STREAM << "DataBase::db_put_device_alias(): this alias exists already !" << std::endl;
    	   TangoSys_OMemStream o;
		   o << "alias " << tmp_alias << " already exists !";
		   Tango::Except::throw_exception(DB_SQLError,
	   				                	  o.str(),
					                	  "DataBase::db_put_device_alias()");
		}

// update the new value for this tuple
    	sql_query_stream.str("");
		sql_query_stream << "UPDATE device set alias=\'" << tmp_alias
	                	 << "\',started=NOW() where name LIKE \'" << tmp_device << "\'";
		DEBUG_STREAM << "DataBase::db_put_device_alias(): sql_query " << sql_query_stream.str() << std::endl;
		simple_query(sql_query_stream.str(),"db_put_device_alias()",al.get_dch());
	}

	/*----- PROTECTED REGION END -----*/	//	DataBase::db_put_device_alias
}
//--------------------------------------------------------
/**
 *	Command DbPutDeviceAttributeProperty related method
 *	Description: Create/Update device attribute property(ies) in database
 *
 *	@param argin Str[0] = Device name
 *               Str[1] = Attribute number
 *               Str[2] = Attribute name
 *               Str[3] = Property number
 *               Str[4] = Property name
 *               Str[5] = Property value
 *               .....
 */
//--------------------------------------------------------
void DataBase::db_put_device_attribute_property(const Tango::DevVarStringArray *argin)
{
	DEBUG_STREAM << "DataBase::DbPutDeviceAttributeProperty()  - " << device_name << std::endl;
	/*----- PROTECTED REGION ID(DataBase::db_put_device_attribute_property) ENABLED START -----*/

	const Tango::DevVarStringArray  *property_list = argin;
	TangoSys_MemStream sql_query_stream;
	const char *tmp_device, *tmp_attribute, *tmp_name;

	TimeVal	before, after;
	GetTime(before);

	const int n_attributes = ParseString<int>((*property_list)[1]);
	INFO_STREAM << "DataBase::PutAttributeProperty(): put " << n_attributes << " attributes for device " << (*property_list)[0] << std::endl;

	{
		AutoLock al(this);

		int i, j, k;
		k = 2;
		for (i=0; i<n_attributes; i++)
		{
		   tmp_device = (*property_list)[0];
		   tmp_attribute = (*property_list)[k];
		   const int n_properties = ParseString<int>((*property_list)[k+1]);

		   for (j=k+2; j<k+n_properties*2+2; j=j+2)
		   {
	    	  tmp_name = (*property_list)[j];
        	  std::string tmp_escaped_string = escape_string((*property_list)[j+1]);

// first delete the tuple (device,name,count) from the property table
				sql_query_stream.str("");
				sql_query_stream << "DELETE FROM property_attribute_device WHERE device LIKE \"" \
												 << tmp_device << "\" AND attribute LIKE \"" << tmp_attribute \
												 << "\" AND name LIKE \"" << tmp_name << "\"";
				DEBUG_STREAM << "DataBase::PutAttributeProperty(): sql_query " << sql_query_stream.str() << std::endl;

				simple_query(sql_query_stream.str(),"db_put_device_attribute_property()",al.get_dch());

// then insert the new value for this tuple
				sql_query_stream.str("");
				sql_query_stream << "INSERT INTO property_attribute_device SET device='" << tmp_device \
												 << "',attribute='" << tmp_attribute \
												 << "',name='" << tmp_name \
												 << "',count='1',value='" << tmp_escaped_string \
												 << "',updated=NOW(),accessed=NOW()";
	      		DEBUG_STREAM << "DataBase::PutAttributeProperty(): sql_query " << sql_query_stream.str() << std::endl;
		  		simple_query(sql_query_stream.str(),"db_put_device_attribute_property()",al.get_dch());

// then insert the new value for this tuple into the history table
          		Tango::DevULong64 device_attribute_property_hist_id = get_id("device_attribute",al.get_dch());
				sql_query_stream.str("");
				sql_query_stream << "INSERT INTO property_attribute_device_hist SET device='" << tmp_device \
												 << "',attribute='" << tmp_attribute \
												 << "',name='" << tmp_name \
												 << "',id='" << device_attribute_property_hist_id \
												 << "',count='1',value='" << tmp_escaped_string << "'";
	      		DEBUG_STREAM << "DataBase::PutAttributeProperty(): sql_query " << sql_query_stream.str() << std::endl;
		  		simple_query(sql_query_stream.str(),"db_put_device_attribute_property()",al.get_dch());

	      		purge_att_property("property_attribute_device_hist","device",tmp_device,tmp_attribute,tmp_name,al.get_dch());
		   }
		   k = k+n_properties*2+2;
		}
	}

	GetTime(after);
	update_timing_stats(before, after, "DbPutDeviceAttributeProperty");
	return;

	/*----- PROTECTED REGION END -----*/	//	DataBase::db_put_device_attribute_property
}
//--------------------------------------------------------
/**
 *	Command DbPutDeviceAttributeProperty2 related method
 *	Description: Put device attribute property. This command adds the possibility to have attribute property
 *               which are arrays. Not possible with the old DbPutDeviceAttributeProperty command.
 *               This old command is not deleted for compatibility reasons.
 *
 *	@param argin Str[0] = Device name
 *               Str[1] = Attribute number
 *               Str[2] = Attribute name
 *               Str[3] = Property number
 *               Str[4] = Property name
 *               Str[5] = Property value number (array case)
 *               Str[5] = Property value 1
 *               Str[n] = Property value n (array case)
 *               .....
 */
//--------------------------------------------------------
void DataBase::db_put_device_attribute_property2(const Tango::DevVarStringArray *argin)
{
	DEBUG_STREAM << "DataBase::DbPutDeviceAttributeProperty2()  - " << device_name << std::endl;
	/*----- PROTECTED REGION ID(DataBase::db_put_device_attribute_property2) ENABLED START -----*/

	TangoSys_MemStream sql_query_stream;
	char tmp_count_str[256];
	const char *tmp_device, *tmp_attribute, *tmp_name;

	TimeVal	before, after;
	GetTime(before);

    if (argin->length() == 7 &&
        ::strcmp((*argin)[1].in(),"1") == 0 &&
        ::strcmp((*argin)[3].in(),"1") == 0 &&
        ::strcmp((*argin)[4].in(),"__value") == 0 &&
        ::strcmp((*argin)[5].in(),"1") == 0)
    {
        create_update_mem_att(argin);
    }
    else
    {
        const int n_attributes = ParseString<int>((*argin)[1]);
        INFO_STREAM << "DataBase::PutAttributeProperty2(): put " << n_attributes << " attributes for device " << (*argin)[0] << std::endl;

        {
            AutoLock al(this);

            int tmp_count, i, j, k, l, jj;
            k = 2;
            for (i=0; i<n_attributes; i++)
            {
                tmp_device = (*argin)[0];
                tmp_attribute = (*argin)[k];
                const int n_properties = ParseString<int>((*argin)[k+1]);
                for (jj=0; jj<n_properties; jj++)
                {
                    j = k + 2;
                    tmp_name = (*argin)[j];

// first delete the tuple (device,name,count) from the property table
                    sql_query_stream.str("");
                    sql_query_stream << "DELETE FROM property_attribute_device WHERE device LIKE \""
                                         << tmp_device << "\" AND attribute LIKE \"" << tmp_attribute
                                         << "\" AND name LIKE \"" << tmp_name << "\" ";
                    DEBUG_STREAM << "DataBase::PutAttributeProperty2(): sql_query " << sql_query_stream.str() << std::endl;
                    simple_query(sql_query_stream.str(),"db_put_device_attribute_property2()",al.get_dch());

                    const int n_rows = ParseString<int>((*argin)[j+1]);
                    tmp_count = 0;
                    Tango::DevULong64 device_attribute_property_hist_id = get_id("device_attribute",al.get_dch());

                    for (l=j+1; l<j+n_rows+1; l++)
                    {
                        std::string tmp_escaped_string = escape_string((*argin)[l+1]);
                        tmp_count++; sprintf(tmp_count_str, "%d", tmp_count);

// then insert the new value for this tuple
                        sql_query_stream.str("");
                        sql_query_stream << "INSERT INTO property_attribute_device SET device=\'"
                                             << tmp_device << "\',attribute=\'" << tmp_attribute
                                             << "\',name=\'" << tmp_name << "\',count=\'" << tmp_count_str
                                             << "\',value=\'" << tmp_escaped_string << "\',updated=NOW(),accessed=NOW()";
                        DEBUG_STREAM << "DataBase::PutAttributeProperty(): sql_query " << sql_query_stream.str() << std::endl;
                        simple_query(sql_query_stream.str(),"db_put_device_attribute_property2()",al.get_dch());

// then insert the new value into the history table
                        sql_query_stream.str("");
                        sql_query_stream << "INSERT INTO property_attribute_device_hist SET device=\'"
                                             << tmp_device << "\',attribute=\'" << tmp_attribute
                                             << "\',name=\'" << tmp_name << "\',count=\'" << tmp_count_str
                                             << "\',id=\'" << device_attribute_property_hist_id
                                             << "\',value=\'" << tmp_escaped_string << "\'";
                        DEBUG_STREAM << "DataBase::PutAttributeProperty(): sql_query " << sql_query_stream.str() << std::endl;
                        simple_query(sql_query_stream.str(),"db_put_device_attribute_property2()",al.get_dch());

                    }
                    purge_att_property("property_attribute_device_hist","device",tmp_device,tmp_attribute,tmp_name,al.get_dch());
                    k = k + n_rows + 2;
                }
                k = k+2;
            }
        }
    }

	GetTime(after);
	update_timing_stats(before, after, "DbPutDeviceAttributeProperty2");
	return;

	/*----- PROTECTED REGION END -----*/	//	DataBase::db_put_device_attribute_property2
}
//--------------------------------------------------------
/**
 *	Command DbPutDeviceProperty related method
 *	Description: Create / Update device property(ies)
 *
 *	@param argin Str[0] = Tango device name
 *               Str[1] = Property number
 *               Str[2] = Property name
 *               Str[3] = Property value number
 *               Str[4] = Property value 1
 *               Str[n] = Property value n
 *               ....
 */
//--------------------------------------------------------
void DataBase::db_put_device_property(const Tango::DevVarStringArray *argin)
{
	DEBUG_STREAM << "DataBase::DbPutDeviceProperty()  - " << device_name << std::endl;
	/*----- PROTECTED REGION ID(DataBase::db_put_device_property) ENABLED START -----*/

	const Tango::DevVarStringArray  *property_list = argin;
	TangoSys_MemStream sql_query_stream;
	char tmp_count_str[256];
	const char *tmp_device;
	std::string tmp_name;

	TimeVal	before, after;
	GetTime(before);

	const int n_properties = ParseString<int>((*property_list)[1]);
	INFO_STREAM << "DataBase::PutDeviceProperty(): put " << n_properties << " properties for device " << (*property_list)[0] << std::endl;

	{
		AutoLock al(this);

		int i, j, k;
		int tmp_count;

		k = 2;
		for (i=0; i<n_properties; i++)
		{
		   tmp_count = 0;
		   tmp_device = (*property_list)[0];
		   tmp_name = (*property_list)[k];

// first delete all tuples (device,name) from the property table
    	   sql_query_stream.str("");
		   sql_query_stream << "DELETE FROM property_device WHERE device LIKE \"" << tmp_device \
													 << "\" AND name LIKE \"" << tmp_name << "\"";
		   DEBUG_STREAM << "DataBase::PutDeviceProperty(): sql_query " << sql_query_stream.str() << std::endl;

		   simple_query(sql_query_stream.str(),"db_put_device_property()",al.get_dch());
		   const int n_rows = ParseString<int>((*property_list)[k+1]);
		   Tango::DevULong64 device_property_hist_id = get_id("device",al.get_dch());

		   for (j=k+2; j<k+n_rows+2; j++)
		   {
        	  std::string tmp_escaped_string = escape_string((*property_list)[j]);
	    	  tmp_count++; sprintf(tmp_count_str, "%d", tmp_count);

			// then insert the new value for this tuple
					sql_query_stream.str("");
					sql_query_stream << "INSERT INTO property_device SET device='" << tmp_device \
													 << "',name='" << tmp_name \
													 << "',count='" << tmp_count_str \
													 << "',value='" << tmp_escaped_string \
													 << "',updated=NOW(),accessed=NOW()";
	    	  DEBUG_STREAM << "DataBase::PutDeviceProperty(): sql_query " << sql_query_stream.str() << std::endl;

			  simple_query(sql_query_stream.str(),"db_put_device_property",al.get_dch());

			// insert the new value into the history table
					sql_query_stream.str("");
					sql_query_stream << "INSERT INTO property_device_hist SET device='" << tmp_device \
													 << "',id='" << device_property_hist_id \
													 << "',name='" << tmp_name \
													 << "',count='" << tmp_count_str \
													 << "',value='" << tmp_escaped_string \
													 << "'";

	    	  DEBUG_STREAM << "DataBase::PutDeviceProperty(): sql_query " << sql_query_stream.str() << std::endl;

			  simple_query(sql_query_stream.str(),"db_put_device_property",al.get_dch());

		   }
		   purge_property("property_device_hist","device",tmp_device,tmp_name.c_str(),al.get_dch());
		   k = k+n_rows+2;
		}
	}

	GetTime(after);
	update_timing_stats(before, after, "DbPutDeviceProperty");
	return;

	/*----- PROTECTED REGION END -----*/	//	DataBase::db_put_device_property
}
//--------------------------------------------------------
/**
 *	Command DbPutProperty related method
 *	Description: Create / Update free object property(ies)
 *
 *	@param argin Str[0] = Object name
 *               Str[1] = Property number
 *               Str[2] = Property name
 *               Str[3] = Property value number
 *               Str[4] = Property value 1
 *               Str[n] = Property value n
 *               ....
 */
//--------------------------------------------------------
void DataBase::db_put_property(const Tango::DevVarStringArray *argin)
{
	DEBUG_STREAM << "DataBase::DbPutProperty()  - " << device_name << std::endl;
	/*----- PROTECTED REGION ID(DataBase::db_put_property) ENABLED START -----*/

	const Tango::DevVarStringArray  *property_list = argin;
	TangoSys_MemStream	sql_query_stream;
	const char *tmp_object;
	std::string tmp_name;

	tmp_object = (*property_list)[0];
	const int n_properties = ParseString<int>((*property_list)[1]);
	INFO_STREAM << "DataBase::db_put_property(): put " << n_properties << " properties for object " << (*property_list)[0] << std::endl;

	{
		AutoLock al(this);

		int	k = 2;
		int	tmp_count;

		for (int i=0; i<n_properties; i++)
		{
			tmp_count = 0;
			tmp_name = (*property_list)[k];
			const int n_rows = ParseString<int>((*property_list)[k+1]);

			// first delete the property from the property table
			sql_query_stream.str("");
			sql_query_stream << "DELETE FROM property WHERE object=\"" << tmp_object
											 << "\" AND name=\"" << tmp_name << "\"";
			DEBUG_STREAM  << "DataBase::db_put_property(): sql_query " << sql_query_stream.str() << std::endl;

			simple_query(sql_query_stream.str(),"db_put_property()",al.get_dch());
			Tango::DevULong64 object_property_hist_id = get_id("object",al.get_dch());
	    	for (int j=k+2 ; j<k+n_rows+2 ; j++)
	    	{
        	  std::string tmp_escaped_string = escape_string((*property_list)[j]);
	    	  tmp_count++;

			  // then insert the new value for this tuple
			  sql_query_stream.str("");
			  sql_query_stream << "INSERT INTO property SET object='" << tmp_object
											 << "',name='" << tmp_name
											 << "',count='" << tmp_count
											 << "',value='" << tmp_escaped_string
											 << "',updated=NOW(),accessed=NOW()";
	    	  DEBUG_STREAM << "DataBase::db_put_property(): sql_query " << sql_query_stream.str() << std::endl;
			  simple_query(sql_query_stream.str(),"db_put_property()",al.get_dch());

			  // then insert the new value into history table
			  sql_query_stream.str("");
			  sql_query_stream << "INSERT INTO property_hist SET object='" << tmp_object
											 << "',name='" << tmp_name
											 << "',count='" << tmp_count
											 << "',id='" << object_property_hist_id
											 << "',value='" << tmp_escaped_string << "'";
	    	  DEBUG_STREAM << "DataBase::db_put_property(): sql_query " << sql_query_stream.str() << std::endl;
			  simple_query(sql_query_stream.str(),"db_put_property()",al.get_dch());
			}
			purge_property("property_hist","object",tmp_object,tmp_name.c_str(),al.get_dch());
			k = k+n_rows+2;
		}
	}

	return;

	/*----- PROTECTED REGION END -----*/	//	DataBase::db_put_property
}
//--------------------------------------------------------
/**
 *	Command DbPutServerInfo related method
 *	Description: Update server info including host, mode and level
 *
 *	@param argin server info
 */
//--------------------------------------------------------
void DataBase::db_put_server_info(const Tango::DevVarStringArray *argin)
{
	DEBUG_STREAM << "DataBase::DbPutServerInfo()  - " << device_name << std::endl;
	/*----- PROTECTED REGION ID(DataBase::db_put_server_info) ENABLED START -----*/

	const Tango::DevVarStringArray  *server_info = argin;
	TangoSys_MemStream sql_query_stream;
	const char *tmp_host, *tmp_mode, *tmp_level;
	std::string tmp_server;

	if (server_info->length() < 4) {
   		WARN_STREAM << "DataBase::db_put_server_info(): insufficient info for server ";
   		WARN_STREAM << std::endl;
   		Tango::Except::throw_exception(DB_IncorrectArguments,
					       "insufficient server info",
					       "DataBase::db_put_server_info()");
	}

	INFO_STREAM << "DataBase::db_put_server_info(): put " << server_info->length()-1 << " export info for device " << (*server_info)[0] << std::endl;

	tmp_server = (*server_info)[0];

	// replace uppercase by lowercase
	for (unsigned int i=0; i<tmp_server.length(); i++) {
		tmp_server[i] = tolower(tmp_server[i]);
	}
	tmp_host = (*server_info)[1];
	tmp_mode = (*server_info)[2];
	tmp_level = (*server_info)[3];

//
//	If it is an empty host name -> get previous host where running
//

	std::string previous_host("");
	{
		AutoLock al(this);

		if (fireToStarter==true)
		{
			if (tmp_host[0] == '\0')
			{
				omni_mutex_lock oml(starter_mutex);

				//	Get database server name
				//--------------------------------------
				Tango::Util *tg = Tango::Util::instance();
				std::string	db_serv = tg->get_ds_name();
				transform(db_serv.begin(), db_serv.end(), db_serv.begin(), ::tolower);
				std::string	adm_dev = "dserver/";
				adm_dev += tmp_server;

				char *tmp_ptr = db_get_device_host((Tango::DevString)adm_dev.c_str(),al.get_dch());
				previous_host = tmp_ptr;
				DEBUG_STREAM << tmp_server << " was running on " << previous_host << std::endl;
				CORBA::string_free(tmp_ptr);
			}
		}
// first delete the server from the server table

		sql_query_stream << "DELETE FROM server WHERE name = \"" << tmp_server << "\"";
		DEBUG_STREAM << "DataBase::db_put_server_info(): sql_query " << sql_query_stream.str() << std::endl;
		simple_query(sql_query_stream.str(),"db_put_server_info()",al.get_dch());

// insert the new info for this server

    	sql_query_stream.str("");
		sql_query_stream << "INSERT INTO server SET name=\'" << tmp_server << "\',host=\'"
	                	 << tmp_host << "\',mode=\'" << tmp_mode << "\',level=\'" << tmp_level << "\'";
		DEBUG_STREAM << "DataBase::db_put_server_info(): sql_query " << sql_query_stream.str() << std::endl;
		simple_query(sql_query_stream.str(),"db_put_server_info()",al.get_dch());
	}

	//	Update host's starter to update controlled servers list
	if (fireToStarter==true)
	{
		omni_mutex_lock oml(starter_mutex);

		std::vector<std::string>	hosts;
		if (previous_host=="")
			hosts.push_back(tmp_host);
		else
			hosts.push_back(previous_host);
		starter_shared->send_starter_cmd(hosts);
	}

	/*----- PROTECTED REGION END -----*/	//	DataBase::db_put_server_info
}
//--------------------------------------------------------
/**
 *	Command DbUnExportDevice related method
 *	Description: Mark a device as non exported in database
 *
 *	@param argin Device name
 */
//--------------------------------------------------------
void DataBase::db_un_export_device(Tango::DevString argin)
{
	DEBUG_STREAM << "DataBase::DbUnExportDevice()  - " << device_name << std::endl;
	/*----- PROTECTED REGION ID(DataBase::db_un_export_device) ENABLED START -----*/

	Tango::DevString  devname = argin;
	TangoSys_MemStream sql_query_stream;
	char *tmp_device;

	INFO_STREAM << "DataBase::UnExportDevice(): un-export " << devname << " device " << std::endl;

	tmp_device = (char*)malloc(strlen(devname)+1);
	sprintf(tmp_device,"%s",devname);
	for (unsigned int i=0; i<strlen(tmp_device); i++) {
		tmp_device[i] = tolower(tmp_device[i]);
	}

// un-export device from database by seting ior="not exported"
    sql_query_stream << "UPDATE device SET exported=0,stopped=NOW() WHERE name like \""
	                 << tmp_device << "\"";
	DEBUG_STREAM << "DataBase::UnExportDevice(): sql_query " << sql_query_stream.str() << std::endl;
	simple_query(sql_query_stream.str(),"db_export_device()");

	free(tmp_device);

	return;

	/*----- PROTECTED REGION END -----*/	//	DataBase::db_un_export_device
}
//--------------------------------------------------------
/**
 *	Command DbUnExportEvent related method
 *	Description: Mark one event channel as non exported in database
 *
 *	@param argin name of event channel or factory to unexport
 */
//--------------------------------------------------------
void DataBase::db_un_export_event(Tango::DevString argin)
{
	DEBUG_STREAM << "DataBase::DbUnExportEvent()  - " << device_name << std::endl;
	/*----- PROTECTED REGION ID(DataBase::db_un_export_event) ENABLED START -----*/

	Tango::DevString  event_name = argin;
	TangoSys_MemStream sql_query_stream;
	std::string tmp_event;

	INFO_STREAM << "DataBase::un_export_event(): un-export " << event_name << " device " << std::endl;

	tmp_event = event_name;
	for (unsigned int i=0; i<tmp_event.size(); i++) {
		tmp_event[i] = tolower(tmp_event[i]);
	}
	tmp_event = replace_wildcard(tmp_event.c_str());

// un-export event from database by seting ior="not exported"

	sql_query_stream << "UPDATE event SET exported=0,stopped=NOW() WHERE name like \"" << tmp_event << "\"";
	DEBUG_STREAM << "DataBase::un_export_event(): sql_query " << sql_query_stream.str() << std::endl;
	simple_query(sql_query_stream.str(),"db_un_export_event()");

	/*----- PROTECTED REGION END -----*/	//	DataBase::db_un_export_event
}
//--------------------------------------------------------
/**
 *	Command DbUnExportServer related method
 *	Description: Mark all devices belonging to a specified device server
 *               process as non exported
 *
 *	@param argin Device server name (executable/instance)
 */
//--------------------------------------------------------
void DataBase::db_un_export_server(Tango::DevString argin)
{
	DEBUG_STREAM << "DataBase::DbUnExportServer()  - " << device_name << std::endl;
	/*----- PROTECTED REGION ID(DataBase::db_un_export_server) ENABLED START -----*/

	Tango::DevString  server_name = argin;
	TangoSys_MemStream sql_query_stream;
	char *tmp_server;

	TimeVal	before, after;
	GetTime(before);

	INFO_STREAM << "DataBase::UnExportServer(): un-export all device(s) from server " << server_name << " device " << std::endl;

	tmp_server = (char*)malloc(strlen(server_name)+1);
	sprintf(tmp_server,"%s",server_name);
	for (unsigned  int i=0; i<strlen(tmp_server); i++) {
		tmp_server[i] = tolower(tmp_server[i]);
	}

// un-export all devices belonging to this server from database by setting exported="false"

	sql_query_stream << "UPDATE device SET exported=0,stopped=NOW() WHERE server like \""
	                 << tmp_server << "\"";
	DEBUG_STREAM << "DataBase::UnExportServer(): sql_query " << sql_query_stream.str() << std::endl;
	simple_query(sql_query_stream.str(),"db_un_export_server()");

	free(tmp_server);

	GetTime(after);
	update_timing_stats(before, after, "DbUnExportServer");

	/*----- PROTECTED REGION END -----*/	//	DataBase::db_un_export_server
}
//--------------------------------------------------------
/**
 *	Command ResetTimingValues related method
 *	Description: Reset the timing attribute values.
 *
 */
//--------------------------------------------------------
void DataBase::reset_timing_values()
{
	DEBUG_STREAM << "DataBase::ResetTimingValues()  - " << device_name << std::endl;
	/*----- PROTECTED REGION ID(DataBase::reset_timing_values) ENABLED START -----*/

	timing_stats_mutex.lock();

	//	Loop over map to re-initialise remaining variables
	std::map<std::string,TimingStatsStruct*>::iterator iter;
	for (iter=timing_stats_map.begin(); iter!=timing_stats_map.end(); iter++)
	{
		iter->second->average       =
		iter->second->minimum       =
		iter->second->maximum       =
		iter->second->total_elapsed =
		iter->second->calls         = 0.0;
	}

	timing_stats_mutex.unlock();

	/*----- PROTECTED REGION END -----*/	//	DataBase::reset_timing_values
}
//--------------------------------------------------------
/**
 *	Command DbGetDataForServerCache related method
 *	Description: This command returns all the data needed by a device server process during its
 *               startup sequence. The aim of this command is to minimize database access during
 *               device server startup sequence.
 *
 *	@param argin Elt[0] = DS name (exec_name/inst_name), Elt[1] = Host name
 *	@returns All the data needed by the device server during its startup sequence. Precise list depend on the device server
 */
//--------------------------------------------------------
Tango::DevVarStringArray *DataBase::db_get_data_for_server_cache(const Tango::DevVarStringArray *argin)
{
	Tango::DevVarStringArray *argout;
	DEBUG_STREAM << "DataBase::DbGetDataForServerCache()  - " << device_name << std::endl;
	/*----- PROTECTED REGION ID(DataBase::db_get_data_for_server_cache) ENABLED START -----*/

	//	POGO has generated a method core with argout allocation.
	//	If you would like to use a static reference without copying,
	//	See "TANGO Device Server Programmer's Manual"
	//		(chapter : Writing a TANGO DS / Exchanging data)
	//------------------------------------------------------------

	DEBUG_STREAM << "DataBase::db_get_data_for_server_cache(): entering... !" << std::endl;


	if (argin->length() != 2)
	{
	   WARN_STREAM << "DataBase::DbGetDataForServerCache(): incorrect number of input arguments " << std::endl;
	   Tango::Except::throw_exception(DB_IncorrectArguments,
	   				  "Incorrect no. of input arguments, needs 2 (ds_name,host_name)",
					  "DataBase::DbGetDataForServerCache()");
	}

	argout  = new Tango::DevVarStringArray();
	TimeVal	before, after;
	GetTime(before);

	std::string	sql_query;
	std::string svc((*argin)[0]);
	std::string host((*argin)[1]);
	MYSQL_RES *res;
	MYSQL_ROW row;

	Tango::Util *tg = Tango::Util::instance();
	std::string	&db_inst_name = tg->get_ds_inst_name();
	std::string tmp_var_name("@param_out");
	tmp_var_name = tmp_var_name + db_inst_name;

//
// Do not use methods query() or simple_query() because we are
// calling a stored procedure.
// Calling a stored procedure needs special care to retrieve its OUT
// parameter(s). We have to code a loop using mysql_next_result
// function. The first result with data is the one we are
// interested in
//

	sql_query = "CALL ";
	sql_query = sql_query + mysql_db_name;
	sql_query = sql_query + ".ds_start('" + svc + "','" + host + "'," + tmp_var_name + ")";
	sql_query = sql_query + ";SELECT " + tmp_var_name;
//  TANGO_LOG << "Query = " << sql_query << std::endl;

	DatabaseConnectionHandle dch(dcp);

	if (mysql_real_query(dch.db(), sql_query.c_str(),sql_query.length()) != 0)
	{
		delete argout;
		TangoSys_OMemStream o;

		WARN_STREAM << "DataBase::db_get_data_for_server_cache failed to query TANGO database:" << std::endl;
		WARN_STREAM << "  query = " << sql_query << std::endl;
		WARN_STREAM << " (SQL error=" << mysql_error(dch.db()) << ")" << std::endl;

		o << "Failed to query TANGO database (error=" << mysql_error(dch.db()) << ")";
		o << "\nThe query was: " << sql_query << std::ends;

		Tango::Except::throw_exception(DB_SQLError,o.str(),
									   "DataBase::DbGetDataForServerCache()");
	}

	int status;
	do
	{
		if ((res = mysql_store_result(dch.db())) != NULL)
		{
			break;
		}
		else
		{
			if (mysql_field_count(dch.db()) != 0)
			{
				delete argout;
				TangoSys_OMemStream o;

				WARN_STREAM << "DataBase::db_get_data_for_server_cache: mysql_store_result() failed  (error=" << mysql_error(dch.db()) << ")" << std::endl;

				o << "mysql_store_result() failed (error=" << mysql_error(dch.db()) << ")";

				Tango::Except::throw_exception(DB_SQLError,o.str(),
											   "DataBase::DbGetDataForServerCache()");
			}

			if ((status = mysql_next_result(dch.db())) > 0)
			{
				delete argout;
				TangoSys_OMemStream o;

				WARN_STREAM << "DataBase::db_get_data_for_server_cache: mysql_next_result() failed  (error=" << mysql_error(dch.db()) << ")" << std::endl;

				o << "mysql_next_result() failed (error=" << mysql_error(dch.db()) << ")";

				Tango::Except::throw_exception(DB_SQLError,o.str(),
											   "DataBase::DbGetDataForServerCache()");
			}
		}
	}while (status == 0);

	row = mysql_fetch_row(res);
	unsigned long *length_ptr = mysql_fetch_lengths(res);
	std::string str(row[0],length_ptr[0]);
	int nb_field = count(str.begin(),str.end(),'\0');

	if (nb_field == 0)
	{
		if (str.size() == 0)
		{
			delete argout;
			mysql_free_result(res);
			WARN_STREAM << "DataBase::DbGetDataForServerCache(): Stored procedure does not return any result!!!" << std::endl;
			Tango::Except::throw_exception("DB_StoredProcedureNoResult",
						"The stored procedure did not return any results!!!",
						"DataBase::DbGetDataForServerCache()");
		}
		else
		{
			delete argout;
			mysql_free_result(res);
			WARN_STREAM << "DataBase::DbGetDataForServerCache(): Stored procedure failed with a MySQL error!!!" << std::endl;
			Tango::Except::throw_exception("DB_StoredProcedureFailed",
						"The stored procedure failed with a MySQL error!!!",
						"DataBase::DbGetDataForServerCache()");
		}
	}

	argout->length(nb_field + 1);

	std::string::size_type pos = 0;
	std::string::size_type start = 0;
	int idx = 0;
	std::string tmp_elt;

	pos = str.find('\0');
	while (pos != std::string::npos)
	{
		tmp_elt = str.substr(start,pos - start);
		(*argout)[idx] = CORBA::string_dup(tmp_elt.c_str());
		start = pos + 1;
		idx++;
		pos = str.find('\0',start);
	}
	tmp_elt = str.substr(start);
	(*argout)[idx] = CORBA::string_dup(tmp_elt.c_str());

	mysql_free_result(res);

	GetTime(after);
	update_timing_stats(before, after, "DbGetDataForServerCache");

	/*----- PROTECTED REGION END -----*/	//	DataBase::db_get_data_for_server_cache
	return argout;
}
//--------------------------------------------------------
/**
 *	Command DbDeleteAllDeviceAttributeProperty related method
 *	Description: Delete all attribute properties for the specified device attribute(s)
 *
 *	@param argin str[0] = device name
 *               Str[1]...str[n] = attribute name(s)
 */
//--------------------------------------------------------
void DataBase::db_delete_all_device_attribute_property(const Tango::DevVarStringArray *argin)
{
	DEBUG_STREAM << "DataBase::DbDeleteAllDeviceAttributeProperty()  - " << device_name << std::endl;
	/*----- PROTECTED REGION ID(DataBase::db_delete_all_device_attribute_property) ENABLED START -----*/

	TangoSys_MemStream sql_query_stream;
	const char *attribute;
	std::string tmp_device;
	MYSQL_RES *result;
	MYSQL_ROW row;

	if (argin->length() < 2) {
   		WARN_STREAM << "DataBase::db_delete_all_device_attribute_property(): insufficient number of arguments ";
   		WARN_STREAM << std::endl;
   		Tango::Except::throw_exception(DB_IncorrectArguments,
					       "insufficient number of arguments to delete all device attribute(s) property",
					       "DataBase::db_delete_all_device_attribute_property()");
	}

	tmp_device = (*argin)[0];
	if (!check_device_name(tmp_device))
	{
        	WARN_STREAM << "DataBase::db_delete_all_device_attribute(): device name  " << tmp_device << " incorrect ";
         	WARN_STREAM << std::endl;
         	Tango::Except::throw_exception(DB_IncorrectDeviceName,
				       	"Failed to delete all device attribute(s) property, device name incorrect",
				       	"DataBase::db_delete_all_device_attribute()");
	}


	{
		AutoLock al(this);

		for (unsigned int i=0; i<argin->length()-1; i++)
		{
			attribute = (*argin)[i+1];

			INFO_STREAM << "DataBase::db_delete_all_device_attribute_property(): delete device " << tmp_device ;
			INFO_STREAM << " attribute " << attribute << " property(ies) from database" << std::endl;

// Is there something to delete ?

			sql_query_stream.str("");
			sql_query_stream << "SELECT DISTINCT name FROM property_attribute_device WHERE device = \"" << tmp_device
		                	 <<"\" AND attribute = \"" << attribute << "\" ";
			result = query(sql_query_stream.str(),"db_delete_all_device_attribute_property()",al.get_dch());
			my_ulonglong count = mysql_num_rows(result);

			if (count != 0)
			{

// then delete property from the property_attribute_device table

				sql_query_stream.str("");
				sql_query_stream << "DELETE FROM property_attribute_device WHERE device = \"" << tmp_device
		       					<<"\" AND attribute = \"" << attribute << "\" ";
				DEBUG_STREAM << "DataBase::db_delete_all_device_attribute_property(): sql_query " << sql_query_stream.str() << std::endl;
				simple_query(sql_query_stream.str(),"db_delete_all_device_attribute_property()",al.get_dch());

// Mark this property as deleted

				for(unsigned int j=0;j<count;j++)
				{
					row = mysql_fetch_row(result);
					Tango::DevULong64 device_attribute_property_hist_id = get_id("device_attribute",al.get_dch());
					sql_query_stream.str("");
					sql_query_stream << "INSERT INTO property_attribute_device_hist SET device='" << tmp_device
			   					 << "',attribute='" << attribute
			   					 << "',name='" << row[0]
			   					 << "',id='" << device_attribute_property_hist_id
			   					 << "',count='0',value='DELETED'";
					DEBUG_STREAM << "DataBase::DeletAllDeviceAttributeProperty(): sql_query " << sql_query_stream.str() << std::endl;
					simple_query(sql_query_stream.str(),"db_delete_all_device_attribute_property()",al.get_dch());
					purge_att_property("property_attribute_device_hist","device",tmp_device.c_str(),attribute,row[0],al.get_dch());
				}
			}
			mysql_free_result(result);
		}
	}

	return;

	/*----- PROTECTED REGION END -----*/	//	DataBase::db_delete_all_device_attribute_property
}
//--------------------------------------------------------
/**
 *	Command DbMySqlSelect related method
 *	Description: This is a very low level command.
 *               It executes the specified  SELECT command on TANGO database and returns its result without filter.
 *
 *	@param argin MySql Select command
 *	@returns MySql Select command result
 *            - svalues : select results
 *            - lvalue[n] : =0 if svalue[n] is null else =1
 *            (last lvalue -1) is number of rows, (last lvalue) is number of fields
 */
//--------------------------------------------------------
Tango::DevVarLongStringArray *DataBase::db_my_sql_select(Tango::DevString argin)
{
	Tango::DevVarLongStringArray *argout;
	DEBUG_STREAM << "DataBase::DbMySqlSelect()  - " << device_name << std::endl;
	/*----- PROTECTED REGION ID(DataBase::db_my_sql_select) ENABLED START -----*/

	TimeVal	before, after;
	GetTime(before);

	//	Check if SELECT key is alread inside command
	std::string	cmd(argin);
	std::string	tmp(argin);
	transform(tmp.begin(), tmp.end(), tmp.begin(), ::tolower);
	std::string::size_type	idx = tmp.find("select");
	if (idx == std::string::npos)
		cmd = "SELECT " + cmd;

	// Check that there is no SQL injection

	idx = tmp.find(';');
	if ((idx != std::string::npos) && (tmp.size() > (idx + 1)))
	{
 	    TangoSys_OMemStream o;
		o << "SQL command not valid: \'" << argin << "\'";
		std::string msg = o.str();
		WARN_STREAM << msg << std::endl;
		Tango::Except::throw_exception(DB_IncorrectArguments,
	   				                   msg,
					                   "DataBase::db_my_sql_select()");
	}

	INFO_STREAM << "DataBase::db_my_sql_select(): \ncmd: " << cmd << std::endl;

	MYSQL_RES	*result   = query(cmd, "db_my_sql_select()");
	int			nb_rows   = mysql_num_rows(result);
	int			nb_fields = mysql_num_fields(result);
	int			nb_data   = nb_rows*nb_fields;

	DEBUG_STREAM << "DataBase::db_my_sql_select(): mysql_num_rows() " << nb_rows << std::endl;


	argout = new Tango::DevVarLongStringArray;
	(argout->svalue).length(nb_data);
	(argout->lvalue).length(nb_data+2);

	MYSQL_ROW	row;
	idx = 0;

	if (nb_rows>0)
	{
		for (int i=0; i<nb_rows; i++)
		{
			row = mysql_fetch_row(result);
			for (int j=0 ; j<nb_fields ; j++)
			{
				if (row==NULL)
				{
					(argout->svalue)[idx] = CORBA::string_dup("");
					(argout->lvalue)[idx++] = 0;	//	data is null
				}
				else
				if (row[j]==NULL)
					(argout->svalue)[idx] = CORBA::string_dup("");	//	data is null
				else
					(argout->svalue)[idx] = CORBA::string_dup(row[j]);	//	data is NOT null
				(argout->lvalue)[idx++] = (row[j]!=NULL);
			}
		}
	}
	//	Add nb rows and nb fields at end of lvalue.
	(argout->lvalue)[idx++] = nb_rows;
	(argout->lvalue)[idx++] = nb_fields;
	mysql_free_result(result);

	GetTime(after);
	update_timing_stats(before, after, "DbMySqlSelect");

	/*----- PROTECTED REGION END -----*/	//	DataBase::db_my_sql_select
	return argout;
}
//--------------------------------------------------------
/**
 *	Command DbGetCSDbServerList related method
 *	Description: Get a list of host:port for all database server defined in the control system
 *
 *	@returns List of host:port with one element for each database server
 */
//--------------------------------------------------------
Tango::DevVarStringArray *DataBase::db_get_csdb_server_list()
{
	Tango::DevVarStringArray *argout;
	DEBUG_STREAM << "DataBase::DbGetCSDbServerList()  - " << device_name << std::endl;
	/*----- PROTECTED REGION ID(DataBase::db_get_csdb_server_list) ENABLED START -----*/

	TangoSys_MemStream	sql_query_stream;
	MYSQL_RES *result;
	MYSQL_ROW row;
	int n_rows;

	sql_query_stream << "SELECT DISTINCT ior FROM device WHERE exported=1 AND domain=\'sys\' AND family=\'database\'";

	DEBUG_STREAM << "DataBase::db_get_csdb_server_list(): sql_query " << sql_query_stream.str() << std::endl;

	result = query(sql_query_stream.str(),"db_get_csdb_server_list()");

	n_rows = mysql_num_rows(result);
	DEBUG_STREAM << "DataBase::db_get_csdb_server_list(): mysql_num_rows() " << n_rows << std::endl;
	argout = new Tango::DevVarStringArray;

	if (n_rows > 0)
	{
	   argout->length(n_rows);
	   for (int i=0; i<n_rows; i++)
	   {
	      if ((row = mysql_fetch_row(result)) != NULL)
	      {
	         DEBUG_STREAM << "DataBase::db_get_csdb_server_list(): ior[ "<< i << "] " << row[0] << std::endl;
			 std::string h_p;
			 bool ret = host_port_from_ior(row[0],h_p);
			 if (ret == true)
	         	(*argout)[i] = CORBA::string_dup(h_p.c_str());
			 else
			 {
				mysql_free_result(result);
				delete argout;
 	    		TangoSys_OMemStream o;
				o << "Wrong IOR in database for at least one of the database server(s)";
				std::string msg = o.str();
				WARN_STREAM << msg << std::endl;
				Tango::Except::throw_exception("DB_WrongIORForDbServer",
	   				                   msg,
					                   "DataBase::db_get_csdb_server_list()");
			 }
	      }
	   }
	}
	else
		argout->length(0);
	mysql_free_result(result);

	/*----- PROTECTED REGION END -----*/	//	DataBase::db_get_csdb_server_list
	return argout;
}
//--------------------------------------------------------
/**
 *	Command DbGetAttributeAlias2 related method
 *	Description: Get the attribute alias from the attribute name.
 *               Returns one empty string if nothing found in database
 *
 *	@param argin The attribute name (dev_name/att_name)
 *	@returns The attribute alias name (or empty string)
 */
//--------------------------------------------------------
Tango::DevString DataBase::db_get_attribute_alias2(Tango::DevString argin)
{
	Tango::DevString argout;
	DEBUG_STREAM << "DataBase::DbGetAttributeAlias2()  - " << device_name << std::endl;
	/*----- PROTECTED REGION ID(DataBase::db_get_attribute_alias2) ENABLED START -----*/

	TangoSys_MemStream sql_query_stream;
	MYSQL_RES *result;
	MYSQL_ROW row;
	long n_rows=0;
	argout  = new char[256];

	INFO_STREAM << "DataBase::db_get_attribute_alias2(): get " << argin << std::endl;

// first check to see if this alias exists

	sql_query_stream << "SELECT alias from attribute_alias WHERE name LIKE \'" << argin << "\' ";
	DEBUG_STREAM << "DataBase::db_get_attribute_alias2(): sql_query " << sql_query_stream.str() << std::endl;

	result = query(sql_query_stream.str(),"db_get_attribute_alias2()");

	n_rows = mysql_num_rows(result);
	DEBUG_STREAM << "DataBase::db_get_attribute_alias2(): mysql_num_rows() " << n_rows << std::endl;

	if (n_rows > 0)
	{
        if ((row = mysql_fetch_row(result)) != NULL)
        {
            DEBUG_STREAM << "DataBase::db_get_attribute_alias2(): attribute name "<< row[0] << std::endl;
            strcpy(argout,row[0]);
		}
	}
	else
	{
		//strcpy(argout,"");
        TangoSys_OMemStream o;
	   	o << "No alias found for attribute  \'" << argin << "\'";
		mysql_free_result(result);
		delete [] argout;
	   	Tango::Except::throw_exception(DB_SQLError,
	   				  	               o.str(),
					  	               "DataBase::db_get_attribute_alias2()");
	}

	/*----- PROTECTED REGION END -----*/	//	DataBase::db_get_attribute_alias2
	return argout;
}
//--------------------------------------------------------
/**
 *	Command DbGetAliasAttribute related method
 *	Description: Get the attribute name from the given alias.
 *               If the given alias is not found in database, returns an empty string
 *
 *	@param argin The attribute alias
 *	@returns The attribute name (dev_name/att_name)
 */
//--------------------------------------------------------
Tango::DevString DataBase::db_get_alias_attribute(Tango::DevString argin)
{
	Tango::DevString argout;
	DEBUG_STREAM << "DataBase::DbGetAliasAttribute()  - " << device_name << std::endl;
	/*----- PROTECTED REGION ID(DataBase::db_get_alias_attribute) ENABLED START -----*/

	TangoSys_MemStream sql_query_stream;
	MYSQL_RES *result;
	MYSQL_ROW row;
	long n_rows=0;
	argout  = new char[256];

	INFO_STREAM << "DataBase::db_get_alias_attribute(): get " << argin << std::endl;

// first check to see if this alias exists

	sql_query_stream << "SELECT name from attribute_alias WHERE alias LIKE \'" << argin << "\' ";
	DEBUG_STREAM << "DataBase::db_get_alias_attribute(): sql_query " << sql_query_stream.str() << std::endl;

	result = query(sql_query_stream.str(),"db_get_alias_attribute()");

	n_rows = mysql_num_rows(result);
	DEBUG_STREAM << "DataBase::db_get_alias_attribute(): mysql_num_rows() " << n_rows << std::endl;

	if (n_rows > 0)
	{
        if ((row = mysql_fetch_row(result)) != NULL)
        {
            DEBUG_STREAM << "DataBase::db_get_alias_attribute(): attribute name "<< row[0] << std::endl;
            strcpy(argout,row[0]);
		}
	}
	else
	{
		//strcpy(argout,"");
        TangoSys_OMemStream o;
	   	o << "No attribute found for alias  \'" << argin << "\'";
		mysql_free_result(result);
		delete [] argout;
	   	Tango::Except::throw_exception(DB_SQLError,
	   				  	               o.str(),
					  	               "DataBase::db_get_alias_attribute()");
	}

	mysql_free_result(result);

	/*----- PROTECTED REGION END -----*/	//	DataBase::db_get_alias_attribute
	return argout;
}
//--------------------------------------------------------
/**
 *	Command DbRenameServer related method
 *	Description: Rename a device server process
 *
 *	@param argin s[0] = old device server name (exec/instance)
 *               s[1] = new device server name (exec/instance)
 */
//--------------------------------------------------------
void DataBase::db_rename_server(const Tango::DevVarStringArray *argin)
{
	DEBUG_STREAM << "DataBase::DbRenameServer()  - " << device_name << std::endl;
	/*----- PROTECTED REGION ID(DataBase::db_rename_server) ENABLED START -----*/


//
// Check argument validity
//

	if (argin->length() != 2)
	{
		Tango::Except::throw_exception("DB_WrongArgNUmber",
	   				                   "Wrong number of args (two required: old name and new name)",
					                   "DataBase::db_rename_server()");
	}

	std::string old_name((*argin)[0]);
	std::string new_name((*argin)[1]);

	std::string::size_type pos_old,pos_new;

	pos_old = old_name.find('/');
	pos_new = new_name.find('/');

	if ((pos_old == std::string::npos) || (pos_new == std::string::npos))
	{
		Tango::Except::throw_exception("Db_WrongArgument","Wrong syntax in command args (ds_exec_name/inst_name)",
										"DataBase::db_rename_server()");
	}

//
// Check that the new name is not already used
//

	std::string new_adm_name("dserver/");
	new_adm_name = new_adm_name + new_name;

	TangoSys_MemStream sql_query_stream;
	MYSQL_RES *result;
	long n_rows=0;

	sql_query_stream << "SELECT name from device WHERE name = \'" << new_adm_name << "\' ";
	DEBUG_STREAM << "DataBase::db_rename_server(): sql_query " << sql_query_stream.str() << std::endl;

	result = query(sql_query_stream.str(),"db_rename_server()");

	n_rows = mysql_num_rows(result);
	DEBUG_STREAM << "DataBase::db_rename_server(): mysql_num_rows() " << n_rows << std::endl;

	if (n_rows > 0)
	{
		mysql_free_result(result);

		std::stringstream ss;
		ss << "Device server process name " << new_name << " is already used";
		Tango::Except::throw_exception("Db_WrongArgument",ss.str(),"DataBase::db_rename_server()");
	}

//
//	get  host where running
//
	std::string	previous_host("");
	if (fireToStarter==true)
	{
		omni_mutex_lock oml(starter_mutex);

		std::string	adm_dev("dserver/");
		adm_dev += old_name;
		try
		{
			char *tmp_ptr = db_get_device_host((Tango::DevString)adm_dev.c_str());
			previous_host = tmp_ptr;
			DEBUG_STREAM << old_name << " was running on " << previous_host << std::endl;
			CORBA::string_free(tmp_ptr);
		}
		catch (Tango::DevFailed &e)
		{
			std::string reason(e.errors[0].reason.in());
			if (reason == DB_DeviceNotDefined)
			{
				WARN_STREAM << "DataBase::db_delete_server(): server " << old_name << " not defined in DB" << std::endl;
				TangoSys_OMemStream o;
				o << "Server " << old_name << " not defined in database !";
				Tango::Except::throw_exception(DB_IncorrectServerName,o.str(),
							   "DataBase::db_delete_server()");
			}
		}

	}


//
// Change ds exec name. This means
// 1 - Update the device's server column
// 2 - Change the ds admin device name
// 3 - Change admin device property (if any)
// 4 - Change admin device attribute property (if any)
//

	std::string old_adm_name("dserver/");
	old_adm_name = old_adm_name + old_name;

	std::string new_exec = new_name.substr(0,pos_new);
	std::string new_inst = new_name.substr(pos_new + 1);

	{
		AutoLock al(this);

   		sql_query_stream.str("");
		sql_query_stream << "UPDATE device set server=\'" << new_name << "\' where server=\'" << old_name << "\'";
		DEBUG_STREAM << "DataBase::db_rename_server(): sql_query " << sql_query_stream.str() << std::endl;

		simple_query(sql_query_stream.str(),"db_rename_server()",al.get_dch());

   		sql_query_stream.str("");
		sql_query_stream << "UPDATE device set name=\'" << new_adm_name;
		sql_query_stream << "\', family=\'" << new_exec;
		sql_query_stream << "\', member=\'" << new_inst;
		sql_query_stream << "\' where name=\'" << old_adm_name << "\'";
		DEBUG_STREAM << "DataBase::db_rename_server(): sql_query " << sql_query_stream.str() << std::endl;

		simple_query(sql_query_stream.str(),"db_rename_server()",al.get_dch());

   		sql_query_stream.str("");
		sql_query_stream << "UPDATE property_device set device=\'" << new_adm_name;
		sql_query_stream << "\' where device=\'" << old_adm_name << "\'";
		DEBUG_STREAM << "DataBase::db_rename_server(): sql_query " << sql_query_stream.str() << std::endl;

		simple_query(sql_query_stream.str(),"db_rename_server()",al.get_dch());

   		sql_query_stream.str("");
		sql_query_stream << "UPDATE property_attribute_device set device=\'" << new_adm_name;
		sql_query_stream << "\' where device=\'" << old_adm_name << "\'";
		DEBUG_STREAM << "DataBase::db_rename_server(): sql_query " << sql_query_stream.str() << std::endl;

		simple_query(sql_query_stream.str(),"db_rename_server()",al.get_dch());
	}

//
//	Update host's starter to update controlled servers list
//
	if (fireToStarter==true)
	{
		omni_mutex_lock oml(starter_mutex);

		std::vector<std::string>	hosts;
		if (previous_host!="")
		{
			hosts.push_back(previous_host);
			starter_shared->send_starter_cmd(hosts);
		}
	}
	/*----- PROTECTED REGION END -----*/	//	DataBase::db_rename_server
}
//--------------------------------------------------------
/**
 *	Command DbGetClassPipeProperty related method
 *	Description: Retrieve class pipe properties
 *
 *	@param argin Str[0] = Tango class name
 *               Str[1] = Pipe name
 *               Str[n] = Pipe name
 *	@returns Str[0] = Tango class name
 *           Str[1] = Pipe property  number
 *           Str[2] = Pipe property 1 name
 *           Str[3] = Pipe property 1 value number (array case)
 *           Str[4] = Pipe property 1 value
 *           Str[n] = Pipe property 1 value (array case)
 *           Str[n + 1] = Pipe property 2 name
 *           Str[n + 2] = Pipe property 2 value number (array case)
 *           Str[n + 3] = Pipe property 2 value
 *           Str[n + m] = Pipe property 2 value (array case)
 */
//--------------------------------------------------------
Tango::DevVarStringArray *DataBase::db_get_class_pipe_property(const Tango::DevVarStringArray *argin)
{
	Tango::DevVarStringArray *argout;
	DEBUG_STREAM << "DataBase::DbGetClassPipeProperty()  - " << device_name << std::endl;
	/*----- PROTECTED REGION ID(DataBase::db_get_class_pipe_property) ENABLED START -----*/


	const Tango::DevVarStringArray  *property_names = argin;
	DEBUG_STREAM << "DataBase::db_get_class_pipe_property(): entering... !" << std::endl;

	TangoSys_MemStream sql_query_stream;
	char n_rows_str[256];
	char prop_size_str[256];
	MYSQL_RES *result;
	MYSQL_ROW row;
	int n_rows=0, n_props=0;
	argout = new Tango::DevVarStringArray;
	const char *tmp_class, *tmp_pipe;

	INFO_STREAM << "DataBase::GetClassPipeProperty(): get properties for " << property_names->length()-1 << " pipe(s) for class " << (*property_names)[0] << std::endl;

	tmp_class = (*property_names)[0];
	n_props = 2;
	argout->length(n_props);
	(*argout)[n_props-2] = CORBA::string_dup(tmp_class);
	(*argout)[n_props-1] = to_corba_string(property_names->length() - 1);

	for (unsigned int i=1; i<property_names->length(); i++)
	{
	   	tmp_pipe = (*property_names)[i];
		sql_query_stream.str("");
		sql_query_stream << "SELECT name,value FROM property_pipe_class WHERE class = \""
		                 << tmp_class << "\" AND pipe LIKE \"" << tmp_pipe
						 << "\" ORDER BY name,count";
	   	DEBUG_STREAM << "DataBase::GetClassPipeProperty(): sql_query " << sql_query_stream.str() << std::endl;

		result = query(sql_query_stream.str(),"db_get_class_pipe_property()");

	   	n_rows = mysql_num_rows(result);
	   	DEBUG_STREAM << "DataBase::GetClassPipeProperty(): mysql_num_rows() " << n_rows << std::endl;
	   	n_props = n_props+2;
	   	argout->length(n_props);
	   	(*argout)[n_props-2] = CORBA::string_dup(tmp_pipe);
		int prop_number_idx = n_props-1;
		int prop_number = 0;
	   	if (n_rows > 0)
	   	{
			std::string name, old_name;
			bool new_prop = true;
			int prop_size_idx = 0;
			int prop_size = 0;
	      	for (int j=0; j<n_rows; j++)
	      	{
	        	if ((row = mysql_fetch_row(result)) != NULL)
	         	{
					name = row[0];
					if (j == 0)
						old_name = name;
					else
					{
						name = row[0];
						if (name != old_name)
						{
							new_prop = true;
							old_name = name;
						}
						else
							new_prop = false;
					}
//	            			DEBUG_STREAM << "DataBase::GetClassPipeProperty(): property[ "<< i << "] count " << row[0] << " value " << row[1] << std::endl;
					if (new_prop == true)
					{
						n_props = n_props + 3;
						argout->length(n_props);
	            		(*argout)[n_props-3] = CORBA::string_dup(row[0]);
	            		(*argout)[n_props-1] = CORBA::string_dup(row[1]);
						if (prop_size != 0)
						{
							sprintf(prop_size_str,"%d",prop_size);
							(*argout)[prop_size_idx] = CORBA::string_dup(prop_size_str);
							prop_number++;
						}
						prop_size_idx = n_props - 2;
						prop_size = 1;
					}
					else
					{
						n_props = n_props + 1;
						argout->length(n_props);
						(*argout)[n_props-1] = CORBA::string_dup(row[1]);
						prop_size++;
					}
	         	}
	      	}
			if (prop_size != 0)
			{
				sprintf(prop_size_str,"%d",prop_size);
				(*argout)[prop_size_idx] = CORBA::string_dup(prop_size_str);
				prop_number++;
			}
	   	}
	   	sprintf(n_rows_str,"%d",prop_number);
		(*argout)[prop_number_idx] = CORBA::string_dup(n_rows_str);
	   	mysql_free_result(result);
	}

	DEBUG_STREAM << "DataBase::GetClassPipeProperty(): argout->length() "<< argout->length() << std::endl;

	/*----- PROTECTED REGION END -----*/	//	DataBase::db_get_class_pipe_property
	return argout;
}
//--------------------------------------------------------
/**
 *	Command DbGetDevicePipeProperty related method
 *	Description: Retrieve device pipe properties
 *
 *	@param argin Str[0] = Device name
 *               Str[1] = Pipe name
 *               Str[n] = Pipe name
 *	@returns Str[0] = Device name
 *           Str[1] = Pipe property  number
 *           Str[2] = Pipe property 1 name
 *           Str[3] = Pipe property 1 value number (array case)
 *           Str[4] = Pipe property 1 value
 *           Str[n] = Pipe property 1 value (array case)
 *           Str[n + 1] = Pipe property 2 name
 *           Str[n + 2] = Pipe property 2 value number (array case)
 *           Str[n + 3] = Pipe property 2 value
 *           Str[n + m] = Pipe property 2 value (array case)
 */
//--------------------------------------------------------
Tango::DevVarStringArray *DataBase::db_get_device_pipe_property(const Tango::DevVarStringArray *argin)
{
	Tango::DevVarStringArray *argout;
	DEBUG_STREAM << "DataBase::DbGetDevicePipeProperty()  - " << device_name << std::endl;
	/*----- PROTECTED REGION ID(DataBase::db_get_device_pipe_property) ENABLED START -----*/

	const Tango::DevVarStringArray  *property_names = argin;
	TangoSys_MemStream sql_query_stream;
	char n_rows_str[256];
	char prop_size_str[256];
	MYSQL_RES *result;
	MYSQL_ROW row;
	int n_rows=0, n_props=0;
	argout = new Tango::DevVarStringArray;
	const char *tmp_device, *tmp_pipe;

	TimeVal	before, after;
	GetTime(before);

	INFO_STREAM << "DataBase::GetDevicePipeProperty(): get properties for " << property_names->length()-1 << " pipe(s) for device " << (*property_names)[0] << std::endl;

	tmp_device = (*property_names)[0];
	n_props = 2;
	argout->length(n_props);
	(*argout)[n_props-2] = CORBA::string_dup(tmp_device);
	(*argout)[n_props-1] = to_corba_string(property_names->length() - 1);

//
// First, get how many pipes belonging to the device have
// properties defined in the db
//

	bool all_pipe = false;
	sql_query_stream << "SELECT COUNT(DISTINCT pipe) FROM property_pipe_device WHERE device = \"" << tmp_device << "\"";
	DEBUG_STREAM << "Database::GetDevicePipeProperty(): sql_query " << sql_query_stream.str() << std::endl;

	result = query(sql_query_stream.str(),"db_get_device_pipe_property()");
	n_rows = mysql_num_rows(result);
	DEBUG_STREAM << "DataBase::GetDevicePipeProperty(): mysql_num_rows() " << n_rows << std::endl;

	if (n_rows != 0)
	{
		if ((row = mysql_fetch_row(result)) != NULL)
		{
			std::stringstream tmp_str;
			std::string nb_pipe_str = row[0];
		 	tmp_str << nb_pipe_str;
			unsigned int nb_pipe = 0;
			tmp_str >> nb_pipe;
			if (property_names->length()-1 >= nb_pipe)
				all_pipe = true;
	   		mysql_free_result(result);
		}
	}

	if (all_pipe == true)
	{
		DEBUG_STREAM << "DataBase::GetDevicePipeProperty(): Get pipe properties for all pipe(s)" << std::endl;
	}

	if (all_pipe == false)
	{
		for (unsigned int i=1; i<property_names->length(); i++)
		{
	   		tmp_pipe = (*property_names)[i];
			sql_query_stream.str("");
			sql_query_stream << "SELECT name,value FROM property_pipe_device WHERE device = \""
		                 << tmp_device << "\" AND pipe LIKE \"" << tmp_pipe
						 << "\" ORDER BY name,count";
	   		DEBUG_STREAM << "DataBase::GetDevicePipeProperty(): sql_query " << sql_query_stream.str() << std::endl;

			result = query(sql_query_stream.str(),"db_get_device_pipe_property()");

	   		n_rows = mysql_num_rows(result);
	   		DEBUG_STREAM << "DataBase::GetDevicePipeProperty(): mysql_num_rows() " << n_rows << std::endl;
	   		n_props = n_props+2;
	   		argout->length(n_props);
	   		(*argout)[n_props-2] = CORBA::string_dup(tmp_pipe);
			int prop_number_idx = n_props-1;
			int prop_number = 0;
	   		if (n_rows > 0)
	   		{
				std::string name, old_name;
				bool new_prop = true;
				int prop_size_idx = 0;
				int prop_size = 0;
	      		for (int j=0; j<n_rows; j++)
	      		{
	        		if ((row = mysql_fetch_row(result)) != NULL)
	         		{
						name = row[0];
						if (j == 0)
							old_name = name;
						else
						{
							name = row[0];
							if (name != old_name)
							{
								new_prop = true;
								old_name = name;
							}
							else
								new_prop = false;
						}
//	            			DEBUG_STREAM << "DataBase::GetDevicePipeProperty(): property[ "<< i << "] count " << row[0] << " value " << row[1] << std::endl;
						if (new_prop == true)
						{
							n_props = n_props + 3;
							argout->length(n_props);
	            			(*argout)[n_props-3] = CORBA::string_dup(row[0]);
	            			(*argout)[n_props-1] = CORBA::string_dup(row[1]);
							if (prop_size != 0)
							{
								sprintf(prop_size_str,"%d",prop_size);
								(*argout)[prop_size_idx] = CORBA::string_dup(prop_size_str);
								prop_number++;
							}
							prop_size_idx = n_props - 2;
							prop_size = 1;
						}
						else
						{
							n_props = n_props + 1;
							argout->length(n_props);
							(*argout)[n_props-1] = CORBA::string_dup(row[1]);
							prop_size++;
						}
	         		}
	      		}
				if (prop_size != 0)
				{
					sprintf(prop_size_str,"%d",prop_size);
					(*argout)[prop_size_idx] = CORBA::string_dup(prop_size_str);
					prop_number++;
				}
	   		}
	   		sprintf(n_rows_str,"%d",prop_number);
			(*argout)[prop_number_idx] = CORBA::string_dup(n_rows_str);
	   		mysql_free_result(result);
		}
	}
	else
	{
		sql_query_stream.str("");
		sql_query_stream << "SELECT pipe,name,value FROM property_pipe_device WHERE device = \""
		                 << tmp_device << "\" ORDER BY pipe,name,count";
	   	DEBUG_STREAM << "DataBase::GetDevicePipeProperty(): sql_query " << sql_query_stream.str() << std::endl;

		result = query(sql_query_stream.str(),"db_get_device_pipe_property()");
		n_rows = mysql_num_rows(result);
		DEBUG_STREAM << "DataBase::GetDevicePipeProperty(): mysql_num_rows() " << n_rows << std::endl;

		std::map<std::string,std::vector<PropDef> > db_data;

		std::string pipe,prev_pipe;
		std::string p_name,prev_p_name;
		std::string value;
		PropDef prop;
		std::vector<PropDef> pipe_props;

//
// Create a map with data coming from db
//

		for (int j = 0;j < n_rows;j++)
		{
			if ((row = mysql_fetch_row(result)) != NULL)
			{
				pipe = row[0];
				transform(pipe.begin(),pipe.end(),pipe.begin(),::tolower);

				if (pipe != prev_pipe)
				{
					if (j != 0)
					{
						pipe_props.push_back(prop);
						db_data.insert(make_pair(prev_pipe,pipe_props));
						prop.prop_val.clear();
						pipe_props.clear();
					}
					p_name = row[1];
					prop.prop_name_cd = p_name;
					transform(p_name.begin(),p_name.end(),p_name.begin(),::tolower);

					prop.prop_name = p_name;
					value = row[2];
					prop.prop_val.push_back(value);

					prev_p_name = p_name;
					prev_pipe = pipe;
				}
				else
				{
					p_name = row[1];
					transform(p_name.begin(),p_name.end(),p_name.begin(),::tolower);

					if (p_name != prev_p_name)
					{
						pipe_props.push_back(prop);
						prop.prop_val.clear();

						prop.prop_name = p_name;
						prop.prop_name_cd = row[1];
						value = row[2];
						prop.prop_val.push_back(value);

						prev_p_name = p_name;
					}
					else
					{
						value = row[2];
						prop.prop_val.push_back(value);
					}
				}
			}
		}
	   	mysql_free_result(result);

		if (n_rows != 0)
		{
			pipe_props.push_back(prop);
			db_data.insert(make_pair(pipe,pipe_props));
		}

//
// Initialized data returned to caller
//

		for (unsigned int i=1; i<property_names->length(); i++)
		{
	   		std::string tmp_pipe((*property_names)[i]);
			std::string tmp_pipe_lower(tmp_pipe);
			transform(tmp_pipe_lower.begin(),tmp_pipe_lower.end(),tmp_pipe_lower.begin(),::tolower);

			std::map<std::string,std::vector<PropDef> >::iterator pos = db_data.find(tmp_pipe_lower);

//
// Data for this pipe in map?
//

			if (pos == db_data.end())
			{
	   			n_props = n_props+2;
	   			argout->length(n_props);
	   			(*argout)[n_props-2] = CORBA::string_dup(tmp_pipe.c_str());
				(*argout)[n_props-1] = CORBA::string_dup("0");
			}
			else
			{
				int prop_nb = pos->second.size();

	   			n_props = n_props + 2;
	   			argout->length(n_props);
	   			(*argout)[n_props - 2] = CORBA::string_dup(tmp_pipe.c_str());
	   			sprintf(n_rows_str,"%d",prop_nb);
				(*argout)[n_props - 1] = CORBA::string_dup(n_rows_str);

				for (int i = 0;i < prop_nb;i++)
				{
					PropDef &pd = (pos->second)[i];
					int prop_size = pd.prop_val.size();
					int old_n_props = n_props;
					n_props = n_props + 2 + prop_size;

					argout->length(n_props);
					(*argout)[old_n_props++] = CORBA::string_dup(pd.prop_name_cd.c_str());
	   				sprintf(n_rows_str,"%d",prop_size);
					(*argout)[old_n_props++] = CORBA::string_dup(n_rows_str);

					for (int j = 0;j < prop_size;j++)
					{
						(*argout)[old_n_props++] = CORBA::string_dup(pd.prop_val[j].c_str());
					}
				}
			}
		}
	}

	DEBUG_STREAM << "DataBase::GetDevicePipeProperty(): argout->length() "<< argout->length() << std::endl;

	GetTime(after);
	update_timing_stats(before, after, "DbGetDevicePipeProperty");

	/*----- PROTECTED REGION END -----*/	//	DataBase::db_get_device_pipe_property
	return argout;
}
//--------------------------------------------------------
/**
 *	Command DbDeleteClassPipe related method
 *	Description: Delete a class pipe and all its properties from database
 *
 *	@param argin Str[0] = Tango class name
 *               Str[1] = Pipe name
 */
//--------------------------------------------------------
void DataBase::db_delete_class_pipe(const Tango::DevVarStringArray *argin)
{
	DEBUG_STREAM << "DataBase::DbDeleteClassPipe()  - " << device_name << std::endl;
	/*----- PROTECTED REGION ID(DataBase::db_delete_class_pipe) ENABLED START -----*/

	TangoSys_MemStream sql_query_stream;
	const char *pipe;
	std::string tmp_class;

	if (argin->length() < 2) {
   		WARN_STREAM << "DataBase::db_delete_class_pipe(): insufficient number of arguments ";
   		WARN_STREAM << std::endl;
   		Tango::Except::throw_exception(DB_IncorrectArguments,
					       "insufficient number of arguments to delete class pipe",
					       "DataBase::db_delete_class_pipe()");
	}

	tmp_class = (*argin)[0];
	pipe = (*argin)[1];

	INFO_STREAM << "DataBase::db_delete_class_pipe(): delete " << tmp_class << " from database" << std::endl;

// then delete class from the property_pipe_class table

    sql_query_stream << "DELETE FROM property_pipe_class WHERE class LIKE \"" << tmp_class
	                 << "\" AND pipe LIKE \"" << pipe << "\" ";
    DEBUG_STREAM << "DataBase::db_delete_class_pipe(): sql_query " << sql_query_stream.str() << std::endl;
	simple_query(sql_query_stream.str(),"db_delete_class_pipe()");

	/*----- PROTECTED REGION END -----*/	//	DataBase::db_delete_class_pipe
}
//--------------------------------------------------------
/**
 *	Command DbDeleteDevicePipe related method
 *	Description: Delete device pipe properties from database
 *
 *	@param argin Str[0] = Device name
 *               Str[1] = Pipe name
 */
//--------------------------------------------------------
void DataBase::db_delete_device_pipe(const Tango::DevVarStringArray *argin)
{
	DEBUG_STREAM << "DataBase::DbDeleteDevicePipe()  - " << device_name << std::endl;
	/*----- PROTECTED REGION ID(DataBase::db_delete_device_pipe) ENABLED START -----*/

	TangoSys_MemStream sql_query_stream;
	const char *pipe;
	std::string tmp_device;

	if (argin->length() < 2) {
   		WARN_STREAM << "DataBase::db_delete_device_pipe(): insufficient number of arguments ";
   		WARN_STREAM << std::endl;
   		Tango::Except::throw_exception(DB_IncorrectArguments,
					       "insufficient number of arguments to delete device pipe",
					       "DataBase::db_delete_device_pipe()");
	}

	tmp_device = (*argin)[0].in();
	pipe = (*argin)[1];

	INFO_STREAM << "DataBase::db_delete_device_pipe(): delete pipe " << pipe << " for device " << tmp_device << " from database" << std::endl;

// first check the device name

	if (!check_device_name(tmp_device))
	{
         	WARN_STREAM << "DataBase::db_delete_device_pipe(): device name  " << tmp_device << " incorrect ";
         	WARN_STREAM << std::endl;
         	Tango::Except::throw_exception(DB_IncorrectDeviceName,
					       "Failed to delete device pipe, device name incorrect",
					       "DataBase::db_delete_device_pipe()");
	}

// replace database wildcards (% and _)

	std::string tmp_wildcard = replace_wildcard(tmp_device.c_str());

// then delete device from the property_attribute_device table

    sql_query_stream << "DELETE FROM property_pipe_device WHERE device LIKE \""
	                 << tmp_wildcard << "\" AND pipe LIKE \"" << pipe << "\" ";
    DEBUG_STREAM << "DataBase::db_delete_device_pipe(): sql_query " << sql_query_stream.str() << std::endl;
	simple_query(sql_query_stream.str(),"db_delete_device_pipe()");

	/*----- PROTECTED REGION END -----*/	//	DataBase::db_delete_device_pipe
}
//--------------------------------------------------------
/**
 *	Command DbDeleteClassPipeProperty related method
 *	Description: Delete class pipe properties from database
 *
 *	@param argin Str[0] = Tango class name
 *               Str[1] = Pipe name
 *               Str[2] = Property name
 *               Str[n] = Property name
 */
//--------------------------------------------------------
void DataBase::db_delete_class_pipe_property(const Tango::DevVarStringArray *argin)
{
	DEBUG_STREAM << "DataBase::DbDeleteClassPipeProperty()  - " << device_name << std::endl;
	/*----- PROTECTED REGION ID(DataBase::db_delete_class_pipe_property) ENABLED START -----*/

	TangoSys_MemStream sql_query_stream;
	const char *pipe, *property;
	std::string tmp_class;
	MYSQL_RES *result;
	MYSQL_ROW row;

	if (argin->length() < 3) {
   		WARN_STREAM << "DataBase::db_delete_class_pipe_property(): insufficient number of arguments ";
   		WARN_STREAM << std::endl;
   		Tango::Except::throw_exception(DB_IncorrectArguments,
					       "Insufficient number of arguments to delete class pipe property",
					       "DataBase::db_delete_class_pipe_property()");
	}

	tmp_class = (*argin)[0];
	pipe = (*argin)[1];

	{
		AutoLock al(this);

		for (unsigned  int i=0; i<argin->length()-2; i++)
		{
			property = (*argin)[i+2];

			INFO_STREAM << "DataBase::db_delete_class_pipe_property(): delete class " << tmp_class ;
			INFO_STREAM << " pipe " << pipe << " property[" << i <<"] " << property << " from database" << std::endl;

// Is there something to delete ?

        	sql_query_stream.str("");
			sql_query_stream << "SELECT count(*) FROM property_pipe_class WHERE class = \"" << tmp_class
		                	 << "\" AND pipe = \"" << pipe << "\" AND name = \"" << property
							 << "\" ";
   			DEBUG_STREAM << "DataBase::db_delete_class_pipe_property(): sql_query " << sql_query_stream.str() << std::endl;
			result = query(sql_query_stream.str(),"db_delete_class_pipe_property()",al.get_dch());
 	    	row = mysql_fetch_row(result);
			int count;
			std::stringstream ss;
			ss << row[0];
			ss >> count;
  	    	mysql_free_result(result);

			if(count) {

// then delete property from the property_attribute_class table

        	  sql_query_stream.str("");
			  sql_query_stream << "DELETE FROM property_pipe_class WHERE class = \"" << tmp_class
		                	   << "\" AND pipe = \"" << pipe << "\" AND name = \"" << property
							   << "\" ";
   			  DEBUG_STREAM << "DataBase::db_delete_class_pipe_property(): sql_query " << sql_query_stream.str() << std::endl;
			  simple_query(sql_query_stream.str(),"db_delete_class_pipe_property()",al.get_dch());

// Mark this property as deleted

        	  Tango::DevULong64 class_pipe_property_hist_id = get_id("class_pipe",al.get_dch());
        	  sql_query_stream.str("");
			  sql_query_stream << "INSERT INTO property_pipe_class_hist SET class='" << tmp_class \
													 << "',pipe='" << pipe \
													 << "',name='" << property \
													 << "',id='" << class_pipe_property_hist_id \
													 << "',count='0',value='DELETED'";
	    	  DEBUG_STREAM << "DataBase::db_delete_class_pipe_property(): sql_query " << sql_query_stream.str() << std::endl;
			  simple_query(sql_query_stream.str(),"db_delete_class_pipe_property()",al.get_dch());

			}
			purge_pipe_property("property_pipe_class_hist","class",tmp_class.c_str(),pipe,property,al.get_dch());
		}
	}

	/*----- PROTECTED REGION END -----*/	//	DataBase::db_delete_class_pipe_property
}
//--------------------------------------------------------
/**
 *	Command DbDeleteDevicePipeProperty related method
 *	Description: Delete device pipe properties from database
 *
 *	@param argin Str[0] = Device name
 *               Str[1] = Pipe name
 *               Str[2] = Property name
 *               Str[n] = Property name
 */
//--------------------------------------------------------
void DataBase::db_delete_device_pipe_property(const Tango::DevVarStringArray *argin)
{
	DEBUG_STREAM << "DataBase::DbDeleteDevicePipeProperty()  - " << device_name << std::endl;
	/*----- PROTECTED REGION ID(DataBase::db_delete_device_pipe_property) ENABLED START -----*/

	TangoSys_MemStream sql_query_stream;
	const char *pipe, *property;
	std::string tmp_device;
	MYSQL_RES *result;
	MYSQL_ROW row;

	if (argin->length() < 3) {
   		WARN_STREAM << "DataBase::db_delete_device_pipe_property(): insufficient number of arguments ";
   		WARN_STREAM << std::endl;
   		Tango::Except::throw_exception(DB_IncorrectArguments,
					       "Insufficient number of arguments to delete device pipe property",
					       "DataBase::db_delete_device_pipe_property()");
	}

	tmp_device = (*argin)[0];
	if (!check_device_name(tmp_device))
	{
        	WARN_STREAM << "DataBase::db_delete_device_pipe(): device name  " << tmp_device << " incorrect ";
         	WARN_STREAM << std::endl;
         	Tango::Except::throw_exception(DB_IncorrectDeviceName,
				       	"Failed to delete device pipe, device name incorrect",
				       	"DataBase::db_delete_device_pipe_property()");
	}
	pipe = (*argin)[1];

	{
		AutoLock al(this);

		unsigned int i;
		for (i=0; i<argin->length()-2; i++)
		{
			property = (*argin)[i+2];

			INFO_STREAM << "DataBase::db_delete_device_pipe_property(): delete device " << tmp_device ;
			INFO_STREAM << " pipe " << pipe << " property[" << i <<"] " << property << " from database" << std::endl;

// Is there something to delete ?

			sql_query_stream.str("");
			sql_query_stream << "SELECT count(*) FROM property_pipe_device WHERE device = \"" << tmp_device
		                	 <<"\" AND pipe = \"" << pipe << "\" AND name = \"" << property << "\" ";
			result = query(sql_query_stream.str(),"db_delete_device_pipe_property()",al.get_dch());
 	    	row = mysql_fetch_row(result);
			int count;
			std::stringstream ss;
			ss << row[0];
			ss >> count;
  	    	mysql_free_result(result);

			if(count) {

// then delete property from the property_pipe_device table

			  sql_query_stream.str("");
			  sql_query_stream << "DELETE FROM property_pipe_device WHERE device = \"" << tmp_device
		                	   <<"\" AND pipe = \"" << pipe << "\" AND name = \"" << property << "\" ";
   			  DEBUG_STREAM << "DataBase::db_delete_device_pipe_property(): sql_query " << sql_query_stream.str() << std::endl;
			  simple_query(sql_query_stream.str(),"db_delete_device_pipe_property()",al.get_dch());

// Mark this property as deleted

        	  Tango::DevULong64 device_pipe_property_hist_id = get_id("device_pipe",al.get_dch());
			  sql_query_stream.str("");
			  sql_query_stream << "INSERT INTO property_pipe_device_hist SET device='" << tmp_device
							   << "',pipe='" << pipe
							   << "',name='" << property
							   << "',id='" << device_pipe_property_hist_id
							   << "',count='0',value='DELETED'";
	    	  DEBUG_STREAM << "DataBase::DbDeleteDevicePipeProperty(): sql_query " << sql_query_stream.str() << std::endl;
			  simple_query(sql_query_stream.str(),"db_delete_device_pipe_property()",al.get_dch());

			}
			purge_pipe_property("property_pipe_device_hist","device",tmp_device.c_str(),pipe,property,al.get_dch());
		}
	}

	/*----- PROTECTED REGION END -----*/	//	DataBase::db_delete_device_pipe_property
}
//--------------------------------------------------------
/**
 *	Command DbGetClassPipeList related method
 *	Description: Get pipe list for a given Tango class with a specified filter
 *
 *	@param argin Str[0] = Tango class name
 *               Str[1] = Pipe name filter (eg: pip*)
 *	@returns Str[0] = Class pipe name
 *           Str[n] = Class pipe name
 */
//--------------------------------------------------------
Tango::DevVarStringArray *DataBase::db_get_class_pipe_list(const Tango::DevVarStringArray *argin)
{
	Tango::DevVarStringArray *argout;
	DEBUG_STREAM << "DataBase::DbGetClassPipeList()  - " << device_name << std::endl;
	/*----- PROTECTED REGION ID(DataBase::db_get_class_pipe_list) ENABLED START -----*/

	const Tango::DevVarStringArray  *class_wildcard = argin;
	TangoSys_MemStream sql_query_stream;
	MYSQL_RES *result;
	MYSQL_ROW row;
	int n_rows=0;
	argout = new Tango::DevVarStringArray;
	const char *class_name, *wildcard;
	std::string tmp_wildcard;

	class_name = (*class_wildcard)[0];
	INFO_STREAM << "DataBase::db_get_class_pipe_list(): get pipes for class " << class_name << std::endl;

	wildcard = (*class_wildcard)[1];
	if (wildcard == NULL)
	{
#ifdef WIN32
		sql_query_stream << "SELECT DISTINCT pipe FROM property_pipe_class WHERE class = \"" << class_name << "\"  AND pipe like \"\\%\"";
#else
		sql_query_stream << "SELECT DISTINCT pipe FROM property_pipe_class WHERE class = \"" << class_name << "\"  AND pipe like \"%%\"";
#endif /* WIN32 */
	}
	else
	{
		tmp_wildcard = replace_wildcard(wildcard);
		sql_query_stream << "SELECT DISTINCT pipe FROM property_pipe_class WHERE class = \""
		                 << class_name << "\"  AND pipe like \"" << tmp_wildcard << "\"";
	}
	DEBUG_STREAM << "DataBase::DbGetClassPipeList(): sql_query " << sql_query_stream.str() << std::endl;

	result = query(sql_query_stream.str(),"db_get_class_pipe_list()");

	n_rows = mysql_num_rows(result);
	DEBUG_STREAM << "DataBase::DbGetClassPipeList(): num_rows() " << n_rows << std::endl;
	if (n_rows > 0)
	{
		  int n_pipes=0;
	      for (int j=0; j<n_rows; j++)
	      {
	         if ((row = mysql_fetch_row(result)) != NULL)
	         {
	            DEBUG_STREAM << "DataBase::DbGetClassPipeList(): pipe[ "<< j << "] " << row[0] << std::endl;
		    	n_pipes++;
		    	argout->length(n_pipes);
	            (*argout)[n_pipes-1] = CORBA::string_dup(row[0]);
	         }
	      }
	}
	mysql_free_result(result);

	DEBUG_STREAM << "DataBase::DbGetClassPipeList(): argout->length() "<< argout->length() << std::endl;

	/*----- PROTECTED REGION END -----*/	//	DataBase::db_get_class_pipe_list
	return argout;
}
//--------------------------------------------------------
/**
 *	Command DbGetDevicePipeList related method
 *	Description: Return list of pipes matching the wildcard for the specified device
 *
 *	@param argin Str[0] = Device name
 *               Str[1] = Wildcard
 *	@returns Pipe name list
 */
//--------------------------------------------------------
Tango::DevVarStringArray *DataBase::db_get_device_pipe_list(const Tango::DevVarStringArray *argin)
{
	Tango::DevVarStringArray *argout;
	DEBUG_STREAM << "DataBase::DbGetDevicePipeList()  - " << device_name << std::endl;
	/*----- PROTECTED REGION ID(DataBase::db_get_device_pipe_list) ENABLED START -----*/

	const Tango::DevVarStringArray  *device_wildcard = argin;
	TangoSys_MemStream sql_query_stream;
	std::string tmp_wildcard;
	MYSQL_RES *result;
	MYSQL_ROW row;
	int n_rows;
	const char *device, *wildcard;

	device = (*device_wildcard)[0];
	wildcard = (*device_wildcard)[1];
	INFO_STREAM << "DataBase::db_get_device_pipe_list(): device " << device;
	WARN_STREAM << " wildcard " << wildcard << std::endl;

	if (wildcard == NULL)
	{
		sql_query_stream << "SELECT DISTINCT pipe FROM property_pipe_device WHERE device=\""
		                 << device << "\" AND pipe LIKE \"%\" ORDER BY pipe";
	}
	else
	{
		tmp_wildcard = replace_wildcard (wildcard);
		sql_query_stream << "SELECT DISTINCT pipe FROM property_pipe_device WHERE device=\""
		                 << device << "\" AND pipe LIKE \"" << tmp_wildcard << "\" ORDER BY pipe";
	}
	DEBUG_STREAM << "DataBase::db_get_device_attrribute_list(): sql_query " << sql_query_stream.str() << std::endl;

	result = query(sql_query_stream.str(),"db_get_device_pipe_list()");

	n_rows = mysql_num_rows(result);
	DEBUG_STREAM << "DataBase::db_get_device_pipe_list(): mysql_num_rows() " << n_rows << std::endl;
	argout = new Tango::DevVarStringArray;

	if (n_rows > 0)
	{
	   argout->length(n_rows);

	   for (int i=0; i<n_rows; i++)
	   {
	      if ((row = mysql_fetch_row(result)) != NULL)
	      {
	         DEBUG_STREAM << "DataBase::db_get_device_pipe_list(): pipe[ "<< i << "] pipe " << row[0] << std::endl;
	         (*argout)[i]   = CORBA::string_dup(row[0]);
	      }
	   }
	}
	else
		argout->length(0);
	mysql_free_result(result);

	/*----- PROTECTED REGION END -----*/	//	DataBase::db_get_device_pipe_list
	return argout;
}
//--------------------------------------------------------
/**
 *	Command DbDeleteAllDevicePipeProperty related method
 *	Description: Delete all pipe properties for the specified device pipe(s)
 *
 *	@param argin str[0] = device name
 *               Str[1]...str[n] = pipe name(s)
 */
//--------------------------------------------------------
void DataBase::db_delete_all_device_pipe_property(const Tango::DevVarStringArray *argin)
{
	DEBUG_STREAM << "DataBase::DbDeleteAllDevicePipeProperty()  - " << device_name << std::endl;
	/*----- PROTECTED REGION ID(DataBase::db_delete_all_device_pipe_property) ENABLED START -----*/

	TangoSys_MemStream sql_query_stream;
	const char *pipe;
	std::string tmp_device;
	MYSQL_RES *result;
	MYSQL_ROW row;

	if (argin->length() < 2) {
   		WARN_STREAM << "DataBase::db_delete_all_device_pipe_property(): insufficient number of arguments ";
   		WARN_STREAM << std::endl;
   		Tango::Except::throw_exception(DB_IncorrectArguments,
					       "Insufficient number of arguments to delete all device pipe(s) property",
					       "DataBase::db_delete_all_device_pipe_property()");
	}

	tmp_device = (*argin)[0];
	if (!check_device_name(tmp_device))
	{
        	WARN_STREAM << "DataBase::db_delete_all_device_pipe(): device name  " << tmp_device << " incorrect ";
         	WARN_STREAM << std::endl;
         	Tango::Except::throw_exception(DB_IncorrectDeviceName,
				       	"Failed to delete all device pipe(s) property, device name incorrect",
				       	"DataBase::db_delete_all_device_pipe()");
	}


	{
		AutoLock al(this);

		for (unsigned int i=0; i<argin->length()-1; i++)
		{
			pipe = (*argin)[i+1];

			INFO_STREAM << "DataBase::db_delete_all_device_pipe_property(): delete device " << tmp_device ;
			INFO_STREAM << " pipe " << pipe << " property(ies) from database" << std::endl;

// Is there something to delete ?

			sql_query_stream.str("");
			sql_query_stream << "SELECT DISTINCT name FROM property_pipe_device WHERE device = \"" << tmp_device
		                	 <<"\" AND pipe = \"" << pipe << "\" ";
			result = query(sql_query_stream.str(),"db_delete_all_device_pipe_property()",al.get_dch());
			my_ulonglong count = mysql_num_rows(result);

			if (count != 0)
			{

// then delete property from the property_pipe_device table

				sql_query_stream.str("");
				sql_query_stream << "DELETE FROM property_pipe_device WHERE device = \"" << tmp_device
		       					<<"\" AND pipe = \"" << pipe << "\" ";
				DEBUG_STREAM << "DataBase::db_delete_all_device_pipe_property(): sql_query " << sql_query_stream.str() << std::endl;
				simple_query(sql_query_stream.str(),"db_delete_all_device_pipe_property()",al.get_dch());

// Mark this property as deleted

				for(unsigned int j=0;j<count;j++)
				{
					row = mysql_fetch_row(result);
					Tango::DevULong64 device_pipe_property_hist_id = get_id("device_pipe",al.get_dch());
					sql_query_stream.str("");
					sql_query_stream << "INSERT INTO property_pipe_device_hist SET device='" << tmp_device
			   					 << "',pipe='" << pipe
			   					 << "',name='" << row[0]
			   					 << "',id='" << device_pipe_property_hist_id
			   					 << "',count='0',value='DELETED'";
					DEBUG_STREAM << "DataBase::DeletAllDevicePipeProperty(): sql_query " << sql_query_stream.str() << std::endl;
					simple_query(sql_query_stream.str(),"db_delete_all_device_pipe_property()",al.get_dch());
					purge_pipe_property("property_pipe_device_hist","device",tmp_device.c_str(),pipe,row[0],al.get_dch());
				}
			}
			mysql_free_result(result);
		}
	}

	/*----- PROTECTED REGION END -----*/	//	DataBase::db_delete_all_device_pipe_property
}
//--------------------------------------------------------
/**
 *	Command DbPutClassPipeProperty related method
 *	Description: Create/Update class pipe property(ies) in database
 *
 *	@param argin Str[0] = Tango class name
 *               Str[1] = Pipe number
 *               Str[2] = Pipe name
 *               Str[3] = Property number
 *               Str[4] = Property name
 *               Str[5] = Property value number (array case)
 *               Str[5] = Property value 1
 *               Str[n] = Property value n (array case)
 */
//--------------------------------------------------------
void DataBase::db_put_class_pipe_property(const Tango::DevVarStringArray *argin)
{
	DEBUG_STREAM << "DataBase::DbPutClassPipeProperty()  - " << device_name << std::endl;
	/*----- PROTECTED REGION ID(DataBase::db_put_class_pipe_property) ENABLED START -----*/

	TangoSys_MemStream sql_query_stream;
	char tmp_count_str[256];
	const char *tmp_class, *tmp_pipe, *tmp_name;

	const int n_pipes = ParseString<int>((*argin)[1]);
	INFO_STREAM << "DataBase::PutClasspipeProperty2(): put " << n_pipes << " pipes for device " << (*argin)[0] << std::endl;

	{
		AutoLock al(this);

		int tmp_count, i, j, k, l, jj;
		k = 2;
		for (i=0; i<n_pipes; i++)
		{
	   		tmp_class = (*argin)[0];
	   		tmp_pipe = (*argin)[k];
	   		const int n_properties = ParseString<int>((*argin)[k+1]);
	   		for (jj=0; jj<n_properties; jj++)
	   		{
				j = k + 2;
	      		tmp_name = (*argin)[j];

// first delete the tuple (device,name,count) from the property table

				sql_query_stream.str("");
				sql_query_stream << "DELETE FROM property_pipe_class WHERE class LIKE \""
			                	 << tmp_class << "\" AND pipe LIKE \"" << tmp_pipe
								 << "\" AND name LIKE \"" << tmp_name << "\" ";
	      		DEBUG_STREAM << "DataBase::PutClassPipeProperty(): sql_query " << sql_query_stream.str() << std::endl;
				simple_query(sql_query_stream.str(),"db_put_class_pipe_property()",al.get_dch());

				const int n_rows = ParseString<int>((*argin)[j+1]);
				tmp_count = 0;
				Tango::DevULong64 class_pipe_property_hist_id = get_id("class_pipe",al.get_dch());
	   			for (l=j+1; l<j+n_rows+1; l++)
	   			{
          				std::string tmp_escaped_string = escape_string((*argin)[l+1]);
	      				tmp_count++; sprintf(tmp_count_str, "%d", tmp_count);

// then insert the new value for this tuple

 			        sql_query_stream.str("");
					sql_query_stream << "INSERT INTO property_pipe_class SET class=\'"
					                 << tmp_class << "\',pipe=\'" << tmp_pipe
									 << "\',name=\'" << tmp_name << "\',count=\'" << tmp_count_str
									 << "\',value=\'" << tmp_escaped_string
									 << "\',updated=NOW(),accessed=NOW()";
	      			DEBUG_STREAM << "DataBase::PutClassPipeProperty(): sql_query " << sql_query_stream.str() << std::endl;
			        simple_query(sql_query_stream.str(),"db_put_class_pipe_property()",al.get_dch());

// then insert the new value into the history table

 			        sql_query_stream.str("");
					sql_query_stream << "INSERT INTO property_pipe_class_hist SET class=\'"
					                 << tmp_class << "\',pipe=\'" << tmp_pipe
									 << "\',name=\'" << tmp_name << "\',count=\'" << tmp_count_str
									 << "\',id=\'" << class_pipe_property_hist_id
									 << "\',value=\'" << tmp_escaped_string << "\'";
	      			DEBUG_STREAM << "DataBase::PutClassPipeProperty(): sql_query " << sql_query_stream.str() << std::endl;
			        simple_query(sql_query_stream.str(),"db_put_class_pipe_property()",al.get_dch());

				}
		        purge_pipe_property("property_pipe_class_hist","class",tmp_class,tmp_pipe,tmp_name,al.get_dch());
				k = k + n_rows + 2;
	   		}
	   		k = k+2;
		}
	}

	/*----- PROTECTED REGION END -----*/	//	DataBase::db_put_class_pipe_property
}
//--------------------------------------------------------
/**
 *	Command DbPutDevicePipeProperty related method
 *	Description: Create/Update device pipe property(ies) in database
 *
 *	@param argin Str[0] = Device name
 *               Str[1] = Pipe number
 *               Str[2] = Pipe name
 *               Str[3] = Property number
 *               Str[4] = Property name
 *               Str[5] = Property value number (array case)
 *               Str[6] = Property value 1
 *               Str[n] = Property value n (array case)
 */
//--------------------------------------------------------
void DataBase::db_put_device_pipe_property(const Tango::DevVarStringArray *argin)
{
	DEBUG_STREAM << "DataBase::DbPutDevicePipeProperty()  - " << device_name << std::endl;
	/*----- PROTECTED REGION ID(DataBase::db_put_device_pipe_property) ENABLED START -----*/

	TangoSys_MemStream sql_query_stream;
	char tmp_count_str[256];
	const char *tmp_device, *tmp_pipe, *tmp_name;

	TimeVal	before, after;
	GetTime(before);

	const int n_pipes = ParseString<int>((*argin)[1]);
	INFO_STREAM << "DataBase::DbPutDevicePipeProperty(): put " << n_pipes << " pipes for device " << (*argin)[0] << std::endl;

	{
		AutoLock al(this);

		int tmp_count, i, j, k, l, jj;
		k = 2;
		for (i=0; i<n_pipes; i++)
		{
	   		tmp_device = (*argin)[0];
	   		tmp_pipe = (*argin)[k];
	   		const int n_properties = ParseString<int>((*argin)[k+1]);
	   		for (jj=0; jj<n_properties; jj++)
	   		{
				j = k + 2;
	      		tmp_name = (*argin)[j];

// first delete the tuple (device,name,count) from the property table
				sql_query_stream.str("");
	      		sql_query_stream << "DELETE FROM property_pipe_device WHERE device LIKE \""
				                	 << tmp_device << "\" AND pipe LIKE \"" << tmp_pipe
									 << "\" AND name LIKE \"" << tmp_name << "\" ";
	      		DEBUG_STREAM << "DataBase::DbPutDevicePipeProperty(): sql_query " << sql_query_stream.str() << std::endl;
				simple_query(sql_query_stream.str(),"db_put_device_pipe_property()",al.get_dch());

				const int n_rows = ParseString<int>((*argin)[j+1]);
				tmp_count = 0;
            	Tango::DevULong64 device_pipe_property_hist_id = get_id("device_pipe",al.get_dch());

	   			for (l=j+1; l<j+n_rows+1; l++)
	   			{
          			std::string tmp_escaped_string = escape_string((*argin)[l+1]);
	      			tmp_count++; sprintf(tmp_count_str, "%d", tmp_count);

// then insert the new value for this tuple
					sql_query_stream.str("");
					sql_query_stream << "INSERT INTO property_pipe_device SET device=\'"
					                	 << tmp_device << "\',pipe=\'" << tmp_pipe
										 << "\',name=\'" << tmp_name << "\',count=\'" << tmp_count_str
										 << "\',value=\'" << tmp_escaped_string << "\',updated=NOW(),accessed=NOW()";
	      			DEBUG_STREAM << "DataBase::DbPutDevicePipeProperty(): sql_query " << sql_query_stream.str() << std::endl;
					simple_query(sql_query_stream.str(),"db_put_device_pipe_property()",al.get_dch());

// then insert the new value into the history table
					sql_query_stream.str("");
					sql_query_stream << "INSERT INTO property_pipe_device_hist SET device=\'"
					                	 << tmp_device << "\',pipe=\'" << tmp_pipe
										 << "\',name=\'" << tmp_name << "\',count=\'" << tmp_count_str
										 << "\',id=\'" << device_pipe_property_hist_id
										 << "\',value=\'" << tmp_escaped_string << "\'";
	      			DEBUG_STREAM << "DataBase::DbPutDevicePipeProperty(): sql_query " << sql_query_stream.str() << std::endl;
					simple_query(sql_query_stream.str(),"db_put_device_pipe_property()",al.get_dch());

				}
				purge_pipe_property("property_pipe_device_hist","device",tmp_device,tmp_pipe,tmp_name,al.get_dch());
				k = k + n_rows + 2;
	   		}
	   		k = k+2;
		}
	}

	GetTime(after);
	update_timing_stats(before, after, "DbPutDevicePipeProperty");

	/*----- PROTECTED REGION END -----*/	//	DataBase::db_put_device_pipe_property
}
//--------------------------------------------------------
/**
 *	Command DbGetClassPipePropertyHist related method
 *	Description: Retrieve Tango class pipe property history
 *
 *	@param argin Str[0] = Tango class
 *               Str[1] = Pipe name
 *               Str[2] = Property name
 *	@returns Str[0] = Pipe name
 *           Str[1] = Property name
 *           Str[2] = date
 *           Str[3] = Property value number (array case)
 *           Str[4] = Property value 1
 *           Str[n] = Property value n
 */
//--------------------------------------------------------
Tango::DevVarStringArray *DataBase::db_get_class_pipe_property_hist(const Tango::DevVarStringArray *argin)
{
	Tango::DevVarStringArray *argout;
	DEBUG_STREAM << "DataBase::DbGetClassPipePropertyHist()  - " << device_name << std::endl;
	/*----- PROTECTED REGION ID(DataBase::db_get_class_pipe_property_hist) ENABLED START -----*/

	TangoSys_MemStream	sql_query_stream;
	MYSQL_RES *ids;
	MYSQL_RES *result;
	MYSQL_ROW row;
	const char *tmp_class;
	std::string      tmp_pipe;
	std::string      tmp_name;

	if (argin->length() != 3)
	{
	   WARN_STREAM << "DataBase::DbGetClassPipePropertyHist(): incorrect number of input arguments " << std::endl;
	   Tango::Except::throw_exception(DB_IncorrectArguments,
	   				  "Incorrect no. of input arguments, needs 3 (class,pipe,property)",
					  "DataBase::DbGetClassPipePropertyHist()");
	}

	argout = new Tango::DevVarStringArray;

	tmp_class     = (*argin)[0];
	tmp_pipe 	  = replace_wildcard((*argin)[1]);
	tmp_name      = replace_wildcard((*argin)[2]);

	// Get id list

    sql_query_stream << "SELECT DISTINCT id,date FROM property_pipe_class_hist WHERE class = \""
                     << tmp_class << "\" AND pipe LIKE \"" << tmp_pipe
				     << "\" AND name LIKE \"" << tmp_name << "\" ORDER by date ASC";

	{
		AutoLock al(this);

		ids = query(sql_query_stream.str(),"db_get_class_pipe_property_hist()",al.get_dch());

		// Retreive history
		int nb_item = 0;
		argout->length(0);

		for (unsigned int i=0; i<mysql_num_rows(ids); i++)
		{
		   row = mysql_fetch_row(ids);
		   Tango::DevULong64 id;
		   std::stringstream ss;
		   ss << row[0];
		   ss >> id;
		   sql_query_stream.str("");
		   sql_query_stream << "SELECT DATE_FORMAT(date,'%Y-%m-%d %H:%i:%s'),value,pipe,name,count FROM property_pipe_class_hist WHERE id = \""
	                    	<< id << "\" AND class = \"" << tmp_class << "\" ORDER BY count ASC";

		   result = query(sql_query_stream.str(),"db_get_class_pipe_property_hist()",al.get_dch());

		   int count = mysql_num_rows(result);

    	   row = mysql_fetch_row(result);
  		   int deleted = (atoi(row[4]) == 0); // count=0 for deleted property
  		   if(deleted) count = 0;
		   char n_rows_str[256];
		   sprintf(n_rows_str,"%d",count);

    	   argout->length(nb_item+4+count);
		   (*argout)[nb_item+0] = CORBA::string_dup(row[2]);
    	   (*argout)[nb_item+1] = CORBA::string_dup(row[3]);
    	   (*argout)[nb_item+2] = CORBA::string_dup(row[0]);
    	   (*argout)[nb_item+3] = CORBA::string_dup(n_rows_str);

		   for(int j=0;j<count;j++) {
            	 (*argout)[nb_item+4+j] = CORBA::string_dup(row[1]);
            	 row = mysql_fetch_row(result);
		   }

		   nb_item += 4+count;
		   mysql_free_result(result);
		}
	}

	mysql_free_result(ids);

	/*----- PROTECTED REGION END -----*/	//	DataBase::db_get_class_pipe_property_hist
	return argout;
}
//--------------------------------------------------------
/**
 *	Command DbGetDevicePipePropertyHist related method
 *	Description: Retrieve device pipe property history
 *
 *	@param argin Str[0] = Device name
 *               Str[1] = Pipe name
 *               Str[2] = Property name
 *	@returns Str[0] = Pipe name
 *           Str[1] = Property name
 *           Str[2] = date
 *           Str[3] = Property value number (array case)
 *           Str[4] = Property value 1
 *           Str[n] = Property value n
 */
//--------------------------------------------------------
Tango::DevVarStringArray *DataBase::db_get_device_pipe_property_hist(const Tango::DevVarStringArray *argin)
{
	Tango::DevVarStringArray *argout;
	DEBUG_STREAM << "DataBase::DbGetDevicePipePropertyHist()  - " << device_name << std::endl;
	/*----- PROTECTED REGION ID(DataBase::db_get_device_pipe_property_hist) ENABLED START -----*/

	TangoSys_MemStream	sql_query_stream;
	MYSQL_RES *ids;
	MYSQL_RES *result;
	MYSQL_ROW row;
	const char *tmp_device;
	std::string      tmp_pipe;
	std::string      tmp_name;

	if (argin->length() != 3)
	{
	   WARN_STREAM << "DataBase::DbGetDevicePipePropertyHist(): incorrect number of input arguments " << std::endl;
	   Tango::Except::throw_exception(DB_IncorrectArguments,
	   				  "Incorrect no. of input arguments, needs 3 (device,pipe,property)",
					  "DataBase::DbGetDevicePipePropertyHist()");
	}

	argout = new Tango::DevVarStringArray;

	tmp_device    = (*argin)[0];
	tmp_pipe 	  = replace_wildcard((*argin)[1]);
	tmp_name      = replace_wildcard((*argin)[2]);

	// Get id list

    sql_query_stream << "SELECT DISTINCT id,date FROM property_pipe_device_hist WHERE device = \""
	                 << tmp_device << "\" AND pipe LIKE \"" << tmp_pipe
 			         << "\" AND name LIKE \"" << tmp_name << "\" ORDER by date ASC";

	{
		AutoLock al(this);

		ids = query(sql_query_stream.str(),"db_get_device_pipe_property_hist()",al.get_dch());

		// Retreive history
		int nb_item = 0;
		argout->length(0);

		for (unsigned int i=0; i<mysql_num_rows(ids); i++)
		{
		   row = mysql_fetch_row(ids);
		   Tango::DevULong64 id;
		   std::stringstream ss;
		   ss << row[0];
		   ss >> id;
		   sql_query_stream.str("");
		   sql_query_stream << "SELECT DATE_FORMAT(date,'%Y-%m-%d %H:%i:%s'),value,pipe,name,count FROM property_pipe_device_hist WHERE id = \""
	                    	<< id << "\" AND device = \"" << tmp_device << "\" ORDER BY count ASC";

		   result = query(sql_query_stream.str(),"db_get_device_pipe_property_hist()",al.get_dch());

		   int count = mysql_num_rows(result);

    	   row = mysql_fetch_row(result);
  		   int deleted = (atoi(row[4]) == 0); // count=0 for deleted property
  		   if(deleted) count = 0;
		   char n_rows_str[256];
		   sprintf(n_rows_str,"%d",count);

    	   argout->length(nb_item+4+count);
		   (*argout)[nb_item+0] = CORBA::string_dup(row[2]);
    	   (*argout)[nb_item+1] = CORBA::string_dup(row[3]);
    	   (*argout)[nb_item+2] = CORBA::string_dup(row[0]);
    	   (*argout)[nb_item+3] = CORBA::string_dup(n_rows_str);

		   for(int j=0;j<count;j++) {
        	 (*argout)[nb_item+4+j] = CORBA::string_dup(row[1]);
        	 row = mysql_fetch_row(result);
		   }

		   nb_item += 4+count;
		   mysql_free_result(result);
		}
	}

	mysql_free_result(ids);

	/*----- PROTECTED REGION END -----*/	//	DataBase::db_get_device_pipe_property_hist
	return argout;
}
//--------------------------------------------------------
/**
 *	Command DbGetForwardedAttributeListForDevice related method
 *	Description: Get the list of devices using forwarded attribute(s) from specified device
 *
 *	@param argin The specified device name
 *	@returns argout[n]     : device name
 *           argout[n+1] :the forwardef attribute
 *           argout[n+2] :the root attribute (__root_att)
 */
//--------------------------------------------------------
Tango::DevVarStringArray *DataBase::db_get_forwarded_attribute_list_for_device(Tango::DevString argin)
{
	Tango::DevVarStringArray *argout;
	DEBUG_STREAM << "DataBase::DbGetForwardedAttributeListForDevice()  - " << device_name << std::endl;
	/*----- PROTECTED REGION ID(DataBase::db_get_forwarded_attribute_list_for_device) ENABLED START -----*/

	std::string device(argin);

	TangoSys_MemStream	sql_query_stream;
    sql_query_stream << "SELECT device,attribute,value  FROM property_attribute_device WHERE name = \"__root_att"
	                 << "\" AND value LIKE \"" << device << "/%%\"";

    MYSQL_RES *result = query(sql_query_stream.str(),"db_get_forwarded_attribute_list_for_device()");

    int n_rows = mysql_num_rows(result);
    DEBUG_STREAM << "DataBase::DbGetForwardedAttributeListForDevice(): mysql_num_rows() " << n_rows << std::endl;
	argout = new Tango::DevVarStringArray;
    argout->length(n_rows*3);

	MYSQL_ROW row;
    if (n_rows > 0)
    {
      for (int i=0; i<n_rows; i++)
      {
         if ((row = mysql_fetch_row(result)) != NULL)
         {
            DEBUG_STREAM << "DataBase::DbGetForwardedAttributeListForDevice(): property[ "<< i << "] device " << row[0] <<
                            " attribute " << row[1] << " __root_att " << row[1] << std::endl;
            (*argout)[3*i]   = CORBA::string_dup(row[0]);
            (*argout)[3*i+1] = CORBA::string_dup(row[1]);
            (*argout)[3*i+2] = CORBA::string_dup(row[2]);
         }
      }
    }
    mysql_free_result(result);

	/*----- PROTECTED REGION END -----*/	//	DataBase::db_get_forwarded_attribute_list_for_device
	return argout;
}
//--------------------------------------------------------
/**
 *	Command DbGetClassPropertyListWildcard related method
 *	Description: Get property list belonging to the specified class and with
 *               name matching the specified filter
 *
 *	@param argin Str[0] = class name
 *               Str[1] = Filter
 *	@returns Property name list
 */
//--------------------------------------------------------
Tango::DevVarStringArray *DataBase::db_get_class_property_list_wildcard(const Tango::DevVarStringArray *argin)
{
	Tango::DevVarStringArray *argout;
	DEBUG_STREAM << "DataBase::DbGetClassPropertyListWildcard()  - " << device_name << std::endl;
	/*----- PROTECTED REGION ID(DataBase::db_get_class_property_list_wildcard) ENABLED START -----*/

/********************************************************************************************************/

	const Tango::DevVarStringArray  *class_name_wildcard = argin;
	TangoSys_MemStream	sql_query_stream;
	MYSQL_RES *result;
	MYSQL_ROW row;
	int n_rows;
	const char *class_name,*wildcard;
	std::string tmp_wildcard;

	TimeVal	before, after;
	GetTime(before);


	class_name = (*class_name_wildcard)[0];
	wildcard = (*class_name_wildcard)[1];
	INFO_STREAM << "DataBase::db_get_class_property_list_wildcard(): class_name " << class_name ;
	INFO_STREAM << " wildcard " << wildcard << std::endl;

	if (wildcard == NULL)
	{
		sql_query_stream << "SELECT name FROM property_class WHERE class=\"" << class_name
		                 << "\" AND name LIKE \"%\" AND count=1 ORDER BY name";
	}
	else
	{
		tmp_wildcard = replace_wildcard(wildcard);
		sql_query_stream << "SELECT name FROM property_class WHERE class=\"" << class_name
		                 << "\" AND name LIKE \"" << tmp_wildcard << "\" AND count=1 ORDER BY name";
	}
	DEBUG_STREAM << "DataBase::db_get_class_property_list_wildcard(): sql_query " << sql_query_stream.str() << std::endl;

	result = query(sql_query_stream.str(),"db_get_class_property_list_wildcard()");

	n_rows = mysql_num_rows(result);
	DEBUG_STREAM << "DataBase::db_get_class_property_list_wildcard(): mysql_num_rows() " << n_rows << std::endl;
	argout = new Tango::DevVarStringArray;

	if (n_rows > 0)
	{
	   argout->length(n_rows);

	   for (int i=0; i<n_rows; i++)
	   {
	      if ((row = mysql_fetch_row(result)) != NULL)
	      {
	         DEBUG_STREAM << "DataBase::db_get_class_property_list_wildcard(): property[ "<< i << "] alias " << row[0] << std::endl;
	         (*argout)[i]   = CORBA::string_dup(row[0]);
	      }
	   }
	}
	else
	{
		argout->length(0);
	}
	mysql_free_result(result);

	GetTime(after);
	update_timing_stats(before, after, "DbGetClassPropertyListWildcard");

	/*----- PROTECTED REGION END -----*/	//	DataBase::db_get_class_property_list_wildcard
	return argout;
}
//--------------------------------------------------------
/**
 *	Method      : DataBase::add_dynamic_commands()
 *	Description : Create the dynamic commands if any
 *                for specified device.
 */
//--------------------------------------------------------
void DataBase::add_dynamic_commands()
{
	/*----- PROTECTED REGION ID(DataBase::add_dynamic_commands) ENABLED START -----*/

	//	Add your own code to create and add dynamic commands if any

	/*----- PROTECTED REGION END -----*/	//	DataBase::add_dynamic_commands
}

/*----- PROTECTED REGION ID(DataBase::namespace_ending) ENABLED START -----*/

	//	Additional Methods
//============================================================================
//============================================================================
Tango::DevString DataBase::db_get_device_host(Tango::DevString argin, DatabaseConnectionHandle &dch)
{
	TangoSys_MemStream sql_query_stream;
	std::string tmp_argin;
	MYSQL_RES *result;
	MYSQL_ROW row;
	int n_rows;

	tmp_argin = replace_wildcard(argin);
	sql_query_stream << "SELECT host FROM device WHERE name LIKE \"" << tmp_argin << "\"";

	result = query(sql_query_stream.str(),"db_get_device_host()",dch);

	n_rows = mysql_num_rows(result);
	DEBUG_STREAM << "DataBase::db_get_device_host(): mysql_num_rows() " << n_rows << std::endl;
	Tango::DevString	argout = NULL;
	if (n_rows > 0)
	{
		if ((row = mysql_fetch_row(result)) != NULL)
		{
			argout = CORBA::string_dup(row[0]);
		}
	}
	else
	{
		mysql_free_result(result);
 	    TangoSys_OMemStream o;
		o << "No host found for device \'" << argin << "\'";
		std::string msg = o.str();
		WARN_STREAM << msg << std::endl;
		Tango::Except::throw_exception(DB_DeviceNotDefined,
	   				                   msg,
					                   "DataBase::db_get_device_host()");
	}
	mysql_free_result(result); //C.S. 05-10-2004

	return argout;
}

Tango::DevString DataBase::db_get_device_host(Tango::DevString argin)
{
	DatabaseConnectionHandle dch(dcp);

	return db_get_device_host(argin, dch);
}

//--------------------------------------------------------------
/**
 *	Method      : DataBase::create_udate_mem_att()
 *	Description : Update or create (if not already there) entry
 *                in the property_attribute_device table for
 *                memorized attribute.
 *                Don't use the simple_query() method because
 *                we need to know if the UPDATE done first has
 *                modified something in DB and we need to keep the
 *                same DB connection
 */
//--------------------------------------------------------------

void DataBase::create_update_mem_att(const Tango::DevVarStringArray *argin)
{
    const char *tmp_device = (*argin)[0];
    const char *tmp_attribute = (*argin)[2];

//
// First the update
//

    std::stringstream sql_query_stream;
    std::string tmp_escaped_string = escape_string((*argin)[6]);
    sql_query_stream << "UPDATE property_attribute_device SET value=\"" << tmp_escaped_string
                     << "\" WHERE device=\"" << tmp_device << "\" AND attribute=\"" << tmp_attribute
                     << "\" AND name=\"__value\" AND count=1";
    DEBUG_STREAM << "DataBase::PutAttributeProperty2(): sql_query " << sql_query_stream.str() << std::endl;

    DatabaseConnectionHandle dch(dcp);

    std::string sql_query = sql_query_stream.str();
	if (mysql_real_query(dch.db(), sql_query.c_str(),sql_query.length()) != 0)
	{
		std::stringstream o;

		WARN_STREAM << "DataBase::db_put_device_attribute_property2() failed to query TANGO database:" << std::endl;
		WARN_STREAM << "  query = " << sql_query << std::endl;
		WARN_STREAM << " (SQL error=" << mysql_error(dch.db()) << ")" << std::endl;

		o << "Failed to query TANGO database (error=" << mysql_error(dch.db()) << ")";
		o << "\n.The query was: " << sql_query << std::ends;

		Tango::Except::throw_exception(DB_SQLError,o.str(),"Database::db_put_device_attribute_property2()");
	}

    my_ulonglong nb_rows = mysql_affected_rows(dch.db());
    if (nb_rows == 0)
    {

//
// The update hasn't changed anything in DB (0 rows affected). This means that the property is not yet
// created in DB. Therefore, create it now
//

        sql_query_stream.str("");
        sql_query_stream << "INSERT INTO property_attribute_device SET device=\'"
                         << tmp_device << "\',attribute=\'" << tmp_attribute
                         << "\',name=\'__value\',count=1,value=\'" << tmp_escaped_string << "\',updated=NOW(),accessed=NOW()";
        DEBUG_STREAM << "DataBase::PutAttributeProperty(): sql_query " << sql_query_stream.str() << std::endl;

        sql_query = sql_query_stream.str();
        if (mysql_real_query(dch.db(), sql_query.c_str(),sql_query.length()) != 0)
        {
            std::stringstream o;

            WARN_STREAM << "DataBase::db_put_device_attribute_property2() failed to query TANGO database:" << std::endl;
            WARN_STREAM << "  query = " << sql_query << std::endl;
            WARN_STREAM << " (SQL error=" << mysql_error(dch.db()) << ")" << std::endl;

            o << "Failed to query TANGO database (error=" << mysql_error(dch.db()) << ")";
            o << "\n.The query was: " << sql_query << std::ends;

            Tango::Except::throw_exception(DB_SQLError,o.str(),"Database::db_put_device_attribute_property2()");
        }

    }
}

	/*----- PROTECTED REGION END -----*/	//	DataBase::namespace_ending
} //	namespace
