I need to use a native sql query in Hibernate with use of variable.
But hibernate throws an error saying: Space is not allowed after parameter prefix
So there is a conflict with the := mysql variable assignment and hibernate variable assignment.
Here is my sql query:
SET #rank:=0;
UPDATE Rank SET rank_Level=#rank:=#rank+1 ORDER BY Level;
the hibernate code (jpa syntax):
Query query = em.createNativeQuery(theQuery);
query.executeUpdate();
I can't use a stored procedure because my sql query is dynamically generated ('Level' can be 'int' or 'force'...)
How can I do this ?
thanks
Well, I finally use stored procedure (yes, what I don't want initially) to create dynamic query (I don't think it was possible).
Here is my code:
The stored procedure:
DELIMITER |
DROP PROCEDURE IF EXISTS UpdateRank |
CREATE PROCEDURE UpdateRank(IN shortcut varchar(30))
BEGIN
SET #rank=0;
SET #query=CONCAT('UPDATE Rank SET ', shortcut, '=#rank:=#rank+1 ORDER BY ', shortcut);
PREPARE q1 FROM #query;
EXECUTE q1;
DEALLOCATE PREPARE q1;
END;
|
DELIMITER ;
The tip is the use of the CONCAT function to dynamically create a query in the stored procedure.
Then, call the procedure in classic hibernate function:
Query q = em.createNativeQuery("CALL updateRank('lvl')");
q.executeUpdate();
I'll copy paste my answer from https://stackoverflow.com/a/25552002/3987202
Another solution for those of us who can't make the jump to Hibernate 4.1.3.
Simply use /*'*/:=/*'*/ inside the query. Hibernate code treats everything between ' as a string (ignores it). MySQL on the other hand will ignore everything inside a blockquote and will evaluate the whole expression to an assignement operator.
I know it's quick and dirty, but it get's the job done without stored procedures, interceptors etc.
Use MySQL Proxy to rewrite the query after Hibernate has sent the query to the database.
For example supply Hibernate with this,
UPDATE Rank SET rank_Level=incr(#rank) ORDER BY Level;
but rewrite it to this,
UPDATE Rank SET rank_Level=#rank:=#rank+1 ORDER BY Level;
Related
hi friends i googled for this and find different methods use by others to prevent sql injection. i wrote in below stored procedure before finalising to follow specific method i want suggestion from you guys. which method should i follow.
below is the example of my stored procedure, in which i wrote different methods
CREATE DEFINER=`root`#`localhost` PROCEDURE `spTestSQLInjection`(pSelfId VARCHAR(100),bIntSelfId BIGINT(20))
BEGIN
SET #sSelfId = pSelfId;
-- Method:1
-- below code is for injection
SET #selectQuery = CONCAT('select * from userProfile where userId = ',#sSelfId);
PREPARE stmt FROM #selectQuery;
EXECUTE stmt ;
DEALLOCATE PREPARE stmt;
-- Method:2
-- injection doesent affect below code
select * from userProfile where userId = #sSelfId;
-- Method:3
select * from userProfile where userId = bIntSelfId;
-- Method:4
SET #sSelectQuery=
'select * from userProfile where userId = ? ';
PREPARE stmtQuery FROM #sSelectQuery;
EXECUTE stmtQuery USING #sSelfId;
DEALLOCATE PREPARE stmtQuery;
END
executed below stored procedure in workbench :
1)call spTestSQLInjection('231', 231);
result : when i pass proper data then result set gives single user data for all then 4 method.
2)call spTestSQLInjection('231 OR 1=1', 231);
result : when i pass '231 OR 1=1' data then result set gives all user data for method 1 and single record for method,2,3,4.
so concluded that method1 is prone to sql injection so not to follow this method, as its dynamic query
& its advisable not to write dynamic query in stored procedure.
method2, method3 worked & gave single user record, which means this query are not prone to sql injection.
method4 is adviced by most of the developer to follow this to prevent sql injection in stored procedure. but my
live project contains 20 to 30 queries(insert/update/delete) inside a stored procedure, so writing prepared statement
for all is time consuming.
so guide me to follow which method, method2, method3, or method4
Thanking you in advance, any help will be appreciated.
Methods 2, 3, and 4 are safe from SQL injection, but method 3 is the simplest solution.
CREATE DEFINER=`root`#`localhost` PROCEDURE `spTestSQLInjection`(pSelfId VARCHAR(100), bIntSelfId BIGINT(20))
BEGIN
-- Method:3
select * from userProfile where userId = bIntSelfId;
END
There's no need to create a user-defined variable, because the procedure parameter bIntSelfId is already a variable.
There's no need to use a parameter or a prepared statement in this case, because the variable is treated only as a scalar value. It doesn't need to modify any SQL syntax, nor is it used as an identifier, so it can simply be used in the query as shown above.
This assumes your table does not have its own column with the same name of bIntSelfId. If it did, the use of that identifier would be ambiguous. It's recommended to name your parameters distinctly from any of the columns of tables you will query using that variable. Using a user-defined variable or a query parameter would also avoid the ambiguity.
I want write procedure which after execute another procedure change auto increment value in my table. Problem is procedure created ,but not works. When i try to run i have error #1210 - Incorrect arguments to EXECUTE. I find similar problem in link : Set AUTO_INCREMENT value through variable in MySql ,but it's not working for me.
I try change #v_value for v_value (normal variable, not #variable). Also I try use '?' in #v_sql but not working too. I try change 'READS SQL DATA' but no matter. Help what's going wrong.
DELIMITER //
CREATE PROCEDURE check_increment_value()
READS SQL DATA
BEGIN
SET #v_value = (SELECT MAX(id_version)+1 FROM versions);
SET #v_sql = CONCAT('ALTER TABLE `wersje` AUTO_INCREMENT = ',#v_value);
PREPARE st FROM #v_sql;
EXECUTE st USING #v_value;
END
//
Thanks for your help :)
You pass the parameter via string interpolation, not via the prepared statement, so you do not need to specify the using clause:
EXECUTE st;
I already wrote a pretty complex stored procedure, but now i want to bring some dynamics into the procedures using variables. I still call myself a newbiew when it comes to sql programming, so i might be totally on the wrong way with what i'd like to achieve.
I am running the latest MySQL server 8.0.13 on windows (just for local dev).
My current idea for the stored procedure
... uses an input variable
... declares a cursor (using the var)
... create a temp table (using the var)
... iterates through the temp table
... write data to a new table
I think i understand some of the basic tools to do that but i fail again and again with handling the variable(s)
The following code shows the top part of the project where i already fail.
PROCEDURE sprProcedure (
IN vInputParameter varchar(64)
)
BEGIN
DECLARE vFinished INTEGER DEFAULT 0;
-- declare cursor
DECLARE cCursor CURSOR FOR SELECT * FROM tbltmp_(vInputParameter);
DECLARE CONTINUE HANDLER
FOR NOT FOUND SET vFinished = 1;
-- drop / create temp table
DROP TABLE IF EXISTS (vInputParameter);
CREATE TEMPORARY TABLE tbltmp_(vInputParameter)
SELECT * FROM `tbl_DataSource`;
... did not paste any further code as i can't deal with the following issue.
I tried
... using the variable directly > variable is not resolved in DECLARE CURSOR statement
... define user-defined variable before local-variables is not allowed
... CONCAT'ed the string to build a statement and EXECUTE'ed it > does not work in the DECLAREpart of the stored procedure
At this point i am totally open to every hint or totally new ideas about how to approach this.
Thanks for any advice!
[Update]
My approach up there has some flaws and i did not understand the basic concept of temp tables for example being unique to the session. Thanks to 'D's Query' and a little more reading i now have a working stored procedure without having to deal with dynamic names of cursors and temp tables.
I dont know what actually you are focusing on but loading a dynamic tables can be possible with prepared statements in Stored Procedures but prepared statements won't work with CURSORS.
Example of Prepared statement is
SET $sql=CONCAT('SELECT * from ', var_tablename);
PREPARE stmt FROM #sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
Lets say that I want to write a procedure allowing me to call certain function on certain column, for example:
call foo('min','age') -> SELECT min(age) FROM table;
I want my procedure to be safe from sql injection, therefore, I'm willing to use prepared statements and parametrize the input
SET #var = "SELECT ?(?) FROM table;"
PREPARE x FROM #var;
EXECUTE x USING a, b;
Where a and b are input parameters, function and column, respectively.
However, it doesnt seem to be possible - InnoDB keeps throwing an error whenever I want to execute this statement.
Is it possible to solve this this way, or I need to resort to whitelisting?
EDIT:
Full code:
create procedure test(in func varchar(20), in col varchar(20))
begin
set #f = func;
set #c = col;
set #sql = "select ?(?) from table;";
prepare x from #sql;
execute x using #f, #c;
end;
calling:
call test('min','age');
Full error:
[42000][1064] You have an error in your SQL syntax; check the manual
that corresponds to your MySQL server version for the right syntax to
use near '(?) from table' at line 1
You cannot parametrize column/table/function name/alias. As, PREPARE statement only allow "values" part of the SQL query to be used as parameters. Function/Table/Column name/alias are used to determine the validity of the SQL statement; and thus cannot be changed during run-time execution. Changing it at execution time would potentially alter whether the SQL statement was valid.
You can think of it as compiling a code; hence the compiler must know all the function/class name(s) etc for creating a valid executable (yes, we can do dynamic classes, but that is rare). On the other hand, we can change input "values" to the program, but generally cannot change the operations to be done on the input data.
Also, MySQL server would consider the parameters as literals, and apply quotes around them, before using them in query execution.
Now, in your case, you can still use the function name as parameter for Stored procedure, and generate the query string using that. But you cannot use it as a parameter for the query itself.
delimiter $$
create procedure test(in func varchar(20), in col varchar(20))
begin
set #c = col;
-- use concat function to generate the query string using func parameter
set #sql = concat('select ', func, '(?) from table');
-- prepare the statement
prepare stmt from #sql;
-- execute
execute x using #c;
-- don't forget to deallocate the prepared statement
deallocate prepare stmt;
end$$
delimiter ;
I came across this while writing a mySQL query builder plugin. My solution was to prefix column and function names with a "?" character (the user can change the character in the plugin preferences).
The code that builds the prepared statement looks for values that begin with "?" and inserts the subsequent column/function name into the query inline instead of as prepared statement values.
I've got a procedure that uses a loop with a SELECT statement, but the statement is actually just to set a variable. That means there's a lot of stuff being displayed that I don't need to see, and it's flooding my terminal.
Here's an example of what I mean, though this isn't actually what I'm running (because that's company information):
DROP PROCEDURE IF EXISTS test;
DELIMITER #
CREATE PROCEDURE test()
BEGIN
SET #key:=1;
testloop: REPEAT
SELECT
#dummyString := stringField
FROM
aTable;
SET #dummyStringAll :=CONCAT(#dummyStringAll,$dummyString);
SET #key := #key + 1;
UNTIL #key>10
END REPEAT testloop;
END #
DELIMITER ;
Is it possible to run SELECT (whether inside a procedure or not) and not show the results from a SELECT query? Maybe not the most important thing in the world, but it would be helpful.
Stored procedures will return a query resultset if it isn't stored in a variable.
How does it know that you are storing the result in a variable?
Not be using variables in the query but by using the SELECT value INTO <variable> syntax in the query. see: 13.2.9.1 SELECT ... INTO Syntax
From the FAQ:
1) Can MySQL 5.6 stored routines return result sets?
Stored procedures can, but stored functions cannot. If you perform an ordinary SELECT inside a stored procedure, the result set is returned directly to the client.
So, using the 'SELECT ... INTO ...' syntax will prevent the procedure returning the resultset from a query.