While pondering a potential solution to another question on SO, I started considering using a prepared statement within a procedure (no dynamic SQL in functions makes me sad). The naive approach of executing a PREPARE in the procedure seems inefficient, as the statement only needs to be prepared the first time the procedure is called during a session. Is it possible in MySQL to prepare a statement only if it doesn’t already exist? Is there a way of checking for the existence of a prepared statement?
Here’s a sample procedure for people to play with. It creates a statement that SELECTs all columns of the given type from the given table.
DROP PROCEDURE IF EXISTS select_columns_of_type_statement;
delimiter //
CREATE PROCEDURE select_columns_of_type_statement(IN db VARCHAR(255), IN tbl VARCHAR(255), IN type VARCHAR(255), OUT result VARCHAR(4095))
READS SQL DATA
NOT DETERMINISTIC -- as tables can be ALTERed
BEGIN
SET @scots_db=db, @scots_tbl=tbl, @scots_type=type;
PREPARE generate_scots FROM "SELECT CONCAT(
'SELECT ',
GROUP_CONCAT(COLUMN_NAME SEPARATOR ', '),
' FROM `', ?, '`.`', ?, '` '
)
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_SCHEMA=? AND TABLE_NAME=? AND data_type=?
INTO @scots_stmt";
EXECUTE generate_scots USING @scots_db, @scots_tbl, @scots_db, @scots_tbl, @scots_type;
SET result = @scots_stmt;
END //
delimiter ;
Example usage:
CALL select_columns_of_type_statement('mysql', 'user', 'int', @stmt);
SELECT @stmt;
-- or even:
SET @stmt=CONCAT(@stmt, 'LIMIT 3');
PREPARE user_int_cols FROM @stmt;
EXECUTE user_int_cols;
That user variables must be used so much also makes me sad.
Checking existence may not be possible, but the try-and-handle-failure pattern will work.
DECLAREan error handler that defines & executes the prepared statement, and execute the prepared statement outside of the handler. If the statement doesn’t exist, the error handler will run. It’s not pretty, but it works.