Skip to content

Broken interpolation of variables on 10.0. #431

@Jack12816

Description

@Jack12816

Hey there 👋

I've observed a bug which broke my application code while migrating from activerecord-postgis-adapter 9.0 to 10.0. Consider this:

# in a scope..
where("ST_Distance(lonlat, 'POINT(? ?)') < ?", lon, lat, meter_radius)

produces out of a sudden:

ActiveRecord::StatementInvalid:
  PG::InternalError: ERROR:  parse error - invalid geometry
  LINE 1: ...NT(*) FROM "properties" WHERE ST_Distance(lonlat, 'POINT($1 ...
                                                               ^
  HINT:  "POINT($1" <-- parse error at position 8 within geometry
# /usr/local/bundle/gems/activerecord-7.2.2.1/lib/active_record/connection_adapters/postgresql_adapter.rb:894:in 'PG::Connection#exec_params'
# /usr/local/bundle/gems/activerecord-7.2.2.1/lib/active_record/connection_adapters/postgresql_adapter.rb:894:in 'block (2 levels) in ActiveRecord::ConnectionAdapters::PostgreSQLAdapter#exec_no_cache'
# /usr/local/bundle/gems/activerecord-7.2.2.1/lib/active_record/connection_adapters/abstract_adapter.rb:1004:in 'block in ActiveRecord::ConnectionAdapters::AbstractAdapter#with_raw_connection'
# /usr/local/bundle/gems/activesupport-7.2.2.1/lib/active_support/concurrency/load_interlock_aware_monitor.rb:23:in 'Thread.handle_interrupt'
# /usr/local/bundle/gems/activesupport-7.2.2.1/lib/active_support/concurrency/load_interlock_aware_monitor.rb:23:in 'block in ActiveSupport::Concurrency::LoadInterlockAwareMonitorMixin#synchronize'
# /usr/local/bundle/gems/activesupport-7.2.2.1/lib/active_support/concurrency/load_interlock_aware_monitor.rb:19:in 'Thread.handle_interrupt'
# /usr/local/bundle/gems/activesupport-7.2.2.1/lib/active_support/concurrency/load_interlock_aware_monitor.rb:19:in 'ActiveSupport::Concurrency::LoadInterlockAwareMonitorMixin#synchronize'
# /usr/local/bundle/gems/activerecord-7.2.2.1/lib/active_record/connection_adapters/abstract_adapter.rb:976:in 'ActiveRecord::ConnectionAdapters::AbstractAdapter#with_raw_connection'
# /usr/local/bundle/gems/activerecord-7.2.2.1/lib/active_record/connection_adapters/postgresql_adapter.rb:893:in 'block in ActiveRecord::ConnectionAdapters::PostgreSQLAdapter#exec_no_cache'
# /usr/local/bundle/gems/activesupport-7.2.2.1/lib/active_support/notifications/instrumenter.rb:58:in 'ActiveSupport::Notifications::Instrumenter#instrument'
# /usr/local/bundle/gems/activerecord-7.2.2.1/lib/active_record/connection_adapters/abstract_adapter.rb:1119:in 'ActiveRecord::ConnectionAdapters::AbstractAdapter#log'
# /usr/local/bundle/gems/activerecord-7.2.2.1/lib/active_record/connection_adapters/postgresql_adapter.rb:892:in 'ActiveRecord::ConnectionAdapters::PostgreSQLAdapter#exec_no_cache'
# /usr/local/bundle/gems/activerecord-7.2.2.1/lib/active_record/connection_adapters/postgresql_adapter.rb:872:in 'ActiveRecord::ConnectionAdapters::PostgreSQLAdapter#execute_and_clear'
# /usr/local/bundle/gems/marginalia-1.11.1/lib/marginalia.rb:91:in 'Marginalia::ActiveRecordInstrumentation#execute_and_clear_with_marginalia'
# /usr/local/bundle/gems/activerecord-7.2.2.1/lib/active_record/connection_adapters/postgresql/database_statements.rb:66:in 'ActiveRecord::ConnectionAdapters::PostgreSQL::DatabaseStatements#internal_exec_query'
# /usr/local/bundle/gems/activerecord-7.2.2.1/lib/active_record/connection_adapters/abstract/database_statements.rb:647:in 'ActiveRecord::ConnectionAdapters::DatabaseStatements#select'
# /usr/local/bundle/gems/activerecord-7.2.2.1/lib/active_record/connection_adapters/abstract/database_statements.rb:73:in 'ActiveRecord::ConnectionAdapters::DatabaseStatements#select_all'
# /usr/local/bundle/gems/activerecord-7.2.2.1/lib/active_record/connection_adapters/abstract/query_cache.rb:251:in 'ActiveRecord::ConnectionAdapters::QueryCache#select_all'
# /usr/local/bundle/gems/activerecord-7.2.2.1/lib/active_record/relation/calculations.rb:486:in 'block (2 levels) in ActiveRecord::Calculations#execute_simple_calculation'
# /usr/local/bundle/gems/activerecord-7.2.2.1/lib/active_record/connection_adapters/abstract/connection_pool.rb:415:in 'ActiveRecord::ConnectionAdapters::ConnectionPool#with_connection'
# /usr/local/bundle/gems/activerecord-7.2.2.1/lib/active_record/connection_handling.rb:296:in 'ActiveRecord::ConnectionHandling#with_connection'
# /usr/local/bundle/gems/activerecord-7.2.2.1/lib/active_record/relation/calculations.rb:485:in 'block in ActiveRecord::Calculations#execute_simple_calculation'
# /usr/local/bundle/gems/activerecord-7.2.2.1/lib/active_record/relation.rb:1452:in 'ActiveRecord::Relation#skip_query_cache_if_necessary'
# /usr/local/bundle/gems/activerecord-7.2.2.1/lib/active_record/relation/calculations.rb:484:in 'ActiveRecord::Calculations#execute_simple_calculation'
# /usr/local/bundle/gems/activerecord-7.2.2.1/lib/active_record/relation/calculations.rb:441:in 'ActiveRecord::Calculations#perform_calculation'
# /usr/local/bundle/gems/activerecord-7.2.2.1/lib/active_record/relation/calculations.rb:245:in 'ActiveRecord::Calculations#calculate'
# /usr/local/bundle/gems/activerecord-7.2.2.1/lib/active_record/relation/calculations.rb:102:in 'ActiveRecord::Calculations#count'

The produced log looks interesting:

D, [2025-06-26T12:22:52.265829 #817] DEBUG -- :   Property Count (0.5ms)
/*line:spec/models/property/search_spec.rb:106*/
SELECT COUNT(*) FROM "properties" WHERE ST_Distance(lonlat, 'POINT($1 $2)') < $3
[[nil, 12.2821163], [nil, 51.36048700000001], [nil, 5000]] 
  ^-- this should be $1, $2, $n.., but its nil instead

When I generate the sql only everything looks fine:

where("ST_Distance(lonlat, 'POINT(? ?)') < ?", lon, lat, meter_radius).to_sql

# SELECT "properties".* FROM "properties" 
# WHERE ST_Distance(lonlat, 'POINT(12.2821163 51.36048700000001)') < 5000 
# ORDER BY "properties"."created_at" ASC

To get it back working I had to fiddle around with rgeo to generate the point representation as string which I can pass to AR:

where('ST_Distance(lonlat, ?) < ?',
      RGeo::Geographic::Factory.new('Spherical').point(lon, lat).to_s,
      meter_radius)

but this looks like a regression to me, because there is no changelog here which points this out.


Env details:

Ruby: 3.4.4 (2025-05-14 revision a38531fd3f) +PRISM [x86_64-linux]
Rails: 7.2.2.1
activerecord-postgis-adapter: 10.0.1
PostgreSQL: 17.5 (Debian 17.5-1.pgdg120+1)
PostGiS: 3.5.2+dfsg-1.pgdg120+1 (postgresql-17-postgis-3)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions