Commit e4d34aab authored by Pavel Vainerman's avatar Pavel Vainerman

(SQLite): заготовка для интерфейса..

parent ea7a1ff4
......@@ -38,6 +38,7 @@ PKG_CHECK_MODULES(XML, libxml-2.0)
PKG_CHECK_MODULES(OMNI, omniORB4)
PKG_CHECK_MODULES(SIGC, sigc++-2.0)
PKG_CHECK_MODULES(COMCPP, libccgnu2)
PKG_CHECK_MODULES(SQLITE3, sqlite3)
# export
LDFLAGS="${OMNI_LIBS} ${XML_LIBS}"
......@@ -177,6 +178,8 @@ AC_CONFIG_FILES([Makefile
extensions/include/Makefile
extensions/DBServer-MySQL/Makefile
extensions/DBServer-MySQL/libUniSetMySQL.pc
extensions/DBServer-SQLite/Makefile
extensions/DBServer-SQLite/libUniSetSQLite.pc
extensions/IOControl/Makefile
extensions/IOControl/libUniSetIOControl.pc
extensions/ModbusMaster/Makefile
......
/* This file is part of the UniSet project
* Copyright (c) 2002 Free Software Foundation, Inc.
* Copyright (c) 2002 Pavel Vainerman
*
* This program 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 2 of the License, or
* (at your option) any later version.
*
* This program 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 this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
// --------------------------------------------------------------------------
/*! \file
* \brief файл реализации DB-сервера
* \author Pavel Vainerman
*/
// --------------------------------------------------------------------------
#include <sys/time.h>
#include <sstream>
#include <iomanip>
#include "ORepHelpers.h"
#include "DBServer_SQLite.h"
#include "Configuration.h"
#include "Debug.h"
#include "UniXML.h"
// --------------------------------------------------------------------------
using namespace UniSetTypes;
using namespace std;
// --------------------------------------------------------------------------
const Debug::type DBLEVEL = Debug::LEVEL1;
// --------------------------------------------------------------------------
DBServer_SQLite::DBServer_SQLite( ObjectId id ):
DBServer(id),
db(new SQLiteInterface()),
PingTime(300000),
ReconnectTime(180000),
connect_ok(false),
activate(true),
lastRemove(false)
{
if( getId() == DefaultObjectId )
{
ostringstream msg;
msg << "(DBServer_SQLite): init failed! Unknown ID!" << endl;
throw Exception(msg.str());
}
}
DBServer_SQLite::DBServer_SQLite():
DBServer(conf->getDBServer()),
db(new SQLiteInterface()),
PingTime(300000),
ReconnectTime(180000),
connect_ok(false),
activate(true),
lastRemove(false)
{
// init();
if( getId() == DefaultObjectId )
{
ostringstream msg;
msg << "(DBServer_SQLite): init failed! Unknown ID!" << endl;
throw Exception(msg.str());
}
}
//--------------------------------------------------------------------------------------------
DBServer_SQLite::~DBServer_SQLite()
{
if( db != NULL )
{
db->close();
delete db;
}
}
//--------------------------------------------------------------------------------------------
void DBServer_SQLite::processingMessage( UniSetTypes::VoidMessage *msg )
{
switch(msg->type)
{
case Message::Timer:
{
TimerMessage tm(msg);
timerInfo(&tm);
break;
}
default:
DBServer::processingMessage(msg);
break;
}
}
//--------------------------------------------------------------------------------------------
void DBServer_SQLite::sysCommand( UniSetTypes::SystemMessage *sm )
{
switch( sm->command )
{
case SystemMessage::StartUp:
break;
case SystemMessage::Finish:
{
activate = false;
db->close();
}
break;
case SystemMessage::FoldUp:
{
activate = false;
db->close();
}
break;
default:
break;
}
}
//--------------------------------------------------------------------------------------------
void DBServer_SQLite::parse( UniSetTypes::DBMessage* dbm )
{
if( dbm->tblid == UniSetTypes::Message::Unused )
{
unideb[Debug::CRIT] << myname << "(dbmessage): не задан tblId...\n";
return;
}
ostringstream query;
switch( dbm->qtype )
{
case DBMessage::Query:
query << dbm->data;
break;
case DBMessage::Update:
query << "UPDATE " << tblName(dbm->tblid) << " SET " << dbm->data;
break;
case DBMessage::Insert:
query << "INSERT INTO " << tblName(dbm->tblid) << " VALUES (" << dbm->data << ")";
break;
}
if( !writeToBase(query.str()) )
{
unideb[Debug::CRIT] << myname << "(update): error: "<< db->error() << endl;
// if( dbm->qtype == DBMessage::Query )
// db->freeResult();
}
}
//--------------------------------------------------------------------------------------------
void DBServer_SQLite::parse( UniSetTypes::ConfirmMessage* cem )
{
try
{
ostringstream data;
data << "UPDATE " << tblName(cem->type)
<< " SET confirm='" << cem->confirm << "'"
<< " WHERE sensor_id='" << cem->sensor_id << "'"
<< " AND date='" << ui.dateToString(cem->time, "-")<<" '"
<< " AND time='" << ui.timeToString(cem->time, ":") <<" '"
<< " AND time_usec='" << cem->time_usec <<" '";
if( unideb.debugging(DBLEVEL) )
unideb[DBLEVEL] << myname << "(update_confirm): " << data.str() << endl;
if( !writeToBase(data.str()) )
{
if( unideb.debugging(Debug::CRIT) )
unideb[Debug::CRIT] << myname << "(update_confirm): db error: "<< db->error() << endl;
}
}
catch( Exception& ex )
{
if( unideb.debugging(Debug::CRIT) )
unideb[Debug::CRIT] << myname << "(update_confirm): " << ex << endl;
}
catch( ... )
{
if( unideb.debugging(Debug::CRIT) )
unideb[Debug::CRIT] << myname << "(update_confirm): catch..." << endl;
}
}
//--------------------------------------------------------------------------------------------
bool DBServer_SQLite::writeToBase( const string& query )
{
if( unideb.debugging(DBLogInfoLevel) )
unideb[DBLogInfoLevel] << myname << "(writeToBase): " << query << endl;
// cout << "DBServer_SQLite: " << query << endl;
if( !db || !connect_ok )
{
uniset_mutex_lock l(mqbuf,200);
qbuf.push(query);
if( qbuf.size() > qbufSize )
{
std::string qlost;
if( lastRemove )
qlost = qbuf.back();
else
qlost = qbuf.front();
qbuf.pop();
if( unideb.debugging(Debug::CRIT) )
unideb[Debug::CRIT] << myname << "(writeToBase): DB not connected! buffer(" << qbufSize
<< ") overflow! lost query: " << qlost << endl;
}
return false;
}
// На всякий скидываем очередь
flushBuffer();
// А теперь собственно запрос..
db->query(query);
// Дело в том что на INSERT И UPDATE запросы
// db->query() может возвращать false и надо самому
// отдельно проверять действительно ли произошла ошибка
// см. SQLiteInterface::query.
string err(db->error());
if( err.empty() )
return true;
return false;
}
//--------------------------------------------------------------------------------------------
void DBServer_SQLite::flushBuffer()
{
uniset_mutex_lock l(mqbuf,400);
// Сперва пробуем очистить всё что накопилось в очереди до этого...
while( !qbuf.empty() )
{
db->query( qbuf.front() );
// Дело в том что на INSERT И UPDATE запросы
// db->query() может возвращать false и надо самому
// отдельно проверять действительно ли произошла ошибка
// см. SQLiteInterface::query.
string err(db->error());
if( err.empty() && unideb.debugging(Debug::CRIT) )
{
unideb[Debug::CRIT] << myname << "(writeToBase): error: " << err <<
" lost query: " << qbuf.front() << endl;
}
qbuf.pop();
}
}
//--------------------------------------------------------------------------------------------
void DBServer_SQLite::parse( UniSetTypes::SensorMessage *si )
{
try
{
// если время не было выставлено (указываем время сохранения в БД)
if( !si->tm.tv_sec )
{
struct timezone tz;
gettimeofday(&si->tm,&tz);
}
// см. DBTABLE AnalogSensors, DigitalSensors
ostringstream data;
data << "INSERT INTO " << tblName(si->type)
<< "(date, time, time_usec, sensor_id, value, node) VALUES( '"
// Поля таблицы
<< ui.dateToString(si->sm_tv_sec,"-") << "','" // date
<< ui.timeToString(si->sm_tv_sec,":") << "','" // time
<< si->sm_tv_usec << "'," // time_usec
<< si->id << "," // sensor_id
<< si->value << "," // value
<< si->node << ")"; // node
if( unideb.debugging(DBLEVEL) )
unideb[DBLEVEL] << myname << "(insert_main_history): " << data.str() << endl;
if( !writeToBase(data.str()) )
{
if( unideb.debugging(Debug::CRIT) )
unideb[Debug::CRIT] << myname << "(insert) sensor msg error: "<< db->error() << endl;
}
}
catch( Exception& ex )
{
unideb[Debug::CRIT] << myname << "(insert_main_history): " << ex << endl;
}
catch( ... )
{
unideb[Debug::CRIT] << myname << "(insert_main_history): catch ..." << endl;
}
}
//--------------------------------------------------------------------------------------------
void DBServer_SQLite::init_dbserver()
{
DBServer::init_dbserver();
if( unideb.debugging(DBLogInfoLevel) )
unideb[DBLogInfoLevel] << myname << "(init): ..." << endl;
if( connect_ok )
{
initDBTableMap(tblMap);
initDB(db);
return;
}
if( conf->getDBServer() == UniSetTypes::DefaultObjectId )
{
ostringstream msg;
msg << myname << "(init): DBServer OFF for this node.."
<< " In " << conf->getConfFileName()
<< " for this node dbserver=''";
throw NameNotFound(msg.str());
}
xmlNode* node = conf->getNode("LocalDBServer");
if( !node )
throw NameNotFound(string(myname+"(init): section <LocalDBServer> not found.."));
UniXML::iterator it(node);
unideb[DBLogInfoLevel] << myname << "(init): init connection.." << endl;
string dbname(conf->getProp(node,"dbname"));
string dbnode(conf->getProp(node,"dbnode"));
string user(conf->getProp(node,"dbuser"));
string password(conf->getProp(node,"dbpass"));
tblMap[UniSetTypes::Message::SensorInfo] = "main_history";
tblMap[UniSetTypes::Message::Confirm] = "main_history";
PingTime = conf->getIntProp(node,"pingTime");
ReconnectTime = conf->getIntProp(node,"reconnectTime");
qbufSize = conf->getArgPInt("--dbserver-buffer-size",it.getProp("bufferSize"),200);
if( findArgParam("--dbserver-buffer-last-remove",conf->getArgc(),conf->getArgv()) != -1 )
lastRemove = true;
else if( it.getIntProp("bufferLastRemove" ) !=0 )
lastRemove = true;
else
lastRemove = false;
if( dbnode.empty() )
dbnode = "localhost";
if( unideb.debugging(DBLogInfoLevel) )
unideb[DBLogInfoLevel] << myname << "(init): connect dbnode=" << dbnode
<< "\tdbname=" << dbname
<< " pingTime=" << PingTime
<< " ReconnectTime=" << ReconnectTime << endl;
#if 0
if( !db->connect(dbnode, user, password, dbname) )
{
// ostringstream err;
if( unideb.debugging(Debug::CRIT) )
unideb[Debug::CRIT] << myname
<< "(init): DB connection error: "
<< db->error() << endl;
// throw Exception( string(myname+"(init): не смогли создать соединение с БД "+db->error()) );
askTimer(DBServer_SQLite::ReconnectTimer,ReconnectTime);
}
else
{
if( unideb.debugging(DBLogInfoLevel) )
unideb[DBLogInfoLevel] << myname << "(init): connect [OK]" << endl;
connect_ok = true;
askTimer(DBServer_SQLite::ReconnectTimer,0);
askTimer(DBServer_SQLite::PingTimer,PingTime);
// createTables(db);
initDB(db);
initDBTableMap(tblMap);
flushBuffer();
}
#endif
}
//--------------------------------------------------------------------------------------------
void DBServer_SQLite::createTables( SQLiteInterface *db )
{
UniXML_iterator it( conf->getNode("Tables") );
if(!it)
{
if( unideb.debugging(Debug::CRIT) )
unideb[Debug::CRIT] << myname << ": section <Tables> not found.."<< endl;
throw Exception();
}
for( it.goChildren();it;it.goNext() )
{
if( it.getName() != "comment" )
{
if( unideb.debugging(DBLogInfoLevel) )
unideb[DBLogInfoLevel] << myname << "(createTables): create " << it.getName() << endl;
ostringstream query;
query << "CREATE TABLE " << conf->getProp(it,"name") << "(" << conf->getProp(it,"create") << ")";
if( !db->query(query.str()) && unideb.debugging(Debug::CRIT) )
unideb[Debug::CRIT] << myname << "(createTables): error: \t\t" << db->error() << endl;
}
}
}
//--------------------------------------------------------------------------------------------
void DBServer_SQLite::timerInfo( UniSetTypes::TimerMessage* tm )
{
switch( tm->id )
{
case DBServer_SQLite::PingTimer:
{
#if 0
if( !db->ping() )
{
if( unideb.debugging(Debug::WARN) )
unideb[Debug::WARN] << myname << "(timerInfo): DB lost connection.." << endl;
connect_ok = false;
askTimer(DBServer_SQLite::PingTimer,0);
askTimer(DBServer_SQLite::ReconnectTimer,ReconnectTime);
}
else
{
connect_ok = true;
if( unideb.debugging(DBLogInfoLevel) )
unideb[DBLogInfoLevel] << myname << "(timerInfo): DB ping ok" << endl;
}
#endif
}
break;
case DBServer_SQLite::ReconnectTimer:
{
if( unideb.debugging(DBLogInfoLevel) )
unideb[DBLogInfoLevel] << myname << "(timerInfo): reconnect timer" << endl;
if( db->isConnection() )
{
#if 0
if( db->ping() )
{
connect_ok = true;
askTimer(DBServer_SQLite::ReconnectTimer,0);
askTimer(DBServer_SQLite::PingTimer,PingTime);
}
#endif
connect_ok = false;
if( unideb.debugging(Debug::WARN) )
unideb[Debug::WARN] << myname << "(timerInfo): DB no connection.." << endl;
}
else
init_dbserver();
}
break;
default:
if( unideb.debugging(Debug::WARN) )
unideb[Debug::WARN] << myname << "(timerInfo): Unknown TimerID=" << tm->id << endl;
break;
}
}
//--------------------------------------------------------------------------------------------
/* This file is part of the UniSet project
* Copyright (c) 2002 Free Software Foundation, Inc.
* Copyright (c) 2002 Pavel Vainerman
*
* This program 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 2 of the License, or
* (at your option) any later version.
*
* This program 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 this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
// --------------------------------------------------------------------------
/*! \file
* \author Pavel Vainerman
*/
// --------------------------------------------------------------------------
#ifndef DBServer_SQLite_H_
#define DBServer_SQLite_H_
// --------------------------------------------------------------------------
#include <map>
#include <queue>
#include "UniSetTypes.h"
#include "SQLiteInterface.h"
#include "DBServer.h"
//------------------------------------------------------------------------------------------
/*!
\page page_DBServer_SQLite (DBServer_SQLite) Реализация сервиса ведения БД на основе SQLite
- \ref sec_DBS_Comm
- \ref sec_DBS_Conf
- \ref sec_DBS_Tables
- \ref sec_DBS_Buffer
\section sec_DBS_Comm Общее описание работы DBServer_SQLite
Сервис предназначен для работы с БД SQLite. В его задачи входит
сохранение всех событий происходищих в системе в БД. К этим
событиям относятся изменение состояния датчиков, различные логи
работы процессов и т.п.
К моменту запуска, подразумевается, что неободимые таблицы уже
созданы, все необходимые настройки mysql сделаны.
\par
При работе с БД, сервис в основном пишет в БД. Обработка накопленных данных
ведётся уже другими программами (web-интерфейс).
\par
Для повышения надежности DBServer переодически ( DBServer_SQLite::PingTimer ) проверяет наличие связи с сервером БД.
В случае если связь пропала (или не была установлена при старте) DBServer пытается вновь каждые DBServer::ReconnectTimer
произвести соединение. При этом все запросы которые поступают для запии в БД, но не мгут быть записаны складываются
в буфер (см. \ref sec_DBS_Buffer).
\warning При каждой попытке восстановить соединение DBServer заново читает конф. файл. Поэтому он может подхватить
новые настройки.
\todo Может не сохранять текст, если задан код... (для экономии в БД)
\section sec_DBS_Conf Настройка DBServer
Объект DBServer берёт настройки из конфигурационного файла из секции \b<LocalDBServer>.
Возможно задать следующие параметры:
- \b dbname - название БД
- \b dbnode - узел БД
- \b dbuser - пользователь
- \b dbpass - пароль для доступа к БД
- \b pingTime - период проверки связи с сервером SQLite
- \b reconnectTime - время повторной попытки соединения с БД
\section sec_DBS_Buffer Защита от потери данных
Для того, чтобы на момент отсутствия связи с БД данные по возможности не потерялись,
сделан "кольцевой" буфер. Размер которго можно регулировать параметром "--dbserver-buffer-size"
или параметром \b bufferSize=".." в конфигурационном файле секции "<LocalDBSErver...>".
Механизм построен на том, что если связь с mysql сервером отсутствует или пропала,
то сообщения помещаются в колевой буфер, который "опустошается" как только она восстановится.
Если связь не восстановилась, а буфер достиг максимального заданного размера, то удаляются
более ранние сообщения. Эту логику можно сменить, если указать параметр "--dbserver-buffer-last-remove"
или \b bufferLastRemove="1", то терятся будут сообщения добавляемые в конец.
\section sec_DBS_Tables Таблицы SQLite
К основным таблицам относятся следующие:
\code
DROP TABLE IF EXISTS `main_history`;
CREATE TABLE `main_history` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`date` date NOT NULL,
`time` time NOT NULL,
`time_usec` int(10) unsigned NOT NULL,
`sensor_id` int(10) unsigned NOT NULL,
`value` double NOT NULL,
`node` int(10) unsigned NOT NULL,
`confirm` int(11) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `main_history_sensor_id` (`sensor_id`),
CONSTRAINT `sensor_id_refs_id_3d679168` FOREIGN KEY (`sensor_id`) REFERENCES `main_sensor` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
DROP TABLE IF EXISTS `main_emergencylog`;
CREATE TABLE `main_emergencylog` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`date` date NOT NULL,
`time` time NOT NULL,
`time_usec` int(10) unsigned NOT NULL,
`type_id` int(10) unsigned NOT NULL,
PRIMARY KEY (`id`),
KEY `main_emergencylog_type_id` (`type_id`),
CONSTRAINT `type_id_refs_id_a3133ca` FOREIGN KEY (`type_id`) REFERENCES `main_emergencytype` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
DROP TABLE IF EXISTS `main_emergencyrecords`;
CREATE TABLE `main_emergencyrecords` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`date` date NOT NULL,
`time` time NOT NULL,
`time_usec` int(10) unsigned NOT NULL,
`log_id` int(11) NOT NULL,
`sensor_id` int(10) unsigned NOT NULL,
`value` double NOT NULL,
PRIMARY KEY (`id`),
KEY `main_emergencyrecords_log_id` (`log_id`),
KEY `main_emergencyrecords_sensor_id` (`sensor_id`),
CONSTRAINT `log_id_refs_id_77a37ea9` FOREIGN KEY (`log_id`) REFERENCES `main_emergencylog` (`id`),
CONSTRAINT `sensor_id_refs_id_436bab5e` FOREIGN KEY (`sensor_id`) REFERENCES `main_sensor` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
\endcode
*/
class DBServer_SQLite:
public DBServer
{
public:
DBServer_SQLite( UniSetTypes::ObjectId id );
DBServer_SQLite();
~DBServer_SQLite();
static const Debug::type DBLogInfoLevel = Debug::LEVEL9;
protected:
typedef std::map<int, std::string> DBTableMap;
virtual void initDB( SQLiteInterface *db ){};
virtual void initDBTableMap(DBTableMap& tblMap){};
virtual void processingMessage( UniSetTypes::VoidMessage *msg );
virtual void timerInfo( UniSetTypes::TimerMessage* tm );
virtual void sysCommand( UniSetTypes::SystemMessage* sm );
// Функции обработки пришедших сообщений
virtual void parse( UniSetTypes::SensorMessage* sm );
virtual void parse( UniSetTypes::DBMessage* dbmsg );
virtual void parse( UniSetTypes::ConfirmMessage* cmsg );
bool writeToBase( const string& query );
virtual void init_dbserver();
void createTables( SQLiteInterface* db );
inline const char* tblName(int key)
{
return tblMap[key].c_str();
}
enum Timers
{
PingTimer, /*!< таймер на переодическую проверку соединения с сервером БД */
ReconnectTimer, /*!< таймер на повторную попытку соединения с сервером БД (или восстановления связи) */
lastNumberOfTimer
};
SQLiteInterface *db;
int PingTime;
int ReconnectTime;
bool connect_ok; /*! признак наличия соеднинения с сервером БД */
bool activate;
typedef std::queue<std::string> QueryBuffer;
QueryBuffer qbuf;
unsigned int qbufSize; // размер буфера сообщений.
bool lastRemove;
void flushBuffer();
UniSetTypes::uniset_mutex mqbuf;
private:
DBTableMap tblMap;
};
//------------------------------------------------------------------------------------------
#endif
#if DISABLE_SQLITE
#else
USQLITE_VER=@LIBVER@
lib_LTLIBRARIES = libUniSet-sqlite.la
libUniSet_sqlite_la_LDFLAGS = -version-info $(USQLITE_VER)
libUniSet_sqlite_la_SOURCES = SQLiteInterface.cc DBServer_SQLite.cc
libUniSet_sqlite_la_LIBADD = $(top_builddir)/lib/libUniSet.la $(SQLITE3_LIBS)
libUniSet_sqlite_la_CXXFLAGS = $(SQLITE3_CFLAGS)
bin_PROGRAMS = uniset-sqlite-dbserver
uniset_sqlite_dbserver_LDADD = libUniSet-sqlite.la $(top_builddir)/lib/libUniSet.la
uniset_sqlite_dbserver_SOURCES = main.cc
include $(top_builddir)/conf/setting.mk
# install
#devel_include_HEADERS = *.h
#devel_includedir = $(includedir)/@PACKAGE@/sqlite
#pkgconfigdir = $(libdir)/pkgconfig
#pkgconfig_DATA = libUniSetSQLite.pc
#endif
\ No newline at end of file
/* This file is part of the UniSet project
* Copyright (c) 2002 Free Software Foundation, Inc.
* Copyright (c) 2002 Pavel Vainerman
*
* This program 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 2 of the License, or
* (at your option) any later version.
*
* This program 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 this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
// --------------------------------------------------------------------------
/*! \file
* \author Pavel Vainerman
*/
// --------------------------------------------------------------------------
#include <sstream>
#include "UniSetTypes.h"
#include "SQLiteInterface.h"
// --------------------------------------------------------------------------
using namespace std;
using namespace UniSetTypes;
// --------------------------------------------------------------------------
SQLiteInterface::SQLiteInterface():
db(0),
lastQ(""),
queryok(false),
connected(false),
opTimeout(300),
opCheckPause(50)
{
}
SQLiteInterface::~SQLiteInterface()
{
close();
delete db;
}
// -----------------------------------------------------------------------------------------
bool SQLiteInterface::connect( const string dbfile )
{
int rc = sqlite3_open(dbfile.c_str(), &db);
if( !rc )
{
cerr << sqlite3_errmsg(db) << endl;
sqlite3_close(db);
db = 0;
connected = false;
return false;
}
if( rc==SQLITE_BUSY || rc==SQLITE_LOCKED || rc==SQLITE_INTERRUPT || rc==SQLITE_IOERR )
{
cerr << sqlite3_errmsg(db) << endl;
sqlite3_close(db);
db = 0;
connected = false;
return false;
}
connected = true;
return true;
}
// -----------------------------------------------------------------------------------------
bool SQLiteInterface::close()
{
if(db)
sqlite3_close(db);
return true;
}
// -----------------------------------------------------------------------------------------
bool SQLiteInterface::insert( const string q )
{
if( !db )
return false;
// char* errmsg;
sqlite3_stmt* pStmt;
// Компилируем SQL запрос
sqlite3_prepare(db, q.c_str(), -1, &pStmt, NULL);
int rc = sqlite3_step(pStmt);
if( rc==SQLITE_BUSY || rc==SQLITE_LOCKED || rc==SQLITE_INTERRUPT || rc==SQLITE_IOERR )
{
if( !wait(pStmt, SQLITE_DONE) )
{
sqlite3_finalize(pStmt);
queryok=false;
return false;
}
}
sqlite3_finalize(pStmt);
queryok=true;
return true;
}
// -----------------------------------------------------------------------------------------
bool SQLiteInterface::query( const string q )
{
if( !db )
return false;
// char* errmsg = 0;
sqlite3_stmt* pStmt;
// Компилируем SQL запрос
sqlite3_prepare(db, q.c_str(), -1, &pStmt, NULL);
int rc = sqlite3_step(pStmt);
if( rc==SQLITE_BUSY || rc==SQLITE_LOCKED || rc==SQLITE_INTERRUPT || rc==SQLITE_IOERR )
{
if( !wait(pStmt, SQLITE_ROW) )
{
sqlite3_finalize(pStmt);
queryok=false;
return false;
}
}
lastQ = q;
// int cnum = sqlite3_column_count(pStmt);
/*
while( (rc = sqlite3_step(pStmt)) == SQLITE_ROW )
{
int coln = sqlite3_data_count(pStmt);
for( int j=0; j<coln; j++ )
{
}
}
*/
sqlite3_finalize(pStmt);
queryok=true;
return true;
}
// -----------------------------------------------------------------------------------------
bool SQLiteInterface::wait( sqlite3_stmt* stmt, int result )
{
PassiveTimer ptTimeout(opTimeout);
while( !ptTimeout.checkTime() )
{
sqlite3_reset(stmt);
int rc = sqlite3_step(stmt);
if( rc == result || rc == SQLITE_DONE )
return true;
msleep(opCheckPause);
}
return false;
}
// -----------------------------------------------------------------------------------------
const string SQLiteInterface::error()
{
if( !db )
return "";
return sqlite3_errmsg(db);
}
// -----------------------------------------------------------------------------------------
const string SQLiteInterface::lastQuery()
{
return lastQ;
}
// -----------------------------------------------------------------------------------------
int SQLiteInterface::insert_id()
{
if( !db )
return 0;
return sqlite3_last_insert_rowid(db);
}
// -----------------------------------------------------------------------------------------
bool SQLiteInterface::isConnection()
{
return connected;
}
// -----------------------------------------------------------------------------------------
/* This file is part of the UniSet project
* Copyright (c) 2002 Free Software Foundation, Inc.
* Copyright (c) 2002 Pavel Vainerman
*
* This program 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 2 of the License, or
* (at your option) any later version.
*
* This program 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 this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
// --------------------------------------------------------------------------
/*! \file
* \author Pavel Vainerman
*/
//----------------------------------------------------------------------------
#ifndef SQLiteInterface_H_
#define SQLiteInterface_H_
// ---------------------------------------------------------------------------
#include <string>
#include <iostream>
#include <sqlite3.h>
#include "PassiveTimer.h"
// ----------------------------------------------------------------------------
class SQLiteInterface
{
public:
SQLiteInterface();
~SQLiteInterface();
bool connect( const std::string dbfile );
bool close();
inline void setOperationTimeout( timeout_t msec ){ opTimeout = msec; }
inline timeout_t getOperationTimeout(){ return opTimeout; }
inline void setOperationCheckPause( timeout_t msec ){ opCheckPause = msec; }
inline timeout_t getOperationCheckPause(){ return opCheckPause; }
bool query( const std::string q );
const std::string lastQuery();
bool insert( const std::string q );
bool isConnection();
int insert_id();
const std::string error();
protected:
bool wait( sqlite3_stmt* stmt, int result );
private:
sqlite3* db;
std::string lastQ;
bool queryok; // успешность текущего запроса
bool connected;
timeout_t opTimeout;
timeout_t opCheckPause;
};
// ----------------------------------------------------------------------------------
#endif
// ----------------------------------------------------------------------------------
prefix=@prefix@
exec_prefix=@exec_prefix@
libdir=@libdir@
includedir=@includedir@
Name: libUniSetSQLite
Description: Support library for libUniSetSQLite
Requires: libUniSet sqlite3
Version: 1.0.0
Libs: -L${libdir} -lUniSet-sqlite
Cflags: -I${includedir}/uniset -I${includedir}/sqlite
#include "Configuration.h"
#include "DBServer_SQLite.h"
#include "ObjectsActivator.h"
#include "Debug.h"
// --------------------------------------------------------------------------
using namespace UniSetTypes;
using namespace std;
// --------------------------------------------------------------------------
static void short_usage()
{
cout << "Usage: uniset-mysql-dbserver [--name ObjectId] [--confile configure.xml]\n";
}
// --------------------------------------------------------------------------
int main(int argc, char** argv)
{
try
{
if( argc > 1 && !strcmp(argv[1],"--help") )
{
short_usage();
return 0;
}
uniset_init(argc,argv,"configure.xml");
ObjectId ID = conf->getDBServer();
// определяем ID объекта
string name = conf->getArgParam("--name");
if( !name.empty())
{
if( ID != UniSetTypes::DefaultObjectId )
{
unideb[Debug::WARN] << "(DBServer::main): переопределяем ID заданнй в "
<< conf->getConfFileName() << endl;
}
ID = conf->oind->getIdByName(conf->getServicesSection()+"/"+name);
if( ID == UniSetTypes::DefaultObjectId )
{
cerr << "(DBServer::main): идентификатор '" << name
<< "' не найден в конф. файле!"
<< " в секции " << conf->getServicesSection() << endl;
return 1;
}
}
else if( ID == UniSetTypes::DefaultObjectId )
{
cerr << "(DBServer::main): Не удалось определить ИДЕНТИФИКАТОР сервера" << endl;
short_usage();
return 1;
}
DBServer_SQLite dbs(ID);
ObjectsActivator act;
act.addObject(static_cast<class UniSetObject*>(&dbs));
act.run(false);
}
catch(Exception& ex)
{
cerr << "(DBServer::main): " << ex << endl;
}
catch(...)
{
cerr << "(DBServer::main): catch ..." << endl;
}
return 0;
}
......@@ -4,8 +4,8 @@
if HAVE_EXTENTIONS
SUBDIRS = lib include SharedMemory IOControl LogicProcessor \
ModbusMaster ModbusSlave SMViewer UniNetwork UNetUDP DBServer-MySQL SharedMemoryPlus \
tests
ModbusMaster ModbusSlave SMViewer UniNetwork UNetUDP DBServer-MySQL DBServer-SQLite \
SharedMemoryPlus tests
#SMDBServer
#SharedMemoryPlus
#UDPExchange
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment