Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

MySQL: Support multiple result sets in prepared queries #825

Conversation

@peace-maker
Copy link
Contributor

peace-maker commented Jun 5, 2018

Prepared statements can return multiple result sets in MySQL 5.5. That can happen when calling stored procedures using CALL x();.

This change removes the previous caching of result bindings, since the number of fields in a result can differ from result set to result set. This could potentially have a negative impact on performance of prepared statements always only returning one result set, since the result binding buffers are recreated everytime the statement is executed instead of once. That difference should be negligible though.

Fixes #823.

Usage is just like with normal queries:

// From https://dev.mysql.com/doc/refman/5.5/en/c-api-prepared-call-statements.html
public void OnPluginStart()
{
	char error[255];
	Database db = SQL_DefConnect(error, sizeof(error));
	if (db == null){
		PrintToServer("Could not connect: %s", error);
		return;
	}

	/*
	CREATE PROCEDURE p1(
	  IN p_in INT,
	  OUT p_out INT,
	  INOUT p_inout INT)
	BEGIN
	  SELECT p_in, p_out, p_inout;
	  SET p_in = 100, p_out = 200, p_inout = 300;
	  SELECT p_in, p_out, p_inout;
	END
	*/

	DBStatement hStmt = SQL_PrepareQuery(db, "CALL p1(?, ?, ?)", error, sizeof(error));
	if (!hStmt){
		PrintToServer(error);
		delete db;
		return;
	}
	
	/* assign values to parameters and execute statement */
	hStmt.BindInt(0, 10); /* p_in */
	hStmt.BindInt(1, 20); /* p_out */
	hStmt.BindInt(2, 30); /* p_inout */

	if (!SQL_Execute(hStmt)){
		SQL_GetError(hStmt, error, sizeof(error));
		PrintToServer(error);
		delete hStmt;
		delete db;
		return;
	}
	
	do 
	{
		int rows = SQL_GetRowCount(hStmt); 
		PrintToServer("Num rows: %d", rows);

		int num_fields = SQL_GetFieldCount(hStmt);
		while (SQL_FetchRow(hStmt))
		{
			for (int i = 0; i < num_fields; i++)
			{
				if (SQL_IsFieldNull(hStmt, i))
					PrintToServer("val[%d] = NULL", i);
				else
					PrintToServer("val[%d] = %d", i, SQL_FetchInt(hStmt, i));
			}
		}
	}
	while (SQL_FetchMoreResults(hStmt));

	delete hStmt;
	delete db;
}

Output:

Num rows: 1
val[0] = 10
val[1] = NULL
val[2] = 30
Num rows: 1
val[0] = 100
val[1] = 200
val[2] = 300
Num rows: 1
val[0] = 200
val[1] = 300
Prepared statements can return multiple result sets since MySQL 5.5. That can happen when calling stored procedures using `CALL x();`.

This change removes the previous caching of result bindings, since the number of fields in a result can differ from result set to result set. This could potentially have a negative impact on prepared statements always only returning one result set, since the result binding buffers are recreated everytime the statement is executed instead of once. That difference should be negligible.

Fixes #823.
Copy link
Member

asherkin left a comment

image

@asherkin asherkin merged commit 6fcb411 into alliedmodders:master Jun 5, 2018
2 checks passed
2 checks passed
continuous-integration/appveyor/pr AppVeyor build succeeded
Details
continuous-integration/travis-ci/pr The Travis CI build passed
Details
@peace-maker peace-maker deleted the peace-maker:mysql_prepared_statements_multi_result branch Jun 5, 2018
@Codes97

This comment has been minimized.

Copy link

Codes97 commented on extensions/mysql/mysql/MyStatement.cpp in df61a6d Jun 5, 2018

Great Job! Thanks you

@Codes97

This comment has been minimized.

Copy link

Codes97 commented Jun 5, 2018

@asherkin When will we be able to use this? (since which version of sourcemod)

@asherkin

This comment has been minimized.

Copy link
Member

asherkin commented Jun 5, 2018

@Codes97 1.10 build 6287

@Codes97

This comment has been minimized.

Copy link

Codes97 commented Jun 5, 2018

@asherkin Sorry I still bothering, but which stable build would it be? And how's the process? how many dev builds do you do to make a stable one?It depends on changes? testing?

@Bara

This comment has been minimized.

Copy link
Contributor

Bara commented Jun 5, 2018

1.10 isn't the current dev-Version ( that's 1.9 ). So it could take some months. If you want that build you can download it here but only available for windows.

@Codes97

This comment has been minimized.

Copy link

Codes97 commented Jun 5, 2018

Thanks Bara, but I need it for linux, no problem, I'll wait

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
4 participants
You can’t perform that action at this time.