Rails 5.2: как мне вернуть специфическую для Postgres интерпретацию массива в 'where' как параметризованное предложение IN? - PullRequest
0 голосов
/ 24 августа 2018

После обновления с Rails 5.1 до Rails 5.2 только для Postgres (с использованием гема pg, но не с MySql) реализация запросов вроде Foo.where(id: [1, 2, 3]) изменилась с SELECT "foos".* FROM "foos" WHERE "foos"."id" IN (1, 2, 3) на SELECT "foos".* FROM "foos" WHERE "foos"."id" IN ($1, $2, $3) [["id", 1], ["id", 2], ["id", 3]].

Это не является необоснованным изменением, за исключением того, что PG имеет ограничение ~ 65K параметров в параметризованном запросе, тогда как единственным ограничением на число значений в предложении IN является общий размер строки запроса. Это приведет к нарушению поведения в производственной системе.если мы закончим с обновлением до 5.2.

Кто-нибудь знает, возможно ли вернуться к старому поведению без понижения Rails?Запретить какие-либо ссылки на любую документацию по этому изменению?

Спасибо.

1 Ответ

0 голосов
/ 24 августа 2018

Ой, это неудачный крайний случай.

Это специально не задокументировано, потому что это просто еще один шаг в общем процессе привязки всех параметров запроса.

Лучшей рекомендацией будет «Не делай этого»: если эти идентификаторы поступают из базы данных, используйте подзапрос вместо того, чтобы направлять их через прикладной уровень. (Я видел много приложений, которые вынуждают списки идентификаторов, когда эквивалент подзапроса меньше кода и более эффективен с БД.) Если они приходят из других мест, и у вас нет другого выбора, я бы попытался расположить запрос в способ, который позволил разбить их на наборы по 50к или около того.

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

# Obviously be very careful when doing this; we're deliberately avoiding
# the feature that normally protects against SQL injection

foos.where("id IN (#{[1, 2, 3].map(&:to_i).join(",")})")

Вам не нужно иметь , чтобы идти так грубо - есть немного безопаснее

foos.where(Foo.sanitize_sql(["id IN (?)", [1, 2, 3]]))

... но, хотя это будет работать и сейчас, вполне возможно, что метод может начать использовать привязки в будущем выпуске (6.0 или новее).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...