странность хранимых процедур mysql

#mysql #sql #stored-procedures #prepared-statement

#mysql #sql #хранимые процедуры #подготовленный оператор

Вопрос:

Сегодня из этого раздела документации MySQL я узнал, что подготовленные инструкции не могут быть выполнены в хранимых функциях, но, начиная с версии MySQL 5.0.13, они могут выполняться в хранимых процедурах.

Сегодня я собирал хранимую процедуру и изначально подумал, что было бы интересно попробовать выполнить инструкцию INSERT в ней как подготовленную инструкцию. Однако, несмотря на то, что это предположительно возможно (я использую MySQL 5.5.14), ? маркер параметра в строке инструкции вызвал синтаксическую ошибку MySQL.

Я собрал пару упрощенных примеров, используя тот же синтаксис, который я использовал для подготовленного оператора INSERT . Я надеюсь, что у меня просто где-то есть синтаксическая ошибка, которую я просто не уловил. Первый блок, приведенный ниже, — это процедура, которая работает, то есть она использует стандартный синтаксис CONCAT (вашей строки запроса).

 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 ;
  

При вызове процедуры с этим кодом происходит ожидаемое; 5 сохраняется в поле fooId вновь сгенерированной таблицы Foo. Однако, если мы изменим строки между двумя директивами DEALLOCATE PREPARE для этого:

 SET @tn := 'Foo';
SET @sql := 'INSERT INTO ? VALUES (5)';
PREPARE stmt FROM @sql;
EXECUTE stmt USING @tn;
  

Мы получаем сообщение об ошибке, которое подсказывает нам проверить синтаксис оператора near ‘? ЗНАЧЕНИЯ (5)’.

Неужели просто невозможно заменить имя таблицы маркером параметра? Я не пробовал делать что-то вроде ‘SELECT? ИЗ Foo’, чтобы посмотреть, будет ли это работать. Кроме того, и я не знаю, важно ли это, я пробовал это, используя MySQL Workbench 5.2.35 CE, а не командную строку.

У меня нет какой-либо конкретной необходимости запускать запросы как подготовленные операторы в procedures ATM, я просто хочу убедиться, что у меня есть правильный синтаксис для этого, если мне когда-нибудь понадобится.

Ответ №1:

Параметр ‘?’ не может использоваться для идентификаторов. Используйте первый вариант. Из ссылки — маркеры параметров могут использоваться только там, где должны отображаться значения данных, а не для ключевых слов SQL, идентификаторов и так далее.

Ответ №2:

Неужели просто невозможно заменить имя таблицы маркером параметра?

Нет, это невозможно. Если вы когда-нибудь подумаете, что вам нужна эта функция, это может быть признаком того, что у вас плохой дизайн таблицы.

Если вам действительно нужно указать таблицу во время выполнения, вы можете использовать динамический SQL, но будьте осторожны, чтобы не вводить уязвимости SQL-инъекций.

Комментарии:

1. Интересно… Оператор INSERT не был особенно важен; Я надеялся создать несколько хранимых процедур общего назначения для некоторых общих задач. В частности, я хотел адаптировать что-то вроде функции PersonName на этой странице , чтобы она не была привязана к определенной таблице. Однако я понимаю, почему это было бы плохой идеей.