• We’re currently investigating an issue related to the forum theme and styling that is impacting page layout and visual formatting. The problem has been identified, and we are actively working on a resolution. There is no impact to user data or functionality, this is strictly a front-end display issue. We’ll post an update once the fix has been deployed. Thanks for your patience while we get this sorted.

Mysql++ library - checking if connection still alive

Red Squirrel

No Lifer
Anyone know how I would go about checking that the server is still available before making a query on an open connection?

If the connection is not available, rather then return an error, it actually crashes the program. So I need a way to check before I do the query.
 
Hmm, I haven't done any MySQL in a year or so, but why are you keeping the connection open? I think I'd focus on why the program is crashing. Is it an unhandled exception? You're going to have to write the code to handle unexpected connection failures gracefully in any case.
 
It seems to crash if the mysql connection is lost, which could be due to any outside cause such as a server going down. The crash dump looks like this:

Code:
Nov-15-2009 08:34:40pm (2) Connected TCP client: 127.0.0.1:50742
Nov-15-2009 08:34:40pm (4) 127.0.0.1:50742: Recieved packet with ID 0x0
Nov-15-2009 08:34:40pm (4) 127.0.0.1:50742 Logon packet handler: init
Nov-15-2009 08:34:40pm (5) 127.0.0.1:50742 Logon packet handler: Read 8-bit int: 4
Nov-15-2009 08:34:40pm (5) 127.0.0.1:50742 Logon packet handler: Read 4-byte string: 0x72 0x6F 0x6F 0x74
Nov-15-2009 08:34:40pm (5) 127.0.0.1:50742 Logon packet handler: Read 8-bit int: 4
Nov-15-2009 08:34:40pm (5) 127.0.0.1:50742 Logon packet handler: Read 4-byte string: 0x74 0x65 0x73 0x74
Nov-15-2009 08:34:40pm (4) MySQL[1] Performing SQL query: SELECT * FROM users WHERE uname='root' AND upass='test' LIMIT 1;
Nov-15-2009 08:34:40pm (1) MySQL[1] ERROR: MySQL server has gone away
terminate called after throwing an instance of 'mysqlpp::UseQueryError'
  what():  Results not fetched

Program received signal SIGABRT, Aborted.
0x00110402 in __kernel_vsyscall ()
#0  0x00110402 in __kernel_vsyscall ()
#1  0x00139df0 in raise () from /lib/libc.so.6
#2  0x0013b701 in abort () from /lib/libc.so.6
#3  0x02f19ab0 in __gnu_cxx::__verbose_terminate_handler () from /usr/lib/libstdc++.so.6
#4  0x02f17515 in ?? () from /usr/lib/libstdc++.so.6
#5  0x02f17552 in std::terminate () from /usr/lib/libstdc++.so.6
#6  0x02f1768a in __cxa_throw () from /usr/lib/libstdc++.so.6
#7  0x00b847ec in mysqlpp::UseQueryResult::fetch_row (this=0xbfe961f8) at ./lib/result.cpp:185
#8  0x0807f1d8 in core::AuthenticateUser (this=0x9bd9890, username=
        {static npos = 4294967295, _M_dataplus = {<std::allocator<char>> = {<__gnu_cxx::new_allocator<char>> = {<No data fields>}, <No data fields>}, _M_p = 0xbfe962cc ",'&#239;&#191;&#189;\t\001\001\001\001&#239;&#191;&#189;\037&#37;"}}, pass=
        {static npos = 4294967295, _M_dataplus = {<std::allocator<char>> = {<__gnu_cxx::new_allocator<char>> = {<No data fields>}, <No data fields>}, _M_p = 0xbfe962c8 "l(&#239;&#191;&#189;\t,'&#239;&#191;&#189;\t\001\001\001\001&#239;&#191;&#189;\037%"}}) at includes/core.cpp:345
#9  0x08096fac in LogonPacketHandler::OnEndProcess (this=0x9c014d0) at includes/network/packethandlers/LogonPacketHandler.cpp:34
#10 0x0807feb0 in NetSession::Slice (this=0x9c02258) at includes/network/NetSession.cpp:128
#11 0x0807ff05 in SWlistener::SessionPoll (this=0x9bf9178) at includes/network/SWlistener.cpp:73
#12 0x0809a9b7 in core::Slice (this=0x9bd9890) at includes/core.cpp:66
#13 0x0809bd5a in main (argc=3, argv=0xbfe965f4) at serverweave.cpp:176
The program is running.  Exit anyway? (y or n) [answered Y; input not from terminal]


It's kinda odd as it seems to take a few tries to cause that crash, so maybe it's actually something else in my app causing it.
 
This is the function:

Code:
UseQueryResult MySQLConnector::DoQuery(string querystr,bool & goterror)
{
	UseQueryResult res;
		
	if(!IsConnected())
	{
		goterror=true;
		Debug(1,"Unable to perform query: " + querystr + " - Not connected");
		return res;
	}	
		
	Query thequery = CON->query(querystr);	
	
	res = thequery.use();	
	
	Debug(4,"Performing SQL query: " + querystr);
	
	if(CON->errnum())
	{
		goterror=true;
		string err=CON->error();
		m_error=err;
		Debug(1,"ERROR: " + err);
	}
	else m_MySqlAffectedRows=thequery.affected_rows();
	
	thequery.reset();
	
	return res;
}

And in case you want to see more, this is the whole class:

Code:
/**********************************************************
Server Weave 0.1 Dev C++ source file
http://www.serverweave.com
Filepath: includes/mysql/MySQLConnector.cpp
Lines of code: 135
***********************************************************/




MySQLConnector::MySQLConnector(string host,string user,string pass)
{
		m_host=host;
		m_user=user;
		m_pass=pass;
		m_error="";	
		CON=NULL;
		m_connectionid_str="NULL";
}

MySQLConnector::MySQLConnector()
{
		m_host=Core->GetSetting("mysql_server");
		m_user="root";
		m_pass=Core->GetSetting("mysql_rootpass");		
		m_error="";	
		CON=NULL;
		m_connectionid_str="NULL";
}

void MySQLConnector::SetName(string name)
{
	m_connectionid_str=name;
}

uli  MySQLConnector::m_connectionid=0;

void MySQLConnector::Debug(int level,string str)
{
	Core->Debug(level,"MySQL[" + m_connectionid_str + "] " + str);
}


bool MySQLConnector::Connect(string host,string user,string pass)
{
	if(CON!=NULL)
	{
		delete CON;
		CON=NULL;
	}

	if(m_connectionid_str=="NULL")
	{
		m_connectionid++;
		m_connectionid_str=BitStream::Int2Str(m_connectionid);	
	}
	
	CON = new Connection(false);
	
	bool ret=CON->connect(0,host.c_str(),user.c_str(),pass.c_str());	
	if(!ret)
	{
		string errstr=CON->error();
		m_error=errstr;
		Debug(1,"Failed to connect to DB (srv: " + host + " usr: " + user + " ) - " + errstr);
	}
	else Debug(2,"Successfully connected to DB (srv: [" + host + "] usr: [" + user +"])");
		
	return ret;	
}

bool MySQLConnector::Connect()
{
	return Connect(m_host,m_user,m_pass);
}


//TODO: look into reversing the return value and the "goterror" bool

UseQueryResult MySQLConnector::DoQuery(string querystr,bool & goterror)
{
	UseQueryResult res;
		
	if(!IsConnected())
	{
		goterror=true;
		Debug(1,"Unable to perform query: " + querystr + " - Not connected");
		return res;
	}	
		
	Query thequery = CON->query(querystr);	
	
	res = thequery.use();	
	
	Debug(4,"Performing SQL query: " + querystr);
	
	if(CON->errnum())
	{
		goterror=true;
		string err=CON->error();
		m_error=err;
		Debug(1,"ERROR: " + err);
	}
	else m_MySqlAffectedRows=thequery.affected_rows();
	
	thequery.reset();
	
	return res;
}



bool MySQLConnector::CreateDB(string dbname)
{
	if(!IsConnected())
	{
		Debug(1,"Error creating DB: " + dbname + ", Not connected");
		return false;
	}
	
	bool ret= CON->create_db(dbname);
	if(!ret)
	{
		string errstr=CON->error();
		m_error=errstr;
		Debug(1,"Failed to create DB " + dbname + ": " + errstr);		
	}
	else Debug(2,"created db " + dbname);
	
	return ret;
}


bool MySQLConnector::SelectDB(string dbname)
{
	if(!IsConnected())
	{
		Debug(1,"Error selecting DB: " + dbname + ", Not connected");
		return false;
	}	
	
	bool ret= CON->select_db(dbname);	
	if(!ret)
	{
		string errstr=CON->error();
		m_error=errstr;
		Debug(1,"Failed to select DB " + dbname + ": " + errstr);
	}
	else Debug(2,"Selecting DB " + dbname);	
	return ret;
}

bool MySQLConnector::SelectDB()
{
	return SelectDB(Core->GetSetting("mysql_db"));
}



uli MySQLConnector::AffectedRows()
{
	return m_MySqlAffectedRows;
}


void MySQLConnector::Disconnect()
{	
	CON->disconnect();
	
	delete CON;
	CON=NULL;
}

string MySQLConnector::GetError()
{
	string ret =m_error;
	m_error="";
	return ret;
}


bool MySQLConnector::IsConnected()
{
	return CON!=NULL; //TODO: check actual connection state - this will fix queries crashing if connection gets dropped
}

Idealy, whatever I have to do to check the connection should go in IsConnected().
 
Never figured I'd have to actually catch them, I've always just checked the return value of whatever function I'm using, to check for errors.

Which is more than a lot of people do, but I still can't believe you've never run into this before. C++ has had exceptions for at least a decade. Although it does scare me even more and explain a bit about your "It'll be easier to just reimplement this myself!" attitude.
 
Never figured I'd have to actually catch them, I've always just checked the return value of whatever function I'm using, to check for errors.

You don't have to catch them. As you saw with your program the runtime provides an outer handler that catches anything you don't... but that brings the program down.

This isn't the place for a tutorial, but it's worth reading up on exceptions. Once you understand how they work you'll be writing cleaner code that behaves more consistently, and you'll be free of concerns such as how to fit error results into the return from every function/method.
 
Back
Top