Проблема с IF в SELECT при xpdo запросе.Через 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/15347

UPD 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?
Александр Туниеков
10 декабря 2020, 22:14
modx.pro
444
0
Поблагодарить автора Отправить деньги

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

Александр Туниеков
12 декабря 2020, 20:58
0
Для того, чтобы обойти проблемму с фунциями в решении Василия можно заменить маску регулярки так чтобы она искала не ")" а " AS ":
$fields = preg_replace_callback('/\(.*?\bAS\b/i', function($matches) {
						return str_replace(",", "|", $matches[0]);
                    }, $fields);
Так проблемма решается.
Стоит ли это решение отправлять в репозиторий pdoTools?
    Авторизуйтесь или зарегистрируйтесь, чтобы оставлять комментарии.
    1