/*----- PROTECTED REGION ID(DataBase.cpp) ENABLED START -----*/
/* clang-format on */
//=============================================================================
//
// 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"
#include "Utils.h"

/* clang-format off */
/*----- 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 -----*/
/* clang-format on */

//	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());
}

/* clang-format off */
	/*----- 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 -----*/
    /* clang-format on */

    init_device();

    /* clang-format off */
	/*----- 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 -----*/
    /* clang-format on */

    init_device();

    /* clang-format off */
	/*----- 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 -----*/
    /* clang-format on */

    init_device();

    /* clang-format off */
	/*----- PROTECTED REGION END -----*/	//	DataBase::constructor_3
}
//--------------------------------------------------------
DataBase::~DataBase()
{
	delete_device();
}

//--------------------------------------------------------
/**
 *	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 -----*/
    /* clang-format on */

    // 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++)
    {
        CORBA::string_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;
    }

    CORBA::string_free(*attr_StoredProcedureRelease_read);
    delete attr_StoredProcedureRelease_read;

    dcp.reset();

    /* clang-format off */
	/*----- 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 -----*/
    /* clang-format on */

    //	Initialization before get_device_property() call

    /* clang-format off */
	/*----- PROTECTED REGION END -----*/	//	DataBase::init_device_before

	//	No device property to be read from database

	/*----- PROTECTED REGION ID(DataBase::init_device) ENABLED START -----*/
    /* clang-format on */

    //
    //	Initialize device
    //

    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()");
    }

    dcp = std::make_shared<DatabaseConnectionPool>(this);

#if TANGO_VERSION >= TANGO_MAKE_VERSION(10, 0, 0)
    {
        DatabaseConnectionHandle dch(dcp);

        add_version_info("Server info", mysql_get_server_info(dch.db()));
        add_version_info("Host info", mysql_get_host_info(dch.db()));
        add_version_info("Client info", mysql_get_client_info());
    }
#endif

    //
    // 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] == nullptr) //	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 = ParseString<int>((*props)[1]); // nb properties
            if(nb == 1)
            {
                nb = ParseString<int>((*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] != nullptr)
        {
            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();
    attr_StoredProcedureRelease_read = new char *;
    *attr_StoredProcedureRelease_read = nullptr;
    set_state(Tango::ON);
    set_status("Device is OK");

    /* clang-format off */
	/*----- 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 -----*/
    /* clang-format on */

    //	code always executed before all requests

    /* clang-format off */
	/*----- 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 -----*/
    /* clang-format on */

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

    /* clang-format off */
	/*----- PROTECTED REGION END -----*/	//	DataBase::read_attr_hardware
}

//--------------------------------------------------------
/**
 *	Read attribute StoredProcedureRelease related method
 *
 *
 *	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 -----*/
    /* clang-format on */
    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;

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

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

    if(n_fields > 7)
    {
        if((row = mysql_fetch_row(result)) != nullptr)
        {
            CORBA::string_free(*attr_StoredProcedureRelease_read);
            *attr_StoredProcedureRelease_read = CORBA::string_dup(row[7]);
        }
        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);

    /* clang-format off */
	/*----- PROTECTED REGION END -----*/	//	DataBase::read_StoredProcedureRelease
}
//--------------------------------------------------------
/**
 *	Read attribute Timing_average related method
 *
 *
 *	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 -----*/
    /* clang-format on */
    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);

    /* clang-format off */
	/*----- PROTECTED REGION END -----*/	//	DataBase::read_Timing_average
}
//--------------------------------------------------------
/**
 *	Read attribute Timing_minimum related method
 *
 *
 *	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 -----*/
    /* clang-format on */
    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);

    /* clang-format off */
	/*----- PROTECTED REGION END -----*/	//	DataBase::read_Timing_minimum
}
//--------------------------------------------------------
/**
 *	Read attribute Timing_maximum related method
 *
 *
 *	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 -----*/
    /* clang-format on */
    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);

    /* clang-format off */
	/*----- PROTECTED REGION END -----*/	//	DataBase::read_Timing_maximum
}
//--------------------------------------------------------
/**
 *	Read attribute Timing_calls related method
 *
 *
 *	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 -----*/
    /* clang-format on */
    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);

    /* clang-format off */
	/*----- PROTECTED REGION END -----*/	//	DataBase::read_Timing_calls
}
//--------------------------------------------------------
/**
 *	Read attribute Timing_index related method
 *
 *
 *	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 -----*/
    /* clang-format on */
    attr.set_value(timing_stats_index, timing_stats_size);

    /* clang-format off */
	/*----- PROTECTED REGION END -----*/	//	DataBase::read_Timing_index
}
//--------------------------------------------------------
/**
 *	Read attribute Timing_info related method
 *
 *
 *	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 -----*/
    /* clang-format on */
    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++)
        {
            snprintf(info_str,
                     sizeof(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);

    /* clang-format off */
	/*----- 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 -----*/
    /* clang-format on */

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

    /* clang-format off */
	/*----- 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 -----*/
    /* clang-format on */

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

    /* clang-format off */
	/*----- 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 -----*/
    /* clang-format on */

    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 = nullptr;
    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);
    }

    /* clang-format off */
	/*----- 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 -----*/
    /* clang-format on */

    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());
    }

    /* clang-format off */
	/*----- 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 -----*/
    /* clang-format on */

    TangoSys_MemStream sql_query_stream;

    // first check to see if this alias exists
    DatabaseConnectionHandle dch(dcp);
    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()", dch);

    /* clang-format off */
	/*----- 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 -----*/
    /* clang-format on */

    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
    DatabaseConnectionHandle dch(dcp);
    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()", dch);

    /* clang-format off */
	/*----- 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 -----*/
    /* clang-format on */

    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());
        }
    }

    /* clang-format off */
	/*----- 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 -----*/
    /* clang-format on */

    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);
        }
    }

    /* clang-format off */
	/*----- 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 -----*/
    /* clang-format on */

    AutoLock al(this);
    db_delete_device_impl(argin, al.get_dch());

    /* clang-format off */
	/*----- 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 -----*/
    /* clang-format on */

    TangoSys_MemStream sql_query_stream;

    // first check to see if this alias exists
    DatabaseConnectionHandle dch(dcp);
    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()", dch);

    /* clang-format off */
	/*----- 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 -----*/
    /* clang-format on */

    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

    DatabaseConnectionHandle dch(dcp);
    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()", dch);

    /* clang-format off */
	/*----- 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 -----*/
    /* clang-format on */

    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());
        }
    }

    /* clang-format off */
	/*----- 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 -----*/
    /* clang-format on */

    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");

    /* clang-format off */
	/*----- 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 -----*/
    /* clang-format on */

    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);
        }
    }

    /* clang-format off */
	/*----- 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 -----*/
    /* clang-format on */

    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
    //
    AutoLock al(this);

    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_impl((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);
        }
        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()", al.get_dch());

    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)) != nullptr)
            {
                DEBUG_STREAM << "Database::db_deleet_server(): Deleting device " << row[0] << std::endl;
                db_delete_device_impl(row[0], al.get_dch());
            }
        }
    }
    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);
        }
    }

    /* clang-format off */
	/*----- 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 -----*/
    /* clang-format on */

    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
    DatabaseConnectionHandle dch(dcp);
    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()", dch);

    /* clang-format off */
	/*----- 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 -----*/
    /* clang-format on */

    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_impl((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)) != nullptr)
            {
                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");

    /* clang-format off */
	/*----- 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 -----*/
    /* clang-format on */

    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");

    /* clang-format off */
	/*----- 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 -----*/
    /* clang-format on */

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

    argout = nullptr;

    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;

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

    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)) != nullptr)
        {
            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()");
    }

    /* clang-format off */
	/*----- 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 -----*/
    /* clang-format on */

    TangoSys_MemStream sql_query_stream;
    MYSQL_RES *result;
    MYSQL_ROW row;
    long n_rows = 0;
    argout = nullptr;

    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;

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

    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)) != nullptr)
        {
            DEBUG_STREAM << "DataBase::db_get_attribute_alias(): attribute name " << row[0] << std::endl;
            argout = CORBA::string_dup(row[0]);
        }
    }
    else
    {
        TangoSys_OMemStream o;
        o << "No attribute found for alias  \'" << argin << "\'";
        mysql_free_result(result);
        Tango::Except::throw_exception(DB_SQLError, o.str(), "DataBase::db_get_attribute_alias()");
    }

    mysql_free_result(result);

    /* clang-format off */
	/*----- 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 -----*/
    /* clang-format on */

    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;

    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;

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

    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)) != nullptr)
            {
                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);

    /* clang-format off */
	/*----- 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 -----*/
    /* clang-format on */

    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];

    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;

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

    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)) != nullptr)
            {
                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;

    /* clang-format off */
	/*----- 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 -----*/
    /* clang-format on */

    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;

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

        n_rows = mysql_num_rows(result);
        DEBUG_STREAM << "DataBase::GetAttributeProperty(): mysql_num_rows() " << n_rows << std::endl;
        snprintf(n_rows_str, sizeof(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)) != nullptr)
                {
                    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;

    /* clang-format off */
	/*----- 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 -----*/
    /* clang-format on */

    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;

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

        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)) != nullptr)
                {
                    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)
                        {
                            snprintf(prop_size_str, sizeof(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)
            {
                snprintf(prop_size_str, sizeof(prop_size_str), "%d", prop_size);
                (*argout)[prop_size_idx] = CORBA::string_dup(prop_size_str);
                prop_number++;
            }
        }
        snprintf(n_rows_str, sizeof(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;

    /* clang-format off */
	/*----- 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 -----*/
    /* clang-format on */

    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 = (ParseString<int>(row[4]) == 0); // count=0 for deleted property
            if(deleted)
            {
                count = 0;
            }
            char n_rows_str[256];
            snprintf(n_rows_str, sizeof(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);

    /* clang-format off */
	/*----- 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 -----*/
    /* clang-format on */

    //	Get class for device
    argout = nullptr;

    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;

    DatabaseConnectionHandle dch(dcp);
    MYSQL_RES *result = query(tms.str(), "db_get_class_for_device()", dch);
    int n_rows = mysql_num_rows(result);
    if(n_rows == 0)
    {
        mysql_free_result(result);
        TangoSys_MemStream err;
        err << "Class not found for " << argin;
        Tango::Except::throw_exception(DB_IncorrectArguments, err.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 != nullptr)
            {
                argout = CORBA::string_dup(row[0]);
            }
        }
    }
    mysql_free_result(result);

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

    /* clang-format off */
	/*----- 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 -----*/
    /* clang-format on */

    //	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;

    /* clang-format off */
	/*----- 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 -----*/
    /* clang-format on */

    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;

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

    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)) != nullptr)
            {
                //	         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);

    /* clang-format off */
	/*----- PROTECTED REGION END -----*/	//	DataBase::db_get_class_list
	return argout;
}
//--------------------------------------------------------
/**
 *	Command DbGetClassProperty related method
 *
 *
 *	@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 -----*/
    /* clang-format on */

    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;

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

        n_rows = mysql_num_rows(result);
        DEBUG_STREAM << "DataBase::GetClassProperty(): mysql_num_rows() " << n_rows << std::endl;
        snprintf(n_rows_str, sizeof(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)) != nullptr)
                {
                    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;

    /* clang-format off */
	/*----- 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 -----*/
    /* clang-format on */

    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 = (ParseString<int>(row[3]) == 0); // count=0 for deleted property
            if(deleted)
            {
                count = 0;
            }
            char n_rows_str[256];
            snprintf(n_rows_str, sizeof(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);

    /* clang-format off */
	/*----- 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 -----*/
    /* clang-format on */

    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;

    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;

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

    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)) != nullptr)
            {
                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");

    /* clang-format off */
	/*----- 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 -----*/
    /* clang-format on */

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

    argout = nullptr;

    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;

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

    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)) != nullptr)
        {
            if(row[0] == nullptr)
            {
                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);

    /* clang-format off */
	/*----- 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 -----*/
    /* clang-format on */

    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;

    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;

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

    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)) != nullptr)
            {
                //	         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);

    /* clang-format off */
	/*----- 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 -----*/
    /* clang-format on */

    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;

    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;

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

    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)) != nullptr)
            {
                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);

    /* clang-format off */
	/*----- 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 -----*/
    /* clang-format on */

    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::GetDeviceAttributeProperty(): 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::GetDeviceAttributeProperty(): sql_query " << sql_query_stream.str() << std::endl;

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

        n_rows = mysql_num_rows(result);
        DEBUG_STREAM << "DataBase::GetDeviceAttributeProperty(): mysql_num_rows() " << n_rows << std::endl;
        snprintf(n_rows_str, sizeof(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)) != nullptr)
                {
                    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::GetDeviceAttributeProperty(): argout->length() " << argout->length() << std::endl;

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

    /* clang-format off */
	/*----- 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 -----*/
    /* clang-format on */

    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;

    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;

    DatabaseConnectionHandle dch(dcp);
    result = query(sql_query_stream.str(), "db_get_device_attribute_property2()", dch);
    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)) != nullptr)
        {
            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++)
        {
            const char *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()", dch);

            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)) != nullptr)
                    {
                        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)
                            {
                                snprintf(prop_size_str, sizeof(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)
                {
                    snprintf(prop_size_str, sizeof(prop_size_str), "%d", prop_size);
                    (*argout)[prop_size_idx] = CORBA::string_dup(prop_size_str);
                    prop_number++;
                }
            }
            snprintf(n_rows_str, sizeof(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()", dch);
        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)) != nullptr)
            {
                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());
                snprintf(n_rows_str, sizeof(n_rows_str), "%d", prop_nb);
                (*argout)[n_props - 1] = CORBA::string_dup(n_rows_str);

                for(int j = 0; j < prop_nb; j++)
                {
                    PropDef &pd = (pos->second)[j];
                    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());
                    snprintf(n_rows_str, sizeof(n_rows_str), "%d", prop_size);
                    (*argout)[old_n_props++] = CORBA::string_dup(n_rows_str);

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

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

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

    /* clang-format off */
	/*----- 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 -----*/
    /* clang-format on */

    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 = (ParseString<int>(row[4]) == 0); // count=0 for deleted property
            if(deleted)
            {
                count = 0;
            }
            char n_rows_str[256];
            snprintf(n_rows_str, sizeof(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);

    /* clang-format off */
	/*----- 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 -----*/
    /* clang-format on */

    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;

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

    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)) != nullptr)
            {
                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");

    /* clang-format off */
	/*----- PROTECTED REGION END -----*/	//	DataBase::db_get_device_class_list
	return argout;
}
//--------------------------------------------------------
/**
 *	Command DbGetDeviceDomainList related method
 *	Description: Get list of device domain names matching the specified device name
 *
 *	@param argin The device name containing a possible wildcard
 *	@returns List of device domain names without duplicates
 */
//--------------------------------------------------------
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 -----*/
    /* clang-format on */

    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;

    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;

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

    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)) != nullptr)
            {
                //	         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");

    /* clang-format off */
	/*----- 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 -----*/
    /* clang-format on */

    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;

    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;

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

    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)) != nullptr)
            {
                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");

    /* clang-format off */
	/*----- PROTECTED REGION END -----*/	//	DataBase::db_get_device_exported_list
	return argout;
}
//--------------------------------------------------------
/**
 *	Command DbGetDeviceFamilyList related method
 *	Description: Get a list of device name families matching the specified device name
 *
 *	@param argin The device name containing a possible wildcard
 *	@returns List of device family names without duplicates
 */
//--------------------------------------------------------
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 -----*/
    /* clang-format on */

    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;

    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;

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

    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)) != nullptr)
            {
                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");

    /* clang-format off */
	/*----- 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 -----*/
    /* clang-format on */

    TangoSys_MemStream sql_query_stream;
    MYSQL_RES *result;
    MYSQL_ROW row;
    int n_rows = 0;
    int dev_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;

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

    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)) != nullptr)
        {
            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] == nullptr) || (row[5] == nullptr))
            {
                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] != nullptr)
            {
                (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] != nullptr)
                {
                    sql_query_stream.str("");
                    sql_query_stream << "SELECT DATE_FORMAT(\'" << row[x + 6] << "\',\'" << format << "\')";
                    result2 = query(sql_query_stream.str(), "db_get_device_info()", dch);
                    int nb = mysql_num_rows(result2);
                    if(nb > 0)
                    {
                        if((row2 = mysql_fetch_row(result2)) != nullptr &&
                           row2[0] != nullptr) // 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]==nullptr !!!
                        }
                    }
                    else
                    {
                        (argout->svalue)[5 + x] = CORBA::string_dup("?");
                    }
                    mysql_free_result(result2);
                }
                else
                {
                    (argout->svalue)[5 + x] = CORBA::string_dup("?");
                }
            }

            dev_exported = -1;
            if(row[0] != nullptr)
            {
                dev_exported = ParseString<int>(row[0]);
            }
            n_lvalues++;
            (argout->lvalue).length(n_lvalues);
            (argout->lvalue)[n_lvalues - 1] = dev_exported;
            pid = -1;
            if(row[3] != nullptr)
            {
                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);

    /* clang-format off */
	/*----- 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 -----*/
    /* clang-format on */

    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;

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

    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)) != nullptr)
            {
                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);

    /* clang-format off */
	/*----- 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 -----*/
    /* clang-format on */

    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;

    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;

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

    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)) != nullptr)
            {
                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);

    /* clang-format off */
	/*----- PROTECTED REGION END -----*/	//	DataBase::db_get_device_wide_list
	return argout;
}
//--------------------------------------------------------
/**
 *	Command DbGetDeviceMemberList related method
 *	Description: Get a list of device name members matching the specified device name
 *
 *	@param argin The device name containing a possible wildcard
 *	@returns List of device member names without duplicates
 */
//--------------------------------------------------------
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 -----*/
    /* clang-format on */

    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;

    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;

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

    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)) != nullptr)
            {
                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");

    /* clang-format off */
	/*----- PROTECTED REGION END -----*/	//	DataBase::db_get_device_member_list
	return argout;
}
//--------------------------------------------------------
/**
 *	Command DbGetDeviceProperty related method
 *
 *
 *	@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 -----*/
    /* clang-format on */

    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);

    DatabaseConnectionHandle dch(dcp);

    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()", dch);

        n_rows = mysql_num_rows(result);
        DEBUG_STREAM << "DataBase::GetDeviceProperty(): mysql_num_rows() " << n_rows << std::endl;
        snprintf(n_rows_str, sizeof(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)) != nullptr)
                {
                    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");

    /* clang-format off */
	/*----- 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 -----*/
    /* clang-format on */

    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 = (ParseString<int>(row[3]) == 0); // count=0 for deleted property
            if(deleted)
            {
                count = 0;
            }
            char n_rows_str[256];
            snprintf(n_rows_str, sizeof(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);

    /* clang-format off */
	/*----- 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 -----*/
    /* clang-format on */

    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;

    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;

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

    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)) != nullptr)
            {
                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");

    /* clang-format off */
	/*----- 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 -----*/
    /* clang-format on */

    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;

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

    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)) != nullptr)
            {
                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);

    /* clang-format off */
	/*----- 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 -----*/
    /* clang-format on */

    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;

    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;

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

    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)) != nullptr)
            {
                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);

    /* clang-format off */
	/*----- 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 -----*/
    /* clang-format on */

    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;

    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;

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

    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)) != nullptr)
            {
                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");

    /* clang-format off */
	/*----- 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 -----*/
    /* clang-format on */

    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;

    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;

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

    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)) != nullptr)
            {
                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");

    /* clang-format off */
	/*----- 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 -----*/
    /* clang-format on */

    //- struct timeval	t0, t;
    //- gettimeofday(&t0, nullptr);
    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, nullptr);
    //- WARN_STREAM << argin << "; " << 1000.0*(t.tv_sec - t0.tv_sec) +
    //-	((double)t.tv_usec - t0.tv_usec) / 1000 << " ms" << std::endl;

    /* clang-format off */
	/*----- 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 -----*/
    /* clang-format on */

    //	Build a wildcard wing arg in
    std::string wildcard{argin};
    wildcard += "/*";
    Tango::DevVarStringArray *server_list = db_get_server_list(wildcard.data());

    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());
    }

    /* clang-format off */
	/*----- 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 -----*/
    /* clang-format on */

    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;

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

    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)) != nullptr)
            {
                //	         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);

    /* clang-format off */
	/*----- 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 -----*/
    /* clang-format on */

    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;

    DatabaseConnectionHandle dch(dcp);

    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()", dch);

        n_rows = mysql_num_rows(result);
        DEBUG_STREAM << "DataBase::db_get_property(): mysql_num_rows() " << n_rows << std::endl;
        snprintf(n_rows_str, sizeof(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)) != nullptr)
                {
                    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;

    /* clang-format off */
	/*----- 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 -----*/
    /* clang-format on */

    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 = (ParseString<int>(row[3]) == 0); // count=0 for deleted property
            if(deleted)
            {
                count = 0;
            }
            char n_rows_str[256];
            snprintf(n_rows_str, sizeof(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);

    /* clang-format off */
	/*----- 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 -----*/
    /* clang-format on */

    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;

    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;

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

    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)) != nullptr)
            {
                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);

    /* clang-format off */
	/*----- 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 -----*/
    /* clang-format on */

    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;

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

    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)) != nullptr)
        {
            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);

    /* clang-format off */
	/*----- 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 -----*/
    /* clang-format on */

    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;

    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;

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

    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)) != nullptr)
            {
                //	         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");

    /* clang-format off */
	/*----- 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 -----*/
    /* clang-format on */

    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;

    /* clang-format off */
	/*----- 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 -----*/
    /* clang-format on */

    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 dev_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

    //	snprintf(sql_query, sizeof(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)) != nullptr)
        {
            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] != nullptr)
            {
                (argout->svalue)[n_svalues - 5] = CORBA::string_dup(row[1]);
            }
            else
            {
                (argout->svalue)[n_svalues - 5] = CORBA::string_dup("");
            }
            dev_exported = -1;
            if(row[0] != nullptr)
            {
                dev_exported = ParseString<int>(row[0]);
            }
            n_lvalues++;
            (argout->lvalue).length(n_lvalues);
            (argout->lvalue)[n_lvalues - 1] = dev_exported;
            pid = -1;
            if(row[3] != nullptr)
            {
                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");

    /* clang-format off */
	/*----- 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 -----*/
    /* clang-format on */

    Tango::DevString event_name = argin;
    TangoSys_MemStream sql_query_stream;
    MYSQL_RES *result;
    MYSQL_ROW row;
    int n_rows = 0;
    int dev_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;

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

    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)) != nullptr)
        {
            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]);
            dev_exported = -1;
            if(row[0] != nullptr)
            {
                dev_exported = ParseString<int>(row[0]);
            }
            n_lvalues++;
            (argout->lvalue).length(n_lvalues);
            (argout->lvalue)[n_lvalues - 1] = dev_exported;
            pid = -1;
            if(row[3] != nullptr)
            {
                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");

    /* clang-format off */
	/*----- 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 -----*/
    /* clang-format on */

    TangoSys_MemStream sql_query_stream;
    std::string builder;
    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;

    builder = "TANGO Database " + DataBase::db_name;
    n_infos = 1;
    argout->length(n_infos);
    (*argout)[n_infos - 1] = CORBA::string_dup(builder.c_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;

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

    builder = "Running since ...";
    n_rows = mysql_num_rows(result);
    if(n_rows > 0)
    {
        if((row = mysql_fetch_row(result)) != nullptr)
        {
            DEBUG_STREAM << "DataBase::db_info(): database started " << row[0] << std::endl;
            builder = "Running since " + std::string(row[0]);
        }
    }
    mysql_free_result(result);
    n_infos++;
    argout->length(n_infos);
    (*argout)[n_infos - 1] = CORBA::string_dup(builder.c_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()", dch);

    builder = "Devices defined ...";
    n_rows = mysql_num_rows(result);
    if(n_rows > 0)
    {
        if((row = mysql_fetch_row(result)) != nullptr)
        {
            DEBUG_STREAM << "DataBase::db_info(): no. of devices " << row[0] << std::endl;
            builder = "Devices defined  = " + std::string(row[0]);
        }
    }
    mysql_free_result(result);
    n_infos++;
    argout->length(n_infos);
    (*argout)[n_infos - 1] = CORBA::string_dup(builder.c_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()", dch);

    builder = "Devices exported ...";
    n_rows = mysql_num_rows(result);
    if(n_rows > 0)
    {
        if((row = mysql_fetch_row(result)) != nullptr)
        {
            DEBUG_STREAM << "DataBase::db_info(): no. of devices exported " << row[0] << std::endl;
            builder = "Devices exported  = " + std::string(row[0]);
        }
    }
    mysql_free_result(result);
    n_infos++;
    argout->length(n_infos);
    (*argout)[n_infos - 1] = CORBA::string_dup(builder.c_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()", dch);

    builder = "Device servers defined ...";
    n_rows = mysql_num_rows(result);
    if(n_rows > 0)
    {
        if((row = mysql_fetch_row(result)) != nullptr)
        {
            DEBUG_STREAM << "DataBase::db_info(): no. of device servers defined " << row[0] << std::endl;
            builder = "Device servers defined  = " + std::string(row[0]);
        }
    }
    mysql_free_result(result);
    n_infos++;
    argout->length(n_infos);
    (*argout)[n_infos - 1] = CORBA::string_dup(builder.c_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()", dch);

    builder = "Device servers exported ...";
    n_rows = mysql_num_rows(result);
    if(n_rows > 0)
    {
        if((row = mysql_fetch_row(result)) != nullptr)
        {
            DEBUG_STREAM << "DataBase::db_info(): no. of device servers exported " << row[0] << std::endl;
            builder = "Device servers exported  = " + std::string(row[0]);
        }
    }
    mysql_free_result(result);
    n_infos++;
    argout->length(n_infos);
    (*argout)[n_infos - 1] = CORBA::string_dup(builder.c_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()", dch);
    row = mysql_fetch_row(result);
    builder = "Device properties defined  = " + std::string(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()", dch);
    row = mysql_fetch_row(result);
    builder += " [History lgth = " + std::string(row[0]) + "]";
    mysql_free_result(result);
    n_infos++;
    argout->length(n_infos);
    (*argout)[n_infos - 1] = CORBA::string_dup(builder.c_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()", dch);
    row = mysql_fetch_row(result);
    builder = "Class properties defined  = " + std::string(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()", dch);
    row = mysql_fetch_row(result);
    builder += " [History lgth = " + std::string(row[0]) + "]";
    mysql_free_result(result);
    n_infos++;
    argout->length(n_infos);
    (*argout)[n_infos - 1] = CORBA::string_dup(builder.c_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()", dch);
    row = mysql_fetch_row(result);
    builder = "Device attribute properties defined  = " + std::string(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()", dch);
    row = mysql_fetch_row(result);
    builder += " [History lgth = " + std::string(row[0]) + "]";
    mysql_free_result(result);
    n_infos++;
    argout->length(n_infos);
    (*argout)[n_infos - 1] = CORBA::string_dup(builder.c_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()", dch);
    row = mysql_fetch_row(result);
    builder = "Class attribute properties defined  = " + std::string(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()", dch);
    row = mysql_fetch_row(result);
    builder += " [History lgth = " + std::string(row[0]) + "]";
    mysql_free_result(result);
    n_infos++;
    argout->length(n_infos);
    (*argout)[n_infos - 1] = CORBA::string_dup(builder.c_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()", dch);
    row = mysql_fetch_row(result);
    builder = "Object properties defined  = " + std::string(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()", dch);
    row = mysql_fetch_row(result);
    builder += " [History lgth = " + std::string(row[0]) + "]";
    mysql_free_result(result);
    n_infos++;
    argout->length(n_infos);
    (*argout)[n_infos - 1] = CORBA::string_dup(builder.c_str());

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

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

    /* clang-format off */
	/*----- 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 (device/attribute)
 *	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 -----*/
    /* clang-format on */

    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());
    }

    /* clang-format off */
	/*----- 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 -----*/
    /* clang-format on */

    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;
        }
    }

    /* clang-format off */
	/*----- 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 -----*/
    /* clang-format on */

    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++;
                    snprintf(tmp_count_str, sizeof(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;
        }
    }

    /* clang-format off */
	/*----- 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 -----*/
    /* clang-format on */

    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++;
                snprintf(tmp_count_str, sizeof(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");

    /* clang-format off */
	/*----- 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 -----*/
    /* clang-format on */

    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());
    }

    /* clang-format off */
	/*----- 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 -----*/
    /* clang-format on */

    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");

    /* clang-format off */
	/*----- 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 -----*/
    /* clang-format on */

    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)
    {
        AutoLock al(this);
        create_update_mem_att(argin, al);
    }
    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++;
                        snprintf(tmp_count_str, sizeof(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");

    /* clang-format off */
	/*----- 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 -----*/
    /* clang-format on */

    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++;
                snprintf(tmp_count_str, sizeof(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");

    /* clang-format off */
	/*----- 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 -----*/
    /* clang-format on */

    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;
        }
    }

    /* clang-format off */
	/*----- 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 -----*/
    /* clang-format on */

    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_impl((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);
    }

    /* clang-format off */
	/*----- 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 -----*/
    /* clang-format on */

    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);
    snprintf(tmp_device, strlen(devname) + 1, "%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"
    DatabaseConnectionHandle dch(dcp);
    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()", dch);

    free(tmp_device);

    /* clang-format off */
	/*----- 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 -----*/
    /* clang-format on */

    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"

    DatabaseConnectionHandle dch(dcp);
    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()", dch);

    /* clang-format off */
	/*----- 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 -----*/
    /* clang-format on */

    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);
    snprintf(tmp_server, strlen(server_name) + 1, "%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"
    DatabaseConnectionHandle dch(dcp);
    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()", dch);

    free(tmp_server);

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

    /* clang-format off */
	/*----- 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 -----*/
    /* clang-format on */

    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();

    /* clang-format off */
	/*----- 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 -----*/
    /* clang-format on */

    //	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()");
    }

    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;

    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);

    simple_query(sql_query, "DbGetDataForServerCache()", dch);

    argout = new Tango::DevVarStringArray();

    int status;
    do
    {
        if((res = mysql_store_result(dch.db())) != nullptr)
        {
            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");

    /* clang-format off */
	/*----- 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 -----*/
    /* clang-format on */

    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);
        }
    }

    /* clang-format off */
	/*----- 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 -----*/
    /* clang-format on */

    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;

    DatabaseConnectionHandle dch(dcp);
    MYSQL_RES *result = query(cmd, "db_my_sql_select()", dch);
    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 == nullptr)
                {
                    (argout->svalue)[idx] = CORBA::string_dup("");
                    (argout->lvalue)[idx++] = 0; //	data is null
                }
                else if(row[j] == nullptr)
                {
                    (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] != nullptr);
            }
        }
    }
    //	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");

    /* clang-format off */
	/*----- 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 -----*/
    /* clang-format on */

    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;

    DatabaseConnectionHandle dch(dcp);
    result = query(sql_query_stream.str(), "db_get_csdb_server_list()", dch);

    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)) != nullptr)
            {
                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);

    /* clang-format off */
	/*----- 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 -----*/
    /* clang-format on */

    TangoSys_MemStream sql_query_stream;
    MYSQL_RES *result;
    MYSQL_ROW row;
    long n_rows = 0;
    argout = nullptr;

    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;

    DatabaseConnectionHandle dch(dcp);
    result = query(sql_query_stream.str(), "db_get_attribute_alias2()", dch);

    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)) != nullptr)
        {
            DEBUG_STREAM << "DataBase::db_get_attribute_alias2(): attribute name " << row[0] << std::endl;
            argout = CORBA::string_dup(row[0]);
        }
    }
    else
    {
        TangoSys_OMemStream o;
        o << "No alias found for attribute  \'" << argin << "\'";
        mysql_free_result(result);
        Tango::Except::throw_exception(DB_SQLError, o.str(), "DataBase::db_get_attribute_alias2()");
    }

    /* clang-format off */
	/*----- 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 -----*/
    /* clang-format on */

    TangoSys_MemStream sql_query_stream;
    MYSQL_RES *result;
    MYSQL_ROW row;
    long n_rows = 0;
    argout = nullptr;

    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;

    DatabaseConnectionHandle dch(dcp);
    result = query(sql_query_stream.str(), "db_get_alias_attribute()", dch);

    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)) != nullptr)
        {
            DEBUG_STREAM << "DataBase::db_get_alias_attribute(): attribute name " << row[0] << std::endl;
            argout = CORBA::string_dup(row[0]);
        }
    }
    else
    {
        TangoSys_OMemStream o;
        o << "No attribute found for alias  \'" << argin << "\'";
        mysql_free_result(result);
        Tango::Except::throw_exception(DB_SQLError, o.str(), "DataBase::db_get_alias_attribute()");
    }

    mysql_free_result(result);

    /* clang-format off */
	/*----- 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 -----*/
    /* clang-format on */

    //
    // 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;

    DatabaseConnectionHandle dch(dcp);
    result = query(sql_query_stream.str(), "db_rename_server()", dch);

    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);
        }
    }
    /* clang-format off */
	/*----- 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 -----*/
    /* clang-format on */

    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);

    DatabaseConnectionHandle dch(dcp);

    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()", dch);

        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)) != nullptr)
                {
                    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)
                        {
                            snprintf(prop_size_str, sizeof(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)
            {
                snprintf(prop_size_str, sizeof(prop_size_str), "%d", prop_size);
                (*argout)[prop_size_idx] = CORBA::string_dup(prop_size_str);
                prop_number++;
            }
        }
        snprintf(n_rows_str, sizeof(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;

    /* clang-format off */
	/*----- 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 -----*/
    /* clang-format on */

    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;

    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;

    DatabaseConnectionHandle dch(dcp);
    result = query(sql_query_stream.str(), "db_get_device_pipe_property()", dch);
    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)) != nullptr)
        {
            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++)
        {
            const char *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()", dch);

            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)) != nullptr)
                    {
                        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)
                            {
                                snprintf(prop_size_str, sizeof(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)
                {
                    snprintf(prop_size_str, sizeof(prop_size_str), "%d", prop_size);
                    (*argout)[prop_size_idx] = CORBA::string_dup(prop_size_str);
                    prop_number++;
                }
            }
            snprintf(n_rows_str, sizeof(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()", dch);
        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)) != nullptr)
            {
                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());
                snprintf(n_rows_str, sizeof(n_rows_str), "%d", prop_nb);
                (*argout)[n_props - 1] = CORBA::string_dup(n_rows_str);

                for(int j = 0; j < prop_nb; j++)
                {
                    PropDef &pd = (pos->second)[j];
                    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());
                    snprintf(n_rows_str, sizeof(n_rows_str), "%d", prop_size);
                    (*argout)[old_n_props++] = CORBA::string_dup(n_rows_str);

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

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

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

    /* clang-format off */
	/*----- 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 -----*/
    /* clang-format on */

    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
    DatabaseConnectionHandle dch(dcp);
    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()", dch);

    /* clang-format off */
	/*----- 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 -----*/
    /* clang-format on */

    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
    DatabaseConnectionHandle dch(dcp);
    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()", dch);

    /* clang-format off */
	/*----- 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 -----*/
    /* clang-format on */

    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());
        }
    }

    /* clang-format off */
	/*----- 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 -----*/
    /* clang-format on */

    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());
        }
    }

    /* clang-format off */
	/*----- 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 -----*/
    /* clang-format on */

    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];

    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;

    DatabaseConnectionHandle dch(dcp);
    result = query(sql_query_stream.str(), "db_get_class_pipe_list()", dch);

    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)) != nullptr)
            {
                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;

    /* clang-format off */
	/*----- 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 -----*/
    /* clang-format on */

    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;

    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;

    DatabaseConnectionHandle dch(dcp);
    result = query(sql_query_stream.str(), "db_get_device_pipe_list()", dch);

    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)) != nullptr)
            {
                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);

    /* clang-format off */
	/*----- 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 -----*/
    /* clang-format on */

    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);
        }
    }

    /* clang-format off */
	/*----- 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 -----*/
    /* clang-format on */

    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++;
                    snprintf(tmp_count_str, sizeof(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;
        }
    }

    /* clang-format off */
	/*----- 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 -----*/
    /* clang-format on */

    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++;
                    snprintf(tmp_count_str, sizeof(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");

    /* clang-format off */
	/*----- 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 -----*/
    /* clang-format on */

    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 = (ParseString<int>(row[4]) == 0); // count=0 for deleted property
            if(deleted)
            {
                count = 0;
            }
            char n_rows_str[256];
            snprintf(n_rows_str, sizeof(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);

    /* clang-format off */
	/*----- 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 -----*/
    /* clang-format on */

    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 = (ParseString<int>(row[4]) == 0); // count=0 for deleted property
            if(deleted)
            {
                count = 0;
            }
            char n_rows_str[256];
            snprintf(n_rows_str, sizeof(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);

    /* clang-format off */
	/*----- 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 -----*/
    /* clang-format on */

    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 << "/%%\"";

    DatabaseConnectionHandle dch(dcp);
    MYSQL_RES *result = query(sql_query_stream.str(), "db_get_forwarded_attribute_list_for_device()", dch);

    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)) != nullptr)
            {
                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);

    /* clang-format off */
	/*----- 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 -----*/
    /* clang-format on */

    /********************************************************************************************************/

    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;

    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;

    DatabaseConnectionHandle dch(dcp);
    result = query(sql_query_stream.str(), "db_get_class_property_list_wildcard()", dch);

    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)) != nullptr)
            {
                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");

    /* clang-format off */
	/*----- 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 -----*/
    /* clang-format on */

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

    /* clang-format off */
	/*----- PROTECTED REGION END -----*/	//	DataBase::add_dynamic_commands
}

/*----- PROTECTED REGION ID(DataBase::namespace_ending) ENABLED START -----*/
/* clang-format on */

//	Additional Methods
//============================================================================
//============================================================================
Tango::DevString DataBase::db_get_device_host_impl(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 = nullptr;
    if(n_rows > 0)
    {
        if((row = mysql_fetch_row(result)) != nullptr)
        {
            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_impl(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.
 */
//--------------------------------------------------------------

void DataBase::create_update_mem_att(const Tango::DevVarStringArray *argin, AutoLock &al)
{
    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;

    std::string sql_query = sql_query_stream.str();
    simple_query(sql_query, "db_put_device_attribute_property2()", al.get_dch());

    my_ulonglong nb_rows = mysql_affected_rows(al.get_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();
        simple_query(sql_query, "db_put_device_attribute_property2()", al.get_dch());
    }
}

/* clang-format off */
	/*----- PROTECTED REGION END -----*/	//	DataBase::namespace_ending
} //	namespace
