Parameterizing SQL queries in Ruby + TinyTDS - ruby

I am trying to figure out how to parameterize an SQL string before handing it off to be executed, but sadly I find a lot of this on the internet:
sql = "SELECT * FROM table_name WHERE thing LIKE '%#{input}%'"
Which is a bad thing...however, parameterizing sql queries is available in the underlying Sequel library, which is what TinyTDS is built on top of. So I know it's possible. I am just having a hard time figuring it out.
I really wish it could be as simple as this:
#client = TinyTds::Client.new(
:adapter => 'sqlserver',
:host => host,
:database => db,
:username => username,
:password => password)
sql = "SELECT * FROM table_name WHERE thing LIKE ?"
safe_sql = #client.prepare(sql, input)
result = #client.execute(safe_sql)
I seem to have found something called a Dataset class in the sourcecode, which has a prepare method. The question is, how do I use it? Do I need to create another object before handing it off to the execute() method in the #client object? I couldn't find an initialize or a new method, so simple instantiation seems like the wrong way to go.

I implemented the Sequel gem with TinyTds as the adapter. This allows you to parameterize SQL queries. See example below:
require "tiny_tds"
require 'sequel'
DB = Sequel.connect(
adapter: 'tinytds',
host: "dataserver",
database: "database",
user: "username",
password: "password"
)
I then was able to make a SQL insert statement with my values parametrized.
posts_table = DB[:posts]
posts_table.insert(:author => 'John Smith', :title => 'How to parametrize sql queries')
I'm connecting to a MS SQL database.

Related

Ruby activerecord result to array

My aim is to take the result of my activerecord search and print it into a nice array but the print part is where I am having trouble.
I first build my oracle connection with the following which works in isolation.
def oracle_connection(adapter, database, username, password)
begin
ActiveRecord::Base.establish_connection(
adapter: adapter,
database: database,
username: username,
password: password)
end
end
I then create my query with the following function:
def query
"select * from owner.appn where appn_id = #{$id}"
end
And here is the part where I am asking the question on. I want to pass the result of the query being returned out into an 2D array. Below is what I currently have to execute the active connection query.
def oracle_query_into_array(query)
result_set = ActiveRecord::Base.connection.execute(query)
if result_set.present?
#add logic here
else
return nil
end
end
Thanks
I'm assuming you have reasons to use the underlying connection calls rather than the abstractions that are common practise.
With the ActiveRecord::Base.connection.execute(query) I would expect this to return true if it executes. What you want is a cursor on the data, so try this:
result = ActiveRecord::Base.connection.exec_query(query)
puts result.to_a
=> [array of results]
A usual abstraction (ActiveRecord::Base) would take the form of creating a model to represent your data, so in your case, this could look like:
class Appn < ActiveRecord::Base
end
This will be automatically mapped to a table within your connection called Appnn allowing you to update the above code to:
results = Appn.where(appn_id: $id)
puts results.to_a
=> [array of results]

postgres avoiding extra quotes inside a string

I have following select query which I will be passing to the database to get results back,
sql = "select * from movies where title = #{movie_title};"
movie_title contains a value that can sometimes contain single quotes and other chars that need escaping. I have come across dollar quoted string which is working well when used inside a INSERT statement but SELECT is not behaving the same, if I use $$#{movie_title}$$ like this it just doesn't get converted to a value inside movie_title. Is there any solution for this?
I am using postgres 9.5.0 and I am programming using ruby.
Bad idea. Don't do that, as you are making your code vulnerable to SQL injection attacks, and also making your life harder. Read more about prepared SQL statements, SQL injection etc.
In short, unless you are using some ORM, you should do something like:
#!/usr/bin/ruby
require 'pg'
if ARGV.length != 1 then
puts "Usage: prepared_statement.rb rowId"
exit
end
rowId = ARGV[0]
begin
con = PG.connect :dbname => 'testdb', :user => 'janbodnar'
con.prepare 'stm1', "SELECT * FROM Cars WHERE Id=$1"
rs = con.exec_prepared 'stm1', [rowId]
puts rs.values
rescue PG::Error => e
puts e.message
ensure
rs.clear if rs
con.close if con
end
(an example taken from http://zetcode.com/db/postgresqlruby/)
Edit: You don't need to use prepared statements, you can also use your DB lib's methods which provide proper parameter binding:
require 'pg'
conn = PG::Connection.open(:dbname => 'test')
res = conn.exec_params('SELECT $1 AS a, $2 AS b, $3 AS c', [1, 2, nil])
Take a look at docs for PG#exec_params

Sequel default example fails when switched to postgres adapter

I'm trying to run the Sequel example from http://sequel.rubyforge.org/. Everything works fine on sqlite, but fails when I switch to postgres.
This is the connection code:
DB = Sequel.connect(:adapter=>'postgres', :host=>'localhost', :database=>'testing', :user=>'postgres', :default_schema=>'sequel')
This is the error I get:
postgres.rb:145:in `async_exec': PG::Error: ERROR: relation "items" does not exist (Sequel::DatabaseError)
LINE 1: INSERT INTO "items" ("price", "name") VALUES (12.45377636338...
I'm suspecting that the issue is Sequel trying to execute INSERT INTO "items" instead "sequel.items", even though :default_schema is correctly set.
Anyone have any idea what i'm doing wrong?
Thanks in advance.
Edit - this is the code used:
require "rubygems"
require "sequel"
# connect to an in-memory database
#DB = Sequel.sqlite
DB = Sequel.connect(:adapter=>'postgres', :host=>'localhost', :database=>'testing', :user=>'postgres', :default_schema=>'sequel')
# create an items table
DB.create_table :items do
primary_key :id
String :name
Float :price
end
# create a dataset from the items table
items = DB[:items]
# populate the table
items.insert(:name => 'abc', :price => rand * 100)
items.insert(:name => 'def', :price => rand * 100)
items.insert(:name => 'ghi', :price => rand * 100)
# print out the number of records
puts "Item count: #{items.count}"
Looks like you're missing the password in the connect method (that's the only difference from the documentation example). Its common for the password to just be the username, so try that if you're not sure what the password is.
It's also suggested to use a different postgresql user with each project, which also makes naming the user intuitive (the project name.) That avoids potentially clashing names.
Anyway, see if this works:
DB = Sequel.postgres 'testing', host: 'localhost', default_schema: 'sequel',
user: 'postgres', password: 'postgres'

Getting datamapper to ignore 'type' when querying the database

I've got a single table inheritance structure in my application whereby Admins and Mods extends a User class. The table uses a discriminator value so each record has a type of either "admin" or "mod"
When it comes to finding a user (on login) I'd like to write the following:
current_user = User.find(params[:email => email])
However, this creates SQL which includes
SELECT ...... WHERE ("type" IN ('User') AND .....
This means that the record cannot be found. However if I type
current_user = Admin.find(params[:email => email])
I get the user (if they are an admin).
I've also tried the following to no avail since the 'type' IN ('User') is still created:
current_user = User.first(:email => email, :type => [Admin, Mod])
Thanks in advance for any help on this
I think it should be
current_user = User.first(:email => email, :type => ['Admin', 'Mod'])

Preventing SQL Injection/Good Ruby method

What is a good method in Ruby to prevent SQL Injection?
in straight up ruby? use prepared statements:
require 'mysql'
db = Mysql.new('localhost', 'user', 'password', 'database')
statement = db.prepare "SELECT * FROM table WHERE field = ?"
statement.execute 'value'
statement.fetch
statement.close
Not just in Ruby - bind your parameters (be it in the database, or in your client code).
Check out the guide they have up on this: http://guides.rubyonrails.org/security.html#injection
Basically, you want to use bind variables in your models to find data, rather than inline parameters..
Model.find(:first, :conditions => ["login = ? AND password = ?", entered_user_name, entered_password])
According to http://ruby.railstutorial.org/ you can prevent Cross Site Request Forgery by inserting the
<%= csrf_meta_tags %>
tag in the header of app/views/layouts/application.html.erb.
Direct link of example
This thread references:
http://www.ruby-forum.com/topic/90258#new
http://www.ruby-forum.com/topic/82349#143790
ActiveRecord's find() method has built in ways to avoid SQL injection by
using the format
> :conditions => [ "user_name = ?", user_name]
Is there any such system for escaping injection in order? It seems to
only take a string and feed it to the SQL statement. This causes a
vulnerability when using params to set : order as in this function:
def list
sort_by = params[:sort_by]
#book_pages, #books = paginate :books,
:order => sort_by,
:per_page => 10
end
We've tried a few methods to sanitize sort_by such as order => ['?',
sort_by] but it just passes that to the SQL statement like a flattened
array. The 'escaping magic' does not work for order. Should I use
gsub! to sanitize params[:sort_by]?

Resources