0

I'm creating a stored procedure for MySQL in a C# app. The stored procedure contains some dynamically created SQL used to drop an index if it exists, then [re]create it. The SQL code works fine in MySQL Workbench, but when I run it from my C# app, I'm getting a MySQL Exception.

Here's the stored procedure code (as it is used in C#, there are no "@" symbols before identifiers as C# puts them in itself, as I understand it):

CREATE PROCEDURE recreate_index_sp(IN theTable varchar(128), IN theIndexName varchar(128), IN theIndexColumns varchar(128)) 
BEGIN 
    IF ((SELECT COUNT(*) AS index_exists FROM information_schema.statistics WHERE TABLE_SCHEMA = DATABASE() and table_name = theTable AND index_name = theIndexName) > 0) THEN 
        SET s = CONCAT( 'DROP INDEX ', theIndexName, ' ON ', theTable );
        PREPARE stmt FROM s;
        EXECUTE stmt;
        DEALLOCATE PREPARE stmt;
    END IF;
    SET s = CONCAT('CREATE INDEX ' , theIndexName , ' ON ' , theTable, '(', theIndexColumns, ')');
    PREPARE stmt FROM s;
    EXECUTE stmt;
    DEALLOCATE PREPARE stmt;
END;

The exception I'm getting is: MySql.Data.MySqlClient.MySqlException: Unknown system variable 's'.

If I therefore define s at the start of the stored procedure - DECLARE s varchar(255) - I instead get the error 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 's;EXECUTE stmt;DEALLOCATE PREPARE stmt;END' at line 1. But the code I use in MySQL Workbench doesn't need to define the variable, so I don't know why it's insisting on it here.

If I use @s as the variable name instead (including defining it!), the exception says Parameter '@s' must be defined.

Any ideas how I can get this to work?

For info, here is the code I use in MySQL Workbench that creates the procedure quite happily:

CREATE PROCEDURE recreate_index_sp(IN theTable varchar(128), IN theIndexName varchar(128), IN theIndexColumns varchar(128))
BEGIN
    IF ((SELECT COUNT(*) AS index_exists FROM information_schema.statistics WHERE TABLE_SCHEMA = DATABASE() and table_name = @theTable AND index_name = @theIndexName) > 0) THEN
        SET @s = CONCAT( 'DROP INDEX ', @theIndexName, ' ON ', @theTable );
        PREPARE stmt FROM @s;
        EXECUTE stmt;
        DEALLOCATE PREPARE stmt;
    END IF;
    SET @s = CONCAT('CREATE INDEX ', @theIndexName, ' ON ', @theTable, '(', @theIndexColumns, ')');
    PREPARE stmt FROM @s;
    EXECUTE stmt;
    DEALLOCATE PREPARE stmt;
END

EDIT: Thanks to Reubz, I got the code working. Two parts were needed: (1) The connection string needed "Allow User Variables=True;" including, and (2) the @ symbol was required (and the variable did not need declaring).

So here's the working code:

CREATE PROCEDURE recreate_index_sp(IN theTable varchar(128), IN theIndexName varchar(128), IN theIndexColumns varchar(128)) 
BEGIN 
    IF ((SELECT COUNT(*) AS index_exists FROM information_schema.statistics WHERE TABLE_SCHEMA = DATABASE() and table_name = theTable AND index_name = theIndexName) > 0) THEN 
        SET @sqlPrep = CONCAT( 'DROP INDEX ', theIndexName, ' ON ', theTable );
        PREPARE stmt FROM @sqlPrep;
        EXECUTE stmt;
        DEALLOCATE PREPARE stmt;
    END IF;
    SET @sqlPrep = CONCAT('CREATE INDEX ' , theIndexName , ' ON ' , theTable, '(', theIndexColumns, ')');
    PREPARE stmt FROM @sqlPrep;
    EXECUTE stmt;
    DEALLOCATE PREPARE stmt;
END;
10
  • If it makes any difference, I'm using MySQL Connector Net v6.5.5, MySQL Server v5.1, and coding the C# app in Visual Studio 2012 Pro. Commented Aug 16, 2013 at 10:55
  • How are you creating this stored proc in c#? Can you post the actual code? Commented Aug 16, 2013 at 11:11
  • It's fairly hard to post the code as it's wrapped up in inumerable class objects, but suffice to say: I can create other stored procedures, tables and views using the exact same code, so I don't think it's the C# code itself. But I'll see what I can extract. Commented Aug 16, 2013 at 11:15
  • Ok, just trying to understand how the stored proc is created. are you passing this stored proc as a string? Then you'd need to supply the @ symbol for all your variables, not just the s variable. Commented Aug 16, 2013 at 11:17
  • Ok, it's using Reflection to load the MySql .NET dll; the command is executed using a MySql.Data.MySqlClient.MySqlCommand object, calling ExecuteNonQuery(). Works for all other stored procedures I'm creating, just not this one. Commented Aug 16, 2013 at 11:17

1 Answer 1

1

As per our chat:

you have to use the @ symbol for your user defined variable s, in order to differentiate it from a system variable. However, user defined variables are disabled by default in newer versions of the MySQL connector. To enable it, you need to make a change to your connection string and add the User Variables=True parameter.

Sign up to request clarification or add additional context in comments.

1 Comment

Thanks again. I'll post the full working query code in my question for future reference.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.