Mysql plugin issue
#1

Hello,

I just switched from StrickenKid's to G-sTyLeZzZ's mysql plugin. After changing all
the function calls I was able to compile all my filterscripts and my gamemode successfully.
But when trying to start the Server it simply crashes with a segmentation fault.
I was able to figure out that the segmentation fault somehow occurs at the following
"code structure". This worked perfectly well with StrickenKid's plugin.

Код:
public OnFilterScriptInit(){
	new tmp[16];

	mysql = mysql_connect(SQL_HOST, SQL_USER, SQL_DB, SQL_PASS);

	QueryString = "SELECT * FROM `cars` WHERE `cardlship` > 0"; 

	mysql_query(QueryString, -1, 0, mysql);
	mysql_store_result(mysql);

	while(mysql_retrieve_row(mysql)) {
		mysql_fetch_field_row(tmp, "id", mysql);
		CarVars[Iterator][id] = strval(tmp);
		mysql_fetch_field_row(tmp, "type", mysql);
		CarVars[Iterator][type] = strval(tmp);
		AHCars[Iterator][type] = strval(tmp);
		mysql_fetch_field_row(tmp, "direction", mysql);
		CarVars[Iterator][angle] = floatstr(tmp);
		mysql_fetch_field_row(tmp, "posx", mysql);
		CarVars[Iterator][posx] = floatstr(tmp);
		mysql_fetch_field_row(tmp, "posy", mysql);
		CarVars[Iterator][posy] = floatstr(tmp);
		mysql_fetch_field_row(tmp, "posz", mysql);
		CarVars[Iterator][posz] = floatstr(tmp);
		mysql_fetch_field_row(tmp, "color1", mysql);
		CarVars[Iterator][color1] = strval(tmp);
		mysql_fetch_field_row(tmp, "color2", mysql);
		CarVars[Iterator][color2] = strval(tmp);
		mysql_fetch_field_row(tmp, "cardlship", mysql);
		CarVars[Iterator][cardlship] = strval(tmp);


		mysql_fetch_field_row(tmp, "price", mysql);
		AHCars[Iterator][price] = strval(tmp);

		if(!CarVars[Iterator][color1]) CarVars[Iterator][color1] = random(15);
		if(!CarVars[Iterator][color2]) CarVars[Iterator][color2] = random(15);

		AHCars[Iterator][carid] = CreateVehicle(
			CarVars[Iterator][type],
			CarVars[Iterator][posx],
			CarVars[Iterator][posy],
			CarVars[Iterator][posz],
			CarVars[Iterator][angle],
			CarVars[Iterator][color1],
			CarVars[Iterator][color2],
			300
		);

		GMtoDBCarID[Iterator][gmid] = AHCars[Iterator][carid];
		GMtoDBCarID[Iterator][dbid] = CarVars[Iterator][id];

		if (!FirstId) {
			FirstId = AHCars[Iterator][carid];
		}
		Iterator++;
	}

	mysql_free_result(mysql);


	return 1;
}
Mysql log:
Код:
[19:27:39] ---------------------------
[19:27:39] MySQL Debugging activated (06/14/11)
[19:27:39] ---------------------------
[19:27:39]  
[19:27:39] >> mysql_query( Connection handle: 1 )
[19:27:39] CMySQLHandler::Query(SELECT * FROM `cars` WHERE `cardlship` > 0) - Successfully executed.
[19:27:39] >> mysql_store_result( Connection handle: 1 )
[19:27:39] CMySQLHandler::StoreResult() - Result was stored.
[19:27:39] >> mysql_retrieve_row( Connection handle: 1 )
[19:27:39] >> mysql_fetch_field_row( Connection handle: 1 )
[19:27:39] CMySQLHandler::FetchField("id") - 3
[19:27:39] >> mysql_fetch_field_row( Connection handle: 1 )
Thanks in advance,
Blowfish
Reply
#2

I played around a little bit and the problem is always the same.
The first call to mysql_fetch_field_row in the loops is executed normally, but
the second call causes the server to crash. What the hell am I doing wrong?

BTW: I edited the first post, because i made a pretty stupid mistake there
Reply
#3

I'm not so sure about the following, but you can try to remove one of the variables and see what happens.
pawn Код:
mysql_fetch_field_row(tmp, "type", mysql);
CarVars[Iterator][type] = strval(tmp); // Either this
AHCars[Iterator][type] = strval(tmp); // Or this
Using sscanf to split the values would be a better solution, you can search the wiki for that.
Reply
#4

Nothing happens when i remove either of those lines.
The server crashes before reaching that point. The call to mysql_fetch_field_row makes the server crash.
But thanks for you help anyway.
Reply
#5

Maybe this will help you. I've always used sscanf and it works perfectly normal.
Reply
#6

I have always tried to avoid that, because some of my tables are quite big and have up to 60 columns and using sscanf for that can get quite confusing. There must be a way I can get this to work. I mean, it worked with StrickenKid's plugin.
Reply
#7

I'm an idiot (del).
Reply
#8

I dont really know why I'm using connetion handles there. I dont use them anywhere else. But removing that doesn't change anything.
Using mysql_get_field instead won't change anything either. It's just a makro to mysql_fetch_field_row:
Код:
#define mysql_get_field(%1,%2) mysql_fetch_field_row(%2,%1)
Reply
#9

I am right now trying to figure out what the function does in depth and where it crashes.
To see that i made some alterations in the source code of the plugin to get more detailled debug messages:

Код:
cell AMX_NATIVE_CALL NativeFunctions::n_mysql_fetch_field_row( AMX* amx, cell* params )
{
	unsigned int cID = params[3]-1;
	MySQL_Log(">> mysql_fetch_field_row( Connection handle: %d )",cID+1);
	VALID_CONNECTION_HANDLE("mysql_fetch_field_row",cID);
	CMySQLHandler *cHandle = SQLHandle[cID];
	string f_Field = AMX_H->GetString(amx,params[2]);
	MySQL_Log(">> got field name: %s ",f_Field.c_str());
	cHandle->FetchField(f_Field);
	MySQL_Log(">> fetched field");
	AMX_H->SetString(amx,params[1],cHandle->m_szResult);
	MySQL_Log(">> returned result");
	cHandle->m_szResult.clear();
	return 1;
}
After putting these additional debug messages into the plugin the mysql log looks as follows:

Код:
[20:07:04] ---------------------------
[20:07:04] MySQL Debugging activated (06/14/11)
[20:07:04] ---------------------------
[20:07:04]  
[20:07:04] >> mysql_query( Connection handle: 1 )
[20:07:04] CMySQLHandler::Query(SELECT * FROM `cars` WHERE `cardlship` > 0) - Successfully executed.
[20:07:04] >> mysql_store_result( Connection handle: 1 )
[20:07:04] CMySQLHandler::StoreResult() - Result was stored.
[20:07:04] >> mysql_retrieve_row( Connection handle: 1 )
[20:07:04] >> mysql_fetch_field_row( Connection handle: 1 )
[20:07:04] >> got field name: id 
[20:07:04] CMySQLHandler::FetchField("id") - 3
[20:07:04] >> fetched field
[20:07:04] >> returned result
[20:07:04] >> mysql_fetch_field_row( Connection handle: 1 )
[20:07:04] >> got field name: type
So it's pretty obvious that something wrong happens in cHandle->FetchField.
I also put some additional debug messages into that function:
Код:
bool CMySQLHandler::FetchField(string column)
{
	if(!m_bIsConnected) {
		NativeFunctions::MySQL_Log("CMySQLHandler::FetchField(%s) - You cannot call this function now. (Reason: Connection is dead)",column.c_str());
		return 0;
	}
	if(m_stField == NULL || m_stRow == NULL) {
		NativeFunctions::MySQL_Log("CMySQLHandler::FetchField(%s) - You cannot call this function now. (Reason: Fields/Rows are empty.)",column.c_str());
		return 0;
	}
	NativeFunctions::MySQL_Log("CMySQLHandler::FetchField(%s) Everything is cool and froody", column.c_str());
	for(string::size_type i = 0;i < m_dwFields;i++) {
		if(column.compare(m_stField[i].name) == 0) {
			m_cSStream << (m_stRow[i] ? m_stRow[i] : "NULL");
			break;
		}
	}
	NativeFunctions::MySQL_Log("CMySQLHandler::FetchField(%s) Everything is still cool and froody", column.c_str());
	getline(m_cSStream,m_szResult);
	NativeFunctions::MySQL_Log("CMySQLHandler::FetchField(%s) Still nothing is fucked up", column.c_str());
	m_cSStream >> m_szResult;
	NativeFunctions::MySQL_Log("CMySQLHandler::FetchField(\"%s\") - %s",column.c_str(),m_szResult.c_str());
	m_cSStream.clear();
	return 1;
}
And after doing that the mysql log looks like this:
Код:
[20:07:04] ---------------------------
[20:07:04] MySQL Debugging activated (06/14/11)
[20:07:04] ---------------------------
[20:07:04]  
[20:07:04] >> mysql_query( Connection handle: 1 )
[20:07:04] CMySQLHandler::Query(SELECT * FROM `cars` WHERE `cardlship` > 0) - Successfully executed.
[20:07:04] >> mysql_store_result( Connection handle: 1 )
[20:07:04] CMySQLHandler::StoreResult() - Result was stored.
[20:07:04] >> mysql_retrieve_row( Connection handle: 1 )
[20:07:04] >> mysql_fetch_field_row( Connection handle: 1 )
[20:07:04] >> got field name: id 
[20:07:04] CMySQLHandler::FetchField(id) Everything is cool and froody
[20:07:04] CMySQLHandler::FetchField(id) Everything is still cool and froody
[20:07:04] CMySQLHandler::FetchField(id) Still nothing is fucked up
[20:07:04] CMySQLHandler::FetchField("id") - 3
[20:07:04] >> fetched field
[20:07:04] >> returned result
[20:07:04] >> mysql_fetch_field_row( Connection handle: 1 )
[20:07:04] >> got field name: type 
[20:07:04] CMySQLHandler::FetchField(type) Everything is cool and froody
So something seems to go wrong in this piece of code, which I am now trying to understand:
Код:
	for(string::size_type i = 0;i < m_dwFields;i++) {
		if(column.compare(m_stField[i].name) == 0) {
			m_cSStream << (m_stRow[i] ? m_stRow[i] : "NULL");
			break;
		}
	}
Reply
#10

After playing this game for a while (I won't bore you with the details) I figured out the actual problem.
The pointer to the first element of the "array" m_stField is dereferenceable. The second one is a
NULL Pointer and trying to dereference the third one causes the server to crash (normal behavior
when trying to dereference an invalid pointer). But the function mysql_num_fields returns 27 in my case.

So the reason for that is:
mysql_fetch_fields does not really return an array of pointers to all the MYSQL_FIELD structures, as
it is said in the documentation, but only to a single element. I hope that my conclusion is wrong,
because that would mean the bug is neither in my script, nor in G-sTyLeZzZ's MySQL plugin
but in the MySQL API itself.

Please prove me wrong
Reply


Forum Jump:


Users browsing this thread: 1 Guest(s)