Ruby SQLite3 bind_params - ruby

I'm having an issue with Ruby SQLite. This is my code,
require 'socket'
require 'sqlite3'
server = TCPServer.open(1337)
DB = SQLite3::Database.new "./Tavern.db"
loop {
Thread.start(server.accept) do |client|
input = client.gets
input = input.gsub '\n', ''
input = input.split(' ')
case input[0]
when 'register'
stmt = DB.prepare "INSERT INTO Managers (name, job, location, busy)
VALUES (?, ?, ?, 0)"
stmt.bind_params input[1], input[2], client.addr[3]
stmt.execute
when 'request_job'
stmt = DB.prepare "SELECT * FROM Tasks WHERE job = ? AND assigned = 0"
stmt.bind_params input[1]
results = stmt.execute
puts results.next
end
end
}
Where input[1] = "test"
If stmt.bind_params input[1] is changed to stmt.bind_params "test", the sql query works, if it is left as is, it doesn't. I've checked to make absolutely sure that "test" and input[1] are equal with == and by using .bytes on both of them and manually comparing.
Any ideas on why this might be the case?

Have you tried using the stmt.bind_params( 15, "hello" ) style syntax as well?

I have had a similar problem. It turned out that the string I was using had a different encoding than the encoding that was required.
Check what input[1].encoding and "test".encoding yield! If they are different, use the force_encoding-method.

Related

Threading sqlite connections in Ruby

I've been trying to get my ruby script threaded since yesterday. I've since opted for SQLite to save data, with the parallel gem to manage concurrency.
I've built a quick script for testing, but I'm having trouble getting the threading working; the database is locked. I've added db.close to the end, which doesn't help, and I've tried adding sleep until db.closed?, but that just sleeps indefinitely. What am I doing wrong?
The error is "database is locked (SQLite3::BusyException)".
Here's my code:
require 'sqlite3'
require 'pry'
require 'parallel'
STDOUT.sync = true
db = SQLite3::Database.new "test.db"
arr = [1,2,3,4,5,6,7,8,9,10]
rows = db.execute <<-SQL
create table test_table (
original string,
conversion string
);
SQL
def test(num)
db = SQLite3::Database.new "test.db"
puts "the num: #{num}"
sleep 4
{ num => num + 10}.each do |pair|
db.execute "insert into test_table values (?, ?)", pair
end
db.close
end
Parallel.each( -> { arr.pop || Parallel::Stop}, in_processes: 3) { |number| test(number) }
SQLite is threadsafe by default (using its "serialized" mode) and the ruby wrapper apparently supports this to whatever extent it needs to. However, it's not safe across processes, which makes a certain sense since the adapter or engine probably has to negotiate some state in the process to prevent locks.
To fix your example change in_processes to in_threads

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

display postgres sql result using pg gem

How do I display the result set of a postgres query using the pg gem only ? I want it to be in tabular form like it is in pgAdmin GUI tool. The code below does not help. The documentation is not clear, so I am unable to figure another way out. Please help !
require 'pg'
conn = PGconn.connect("db.corp.com", 5432, '', '', "schema", "user", "pass")
sql = 'select * from tbl limit 2'
res = conn.exec(sql)
res.each do |row|
row.each do |column|
end
end
gem list -
pg (0.9.0.pre156 x86-mswin32)
ruby - 1.8.7
Steps -
1. Get list of column names in result set (type PGResult).
2. Iterate each row(hash) of result set.
3. For each row (hash key)/columns found in step 1, find the column values (hash value).
Then print results as csv. I dont think this is efficient, but it gets the job done.
require 'pg'
conn = PGconn.connect("db.corp.com", 5432, '', '', "schema", "user", "pass")
sql = 'select * from tbl limit 2'
res = conn.exec(sql)
rows_count = res.num_tuples
column_names = res.fields
col_header = column_names.join(', ')
puts col_header
for i in 0..rows_count-1
row_hash = res[i]
row_arr = []
column_names.each do |col|
row_arr << row_hash[col]
end
row = row_arr.join(', ')
puts row
end

What's the simplest method in Ruby of telling if SQLite returned a row?

I am very new to Ruby and I am using it with SQLite.
I have written register and deregister functions but I am stuck writing a function to tell if a given user is registered in the database.
This is the current code:
def registered?(l)
db = SQLite3::Database.new "database.db"
db.execute("SELECT user FROM t1 WHERE user = ?, ", l[1])
end
What is the simplest method to tell if SQLite returned a row to this query?
Update
Thanks for the suggestions on how to do it. Here is the updated code:
def registered?(l)
db = SQLite3::Database.new "database.db"
results = db.execute("SELECT user FROM t1 WHERE user = ?, ", l[1])
!results.empty?
end
and I am using it:
if registered?(#nick)
...
end
but I guess this isn't right, because my code under registered?(#nick) doesn't get triggered when the #nick is registered. I have both in the same class User. Am I doing something wrong?
response should not be an empty Array:
res = db.execute("SELECT user FROM t1 WHERE user = ?, ", l[1])
if !res.empty?
# some row is returned
end
The result of your execution is an array (SQLite3::Execute):
class User
def registered?
db = SQLite3::Database.new "database.db"
results = db.execute("SELECT user FROM t1 WHERE user = ?, ", self)
!results.empty?
end
end
Then you'd say #user.registered?

Preparing and executing SQLite Statements in Ruby

I have been trying to puts some executed statements after I prepare them. The purpose of this is to sanitize my data inputs, which I have never done before. I followed the steps here, but I am not getting the result I want.
Here's what I have:
require 'sqlite3'
$db = SQLite3::Database.open "congress_poll_results.db"
def rep_pull(state)
pull = $db.prepare("SELECT name, location FROM congress_members WHERE location = ?")
pull.bind_param 1, state
puts pull.execute
end
rep_pull("MN")
=> #<SQLite3::ResultSet:0x2e69e00>
What I am expecting is a list of reps in MN, but instead I just get "SQLite3::ResultSet:0x2e69e00" thing.
What am I missing here? Thanks very much.
Try this
def rep_pull(state)
pull = $db.prepare("SELECT name, location FROM congress_members WHERE location = ?")
pull.bind_param 1, state
pull.execute do |row|
p row
end
end

Resources