Ошибка при использовании подготовленных операторов PDO и LIMIT в запросе

Я использую PDO в своем приложении. Но у меня проблема, когда я работаю с подготовленными операторами в запросе, содержащем LIMIT . В чем проблема?
коды:

 $start = 0; $rows = 20; $sql = "SELECT * FROM tbl_news ORDER BY date DESC LIMIT ?, ?"; $q = $db->prepare($sql); $q->execute(array($start , $rows)); 

Ошибка:

проверьте руководство, соответствующее версии вашего сервера MySQL, для правильного синтаксиса для использования рядом с '' 0 ',' 20 ''

Что касается размещения ключевого слова LIMIT в MySQL с подготовленным оператором , приведенный ниже код может решить мою проблему.

 $db->setAttribute(PDO::ATTR_EMULATE_PREPARES, FALSE); 

Спасибо Álvaro G. Vicario и Maerlyn

Это известная ошибка, которая была зафиксирована в памяти 5.5.6.

Из статьи: LIMIT не допускает переменные в любом контексте. Его аргументы должны быть целыми константами.

Дальнейшее редактирование: (Существует спор по этому вопросу) Пользовательские переменные принимают аргументы предложения LIMIT в подготовленных операторах, а синтаксис SQL для подготовленных операторов может использоваться в хранимых процедурах.

Третье редактирование: эта ссылка объясняет, что они должны работать с подготовленными операторами.

Вы можете сделать так:

 $sql = SELECT * FROM tbl_news ORDER BY date DESC LIMIT :start, :rows"; $q = $db->prepare($sql); $q->bindParam(':start', $start, PDO::PARAM_INT); $q->bindParam(':rows',$rows, PDO::PARAM_INT); 

Я просто наткнулся на ту же проблему. Для меня, используя мой собственный класс операторов (расширение PDOStatement ) с помощью собственного метода execute() он исправил его.

Это класс:

 class MyPDOStatement extends PDOStatement { public function execute($input_parameters = null) { if (is_array($input_parameters)) { $i = 1; foreach ($input_parameters as $p) { // default to string datatype $parameterType = PDO::PARAM_STR; // now let's see if there is something more appropriate if (is_bool($p)) { $parameterType = PDO::PARAM_BOOL; } elseif (is_null($p)) { $parameterType = PDO::PARAM_NULL; } elseif (is_int($p)) { $parameterType = PDO::PARAM_INT; } // parameters passed to execute() are input-only parameters, so use // bindValue() $this->bindValue($i, $p, $parameterType); $i++; } } return parent::execute(); } } 

Чтобы сообщить PDO использовать этот класс операторов вместо стандартного, сделайте следующее:

 $db = new PDO(...); $db->setAttribute(PDO::ATTR_STATEMENT_CLASS, array('MyPDOStatement')); 

Теперь код в вопросе будет работать:

 $start = 0; $rows = 20; $sql = "SELECT * FROM tbl_news ORDER BY date DESC LIMIT ?, ?"; $q = $db->prepare($sql); $q->execute(array($start , $rows)); 

Единственное, что вам нужно сделать shure, это то, что переменные, связанные с оператором, имеют правильный тип integer. Если у вас есть числовая строка, например, из массива $_GET , вы можете сделать что-то вроде этого:

 if (isset($_GET['start']) && is_numeric($_GET['start']) && is_int($_GET['start'] + 0) { $start = (int) $_GET['start']; } 

Я не уверен, если есть более простой способ для последнего, но, по крайней мере, это отлично работает для меня.

 $sql = "SELECT * FROM tbl_news ORDER BY `date` DESC LIMIT ?, ?"; 

date – это зарезервированное слово, которое вы должны обернуть с помощью back-ticks