Changeset - 2faaeff76d3e
[Not reviewed]
0 2 0
Jan Kaluza - 14 years ago 2011-10-26 17:49:05
hanzz.k@gmail.com
Reconnect mysql connection when it's lost.. NOT TESTED, I will test it after hour :)
2 files changed with 42 insertions and 19 deletions:
0 comments (0 inline, 0 general)
include/transport/mysqlbackend.h
Show inline comments
 
@@ -39,24 +39,25 @@ class MySQLBackend : public StorageBackend
 
		/// \param config cofiguration, this class uses following Config values:
 
		/// 	- database.database - path to SQLite3 database file, database file is created automatically
 
		/// 	- service.prefix - prefix for tables created by createDatabase method
 
		MySQLBackend(Config *config);
 

	
 
		/// Destructor.
 
		~MySQLBackend();
 

	
 
		/// Connects to the database and creates it if it's needed. This method call createDatabase() function
 
		/// automatically.
 
		/// \return true if database is opened successfully.
 
		bool connect();
 
		void disconnect();
 

	
 
		/// Creates database structure.
 
		/// \see connect()
 
		/// \return true if database structure has been created successfully. Note that it returns True also if database structure
 
		/// already exists.
 
		bool createDatabase();
 

	
 
		/// Stores user into database.
 
		/// \param user user struct containing all information about user which have to be stored
 
		void setUser(const UserInfo &user);
 

	
 
		/// Gets user data from database and stores them into user reference.
 
@@ -91,25 +92,25 @@ class MySQLBackend : public StorageBackend
 

	
 
		void beginTransaction();
 
		void commitTransaction();
 

	
 
	private:
 
		bool exec(const std::string &query);
 

	
 
		class Statement {
 
			public:
 
				Statement(MYSQL *conn, const std::string &format, const std::string &statement);
 
				~Statement();
 

	
 
				bool execute();
 
				int execute();
 

	
 
				int fetch();
 

	
 
				// Pushes new data used as input for the statement.
 
				template <typename T>
 
				Statement& operator << (const T& t);
 

	
 
				Statement& operator << (const std::string& str);
 

	
 
				// Pulls fetched data by previous execute(); call.
 
				template <typename T>
 
				Statement& operator >> (T& t);
 
@@ -117,24 +118,26 @@ class MySQLBackend : public StorageBackend
 
				Statement& operator >> (std::string& t);
 
			private:
 
				MYSQL_STMT *m_stmt;
 
				MYSQL *m_conn;
 
				std::vector<MYSQL_BIND> m_params;
 
				std::vector<MYSQL_BIND> m_results;
 
				int m_resultOffset;
 
				int m_offset;
 
				int m_error;
 
				std::string m_string;
 
		};
 

	
 
		bool exec(Statement *stmt);
 

	
 
		MYSQL m_conn;
 
		Config *m_config;
 
		std::string m_prefix;
 

	
 
		// statements
 
// 		MYSQL_STMT *m_setUser;
 
		Statement *m_setUser;
 
		Statement *m_getUser;
 
		Statement *m_getUserSetting;
 
		Statement *m_setUserSetting;
 
		Statement *m_updateUserSetting;
 
		Statement *m_removeUser;
src/mysqlbackend.cpp
Show inline comments
 
@@ -175,36 +175,36 @@ MySQLBackend::Statement::Statement(MYSQL *conn, const std::string &format, const
 
MySQLBackend::Statement::~Statement() {
 
	for (int i = 0; i < m_params.size(); i++) {
 
		free(m_params[i].buffer);
 
		free(m_params[i].length);
 
	}
 
	for (int i = 0; i < m_results.size(); i++) {
 
		free(m_results[i].buffer);
 
		free(m_results[i].length);
 
	}
 
	FINALIZE_STMT(m_stmt);
 
}
 

	
 
bool MySQLBackend::Statement::execute() {
 
int MySQLBackend::Statement::execute() {
 
	// If statement has some input and doesn't have any output, we have
 
	// to clear the offset now, because operator>> will not be called.
 
	m_offset = 0;
 
	m_resultOffset = 0;
 
	int ret;
 

	
 
	if ((ret = mysql_stmt_execute(m_stmt)) != 0) {
 
		LOG4CXX_ERROR(logger, m_string << " " << mysql_stmt_error(m_stmt) << "; " << mysql_error(m_conn));
 
		return false;
 
		return mysql_stmt_errno(m_stmt);
 
	}
 
	return true;
 
	return 0;
 
}
 

	
 
int MySQLBackend::Statement::fetch() {
 
	return mysql_stmt_fetch(m_stmt);
 
}
 

	
 
template <typename T>
 
MySQLBackend::Statement& MySQLBackend::Statement::operator << (const T& t) {
 
	if (m_offset >= m_params.size())
 
		return *this;
 
	int *data = (int *) m_params[m_offset].buffer;
 
	*data = (int) t;
 
@@ -254,24 +254,28 @@ MySQLBackend::Statement& MySQLBackend::Statement::operator >> (std::string& t) {
 
	return *this;
 
}
 

	
 
MySQLBackend::MySQLBackend(Config *config) {
 
	m_config = config;
 
	mysql_init(&m_conn);
 
	my_bool my_true = 1;
 
	mysql_options(&m_conn, MYSQL_OPT_RECONNECT, &my_true);
 
	m_prefix = CONFIG_STRING(m_config, "database.prefix");
 
}
 

	
 
MySQLBackend::~MySQLBackend(){
 
	disconnect();
 
}
 

	
 
void MySQLBackend::disconnect() {
 
	delete m_setUser;
 
	delete m_getUser;
 
	delete m_removeUser;
 
	delete m_removeUserBuddies;
 
	delete m_removeUserSettings;
 
	delete m_removeUserBuddiesSettings;
 
	delete m_addBuddy;
 
	delete m_updateBuddy;
 
	delete m_getBuddies;
 
	delete m_getBuddiesSettings;
 
	delete m_getUserSetting;
 
	delete m_setUserSetting;
 
@@ -378,103 +382,119 @@ bool MySQLBackend::createDatabase() {
 

	
 
	return true;
 
}
 

	
 
bool MySQLBackend::exec(const std::string &query) {
 
	if (mysql_query(&m_conn, query.c_str())) {
 
		LOG4CXX_ERROR(logger, query << " " << mysql_error(&m_conn));
 
		return false;
 
	}
 
	return true;
 
}
 

	
 
bool MySQLBackend::exec(Statement *stmt) {
 
	for (int i = 20; i > 0; i--) {
 
		int ret = stmt->execute();
 
		if (ret == 0)
 
			return true;
 
		if (ret == 2013) {
 
			disconnect();
 
			connect();
 
		}
 
		if (i != 20) {
 
			sleep(1);
 
		}
 
	}
 
	return false;
 
}
 

	
 
void MySQLBackend::setUser(const UserInfo &user) {
 
	*m_setUser << user.jid << user.uin << user.password << user.language << user.encoding << user.vip << user.password;
 
	m_setUser->execute();
 
	exec(m_setUser);
 
}
 

	
 
bool MySQLBackend::getUser(const std::string &barejid, UserInfo &user) {
 
	*m_getUser << barejid;
 
	if (!m_getUser->execute())
 
	if (!exec(m_getUser))
 
		return false;
 

	
 
	int ret = false;
 
	while (m_getUser->fetch() == 0) {
 
		ret = true;
 
		*m_getUser >> user.id >> user.jid >> user.uin >> user.password >> user.encoding >> user.language >> user.vip;
 
	}
 

	
 
	return ret;
 
}
 

	
 
void MySQLBackend::setUserOnline(long id, bool online) {
 
	*m_setUserOnline << online << id;
 
	m_setUserOnline->execute();
 
	exec(m_setUserOnline);
 
}
 

	
 
long MySQLBackend::addBuddy(long userId, const BuddyInfo &buddyInfo) {
 
// 	"INSERT INTO " + m_prefix + "buddies (user_id, uin, subscription, groups, nickname, flags) VALUES (?, ?, ?, ?, ?, ?)"
 
	*m_addBuddy << userId << buddyInfo.legacyName << buddyInfo.subscription;
 
	*m_addBuddy << (buddyInfo.groups.size() == 0 ? "" : buddyInfo.groups[0]);
 
	*m_addBuddy << buddyInfo.alias << buddyInfo.flags;
 

	
 
	m_addBuddy->execute();
 
	exec(m_addBuddy);
 

	
 
	long id = (long) mysql_insert_id(&m_conn);
 

	
 
// 	INSERT OR REPLACE INTO " + m_prefix + "buddies_settings (user_id, buddy_id, var, type, value) VALUES (?, ?, ?, ?, ?)
 
	if (!buddyInfo.settings.find("icon_hash")->second.s.empty()) {
 
		*m_updateBuddySetting << userId << id << buddyInfo.settings.find("icon_hash")->first << (int) TYPE_STRING << buddyInfo.settings.find("icon_hash")->second.s << buddyInfo.settings.find("icon_hash")->second.s;
 
		m_updateBuddySetting->execute();
 
		exec(m_updateBuddySetting);
 
	}
 

	
 
	return id;
 
}
 

	
 
void MySQLBackend::updateBuddy(long userId, const BuddyInfo &buddyInfo) {
 
// 	"UPDATE " + m_prefix + "buddies SET groups=?, nickname=?, flags=?, subscription=? WHERE user_id=? AND uin=?"
 
	*m_updateBuddy << (buddyInfo.groups.size() == 0 ? "" : buddyInfo.groups[0]);
 
	*m_updateBuddy << buddyInfo.alias << buddyInfo.flags << buddyInfo.subscription;
 
	*m_updateBuddy << userId << buddyInfo.legacyName;
 

	
 
	m_updateBuddy->execute();
 
	exec(m_updateBuddy);
 
}
 

	
 
bool MySQLBackend::getBuddies(long id, std::list<BuddyInfo> &roster) {
 
//	SELECT id, uin, subscription, nickname, groups, flags FROM " + m_prefix + "buddies WHERE user_id=? ORDER BY id ASC
 
	*m_getBuddies << id;
 

	
 
// 	"SELECT buddy_id, type, var, value FROM " + m_prefix + "buddies_settings WHERE user_id=? ORDER BY buddy_id ASC"
 
	*m_getBuddiesSettings << id;
 

	
 
	SettingVariableInfo var;
 
	long buddy_id = -1;
 
	std::string key;
 

	
 
	if (!m_getBuddies->execute())
 
	if (!exec(m_getBuddies))
 
		return false;
 

	
 
	while (m_getBuddies->fetch() == 0) {
 
		BuddyInfo b;
 

	
 
		std::string group;
 
		*m_getBuddies >> b.id >> b.legacyName >> b.subscription >> b.alias >> group >> b.flags;
 

	
 
		if (!group.empty())
 
			b.groups.push_back(group);
 

	
 
		roster.push_back(b);
 
	}
 

	
 
	if (!m_getBuddiesSettings->execute())
 
	if (!exec(m_getBuddiesSettings))
 
		return false;
 

	
 
	BOOST_FOREACH(BuddyInfo &b, roster) {
 
		if (buddy_id == b.id) {
 
// 			std::cout << "Adding buddy info setting " << key << "\n";
 
			b.settings[key] = var;
 
			buddy_id = -1;
 
		}
 

	
 
		while(buddy_id == -1 && m_getBuddiesSettings->fetch() == 0) {
 
			std::string val;
 
			*m_getBuddiesSettings >> buddy_id >> var.type >> key >> val;
 
@@ -502,60 +522,60 @@ bool MySQLBackend::getBuddies(long id, std::list<BuddyInfo> &roster) {
 
	}
 

	
 
	while(m_getBuddiesSettings->fetch() == 0) {
 
		// TODO: probably remove those settings, because there's no buddy for them.
 
		// It should not happend, but one never know...
 
	}
 
	
 
	return true;
 
}
 

	
 
bool MySQLBackend::removeUser(long id) {
 
	*m_removeUser << (int) id;
 
	if (!m_removeUser->execute())
 
	if (!exec(m_removeUser))
 
		return false;
 

	
 
	*m_removeUserSettings << (int) id;
 
	if (!m_removeUserSettings->execute())
 
	if (!exec(m_removeUserSettings))
 
		return false;
 

	
 
	*m_removeUserBuddies << (int) id;
 
	if (!m_removeUserBuddies->execute())
 
	if (!exec(m_removeUserBuddies))
 
		return false;
 

	
 
	*m_removeUserBuddiesSettings << (int) id;
 
	if (!m_removeUserBuddiesSettings->execute())
 
	if (!exec(m_removeUserBuddiesSettings))
 
		return false;
 

	
 
	return true;
 
}
 

	
 
void MySQLBackend::getUserSetting(long id, const std::string &variable, int &type, std::string &value) {
 
// 	"SELECT type, value FROM " + m_prefix + "users_settings WHERE user_id=? AND var=?"
 
	*m_getUserSetting << id << variable;
 
	m_getUserSetting->execute();
 
	exec(m_getUserSetting);
 
	if (m_getUserSetting->fetch() != 0) {
 
// 		"INSERT INTO " + m_prefix + "users_settings (user_id, var, type, value) VALUES (?,?,?,?)"
 
		*m_setUserSetting << id << variable << type << value;
 
		m_setUserSetting->execute();
 
		exec(m_setUserSetting);
 
	}
 
	else {
 
		*m_getUserSetting >> type >> value;
 
	}
 
}
 

	
 
void MySQLBackend::updateUserSetting(long id, const std::string &variable, const std::string &value) {
 
// 	"UPDATE " + m_prefix + "users_settings SET value=? WHERE user_id=? AND var=?"
 
	*m_updateUserSetting << value << id << variable;
 
	m_updateUserSetting->execute();
 
	exec(m_updateUserSetting);
 
}
 

	
 
void MySQLBackend::beginTransaction() {
 
	exec("START TRANSACTION;");
 
}
 

	
 
void MySQLBackend::commitTransaction() {
 
	exec("COMMIT;");
 
}
 

	
 
}
 

	
0 comments (0 inline, 0 general)