Проблема с IF в SELECT при xpdo запросе.Через pdoTools
На некотрых запросах использую конструкцию вида:
UPD 12.12.2020
Выяснилось, что эта ошибка возникает от pdoTools.
UPD 13.12.2020
Похоже Василий столкнулся с этой же проблемой когда писал этот блок кода. MODX строку select разбивает в массив колонок по запятым и когда в запросе есть функция с запятыми она также разбивается и по частям попадает на проверку на экранирование и эти части в итоге экранируются.
Решение Василия обходит эту проблемму, но не работает для вложенных функций.
Но если функции SQL вложенные, то у нас несколько вложенных скобочек и preg_replace заменяет не все запятые в функции. И проблемма возвращается.
У меня да и наверно у всех колонка с функцией именнуется ( функция AS имя). Для того, чтобы обойти проблемму с фунциями в решении Василия можно заменить маску регулярки так чтобы она искала не ")" а " AS ":
Стоит ли это решение отправлять в репозиторий pdoTools?
'select'=>[
'MaterialDet'=>'IF(SUM(MaterialDet.status_id)/COUNT(MaterialDet.status_id)<2,1,2) as material_status1',
],
MODX делает экранирование 1:SELECT IF(SUM(MaterialDet.status_id)/ COUNT(MaterialDet.status_id)<2, `1`, 2) AS material_status1
Чудом нашел код в котором это безобразие происходит :-). В файле /core/xpdo/om/mysql/xpdoquery.class.php в строке 57 проверка на экранирование:$escape = !preg_match('/\bAS\b/i', $column) && !preg_match('/\./', $column) && !preg_match('/\(/', $column);
Я нашел выход и добавил проверку на цифры и строку:$escape = !preg_match('/\bAS\b/i', $column) && !preg_match('/\./', $column) && !preg_match('/\(/', $column) && !preg_match('/^\d+[\.,]?\d*$/', trim($column)) && !preg_match('/^\'[^ \']*\'$/', trim($column));
Может кто-нибудь знает лучшее решение? https://github.com/modxcms/revolution/issues/15347UPD 12.12.2020
Выяснилось, что эта ошибка возникает от pdoTools.
if (is_string($fields) && strpos($fields, '(') !== false) {
// Commas in functions
<code>$fields = preg_replace_callback('/\(.*?\)/', function($matches) {
return str_replace(",", "|", $matches[0]);
}, $fields);
$fields = explode(',', $fields);
foreach ($fields as &$field) {
$field = str_replace('|', ',', $field);
}
$this->query->select($fields);
$this->addTime('Added selection of 1 <b>' . $class . '</b>: <small>' . str_replace('`' . $alias . '`.',
'', implode(',', $fields)) . '</small>', microtime(true) - $time);
}
В этом участке кода pdoTools разбивает IF на массив и засовывает его в xpdo запрос. xpdo экранирует эти поля и sql ломается. Вот теперь вопрос на засыпку. Зачем это Василию понадобилось и не сломается ли что-нибудь у кого-нибудь если убрать разбивку скобочек в массив? UPD 13.12.2020
Похоже Василий столкнулся с этой же проблемой когда писал этот блок кода. MODX строку select разбивает в массив колонок по запятым и когда в запросе есть функция с запятыми она также разбивается и по частям попадает на проверку на экранирование и эти части в итоге экранируются.
Решение Василия обходит эту проблемму, но не работает для вложенных функций.
$fields = preg_replace_callback('/\(.*?\)/', function($matches) {
return str_replace(",", "|", $matches[0]);
}, $fields);
Здесь для выражений в скобочках запятая заменяется на |. Затем строка разбивается по запятым. Получаются колонки, в которых затем | обратно заменяется на запятую. И получившийся массив подается в xpdo. А xpdo эти массивы уже не разбивает и не экранирует.Но если функции SQL вложенные, то у нас несколько вложенных скобочек и preg_replace заменяет не все запятые в функции. И проблемма возвращается.
У меня да и наверно у всех колонка с функцией именнуется ( функция AS имя). Для того, чтобы обойти проблемму с фунциями в решении Василия можно заменить маску регулярки так чтобы она искала не ")" а " AS ":
$fields = preg_replace_callback('/\(.*?\bAS\b/i', function($matches) {
return str_replace(",", "|", $matches[0]);
}, $fields);
Так проблемма решается.Стоит ли это решение отправлять в репозиторий pdoTools?
Поблагодарить автора
Отправить деньги
Комментарии: 1
Для того, чтобы обойти проблемму с фунциями в решении Василия можно заменить маску регулярки так чтобы она искала не ")" а " AS ":
Стоит ли это решение отправлять в репозиторий pdoTools?
$fields = preg_replace_callback('/\(.*?\bAS\b/i', function($matches) {
return str_replace(",", "|", $matches[0]);
}, $fields);
Так проблемма решается.Стоит ли это решение отправлять в репозиторий pdoTools?
Авторизуйтесь или зарегистрируйтесь, чтобы оставлять комментарии.