Raised This Month: $32 Target: $400
 8% 

Solved Multi-query SQL?


Post New Thread Reply   
 
Thread Tools Display Modes
Author Message
shavit
AlliedModders Donor
Join Date: Dec 2011
Location: Israel
Old 10-29-2017 , 12:55   Multi-query SQL?
Reply With Quote #1

Here's my code:
Code:
char[] sQuery = new char[1024];
FormatEx(sQuery, 1024,
	"DELIMITER ;; " ...
	"DROP PROCEDURE IF EXISTS UpdateAllPoints;; " ...
	"CREATE PROCEDURE UpdateAllPoints() " ...
	"BEGIN " ...
		"DECLARE authid CHAR(32); " ...
		"DECLARE done INT DEFAULT 0; " ...
		"DECLARE cur CURSOR FOR (SELECT auth FROM %splayertimes WHERE points > 0.0 GROUP BY auth); " ...
		"DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = 1; " ...
		"OPEN cur; " ...
		"ranks: LOOP " ...
			"FETCH cur INTO authid; " ...
			"IF done THEN " ...
				"LEAVE ranks; " ...
			"END IF; " ...
			"UPDATE %susers SET points = (SELECT SUM((points * (@f := 0.975 * @f) / 0.975)) FROM %splayertimes " ...
				"JOIN (SELECT @f := 1.0) params WHERE points > 0.0 AND auth = authid ORDER BY points DESC) " ...
				"WHERE auth = authid; " ...
		"END LOOP; " ...
		"CLOSE cur; " ...
	"END;;" ...
	"\nDELIMITER ;", gS_MySQLPrefix, gS_MySQLPrefix, gS_MySQLPrefix);

#if defined DEBUG
LogError("%s", sQuery);
#endif

if(!SQL_FastQuery(gH_SQL, sQuery))
{
	char[] sError = new char[255];
	SQL_GetError(gH_SQL, sError, 255);
	LogError("Timer (rankings, create procedure) error! Reason: %s", sError);
}
This procedure on its own works fine when executed via any MySQL client (mysql CLI or even a GUI like HeidiSQL or phpMyAdmin) but it doesn't seem to execute through a SourceMod plugin.

This is the error log - the first "error" is the query itself, so we can see it's valid, and the error right after it is the actual MySQL error:
Code:
L 10/29/2017 - 18:52:55: [shavit-rankings.smx] DELIMITER ;; DROP PROCEDURE IF EXISTS UpdateAllPoints;; CREATE PROCEDURE UpdateAllPoints() BEGIN DECLARE authid CHAR(32); DECLARE done INT DEFAULT 0; DECLARE cur CURSOR FOR (SELECT auth FROM playertimes WHERE points > 0.0 GROUP BY auth); DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = 1; OPEN cur; ranks: LOOP FETCH cur INTO authid; IF done THEN LEAVE ranks; END IF; UPDATE users SET points = (SELECT SUM((points * (@f := 0.975 * @f) / 0.975)) FROM playertimes JOIN (SELECT @f := 1.0) params WHERE points > 0.0 AND auth = authid ORDER BY points DESC) WHERE auth = authid; END LOOP; CLOSE cur; END;; 
DELIMITER ;
L 10/29/2017 - 18:52:55: [shavit-rankings.smx] Timer (rankings, create procedure) error! Reason: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'DELIMITER ;; DROP PROCEDURE IF EXISTS UpdateAllPoints;; CREATE PROCEDURE UpdateA' at line 1
So after some debugging, it seems like there's a limitation and you can't execute more than one query in the same string.
Is there any workaround against this; or will I have to use multiple queries?

Thanks.
__________________
retired

Last edited by shavit; 10-31-2017 at 13:04.
shavit is offline
8guawong
AlliedModders Donor
Join Date: Dec 2013
Location: BlackMarke7
Old 10-29-2017 , 13:03   Re: Multi-query SQL?
Reply With Quote #2

use transaction

https://sm.alliedmods.net/new-api/dbi/Transaction
__________________

Last edited by 8guawong; 10-29-2017 at 13:04.
8guawong is offline
shavit
AlliedModders Donor
Join Date: Dec 2011
Location: Israel
Old 10-29-2017 , 13:04   Re: Multi-query SQL?
Reply With Quote #3

Quote:
Originally Posted by 8guawong View Post
Transactions are threaded, I'm unable to use threaded queries for my use case.
__________________
retired
shavit is offline
Neuro Toxin
Veteran Member
Join Date: Oct 2013
Location: { closing the void; }
Old 10-29-2017 , 16:55   Re: Multi-query SQL?
Reply With Quote #4

Generally you need to set a procedure owner when you declare. Otherwise users are unable to drop it.
__________________
Neuro Toxin is offline
shavit
AlliedModders Donor
Join Date: Dec 2011
Location: Israel
Old 10-29-2017 , 23:34   Re: Multi-query SQL?
Reply With Quote #5

Quote:
Originally Posted by Neuro Toxin View Post
Generally you need to set a procedure owner when you declare. Otherwise users are unable to drop it.
Are you sure? My plugin seems to drop them just fine and the user it's executed by isn't root; it just has all privileges to the database.



Upon testing, it worked on both MySQL and MariaDB.
__________________
retired
shavit is offline
ESK0
BANNED
Join Date: May 2014
Location: Czech Republic
Old 10-30-2017 , 01:42   Re: Multi-query SQL?
Reply With Quote #6

Quote:
Originally Posted by shavit View Post
Are you sure? My plugin seems to drop them just fine and the user it's executed by isn't root; it just has all privileges to the database.



Upon testing, it worked on both MySQL and MariaDB.
Maybe increase your array size?
ESK0 is offline
shavit
AlliedModders Donor
Join Date: Dec 2011
Location: Israel
Old 10-30-2017 , 01:49   Re: Multi-query SQL?
Reply With Quote #7

Quote:
Originally Posted by ESK0 View Post
Maybe increase your array size?
That's not the issue, I get the same issue even with a 64 characters long query if it runs multiple queries at once.
__________________
retired

Last edited by shavit; 10-30-2017 at 01:50.
shavit is offline
Miu
Veteran Member
Join Date: Nov 2013
Old 10-31-2017 , 07:58   Re: Multi-query SQL?
Reply With Quote #8

You can't execute multiple statements in a single query. Transactions are explicitly the solution to this. You should either create your stored procedures by a different process or use transactions.

Also, I don't think you're unable to use threaded queries. If the main thread must truly not proceed before the stored procedures have been created, you could block it until the transactions complete. However, it's more likely that you just haven't designed the rest of the code to account for threaded queries in this area -- e.g., you have code that assumes the stored procedures already exist.
Miu is offline
asherkin
SourceMod Developer
Join Date: Aug 2009
Location: OnGameFrame()
Old 10-31-2017 , 08:28   Re: Multi-query SQL?
Reply With Quote #9

SourceMod intentionally disables driver support for delimited queries.

Quote:
Originally Posted by shavit View Post
Transactions are threaded, I'm unable to use threaded queries for my use case.
I suggest working out how to, non-threaded SQL is on the (long-tem) deprecation path.
__________________
asherkin is offline
Neuro Toxin
Veteran Member
Join Date: Oct 2013
Location: { closing the void; }
Old 10-31-2017 , 15:20   Re: Multi-query SQL?
Reply With Quote #10

You can chain statements one after the other.

1. Use datapack, dynamic, stringmap to store all data required for all statements in the chain
2. Build and execute next statement with unique callback
3. In the callback goto step 2

Each step in the chain will need a seperate callback and you can parse your data through each callback.
__________________

Last edited by Neuro Toxin; 10-31-2017 at 15:21.
Neuro Toxin is offline
Reply



Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off

Forum Jump


All times are GMT -4. The time now is 18:14.


Powered by vBulletin®
Copyright ©2000 - 2024, vBulletin Solutions, Inc.
Theme made by Freecode