RailsでArelからSQLを発行した場合、
PostgreSQLのバージョン9.2でエラーが出る。9.4の場合にはエラーが出ない。
CIとして利用しているサービスのPostgreSQLバージョン次第ではローカルでエラーにならずに、
CI上でエラーになったりして混乱するのでメモ。
エラー内容
ActiveRecord::StatementInvalid:
PG::SyntaxError: ERROR: syntax error at or near "FROM"
LINE 1: ...ions".* FROM "reservations" WHERE (EXISTS (SELECT FROM "stor...
^
: SELECT "reservations".* FROM "reservations" WHERE (EXISTS (SELECT FROM "stored_reservations" WHERE "reservations"."id" = "stored_reservations"."id"))
Railsのモデルでのscope
以下のように記述していた。
scope :exists_in_stored, -> do
arel_stored_reservations = Stored::Reservation.arel_table
condition = reservations[:id].eq(arel_stored_reservations[:id])
where(arel_stored_reservations.where(condition).exists)
end
SQL
上記のscopeは以下のSQLを発行する。
SELECT "reservations".*
FROM "reservations"
WHERE (EXISTS (
SELECT FROM "stored_reservations"
WHERE "reservations"."id" = "stored_reservations"."id")
)
原因
EXISTS内のSELECT後にFROMが来る場合にSyntaxエラーとなる。
PostgreSQLのバージョンが9.2の場合にエラーとなる。
解決策
scopeの記述を以下のように変更する。
scope :exists_in_stored, -> do
arel_stored_reservations = Stored::Reservation.arel_table
condition = reservations[:id].eq(arel_stored_reservations[:id])
where(Stored::Reservation.where(condition).exists)
end
すると、SQLは以下のようになる。
SELECT "reservations".*
FROM "reservations"
WHERE (EXISTS (
SELECT "stored_reservations".* FROM "stored_reservations"
WHERE "reservations"."id" = "stored_reservations"."id")
)
これならPostgreSQL9.2でもエラーにならない。
ちなみにwerckerでPostgreSQLのバージョンを指定するには、wercker.ymlで以下のように記述する。
wercker.yml
box: wercker/rvm
no-response-timeout: 10
services:
# 使用できるserviceを検索するには以下を参照
# https://app.wercker.com/#explore/boxes/search/
#- wercker/postgresql
#- wercker/postgresql@0.0.4
- wercker/postgresql9.2@0.0.7
#- bolek-kurowski/postgresql9.3@0.0.8
#- userminddeployer/postgresql9.3@0.0.7-usermind-9.3-1
#- userminddeployer/postgresql9.4@0.0.7-usermind-9.4-3
#- wercker/redis@1.0.1
- wercker/redis
build:
steps:
- rvm-use: