-
-
Notifications
You must be signed in to change notification settings - Fork 256
Description
As I cannot find that our bug is intended for this gem, I am opening the issue.
In one place we need to search data by NOT matching specific GPS point. When using SQL condition, it works, but query is corrupted when using ActiveRecord.
some schema information
create_table "orders", force: :cascade do |t|
...
t.geography "gps", limit: {:srid=>4326, :type=>"st_point", :geographic=>true}
...
end
Let's take a look at the following snippet with SQL statement.
order = Order.find(some_id)
Order.where(id: order.id).where("gps = ST_SetSRID( ST_Point( #{order.gps.x}, #{order.gps.y}), 4326)").explain
=>
EXPLAIN for: SELECT "orders".* FROM "orders" WHERE "orders"."id" = $1 AND (gps = ST_SetSRID( ST_Point( 14.8569972, 50.8526169), 4326)) [["id", 12009736]]
QUERY PLAN
-------------------------------------------------------------------------------------------------
Index Scan using orders_id_company_branch_id_idx on orders (cost=0.43..2.66 rows=1 width=1756)
Index Cond: (id = '12009736'::bigint)
Filter: (gps = '0101000020E6100000F3864556C8B62D402AC2F28C226D4940'::geography)
(3 rows)
Order.where(id: order.id).where.not("gps = ST_SetSRID( ST_Point( #{order.gps.x}, #{order.gps.y}), 4326)").explain
=>
EXPLAIN for: SELECT "orders".* FROM "orders" WHERE "orders"."id" = $1 AND NOT (gps = ST_SetSRID( ST_Point( 14.8569972, 50.8526169), 4326)) [["id", 12009736]]
QUERY PLAN
-------------------------------------------------------------------------------------------------
Index Scan using orders_id_company_branch_id_idx on orders (cost=0.43..2.66 rows=1 width=1756)
Index Cond: (id = '12009736'::bigint)
Filter: (NOT (gps = '0101000020E6100000F3864556C8B62D402AC2F28C226D4940'::geography))
(3 rows)
But when we use ActiveRecord referencing order.gps, data processed by DB are corrupted using where.not condition.
order = Order.find(some_id)
Order.where(id: order.id).where(gps: order.gps).explain
=>
EXPLAIN for: SELECT "orders".* FROM "orders" WHERE "orders"."id" = $1 AND "orders"."gps" = $2 [["id", 12009736], ["gps", "0020000001000010e6402db6c8564586f340496d228cf2c22a"]]
QUERY PLAN
-------------------------------------------------------------------------------------------------
Index Scan using orders_id_company_branch_id_idx on orders (cost=0.43..2.66 rows=1 width=1756)
Index Cond: (id = '12009736'::bigint)
Filter: (gps = '0101000020E6100000F3864556C8B62D402AC2F28C226D4940'::geography)
(3 rows)
Order.where(id: order.id).where.not(gps: order.gps).explain
=>
EXPLAIN for: SELECT "orders".* FROM "orders" WHERE "orders"."id" = $1 AND "orders"."gps" != $2 [["id", 12009736], ["gps", "0020000001000010e6402db6c8564586f340496d228cf2c22a"]]
QUERY PLAN
---------------------------------------------------------------------------------------------------------------------------------------------
Index Scan using orders_id_company_branch_id_idx on orders (cost=0.43..2.66 rows=1 width=1756)
Index Cond: (id = '12009736'::bigint)
Filter: ((gps)::bytea <> '\x3030323030303030303130303030313065363430326462366338353634353836663334303439366432323863663263323261'::bytea)
(3 rows)The result of this behavior is that each statement using AR is returning the order object. It seems to be wrong to me. Rails passes correctly serialized GPS point (0020000001000010e6402db6c8564586f340496d228cf2c22a) as filter condition is same as in case using ST_Point, but where.not looks like it performs some extra encoding of data.