For some reason my orafetch statement is returning the error:
orafetch: handle 0 not open while executing
Can someone please point out where I am going wrong in my statement?
if {[catch {
set crsr [oraopen $DB_LOGON_HANDLE]
} result] } {
puts "Error $result while creating db handles"
exit 1
}
set name "select names from customers where name = 'Tim Kyle'"
set name_query [orasql $crsr $name ]
set get_name [orafetch $name_query -dataarray -indexbyname]
puts $get_name
There is sample code on the Tcler's Wiki which I reproduce here:
# For error reporting:
set program [file tail $argv0]
# Package interface:
package require Oratcl
# Connect to the $env(TWO_TASK) database as USER with PASSWORD:
if [catch {oralogon "USER/PASSWORD"} ora_logon] {
puts stderr "$program: $ora_logon"
exit 1
}
if [catch {oraopen $ora_logon} ora_statement] {
oralogoff $ora_logon
puts stderr "$program: $ora_statement"
exit 1
}
#if [catch {oraconfig $ora_statement fetchrows 1024} ora_error] {
# puts stderr "$program: $ora_error"
#}
# Execute SQL statement:
set sql "SELECT column_1, ... column_N FROM ... WHERE ..."
# Note that for Oratcl 4.x, the $oramsg references have to change to
# [oramsg $ora_statement rc]
if [catch {orasql $ora_statement $sql} ora_error] {
puts stderr "$program: $ora_error"
} elseif {$oramsg(rc) != 0} {
puts stderr "$program: $oramsg(errortxt)"
} else {
# Process each row with column_I bound to var_I:
while {$oramsg(rc) == 0} {
if [catch {orafetch $ora_statement \
{... $var_1 ... $var_N ...} \
'#' var_1 1 ... var_N N} \
ora_error] {
puts stderr "$program: $ora_error"
break
} elseif {$oramsg(rc) == 1403} {
break
} elseif {$oramsg(rc) != 0} {
puts stderr "$program: $oramsg(errortxt)"
break
}
}
}
# Disconnect from the $env(TWO_TASK) database:
if [catch {oraclose $ora_statement ora_error] {
puts stderr "$program: $ora_error"
}
if [catch {oralogoff $ora_logon ora_error] {
puts stderr "$program: $ora_error"
}
Which all seems very complicated to me! Especially everything to do with oramsg (which is what seems to be missing from your code) and orafetch binding.
You might consider using tdbc::oracle as a wrapper, which follows the standard TDBC model (which in turn was developed based on experience with best practices in many database interfaces).
package require tdbc::oracle
tdbc::oratcl connection create db USER/PASSWORD#SID
db foreach rec { select names from customers where name = 'Tim Kyle' } {
puts $rec
}
# Optionally shut everything down at the end with:
# db destroy
Related
Ruby 2.0
Why would the code below give unexpected return (LocalJumpError) ?
# some code here
puts "Scanning for xml files .."
zip_files = Dir.entries(directory).select { |f| File.extname(f) == '.zip' }
if(zip_files.count == 0)
puts "No files found, exiting..."
return
end
# more code here ( if files found)
Error: unexpected return (LocalJumpError)
No files found, exiting...
[Finished in 0.9s with exit code 1]
You're not in a method. You cannot return from there. If you want to exit early, use exit.
Alternatively, you could rescue the LocalJumpError
puts "Scanning for xml files .."
zip_files = Dir.entries(directory).select { |f| File.extname(f) == '.zip' }
begin
return unless zip_files.count > 0
# more code here ( if files found)
rescue LocalJumpError
puts "No files found, exiting..."
end
Say we have a small application (example.rb) which behave like the following ruby code:
#!/usr/bin/env ruby
done = false
out =Thread.new do
cnt = 0
while !done
STDOUT.puts "out #{cnt}"
cnt += 1
sleep 1
end
end
err = Thread.new do
cnt = 0
while !done
STDERR.puts "err #{cnt}"
cnt += 1
sleep 1
end
end
while true
i = STDIN.gets
if i == "q\n"
puts "Quiting"
done = true
break
end
end
out.join
err.join
exit 42
It print something to stdout and to stderr, it must be quited by writing "q\n" to stdin, and when it exit a value is returned in the return code.
Now, I would like to write a small ruby script which can run this program in an external process, where stdout and stdin are captured, and when the external process should be terminated this is done by writing "q\n" to its stdin. This program is called monitor.rb.
This is what I have tried here:
#!/usr/bin/env ruby
require 'open3'
class Monitor
#cmd
attr_accessor :return_code
def initialize cmd
#cmd = cmd
end
def run
#runner_thread = Thread.new do
Open3::popen3(#cmd) do |stdin, stdout, stderr, thread|
puts "#{Time.now} #{#cmd} is running as pid: #{thread.pid}"
stdin.sync = true;
stdout.sync = true;
stderr.sync = true;
#stdin = stdin
t_out = Thread.new do
stdout.readlines do |l|
puts "#{Time.now} STDOUT> #{l}"
end
end
t_err = Thread.new do
stderr.readlines do |l|
puts "#{Time.now} STDERR> #{l}"
end
end
thread.join
t_err.join
t_out.join
#return_code = thread.value
end
end
end
def quit
puts "Quiting"
#stdin.puts "q"
#stdin.close
#runner_thread.join
end
end
mon = Monitor.new "./example.rb"
mon.run
sleep 5
mon.quit
puts "Return code: #{mon.return_code}"
Question 1: What is wrong with my code since the output of the external process is not being printed?
Question 2: Can this be done in a more elegant way, and what would that look like?
The code must be able to run on Linux and portability is not a priority, I uses ruby 2.0.
When run example.rb in a terminal I get:
$ ./example.rb
out 0
err 0
out 1
err 1
out 2
err 2
q
Quiting
When I run the monitor application I get:
$ ./monitor.rb
2013-11-19 14:39:20 +0100 ./example.rb is running as pid: 7228
Quiting
Return code: pid 7228 exit 42
I expected the monitor.rb to print the output from example.rb
Try changing your t_out and t_err threads to use the following code. readlines will read the entire file at once and stdout and stderr will block until your script exits. I think this is why you were not getting any output.
while l = stdout.gets
puts "#{Time.now} STDOUT> #{l}"
end
This should print out to the screen as soon as any output is available.
can somebody explain why the following code won't spawn the passed block ?
require 'daemons'
t = Daemons.call do
# This block does not start
File.open('out.log','w') do # code don't get here to open a file
|fw|
10.times {
fw.puts "=>#{rand(100)}"
sleep 1
}
end
end
#t.start # has no effect
10.times {
puts "Running ? #{t.running?}" # prints "Running ? false" 10 times
sleep 1
}
t.stop
puts 'finished'
Ruby 1.9.3p392, x86_64 Linux
You sure you're not trying to run a Thread for concurrent programming?
Here's what a Thread implementation would look like:
f = File.open('out.log', 'w')
t = Thread.new do
10.times {
f.puts "=>#{rand(100)}"
sleep 1
}
end
10.times {
puts "Running ? #{t.alive?}"
sleep 1
}
t.exit
puts 'finished'
puts "hi"
puts "bye"
I want to store the STDOUT of the code so far (in this case hi \nbye into a variable say 'result' and print it )
puts result
The reason I am doing this is I have integrate an R code into my Ruby code, output of which is given to the STDOUT as the R code runs , but the ouput cannot be accessed inside the code to do some evaluations. Sorry if this is confusing. So the "puts result" line should give me hi and bye.
A handy function for capturing stdout into a string...
The following method is a handy general purpose tool to capture stdout and return it as a string. (I use this frequently in unit tests where I want to verify something printed to stdout.) Note especially the use of the ensure clause to restore $stdout (and avoid astonishment):
def with_captured_stdout
original_stdout = $stdout # capture previous value of $stdout
$stdout = StringIO.new # assign a string buffer to $stdout
yield # perform the body of the user code
$stdout.string # return the contents of the string buffer
ensure
$stdout = original_stdout # restore $stdout to its previous value
end
So, for example:
>> str = with_captured_stdout { puts "hi"; puts "bye"}
=> "hi\nbye\n"
>> print str
hi
bye
=> nil
Redirect Standard Output to a StringIO Object
You can certainly redirect standard output to a variable. For example:
# Set up standard output as a StringIO object.
foo = StringIO.new
$stdout = foo
# Send some text to $stdout.
puts 'hi'
puts 'bye'
# Access the data written to standard output.
$stdout.string
# => "hi\nbye\n"
# Send your captured output to the original output stream.
STDOUT.puts $stdout.string
In practice, this is probably not a great idea, but at least now you know it's possible.
You can do this by making a call to your R script inside backticks, like this:
result = `./run-your-script`
puts result # will contain STDOUT from run-your-script
For more information on running subprocesses in Ruby, check out this Stack Overflow question.
If activesupport is available in your project you may do the following:
output = capture(:stdout) do
run_arbitrary_code
end
More info about Kernel.capture can be found here
For most practical purposes you can put anything into $stdout that responds to write, flush, sync, sync= and tty?.
In this example I use a modified Queue from the stdlib.
class Captor < Queue
alias_method :write, :push
def method_missing(meth, *args)
false
end
def respond_to_missing?(*args)
true
end
end
stream = Captor.new
orig_stdout = $stdout
$stdout = stream
puts_thread = Thread.new do
loop do
puts Time.now
sleep 0.5
end
end
5.times do
STDOUT.print ">> #{stream.shift}"
end
puts_thread.kill
$stdout = orig_stdout
You need something like this if you want to actively act on the data and not just look at it after the task has finished. Using StringIO or a file will have be problematic with multiple threads trying to sync reads and writes simultaneously.
Capture stdout (or stderr) for both Ruby code and subprocesses
# capture_stream(stream) { block } -> String
#
# Captures output on +stream+ for both Ruby code and subprocesses
#
# === Example
#
# capture_stream($stdout) { puts 1; system("echo 2") }
#
# produces
#
# "1\n2\n"
#
def capture_stream(stream)
raise ArgumentError, 'missing block' unless block_given?
orig_stream = stream.dup
IO.pipe do |r, w|
# system call dup2() replaces the file descriptor
stream.reopen(w)
# there must be only one write end of the pipe;
# otherwise the read end does not get an EOF
# by the final `reopen`
w.close
t = Thread.new { r.read }
begin
yield
ensure
stream.reopen orig_stream # restore file descriptor
end
t.value # join and get the result of the thread
end
end
I got inspiration from Zhon.
Minitest versions:
assert_output if you need to ensure if some output is generated:
assert_output "Registrars processed: 1\n" do
puts 'Registrars processed: 1'
end
assert_output
or use capture_io if you really need to capture it:
out, err = capture_io do
puts "Some info"
warn "You did a bad thing"
end
assert_match %r%info%, out
assert_match %r%bad%, err
capture_io
Minitest itself is available in any Ruby version starting from 1.9.3
For RinRuby, please know that R has capture.output:
R.eval <<EOF
captured <- capture.output( ... )
EOF
puts R.captured
Credit to #girasquid's answer. I modified it to a single file version:
def capture_output(string)
`echo #{string.inspect}`.chomp
end
# example usage
response_body = "https:\\x2F\\x2Faccounts.google.com\\x2Faccounts"
puts response_body #=> https:\x2F\x2Faccounts.google.com\x2Faccounts
capture_output(response_body) #=> https://accounts.google.com/accounts
I'm trying to write in some functionality into the Net::SSH::Telnet Library for a project of mine. Specifically I need to be able to read the exit-status of any command that I write.
Here's the Original source from the Net::SSH::Telnet Library that I'm modifying
#buf = ""
#eof = false
#channel = nil
#ssh.open_channel do |channel|
channel.request_pty { |ch,success|
if success == false
raise "Failed to open ssh pty"
end
}
channel.send_channel_request("shell") { |ch, success|
if success
#channel = ch
waitfor(#options['Prompt'], &blk)
return
else
raise "Failed to open ssh shell"
end
}
channel.on_data { |ch,data| #buf << data }
channel.on_extended_data { |ch,type,data| #buf << data if type == 1 }
channel.on_close { #eof = true }
end
#ssh.loop
And now here are the changes I have made:
#stderr = ""
#exit_code = nil
#buf = ""
#eof = false
#channel = nil
#ssh.open_channel do |channel|
channel.request_pty { |ch,success|
if success == false
raise "Failed to open ssh pty"
end
}
channel.send_channel_request("shell") { |ch, success|
if success
#channel = ch
waitfor(#options['Prompt'], &blk)
return
else
raise "Failed to open ssh shell"
end
}
channel.on_data { |ch,data|
#stdout << data
#buf << data
}
channel.on_extended_data { |ch,type,data|
#stderr << data
#buf << data if type == 1
}
channel.on_request("exit-status") do |ch,data|
#exit_code = data.read_long
end
channel.on_close {
#eof = true
}
end
#ssh.loop
The problem is that when I run this, the #exit_code variable never changes from nil.
The reason I am doing this is because I need three major pieces of functionality:
1. Stateful (interactive) communication (so that if I cd into a directory the next command will occur in that directory)
2. The ability to read the exit status of any command I execute
3. The ability to respond to prompts
I selected Net::SSH::Telnet to adjust because it already offered 1 & 3. I figured I could fix it to support number 2.
If anyone can see how to fix this I would greatly appreciate it. The source for the rest of Net::SSH::Telnet is here:
https://github.com/jasonkarns/net-ssh-telnet/
and I have a forked version of the repo here to which I would gladly accept pull requests.
https://github.com/0x783czar/net-ssh-remotescript
Also if anyone has a suggestion of any other ruby libraries that would offer those three functionalities I would greatly appreciate any suggestions.
You may want to take a look at the source for the Ruby "ssh" gem and "remote_task" gem.
http://rubygems.org/gems/ssh
The relevant source code is here:
https://github.com/seattlerb/ssh/blob/master/lib/ssh.rb
It has code for handling the "cd" command, i/o channels, and the exit status.