I am creating a MySQL dump file, that needs to run with multiple databases.
The structure is almost like this :
SET #parent_database = 'db_name';
CREATE OR REPLACE VIEW t_colours AS
SELECT `key_name`, `value`
FROM #parent_database. `colours` as COLOURS WHERE 1;
When I run this query next time, my plan is to only change the variable parent_database.
Is this possible?
Everytime now I run this, I receive an error :
#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 '#parent_database.`colours` as COLOURS WHERE 1' at line 1
Any way to make this happen?
There are many more views to create.
When you execute the queries the mysql thinks of table names as objects and not as string, and hence this would not work as you would expect.
However, there is a way out and you could use something similar to below snippet.
SET #parent_database = 'db_name';
SET #q = CONCAT('CREATE OR REPLACE VIEW t_colours AS SELECT `key_name`,`value` FROM', #parent_database, '.`colours` as COLOURS WHERE 1;');
PREPARE stmt FROM #q;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
Related
I'm racking my head, I can't figure out what the problem is. This SQL code does not work on MySQL 5.7
CREATE PROCEDURE sp_create_message (queue_name VARCHAR(50), data TEXT)
DETERMINISTIC
BEGIN
SET #stm = CONCAT('
INSERT INTO queue_', queue_name, '
(data)
VALUES
(?)
');
PREPARE stm FROM #stm;
EXECUTE stm USING data;
DEALLOCATE PREPARE stm;
END //
#1064 - You have an error in the request. Check the documentation for the MySQL version you are using for the correct syntax about " on line 4
i dont now whats the problem.
Rather than use the value directly from an input parameter,the USING clause in the EXECUTE statement only accept user variables. Try modify the code like this:
set #data=data;
EXECUTE stm USING #data;
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 learned today through this section of the MySQL documentation that prepared statements cannot be performed in stored functions, but, as of MySQL version 5.0.13, they can be performed in stored procedures.
Today I was putting together a stored procedure and thought initially it might be interesting to try doing an INSERT statement in it as a prepared statement. However, despite this supposedly being possible (I'm using MySQL 5.5.14), the ? parameter marker in the statement string caused MySQL to throw a syntax error.
I threw a couple of simplified examples together using the same exact sort of syntax I used for the prepared INSERT statement. I'm hoping I just have a syntax error somewhere I just haven't caught. The first block, below, is the procedure that works, i.e. it uses the standard CONCAT(your query string) syntax.
DROP PROCEDURE IF EXISTS TestConc;
DELIMITER $$
CREATE Procedure TestConc()
BEGIN
SET #sql := CONCAT('CREATE TABLE Foo (FooID INT) ENGINE = InnoDB');
PREPARE stmt FROM #sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
SET #tn := 'Foo';
SET #sql := CONCAT('INSERT INTO ', #tn, ' VALUES (5)');
PREPARE stmt FROM #sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
END;
$$
DELIMITER ;
Upon calling the procedure with this code, the expected happens; 5 is stored in the FooID field of the newly-generated Foo table. However, if we change the lines between the two DEALLOCATE PREPARE directives to this:
SET #tn := 'Foo';
SET #sql := 'INSERT INTO ? VALUES (5)';
PREPARE stmt FROM #sql;
EXECUTE stmt USING #tn;
We get an error that tells us to check the syntax of the statement near '? VALUES (5)'.
Is it just not possible to substitute a parameter marker for a table name? I haven't tried doing something along the lines of 'SELECT ? FROM Foo' to see if this will work yet. Also, and I don't know if it's important, I've been trying this using MySQL Workbench 5.2.35 CE, rather than a command line.
I don't have any specific need to run queries as prepared statements within procedures ATM, I just want to make sure I have the syntax correct for doing so if I ever should need to.
The parameter '?' cannot be used for identifiers. Use first variant. From the reference - Parameter markers can be used only where data values should appear, not for SQL keywords, identifiers, and so forth.
Is it just not possible to substitute a parameter marker for a table name?
No, it's not possible. If you ever think you need this feature, it could be a sign that you have a bad table design.
If you really need to specify the table at runtime, you can use dynamic SQL but be careful not to introduce SQL injection vulnerabilities.
Like EXECUTE IMMEDIATE in Oracle, is there any way to execute code dynamically in a MySQL stored procedure?
I really want to use a prepared statement within a MySQL stored procedure, to generate a new SQL statement in each iteration of a loop.
It actually doesn't work like what I wrote.
I just code like:
set #preparedstmt = concat('SELECT tid, LENGTH(message) len FROM ? where tid=? and first=1');
prepare stmt from prepared_stmt;
execute stmt using v_tid;
drop prepare stmt;
Just take care of the table name,it shouldn't be replaced with the placeholder.So the #preparedstmt should be generated with concat method to make a statement,which is just replaced the parameters in conditions with placeholder,but not the table name.
MariaDB is supporting EXECUTE IMMEDIATE ince 10.2 KB doc is : https://mariadb.com/kb/en/execute-immediate/
DELIMITER $$
CREATE PROCEDURE `Insert1`(IN NAME VARCHAR(100),IN valuees VARCHAR(100))
BEGIN
SET #r = CONCAT('Insert into', NAME,'(name)','VALUES',valuees);
PREPARE smpt FROM #r;
EXECUTE smpt;
DEALLOCATE PREPARE smpt;
END$$
DELIMITER ;
it is successfully compiling...
but when i execute gives me problem...
**CALL Insert1('rishi','duyuu')**
Error Code : 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 'VALUESduyuu' at line 1
There are multiple problems, first see what query has the CONCAT function produced. You will notice that it's not a valid query - 'Insert intorishi(name)VALUESduyuu'. Next, see the documentation on PREPARE/EXECUTE and use a placeholder for the value. The string would need to be put into quotes and escaped if you want to produce a raw query string. So try something like this:
SET #r = CONCAT('INSERT INTO ', NAME, ' (name) VALUES (?)');
SET #v = valuees;
PREPARE smpt FROM #r;
EXECUTE smpt USING #v;
Btw, instead of asking a number of small questions here, maybe you should ask a more high level question, explain what you have tried, what failed, etc. It's easier to help you with high level issues, but if you are doing something the wrong way and ask small technical questions how to fix it so that it works the wrong way, it won't help you much.
Add spaces to the concatenation:
CONCAT('Insert into ', NAME,'(name)',' VALUES ',valuees);