I have a need to sync auto_increment fields between two tables in different databases on the same MySQL server. The hope was to create a stored procedure where the permissions of the admin would let the web user run ALTER TABLE [db1].[table] AUTO_INCREMENT = [num]; without giving it permissions (That just smells of SQL injection).
My problem is I'm receiving errors when creating the store procedure. Is this something that is not allowed by MySQL?
DROP PROCEDURE IF EXISTS sync_auto_increment;
CREATE PROCEDURE set_auto_increment (tableName VARCHAR(64), inc INT)
BEGIN
ALTER TABLE tableName AUTO_INCREMENT = inc;
END;
To extend on the discussion on the comments on Chibu's answer... yes, you can use prepared statements. But you got to use CONCAT to create the sentence instead of using PREPARE ... FROM ....
Here is a working solution:
DROP PROCEDURE IF EXISTS set_auto_increment;
DELIMITER //
CREATE PROCEDURE set_auto_increment (_table VARCHAR(64), _inc INT)
BEGIN
DECLARE _stmt VARCHAR(1024);
SET #SQL := CONCAT('ALTER TABLE ', _table, ' AUTO_INCREMENT = ', _inc);
PREPARE _stmt FROM #SQL;
EXECUTE _stmt;
DEALLOCATE PREPARE _stmt;
END//
DELIMITER;
I've learned this form the article Prepared Statement Failure by Michael McLaughlin.
The problem seems to be that you need to change the delimiter. It thinks that the Alter table line is the end of the function. Try this:
DROP PROCEDURE IF EXISTS sync_auto_increment;
DELIMITER //
CREATE PROCEDURE set_auto_increment (tableName VARCHAR(64), inc INT)
BEGIN
ALTER TABLE tableName AUTO_INCREMENT = inc;
END//
DELIMITER ;
Sometimes mysql is still picky about letting you use stored procedures, so you can do try this if you still can't run it:
DROP PROCEDURE IF EXISTS sync_auto_increment;
DELIMITER //
CREATE PROCEDURE set_auto_increment (tableName VARCHAR(64), inc INT)
DETERMINISTIC
READS SQL DATA
BEGIN
ALTER TABLE tableName AUTO_INCREMENT = inc;
END//
DELIMITER ;
I think you'll find you can't put Data Definition Language statements into a stored procedure. A possible exception would be CREATE TEMPORARY TABLE. I have searched the MySQL manual for more information on that point; it says the stored procedure may contain a statement_list, but nowhere defines what that means. But I think that's the case.
Related
I'm trying to create a store procedure to add a column on a table.
when i use this code(like below),I want to create a column with name like 'newColumn' that I can name when I call procedure. But when I call procedure the column added but not with my name newColumn but with column name x!!
Thank you.
DELIMITER //
CREATE PROCEDURE addColumn(x varchar(20))
BEGIN
alter table proc
add column x varchar(20) not null;
END //
DELIMITER ;
call addColumn('newColumn');
Form the query using concat of the various parts and execute it.
CREATE PROCEDURE addColumn(x varchar(20))
BEGIN
SET #STMT = CONCAT("alter table proc add column ", x, " varchar(20) not null");
PREPARE S FROM #STMT;
EXECUTE S;
DEALLOCATE PREPARE S;
END
But as mentioned in comments, this is dangerous - it can lead to SQL Injection attacks and other problems. At the very least, please sanitize x as much as possible.
I've been trying to dynamically drop tables, procedures, and functions in MySQL. I'm doing this because I am dynamically creating them for a project, when the project version changes I need to clean up and rebuild it.
I can dynamically drop tables, however; I cannot dynamically drop procedures and functions.
Here is an example of the code I am using:
DELIMITER ;;
DROP PROCEDURE IF EXISTS md_remove_project; ;;
CREATE PROCEDURE md_remove_project()
begin
DECLARE TableName text;
DECLARE ProcName text;
DECLARE done int DEFAULT false;
DECLARE statement text;
DECLARE table_cursor CURSOR FOR
SELECT table_name FROM tmp_md_tables;
DECLARE proc_cursor CURSOR FOR
SELECT routine_name FROM tmp_md_procedures;
DECLARE func_cursor CURSOR FOR
SELECT routine_name FROM tmp_md_functions;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = true;
# Drop all the 'md' tables..............................................
# This Works...
DROP TABLE IF EXISTS tmp_md_tables;
CREATE TEMPORARY TABLE tmp_md_tables
SELECT
table_name
FROM
information_schema.tables
WHERE
table_name LIKE 'md_%';
OPEN table_cursor;
table_loop: LOOP
FETCH table_cursor INTO TableName;
IF done THEN
LEAVE table_loop;
END IF;
SET #statement = CONCAT('DROP TABLE IF EXISTS ', TableName, ';');
PREPARE STATEMENT FROM #statement;
EXECUTE STATEMENT;
DEALLOCATE PREPARE STATEMENT;
END LOOP;
CLOSE table_cursor;
DROP TABLE IF EXISTS tmp_md_tables;
#-----------------------------------------------------------------------
# Drop all the 'md' procedures............................................
DROP TABLE IF EXISTS tmp_md_procedures;
CREATE TEMPORARY TABLE tmp_md_procedures
SELECT
routine_name
FROM
information_schema.routines
WHERE
routine_type = 'PROCEDURE'
and
routine_name LIKE 'md_%';
SET done = false;
OPEN proc_cursor;
proc_loop: LOOP
FETCH proc_cursor INTO ProcName;
IF ProcName = 'md_remove_project' THEN
ITERATE proc_loop;
END IF;
IF done THEN
leave proc_loop;
END IF;
SET #statement = CONCAT('DROP PROCEDURE IF EXISTS ', ProcName, ';');
PREPARE STATEMENT FROM #statement;
EXECUTE STATEMENT;
DEALLOCATE PREPARE STATEMENT;
END LOOP;
CLOSE proc_cursor;
DROP TABLE IF EXISTS tmp_md_procedures;
END;
;;
DELIMITER ;
#CALL md_remove_project;
So I create a table with the procedures named md_%, then I loop through the table. For each routine_name, I prepare a statement to drop the procedure. Then I get the following message:
Error Code: 1295. This command is not supported in the prepared statement protocol yet
Are there any other solutions to drop procedures like 'md_%' ???
Thank You.
When using mysqli_... functions, there is no need to attempt to change the delimiter. The change delimiter command is only needed when using the MySQL (command line) Client. The command is, in fact, a MySQL client command (the client never sends it to the server).
The server is smart enough to recognize the CREATE PROCEDURE command and knowns it ends with END;
As a result, you can simply do two queries: first the DROP PROCEDURE IF EXISTS ... followed by the CREATE PROCEDURE ... END; query.
If you must do them in a single call, you could use mysqli::multi_query but I would recommend against it (because of possible serious security implications).
I want to be able to pass arguments to stored procedure, so I searched the net and encountered something like this:
DELIMITER $$
CREATE PROCEDURE addTmpUser
#id varchar(10)
AS
BEGIN
//some sql code
END$$
DELIMITER ;
The problem is that I am getting a syntax error for the # character.
Note: I am using MySQL db.
You are mixing variable types.
#variable is a user variable with a scope for the entire connection.
The variables in stored procedures look different, they don't have the # before them.
Also, you need to declare them. Here is an example
DELIMITER $$
CREATE PROCEDURE addTmpUser(p_id varchar(10))
-- the variable is named p_id as a nameing convention.
-- It is easy for variables to be mixed up with column names otherwise.
BEGIN
DECLARE innerVariable int;
insert into user (id) values (p_id);
-- return all users
select * from user;
END$$
DELIMITER ;
-- and now call it
call addTmpUser(10);
You need to use IN,OUT,INOUT to specify the parameter. So you can try this
DELIMITER $$
CREATE PROCEDURE addTmpUser (IN id VARCHAR(10))
BEGIN
//some sql code
END$$
DELIMITER ;
Look at the documentation
How to Alter a stored procedure in Mysql.
DROP PROCEDURE IF EXISTS sp_Country_UPDATE;
CREATE PROCEDURE sp_Country_UPDATE
( IN p_CountryId int,
IN p_CountryName nvarchar(25),
IN p_CountryDescription nvarchar(25),
IN p_IsActive bit,
IN p_IsDeleted bit )
UPDATE
Country
SET
CountryName = p_CountryName ,
CountryDescription=p_CountryDescription,
IsActive= p_IsActive,
IsDeleted=p_IsDeleted
WHERE
CountryId = p_CountryId ;
How to alter this Stored Procedure?
If you mean you want to edit the Procedure, then you can't according to the MySQL docs:
This statement can be used to change the characteristics of a stored procedure. More than one change may be specified in an ALTER PROCEDURE statement. However, you cannot change the parameters or body of a stored procedure using this statement; to make such changes, you must drop and re-create the procedure using DROP PROCEDURE and CREATE PROCEDURE.
The Alter syntax lets you change the "characteristics" but not the actual procedure itself
http://dev.mysql.com/doc/refman/5.0/en/alter-procedure.html
Here's an example of creating, Altering (the comment) then dropping and recreating:
DROP PROCEDURE myFunc;
DELIMITER //
CREATE PROCEDURE myFunc ()
COMMENT 'test'
BEGIN
SELECT 5;
END //
DELIMITER ;
ALTER PROCEDURE myFunc
COMMENT 'new comment';
CALL myFunc();
DROP PROCEDURE myFunc;
DELIMITER //
CREATE PROCEDURE myFunc ()
COMMENT 'last time'
BEGIN
SELECT 6;
END //
DELIMITER ;
CALL myFunc();
The above CALL myFunc() statments would return 5 and then 6.
Viewing the stored procedure would show a comment of "test", "new comment" or "last time" depending on when you viewed the Procedure body (I'm not sure how to view the comments via the CLI but I can see them in the functions tab in Navicat)
ALTER PROCEDURE proc_name [characteristic ...]
characteristic:
COMMENT 'string'
| LANGUAGE SQL
| { CONTAINS SQL | NO SQL | READS SQL DATA | MODIFIES SQL DATA }
| SQL SECURITY { DEFINER | INVOKER }
This is how you Create
CREATE PROCEDURE GetAllProducts()
BEGIN
SELECT * FROM products;
END //
This is how you Alter
Alter PROCEDURE GetAllProducts()
BEGIN
SELECT * FROM products;
END //
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$$