How to identify current database while inside a stored procedure? - mysql

I am trying to write a simple stored procedure which will clear the contents of some tables in the current database - I'm doing this by matching a prefix against the list of tables in the information_schema:
delimiter $$
create procedure local_flush_cache(db varchar(255))
begin
select #str_sql:=concat('delete from ',group_concat(table_name))
from information_schema.tables
where table_schema=db and table_name like 'cache_%';
prepare stmt from #str_sql;
execute stmt;
drop prepare stmt;
end$$
delimiter ;
I would like to be able to remove the db parameter and have the function work on the currently active database.
I guess I will also need the ability to recognise that a database has not yet been selected and output an error (to prevent accidentally flushing all cache tables in all databases).

Considering that the procedure is tied to a database, the current is the called unless you do CALL db.proc().
However, if you really want the selected one, you can the DATABASE() function:
where table_schema=database() and table_name like 'cache_%';

Related

MySQL: Create stored procedures dynamically

I have a database to which several real users have access using JDBC. The separation of these users is very crucial, such that they are neither able see nor manipulate each other's data.
To separate the users' data, I decided to create the few corresponding tables for every user, and only give the owning user the permissions on this table. This is all done automatically in a stored procedure.
Besides this table separation, I want a user only to execute stored procedures to work with his tables, not arbitrary SQL queries.
Let's consider an example procedure like
DELIMITER //
CREATE PROCEDURE MyProcedure(IN p_identifier VARCHAR(30), IN p_key INT(10))
BEGIN
SET #p_identifier = p_identifier;
SET #p_key = p_key;
SET #s = CONCAT('DELETE FROM ', p_identifier, '_mytable WHERE key =?;');
PREPARE stmt FROM #s;
EXECUTE stmt USING #p_key,
DEALLOCATE PREPARE stmt;
END //
DELIMITER ;
And use it like CALL MyProcedure('ad3e981b', 2);.
So far, so good.
Problems arise since this procedure is used by all users (the first paraeter is the table-prefix). This is bad, because once a user gets execution privileges for MyProcedure, he is able to to provide any table-prefix at will and mess with other user's data - so my user separation is gone. This is the problem I need to solve.
I currently see two solutions:
Don’t use stored procedures: Just give INSERT/DELETE/SELECT privileges on the user's table only to the user. This is simple and works - but I'd prefer to only call stored procedures over JDBC, not arbitrary SQL queries.
Make a stored procedure for EVERY user, in which the table prefix is invariant (e.g, table-prefix_MyProcedure(), which is only executable by one user). Then, assign the execution privilege only to the corresponding user. However, this should be done automatically on request - hence, I need to be able to create a stored procedure with a parameterized name to set this up (phew). As the title suggests, this is the way I want to go - but I really struggle with the syntax of dynamically creating a stored procedure (in a stored procedure) and thus, I'm really not sure if this is how I should proceed.
Any ideas how I got approach this problem?
Regards,
raute

Mysql trigger write data to file

There is a way to write data to disk from a trigger into a file? The file name need to be created dynamically.
Using PREPARE will not work on trigger.
e.g.
SET #Query1 =
CONCAT("SELECT ",'data'," INTO DUMPFILE 'c:/temp/", UNIX_TIMESTAMP(),"-",RAND(), ".txt'");
PREPARE statementCreate FROM #Query1;
EXECUTE statementCreate;
DEALLOCATE PREPARE statementCreate;
Note: data is a variable
Or there is other solution to append to the same file from the trigger? Will work that too.
MySQL documentation says:
SQL prepared statements (PREPARE, EXECUTE, DEALLOCATE PREPARE)
can be used in stored procedures, but not stored functions or triggers.
Thus, stored functions and triggers cannot use dynamic SQL
(where you construct statements as strings and then execute them).
So no - you can't write data to file which name is dynamically created from a trigger.
Since you can't use dynamic sql but you also approve single file name and append data to it you can load data to temporary file, append results of the query and then output full results to a file. Of course it will work only if there is no other need to use dynamically created query except file name.
On example:
DELIMITER $$
CREATE TRIGGER rewrite_file AFTER INSERT tableName
BEGIN
CREATE TEMPORARY TABLE IF NOT EXISTS temp(
pk BIGINT
);
LOAD DATA INFILE 'c:/somefile.txt' INTO TABLE temp
LINES TERMINATED BY '\n';
INSERT INTO temp (pk) SELECT primaryKeyField FROM tableName;
SELECT pk INTO OUTFILE 'c:/somefile.txt'
LINES TERMINATED BY '\n'
FROM temp;
END$$
DELIMITER ;
It will append file c:/somefile.txt on every insert. Of course this solution sucks if your file grows to millions of entries.
The solution is: MySQL UDF:http://www.mysqludf.org.
I install sys_exec function and after that from trigger I have something like
SET #ret_val = sys_exec(CONCAT('echo.>d:/temp/',NEW.id, '-', UNIX_TIMESTAMP() , '.txt'));
This will create a empty file for each insert. Tested on windows and linux(CentOS).

MySQL Stored procedure won't fetch the whole table

First I tried this, (MySQL/phpmyadmin)
CREATE DEFINER=`root`#`localhost` PROCEDURE `tempcheck`() NO SQL
BEGIN
SET #query_string = 'SELECT * FROM properties';
PREPARE query_statement FROM #query_string;
EXECUTE query_statement;
DEALLOCATE PREPARE query_statement;
END
This just fetches the first record of the table 'properties'. The table has more than one value. When I sqlquery 'select * from properties;' it returns the whole table.
I even tried this simple method
BEGIN
SELECT * FROM properties';
END
Tried many stackoverflow Q&As. They all suggest that I make a temp table. Even if I do, how will it return the whole table when it doesn't return the entire table here in the first place. CAN a mysql stored procedure actually return a whole table or NOT. if it can, then how?
Guys thank you all for your help. One of my colleagues helped me fix it. Apparently it's a bug in phpmyadmin. phpmyadmin won't return more than one record

Mysql (5.1.41) dynamic SQL in stored procedure issue

I have a stored procedure that populates a temp table. The temp table is populated using multiple dynamic SQL (it has "having" & "between" clause). I am executing this SQL inside my stored procedure using:
set #sql = concat("insert into my_temp select * from my_table where my_date between ", date1, " and ", date2)
PREPARE stmt1 FROM #sql;
EXECUTE stmt1;
DEALLOCATE PREPARE stmt1;
/* more prepared dynamic statements */
The problem is my driver complaints as soon as it encounters the first EXECUTE statement, apparently it thinks MySQL is trying to return a resultset from a stored procedure. Is that how mysql behaves when it comes to dynamic sqls in stored procedures?
I get this error from ruby/rails/mysql2 driver -
Mysql2::Error: PROCEDURE my_db.sp_special_customers can't return a result set in the given context:
Basically the driver does not support returning result-sets from stored procedure, which is fine. And that's not the issue, the issue for me is why does my driver think that EXECUTE stmt1 means a result set is being returned?
Is there a way in Mysql to fix this?
Have a look at: http://dev.mysql.com/doc/refman/5.0/en/stored-program-restrictions.html
Particularly: "Stored routines cannot contain arbitrary SQL statements. The following statements are not permitted: "
They don't allow 'EXECUTE' in the stored procedure. You can however use prepared statements if you're using mysql 5.x. It might be a viable alternative, depending on what you're trying to accomplish

Mysql - Stored procedure not using the query cache

I have just converted a SQL select statement into a stored procedure
The SQL Statement use select statement takes
0.4784s to run the first time and 0.0003s after that
The Stored procedure takes 0.4784s to run every time.
I assume the query cache is not been used
How can I rectify this?
A simplified version of the code
SELECT * FROM Venues WHERE VenueName = :TheVenue
=======
CREATE PROCEDURE GetVenues
(
TheVenue VarChar(22)
)
BEGIN
SELECT * FROM Venues WHERE VenueName = TheVenue
END;
Welcome to MySQL... it is really difficult to get anything within a stored procedure to take advantage of the query cache. The dev article A Practical Look at the MySQL Query Cache discusses this in some detail. The limitations are also mentioned in the reference documentation here and on the MySQL Performance Blog.
Basically, don't depend on caching of queries executed inside of stored procedures. It is near impossible to get it to work though the first reference does claim that it is possible. This usually isn't a problem if you are using stored procedures to encapsulate complicated logic. Most of the problems that I have seen were caused by using stored procedures for very simple queries where a VIEW would have sufficed.
You could try a dynamic SQL stored procedure, like:
CREATE PROCEDURE GetVenues (TheVenue varchar(22))
BEGIN
SET #s = 'SELECT * FROM Venues WHERE VenueName = ?';
SET #v = TheVenue;
PREPARE stmt1 FROM #s;
EXECUTE stmt1 USING #v;
DEALLOCATE PREPARE stmt1;
END;
No MySQL server by hand to test the syntax, so you might have to tweak it.