Bug #59604 Prepared Statements Fail on alter table to drop a foreign key
Submitted: 19 Jan 2011 6:56 Modified: 19 Jan 2011 7:41
Reporter: Michael McLaughlin Email Updates:
Status: Not a Bug Impact on me:
None 
Category:MySQL Server: Prepared statements Severity:S3 (Non-critical)
Version:5.5.8 OS:Any
Assigned to: CPU Architecture:Any
Tags: Prepared Statements with Alter Table Statement

[19 Jan 2011 6:56] Michael McLaughlin
Description:
A prepared statement supports the ALTER TABLE statement according to the MySQL 5.5 Manual, 12.6 SQL Syntax for Prepared Statements, but you can't submit the following syntax as a prepared statement against an InnoDB table:

SET @stmt := 'ALTER TABLE ? DROP FOREIGN KEY ?';

It raises the following error stack:

ERROR 1064 (42000): 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 '? DROP FOREIGN KEY ?' at line 1
ERROR 1243 (HY000): Unknown prepared statement handler (stmt) given to EXECUTE
ERROR 1243 (HY000): Unknown prepared statement handler (stmt) given to DEALLOCATE PREPARE

How to repeat:
Here's a test case script that demonstrates the error:

SET FOREIGN_KEY_CHECKS = 0; 

-- Conditionally drop objects.
SELECT 'GRANDMA' AS "Drop Table GRANDMA";
DROP TABLE IF EXISTS grandma;

-- ------------------------------------------------------------------
-- Create GRANDMA table.
-- ------------------------------------------------------------------
SELECT 'GRANDMA' AS "Create Table GRANDMA";

CREATE TABLE grandma
( grandma_id        INT UNSIGNED PRIMARY KEY AUTO_INCREMENT
, grandma_name      CHAR(20)     NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin1;

-- Conditionally drop objects.
SELECT 'TWEETY' AS "Drop Table TWEETY";
DROP TABLE IF EXISTS tweety;

-- ------------------------------------------------------------------
-- Create TWEETY table.
-- ------------------------------------------------------------------
SELECT 'TWEETY' AS "Create Table TWEETY";

CREATE TABLE tweety
( tweety_id         INT UNSIGNED PRIMARY KEY AUTO_INCREMENT
, grandma_id        INT UNSIGNED
, tweety_name       CHAR(20)     NOT NULL
, KEY tweety_fk1 (grandma_id)
, CONSTRAINT tweety_fk1 FOREIGN KEY (grandma_id)
  REFERENCES grandma (grandma_id)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;

/* Set statement and variables. */
SELECT 'Set query into @sv_constraint session variable';
SET @sql := 'SELECT constraint_name INTO @sv_constraint FROM information_schema.referential_constraints WHERE table_name = ?';
SET @sv_table := 'tweety';

-- Select session variable value.
SELECT @sv_constraint;

/* Prepare, execute, and deallocate prepare. */
PREPARE stmt FROM @sql;
EXECUTE stmt USING @sv_table;
DEALLOCATE PREPARE stmt;
  
/* Set statement and variables. */
SET @sql := 'ALTER TABLE ? DROP FOREIGN KEY ?';
  
/* Prepare, execute, and deallocate prepare. */
PREPARE stmt FROM @sql;
EXECUTE stmt USING @sv_table, @sv_constraint;
DEALLOCATE PREPARE stmt;

-- Alter the table and drop a foreign key.
SELECT 'ALTER TABLE tweety DROP FOREIGN KEY tweety_fk1' AS "Statement";
ALTER TABLE tweety DROP FOREIGN KEY tweety_fk1;

Suggested fix:
Enable prepared statements to run the 'ALTER TABLE t DROP FOREIGN KEY fk' statement or change the documentation.
[19 Jan 2011 7:41] Valeriy Kravchuk
Our manual (http://dev.mysql.com/doc/refman/5.5/en/prepare.html) clearly says:

"Parameter markers can be used only where data values should appear, not for SQL keywords, identifiers, and so forth."

So, you can build entire ALTER TABLE statement as a string in some variable and then create prepared statement from that variable, but you can not use ? instead of table name or constraint name.