1
ActiveRecord::Base.connection.execute(
          "WITH numberofdays AS 
          (SELECT percent_change FROM asset_histories 
          WHERE date < $1
          AND asset_symbol = $2
          ORDER BY date DESC
          LIMIT $3)
          SELECT stddev_samp(percent_change) as stdev FROM numberofdays",
          [day,symbol,daystolimit])

Where day, symbol and daystolimit are variables assigned before the above code. They are assigned as such:

day = '2013-03-25'
symbol = 'AAPL'
daystolimit = 20

I don't want to use #{variable} because of the potential for malicious intent. As referenced in the title, my statement is returning

PGError ERROR: there is no parameter $1 LINE 1 ... WHERE date <$1 AND...

Using Postgresql 9.2 and rails 3.2

EDIT adding alternative solution I found here:

In addition to mu is too short where he uses connection.method(:quote), I couldn't find documentation on it so I came across another post where quoting was done as such:

a = ActiveRecord::Base.connection
a.execute(%Q{SELECT * FROM table WHERE id = #{a.quote(variable)}...})

1 Answer 1

1

From the fine (?) manual:

execute(sql, name = nil)

Executes an SQL statement, returning a PGresult object on success or raising a PGError exception otherwise.

Note that the second parameter isn't for binding parameters, it is a name for (AFAIK) logging purposes.

ActiveRecord doesn't actually use bound parameters internally, it just does the quoting and escaping itself and builds a big SQL string for the database (cringe). You can mimic this behavior using the quote method and string interpolation:

q = ActiveRecord::Base.connection.method(:quote)
ActiveRecord::Base.connection.execute(%Q{
    WITH numberofdays AS 
    (SELECT percent_change FROM asset_histories 
    WHERE date < #{q[day]}
    AND asset_symbol = #{q[symbol]}
    ORDER BY date DESC
    LIMIT #{daystolimit})
    SELECT stddev_samp(percent_change) as stdev FROM numberofdays
})

You'll have to ensure that daystolimit is a number on your own (or quote it too and cast to an integer inside the SQL).

Alternatively, connect to the database using the raw pg interface and use real prepared statments.

Sign up to request clarification or add additional context in comments.

8 Comments

Ty, I saw others referencing that method as a way to pass parameters here and there and thought it was the correct way. I will look into the quote method more.
@Chowza: Numbered placeholders ($1, $2, ...) are the preferred way to use placeholders with PostgreSQL, the problem is that execute doesn't understand them so you have to do it by hand. If you talk to PostgreSQL through the low level pg interface, then you can use numbered placeholders. I don't know how to get the underlying PostgreSQL connection out of ActiveRecord though.
Thanks. I haven't gotten to the level where I need to learn pg yet so I'm gonna keep everything high level :) By the way, the quotes should be in square brackets like such: #{q[symbol]}. Had to play around with it to figure that out. Thanks for the help and clarification!
Also, I couldn't find documentation on connection.method(:quote) when trying to figure out the square brackets thing, and I came across connection.quote. I'm assuming there is no difference between the two? Would you know? Is there a best practice to use one over the other?
@Chowza: Thanks for spotting the bracket problem, thinking in the wrong language again :) The connection.method(:quote) trick just grabs a short reference to the quote method of connection, that way we don't have to a bunch of noise inside the SQL. See the method method for details. So my q and ActiveRecord::Base.connection.quote are the same thing but q is less noisy.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.