I'm using Ruby cucumber to automate my application. I'm using DSN ODBC driver and "dbi" to connect to my sql server 2012 DB. It is connected successfully and I can get the records. But when I'm trying to get unicode (utf-8) data from a table in ruby scripts, I get garbage characters (???????).
Please help me get unicode characters from DB.
Below is the code what I have used to connect and retrieve data from DB.
# encoding: UTF-8
require 'rubygems'
require 'DBI'
def run_select_query_verifyText(query,verifyString)
connection = nil
status = false
begin
#puts "Connecting to DataBase"
connection = DBI.connect('DBI:ODBC:ODBCDriver','test','xxxxx')
rescue DBI::DatabaseError => e
puts "An error occurred"
puts "Error code: #{e.err}"
puts "Error message: #{e.errstr}"
return false
end
#execute sql query
dataset = connection.execute(query)#.fetch_all
dataset.each do |row|
row.each do |data|
puts "cell data is #{data}"
if data == verifyString then
status = true
break
end
end
if status then
break
end
end
connection.disconnect
return status
end
I had similar issue, which is fixed with following line in env.rb file
ENV['CUCUMBER_OUTPUT_ENCODING'] = 'UFT-8'
Related
I'm new to ruby and I'm trying to make a client to connect to a TCPServer, and it seems that in order to do so I have to call the method close_write every time I finish sending data one way, to let the client/server know that the other end is finished sending data. Whenever I do that then Im not able to write info to the server or client again because the socket is not opened for writing anymore.
This is my code:
client.rb
require "socket"
socket = TCPSocket.open("localhost", 6666)
loop do
input = gets.chomp
socket.puts input # Send data to server
socket.close_write
while(line = socket.gets)
puts line
end # Print sever response
break if input=="EXIT"
end
socket.close
server.rb
require "socket"
server = TCPServer.new 6666
data = Hash.new { |hash, key| hash[key] = {} }
WAITING_SET_VALUE = "1"
WAITING_NEW_COMMAND = "0"
loop do
Thread.start(server.accept) do |session|
thread_status ||= WAITING_NEW_COMMAND
....
puts "Entering If..."
if(thread_status == WAITING_NEW_COMMAND) #Check thread status
puts "thread_status == WAITING_NEW_COMMAND"
puts "CHECKING COMMAND.."
case line.strip
when /^set \w* \w* \d{1,7} \d{1,7}$/
puts "COMMAND SET"
thread_status = WAITING_SET_VALUE
lineArr = line.strip.split(" ")
varName = lineArr[1]
flag = lineArr[2]
ttl = lineArr[3]
size = lineArr[4]
puts "END SET EXECUTION"
session.write "Executed"
session.close_write
...
Is there a way to open the socket for writing again, or a better way to do this back and forth connection between server and client without losing context? Thanks!
When designing a client-server protocol, you have to decide:
How a client knows when a response has more lines/data.
How a client knows when a response is complete.
How a client knows when a response is invalid/valid.
How a client knows when there was some type of server error.
A simple approach is for the server to return a response with the number of lines (as in the code below). However, instead, you could use END or something so that the client knows when there is no more data to read. I would strongly suggest looking into tutorials about Protocols.
Save the below into a file called client_server.rb. First, run the server with ruby ./client_server.rb s and then in a separate terminal run the client with ruby ./client_server.rb c. Next, type in list over and over to see the different responses. I added list so that you don't have to type in set w w 1 1 over and over for testing purposes. Check it out and let me know if you have any questions.
# frozen_string_literal: true
require 'socket'
# Use:
# First, run the server: ruby ./client_server.rb s
# Then, run the client: ruby ./client_server.rb c
# Use "netcat localhost 6666" on the command line to test
# without implementing a client.
# Returns false to close this client socket.
# Returns true to continue reading from this client socket.
def handle_client(client_id, client_socket, command)
# TODO: Define some type of client-server Protocol here.
case command
when /^set \w* \w* \d{1,7} \d{1,7}$/
puts "Running command for client #{client_id}: #{command}"
# This is just for testing purposes.
case rand(3)
when 0
client_socket.puts 'lines 0'
when 1
client_socket.puts 'lines 3'
client_socket.puts 'This is line 1.'
client_socket.puts 'This is line 2.'
client_socket.puts 'This is line 3.'
when 2
client_socket.puts 'The set command returned an error.'
end
when 'list'
puts "Responding to client #{client_id} with list of messages."
# This is just for testing purposes.
case rand(3)
when 0
client_socket.puts 'messages 0'
when 1
client_socket.puts 'messages 2'
client_socket.puts 'This is message 1.'
client_socket.puts 'This is message 2.'
when 2
client_socket.puts 'Unable to retrieve messages due to error.'
end
when 'bye'
puts "Killing client #{client_id}."
return false # Disconnect and kill the thread.
else
client_socket.puts "[ERROR] Invalid command: #{command}"
end
client_socket.flush # Flush all output just in case.
true # Continue connection.
end
case ARGV[0].to_s.downcase
when 's' # server
TCPServer.open(6666) do |server_socket|
global_client_id = 1
loop do
Thread.start(global_client_id, server_socket.accept) do |client_id, client_socket|
puts "Accepting new client #{client_id}."
loop do
command = client_socket.gets
if command.nil?
puts "Client #{client_id} disconnected manually."
break
end
command = command.strip
keep_alive = handle_client(client_id, client_socket, command)
break unless keep_alive
end
client_socket.close
end
global_client_id += 1
end
end
when 'c' # client
TCPSocket.open('localhost', 6666) do |socket|
puts '[Commands]'
puts 'set <word> <word> <num> <num> Run set command.'
puts 'list Get list of messages.'
puts 'exit, bye Exit the client.'
puts
loop do
print '> '
input = $stdin.gets.strip
# TODO: Define some type of client-server Protocol here.
case input
when /EXIT|BYE/i
socket.puts 'bye'
socket.flush
break
when /\Aset .+\z/
socket.puts input
socket.flush
response = socket.gets
if response.nil?
puts 'Server is not running anymore! Disconnecting.'
break
end
response = response.strip
match_data = response.match(/\Alines (?<lines>\d+)\z/)
if match_data
line_count = match_data[:lines].to_i
puts "Received #{line_count} lines from server."
1.upto(line_count) do |i|
line = socket.gets
puts ">> Resp[#{i}] #{line}"
end
else
# Can check for "response == 'ERROR'" or something.
puts "Server error or invalid response from server: #{response}"
end
when 'list'
socket.puts input
socket.flush
response = socket.gets
if response.nil?
puts 'Server is not running anymore! Disconnecting.'
break
end
response = response.strip
match_data = response.match(/\Amessages (?<messages>\d+)\z/)
if match_data
message_count = match_data[:messages].to_i
puts "Received #{message_count} messages from server."
1.upto(message_count) do |i|
line = socket.gets
puts ">> Resp[#{i}] #{line}"
end
else
# Can check for "response == 'ERROR'" or something.
puts "Server error or invalid response from server: #{response}"
end
else
puts "Invalid command: #{input}"
end
end
end
else
puts "Pass in 'c' for client or 's' for server."
end
I am trying to create and edit a reg key in ruby but keep getting the following error:
setKeyStringValue error:
false
error in 'open' system cannot find file specified
My code:
require 'win32/registry'
$hkey_local_machine=Win32::Registry::HKEY_LOCAL_MACHINE
$hkey_current_user=Win32::Registry::HKEY_CURRENT_USER
# Returns the Microsoft Registry path to the Microsoft software information
def getKeyValue(hive, key_path, key_name)
reg_obj=hive.open(key_path, Win32::Registry::KEY_READ)
begin
reg_typ, reg_val = reg_obj.read(key_name)
rescue Win32::Registry::Error
puts "key not found : #{key_name}"
end
return reg_val
end
#used to set a String value for a key
def setKeyStringValue(hive,key_path, key_name, key_value)
begin
reg_key=hive.open(key_path, Win32::Registry::KEY_WRITE)
puts "opened key"
reg_key.write(key_name,Win32::Registry::REG_SZ,key_value)
rescue Win32::Registry::Error
puts "setKeyStringValue error:"
return false
end
return true
end
puts setKeyStringValue(Win32::Registry::HKEY_CURRENT_USER,"SOFTWARE\\PsychSoft","foo","woo")
puts getKeyValue(Win32::Registry::HKEY_CURRENT_USER,"SOFTWARE\\PsychSoft","foo")
Can someone explain why this code doesnt work?
I suppose your registry path needs to be enclosed in single '
Your code works like this
profiles_key = 'Software\Microsoft'
puts setKeyStringValue(Win32::Registry::HKEY_CURRENT_USER, profiles_key, "foo", "woo")
puts getKeyValue(Win32::Registry::HKEY_CURRENT_USER, profiles_key, "foo")
Which gives
opened key
true
woo
I have coded an app in ruby which queries the youtube website for some keywords which are taken from a specific db. After the youtube query is done the resulted videos' id and title are inserted into 2 different dbs. I have run the code and I got this exception:
C:/RailsInstaller/Ruby1.9.3/lib/ruby/gems/1.9.1/gems/sqlite3-1.3.8-x86-mingw32/lib/sqlite3/database.rb:91:in `initialize': near "'tag:youtube.com,2008:video:3taEuL4EHAg'": syntax error (SQLite3::SQLException)
Is this error caused by invalid characters in my queries? Should the SQLite gem that I used handle these?
If you need the code here it is:
require "sqlite3"
require "youtube_it"
database = SQLite3::Database.new("data.db")
client = YouTubeIt::Client.new(:dev_key =>"myyoutubekey")
result = database.query("SELECT `keyphrase` FROM `keyphrases`")
result.each do |array|
array.each do |result|
results = client.videos_by(:query => "#{result}", :page => 1, :per_page => 10)
results.videos.each do |videoone|
database.query("INSERT OR IGNORE INTO `videos` (videoID,cachedTitle) VALUES ('#{videoone.video_id}','videoone.title')")
rezultat = database.query("SELECT `id` FROM `keyphrases` WHERE `keyphrase` = '#{result}' ")
rezultat.each do |n|
id = n.to_s.delete("[").delete("]").to_i
database.query("INSERT INTO `keyphrase2videos` (keyphraseID,videoID) VALUES ('#{id}','#{videoone.video_id}'")
end
end
end
end
p "Recored Entered"
I was missing a " ) " in the VALUES clause
I'm having issues getting Sequel to connect to a MS SQL Database.
I have installed the following:
UnixODBC
FreeTDS
I have configured both software packages, and the following commands allow me to connect to my database without a problem:
isql
tsql
osql
However, when I try it from Ruby code using the Sequel.odbc command, I receive the following error:
ODBC::Error: IM003 (0) [iODBC][Driver Manager]Specified driver could not be loaded.
This is as far as I can get. I used to receive another error first, but managed to solve that by redoing the configuration part. Guess I missed something there.
EDIT
This is the code for my base talker class. It basically loads a YAML file like rails does, holding the database settings and establishes a connection to the database.
This seems to be working, trying it manually returns me a DB object from sequel:
module Talkers
require 'yaml'
require 'sequel'
class BaseTalker
# This function will load the desired settings as a hash from the database.yml file
# in the config folder. The data will be returned as a hash following the standard
# YAML structure.
def self.load_config(name)
cfg = YAML::load(File.open(File.join(ENV['API_ROOT'], 'config', 'database.yml')))
cfg.key?(name) ? cfg[name] : nil
end
# This function will establish a connection with the Florensia User database and return
# the Sequel database object, so that queries can be executed against the database.
def self.connect_to_user_db
settings = self.load_config("florensia_user_#{ENV['RACK_ENV']}")
Sequel.odbc settings['dsn'], :db_type => settings['adapter'], :user => settings['user'], :password => settings['password']
end
end
end
The class below inherits from the talker and performs certain actions for a User. It contains the DB logic specific to the game. When I call this logic, I receive the errors:
module Talkers
require 'yaml'
require 'sequel'
class LoginDbTalker < BaseTalker
#
# Bans the specified User from the game. The function requires the following information
# to be supplied in order for the ban to be properly set:
# - id : The identifier of the account.
# - gm_name : The name of the GM setting the ban.
# - punish_code : The punishment code being applied on the account.
# - days : The duration of the ban in days, starting from today.
#
# The function will return true if the ban has been properly set; otherwise the function
# will return false.
def self.ban_user(options = {})
return false if options.empty?
db = self.connect_to_user_db
ds = db[:tbl_User].filter(:id => options[:id])
ps = ds.prepare(:update, :apply_ban)
ps.call(
:punishcode => options[:punish_code],
:punishstory => "Banned by #{options[:gm_name]}",
:punishdate => Date.today,
:punishfreedate => (options[:days].to_i == -1) ? (Date.today + (30 * 265)) : (Date.today + options[:days].to_i))
true
rescue Exception => e
puts "Exception caught in ban_user: #{e.to_s}"
puts "Provided variables: id=#{options[:id]}, gm_name=#{options[:gm_name]}, punish_code=#{options[:punish_code]}, days=#{options[:days]}"
false
end
#
# Unbans the specified User from the game. The function requires the following information
# to be supplied in order for the ban to be properly lifted:
# - id : The identifier of the account.
# - gm_name : The name of the GM removing the ban.
#
# The function will return true if the ban has been properly lifted; otherwise the function
# will return false.
def self.unban_user(options = {})
db = self.connect_to_user_db
ds = db[:tbl_User].filter(:id => options[:id])
ps = ds.prepare(:update, :lift_ban)
ps.call(
:punishcode => '0',
:punishstory => "Ban removed by #{options[:gm_name]}",
:punishdate => Date.today,
:punishfreedate => Date.today
)
true
rescue Exception => e
puts "Exception caught in unban_user: #{e.to_s}"
puts "Provided variables: id=#{options[:id]}, gm_name=#{options[:gm_name]}"
false
end
#
# Kicks the specified User from the game, regardless on the server or character he currently is on.
# This requires a direct connection to the game servers so a specialized command can be sent that
# instruct the server to close the connection with the offending player.
# The function returns true if the kick succeeded; otherwise false.
def self.kick_player(id)
false
end
end
end
Calling any of the ban/unban functions results in the error message.
EDIT2
I've added the folder /Library/ODBC and linked all config files to there for iODBC. This removes the error I had before and now brings me this error:
ODBC::Error: 01000 (20002) [FreeTDS][SQL Server]Adaptive Server connection failed
So it seems I made some progress again
I recommend you use the tinytds adapter instead of the odbc adapter if you are connecting to Microsoft SQL Server from OS X. I know there are people who have got Sequel/ODBC running on non-Windows boxes, but I only have experience with Sequel/ODBC on Windows.
I need to create a script in ruby to get all the database objects (tables,views,sps, functions, etc) and be able to create files for each of the db objects.
I would like to be able to implement this solution in ruby and use some sort of Win32 class may be?.
I am using SQL Server 2008 R2. Not ruby on rails of course.
# == Name
# SQL Server Library
# == Author
# Maverick
# == Synopsis
# ADO SQL Server Library
# == Notes:
# Modify the following global variables in order to set up an execution environment
# sql_str: This is the SQL CMD command option and arguments -> Change the -U and -P arguments for -E to enable integrated security
# http://rubyonwindows.blogspot.com/2007/03/ruby-ado-and-sqlserver.html
Thread.abort_on_exception = true
require 'win32ole'
require 'win32api'
CoInitialize = Win32API.new('ole32', 'CoInitialize', 'P', 'L')
# This class manages database connection and queries
class SqlServer
attr_accessor :connection, :data, :fields
def initialize
#connection = nil
#data = nil
#cmd_time_out = 900
end
#opens a database connection using integrated security
def open(server,database)
connection_string = "Provider=SQLOLEDB.1;"
connection_string << "Persist Security Info=False;"
connection_string << "Integrated Security=SSPI;"
connection_string << "Initial Catalog=#{database};"
connection_string << "Data Source=#{server};"
connection_string << "Network Library=dbmssocn"
CoInitialize.call( 0 )
if server.eql?(nil) or database.eql?(nil) or server.eql?('') or database.eql?('') then
raise Exception, "Application Error: Server or Database parameters are missing"
end
begin
#connection = WIN32OLE.new('ADODB.Connection')
#connection.ConnectionString = connection_string
#connection.open
rescue Exception => e
#connection.Errors.Count.times { |x|
show_ado_error(#connection.Errors)
}
raise Exception, "Application Error: #{e.message} \n Can't open a connection with the server. Verify user credentials"
end
end
def get_connection
return #connection
end
#executes a query without returning any rows
def execute_non_query(query)
begin
command = WIN32OLE.new('ADODB.Command')
command.CommandType = 1
command.ActiveConnection = #connection
command.CommandText = query
command.CommandTimeOut = #cmd_time_out
result = command.Execute
if #connection.Errors.Count > 1 then
raise Exception,"ADODB Connection contains errors"
end
rescue Exception => e
show_ado_error(#connection.Errors)
raise Exception, "Application Error: #{e.message} \n Can't execute query. Verify sql syntax"
end
return result
end
#prints ado db errors using ado connection error property
def show_ado_error(obj)
obj.Count.times { |x|
puts "#{x}. ADODB Error Number: " + #connection.Errors(x).Number.to_s
puts "#{x}. ADODB Generated By: " + #connection.Errors(x).Source
puts "#{x}. ADODB SQL State: " + #connection.Errors(x).SQLState
puts "#{x}. ADODB Native Error: " + #connection.Errors(x).NativeError.to_s
puts "#{x}. ADODB Description: " + #connection.Errors(x).Description
}
end
#executes a query returning an array of rows
def execute_query(sql_query)
# Create an instance of an ADO Record set
begin
record_set = WIN32OLE.new('ADODB.Recordset')
# Open the record set, using an SQL statement and the
# existing ADO connection
record_set.open(sql_query, #connection)
# Create and populate an array of field names
#fields = []
record_set.fields.each do |field|
#fields << field.Name
end
begin
# Move to the first record/row, if any exist
record_set.movefirst
# Grab all records
#data = record_set.getrows
rescue
#data = []
end
record_set.close
# An ADO Recordset's GetRows method returns an array
# of columns, so we'll use the transpose method to
# convert it to an array of rows
#data = #data.transpose
rescue
raise Exception, "Application Error: Can't execute query. Verify SQL Query syntax"
end
end
def close
#connection.Close
end
end