Search code examples
ruby-on-railspostgresqlshellmigrationexecute

Why is `execute` dropping back to the shell instead of sending SQL directly to my Postgres server?


I have a migration which is using execute to send raw SQL to the Postgres backend.

class TestExecuteMethod < ActiveRecord::Migration
  def self.up
    execute ('SELECT 1;')
  end

  def self.down
  end
end

Instead of going to my database, it seems execute is going to the shell:

** Invoke db:migrate (first_time)
** Invoke environment (first_time)
** Execute environment
** Execute db:migrate
==  TestExecuteMethod: migrating ==============================================

++ executing: SELECT 1;
sh: SELECT: command not found
++   [FAIL]
==  TestExecuteMethod: migrated (0.0041s) =====================================

** Invoke db:schema:dump (first_time)
** Invoke environment 
** Execute db:schema:dump

But, when I instead do

ActiveRecord::Base.connection.execute(sql)

It works as expected.

Why is this?

I'm using Rails 3.0.9 and the pg gem.


Solution

  • Add this to your migration:

    def self.trace_execute(io=$stderr, &block)
      set_trace_func proc {|event, file, line, id, binding, classname|
        io.printf "%8s %s:%-2d %10s %8s\n", event, file, line, id, classname if id.to_s == 'execute'
      }
      # trace the passed block
      yield
    
    ensure
      # disable (note: the disable call is the last thing traced)
      set_trace_func nil
    end
    

    Then wrap your execute call in a block like this:

    trace_execute { execute ('SELECT 1;') }
    

    and paste the first few lines of trace output. I suspect something is intercepting the execute call before the db adapter can receive it.

    Usually I'd recommend using something like

    puts method(:execute).inspect
    

    but that probably won't work in this case because method_missing is involved.