I am running a query in MySQL 5.6.11. I have created a following stored procedure
DELIMITER $$
CREATE DEFINER=`root`#`localhost` PROCEDURE `digital_audio_test_detail`(IN temp VARCHAR(50), IN temp2 VARCHAR(50))
BEGIN
SET #temp_query = CONCAT('SELECT * FROM ',temp);
SET #final_query = CONCAT(#temp_query,'WHERE', temp,'.unit_test_result_id =',temp2);
PREPARE stmt FROM #final_query;
EXECUTE stmt;
END
When I call this procedure in my query page, I get syntax error at its CALL. This is how I execute my queries.
SELECT unit_test_result.*, #temp1 := unit_test.name, #temp2 := unit_test_result.id
FROM unit_test_result, unit_test
WHERE unit_test_result.test_run_id = 2
AND unit_test.id = unit_test_result.unit_test_id;
CALL digital_audio_test_detail(#temp1, #temp2);
I have to pass two parameters to the procedure. When I create a procedure with only first parameter and CALL it one parameter, it executes fine. But When I do with two parameters I get syntax error. Need help. Thanks
SET #final_query = CONCAT(#temp_query,'WHERE', temp,'.unit_test_result_id =',temp2);
The string you are building is not a valid query.
Add space before and after WHERE, as in
SET #final_query = CONCAT(#temp_query,' WHERE ', temp,'.unit_test_result_id =',temp2);
Related
Consider the following stored procedure and its usage:
DROP PROCEDURE IF EXISTS ShowMIHoles;
DELIMITER $$
CREATE PROCEDURE ShowMIHoles(IN CourseID VARCHAR(255))
BEGIN
select * from tblcourses where id=CourseID;
END $$
DELIMITER ;
call ShowMIHoles(1299)
That works, and returns the row of table tblcourses with id 1299.
However, it isn't protected from SQL injection.
So, I read that quote() should be used to make a value safe.
This is my attempt to use quote:
DROP PROCEDURE IF EXISTS ShowMIHoles;
DELIMITER $$
CREATE PROCEDURE ShowMIHoles(IN CourseID VARCHAR(255))
BEGIN
select * from tblcourses where id=quote(CourseID);
END $$
DELIMITER ;
call ShowMIHoles(1299)
That results in "0 rows returned". No error message. MySQL 5.7.28.
I tried various tests to see what was going wrong. The ones that don't use CourseID parameter, I tested both inside procedure, and as a stand-alone query.
select quote(1299);
=> '1299'
select * from tblcourses where id='1299';
=> The expected row with id 1299.
select * from tblcourses where id=quote(1299);
=> 0 rows returned.
It is possible to make this work, via prepared statement:
...
BEGIN
SET #sql = CONCAT('select * from tblcourses where id=', quote(CourseID));
prepare stmt from #sql;
execute stmt;
END $$
...
=> The expected row with id 1299.
Question:
Is there any way to safely use this parameter as an expression value in the where clause, without dynamically preparing a statement?
You do not need to worry about SQL injection inside a stored procedure unless you are using dynamic SQL. Strings will always be treated like whole string and numbers as numbers.
So, the first version you are showing is perfectly fine. Just make sure that when you call the procedure, your code is safe.
Am I able to write a stored procedure with a parameter, which is the mysql query and the stored procedure returns the column names of the query?
For example I call the procedure:
call selector('select * from users')
And the procedure returns the column names.
It would be easy with information.schema but if I have a more complicated query and alias in it?
Found a solution
CREATE DEFINER=`admin`#`localhost` PROCEDURE `selector`(
IN `sql_query` VARCHAR(50))
LANGUAGE SQL
NOT DETERMINISTIC
CONTAINS SQL
SQL SECURITY DEFINER
COMMENT ''
BEGiN
drop table if exists tmp111;
SET #sql = concat('create table tmp111 as ', sql_query);
PREPARE stmt FROM #sql;
Execute stmt;
describe tmp111;
END
Then call it like:
call selector('select name as n, email as e from users')
I am trying to create a new SQL procedure and am getting a syntax error. I am not the greatest with SQL so I am sure I have an error in there somewhere. Can someone tell me what is wrong with it? thanks for any help.
create PROCEDURE `p_provider_get_distributors_by_sort`(varOffset INT(11), varSortName varchar(50), varSortDirection varchar(6))
BEGIN
SET #st := concat('(SELECT id FROM distributor WHERE status = "AC") ORDER BY 'varSortName, varSortDirection' LIMIT 100 OFFSET ', varOffset);
PREPARE stmt FROM #st;
EXECUTE stmt;
END //
You missed lot of things in your sp
first of all, You have to add prefix '#' with all your parameters
Secondly, You must have to declare your #st object
I've written a stored procedure function to get a name from a table. The trouble is that I want the table name to be passed in as a parameter (there are several different tables I need to use this function with):
DELIMITER $$
CREATE DEFINER=`root`#`localhost` FUNCTION `getName`(tableName VARCHAR(50), myId INT(11)) RETURNS VARCHAR(50)
begin
DECLARE myName VARCHAR(50);
SELECT
'name' INTO myName
FROM
tableName
WHERE
id=myId;
RETURN myName;
end
This method has an error because it uses the variable name "tableName" instead of the actual value of the variable.
I can work around this problem in a procedure by using a CONCAT like this:
SET #GetName = CONCAT("
SELECT
'name'
FROM
",tableName,"
WHERE
id=",myId,";
");
PREPARE stmt FROM #GetName;
EXECUTE stmt;
...but, when I try to do this in a function I get a message saying:
Dynamic SQL is not allowed in stored function or trigger
I tried to use a procedure instead, but I couldn't get it to just return a value, like a function does.
So, can anyone see a way to get around this problem. It seems incredibly basic really.
If you want to buld a SQL statement using identifiers, then you need to use prepared statements; but prepared statements cannot be used in functions. So, you can create a stored procedure with OUT parameter -
CREATE PROCEDURE getName
(IN tableName VARCHAR(50), IN myId INT(11), OUT myName VARCHAR(50))
BEGIN
SET #GetName =
CONCAT('SELECT name INTO #var1 FROM ', tableName, ' WHERE id=', myId);
PREPARE stmt FROM #GetName;
EXECUTE stmt;
SET myName = #var1;
END
Using example -
SET #tableName = 'tbl';
SET #myId = 1005;
SET #name = NULL;
CALL getName(#tableName, #myId, #name);
SELECT #name;
I've written a stored procedure. It's working fine except taking the table name as input parameter.
Let see my proc in MySQL:
DELIMITER $$
USE `db_test`$$
DROP PROCEDURE IF EXISTS test_proc$$
CREATE DEFINER=`root`#`localhost`
PROCEDURE `test_proc`(IN serviceName VARCHAR(10),IN newsInfoTable VARCHAR(100))
BEGIN
SELECT COUNT(*) FROM newsInfoTable WHERE newsServiceName=serviceName;
END$$
DELIMITER ;
Stored procedure calling parameters:
USE db_test;
CALL test_proc('abc','tbl_test_news');
Here the service name parameter is working fine. But if I include the newsInfoTable variable as table input parameter then a error shows.
Table 'db_test.newsinfotable' doesn't exist
Why does this happen only for table parameter? How can I retrieve from this error or
How I pass a table name into a stored procedure as a parameter?
An SP cannot be optimized with a dynamic table name, so many DBs, MySQL included, don't allow table names to be specified dynamically.
One way around this is to use Dynamic SQL.
CREATE DEFINER=`root`#`localhost` PROCEDURE `test_proc`(IN serviceName VARCHAR(10),IN newsInfoTable VARCHAR(100))
BEGIN
SET #sql = CONCAT('SELECT COUNT(*) FROM ',newsInfoTable,' WHERE newsServiceName=?;');
PREPARE s1 from #sql;
SET #paramA = serviceName;
EXECUTE s1 USING #paramA;
END$$
You can use EXECUTE IMMEDIATE for a "less is more" solution (for me, less code = good)
CREATE PROCEDURE test_proc(IN serviceName VARCHAR(10), IN newsInfoTable VARCHAR(100))
BEGIN
EXECUTE IMMEDIATE CONCAT('SELECT COUNT(*) FROM ',newsInfoTable,' WHERE newsServiceName=''', serviceName, '''');
END
that part of a query cannot be dynamic.
you may consider implementing as a string that is executed dynamically at runtime
Although may not be what you want, alternatively, can consider to use conditionally if and prepare the statement.
DELIMITER $$
CREATE PROCEDURE select_count(IN table_name VARCHAR(20))
BEGIN
IF table_name = 'xxx' THEN
SELECT * FROM xxx;
ELSEIF table_name = 'yyy' THEN
...
ENDIF
END$$