2016-03-02 68 views
0

我试图在Ruby中创建一个简单的脚本,用于访问MySQL数据库并根据用户输入运行查询。如何区分例外

如果用户提供了错误登录信息,或者尝试SELECTFROM表或列不存在,我想用户重新输入是造成,而不必问题的信息重新输入所有信息。

我希望这个代码基于查询的哪一部分来引发异常抛出一个错误:

#!/usr/local/bin/ruby 
require "mysql2" 
require "watir" 
require "csv" 

Mysql2::Client.default_query_options.merge!(:as => :array) 
mysql = Mysql2::Client.new(:host => "1.2.3.4", :username => "usr", :password => "pass123", :database => "db") 

db = "db" 

puts "Please enter all `table`.`column` pairs you wish to select from; separated by a comma and space." 
tCP = gets.chomp.split(", ") 

dynQ = "SELECT " 
tCP.each {|pair| dynQ << (db + "." + pair + ", ") } 

puts "Please enter the `table` you wish to select from:" 
tF = db + "." + gets.chomp 

dynQ = dynQ.chop!.chop! + " FROM " + tF + " LIMIT 10;" 

report = mysql.query(dynQ) 

begin 
    report = mysql.query(dynQ) 
    report.each {|row| puts row} 

    puts "Query Successful!" 

rescue Mysql2::Error => e 
    puts e.errno 
    puts e.error 

    puts "Please re-nter all `table`.`column` pairs separated by, ', '." 
    tCP = gets.chomp!.split(", ") 

    dynQ = "SELECT " 
    tCP.each {|pair| dynQ << (db + "." + pair + ", ") } 

    tF = db + "." 
    puts "Now re-enter the `table` to select `FROM`:" 
    tF << gets.chomp! 

    dynQ = dynQ.chop!.chop! + " FROM " + tF + " LIMIT 10;" 

    retry 
end 

例如,如果我SELECT从一个表或列不存在,我得到这样的:

/Users/guy/.rvm/gems/ruby-2.3.0/gems/mysql2-0.4.2/lib/mysql2/client.rb:107:in '_query': Table 'db.table_dne' doesn't exist (Mysql2::Error) 
    from /Users/guy/.rvm/gems/ruby-2.3.0/gems/mysql2-0.4.2/lib/mysql2/client.rb:107:in 'block in query' 
    from /Users/guy/.rvm/gems/ruby-2.3.0/gems/mysql2-0.4.2/lib/mysql2/client.rb:106:in 'handle_interrupt' 
    from /Users/guy/.rvm/gems/ruby-2.3.0/gems/mysql2-0.4.2/lib/mysql2/client.rb:106:in 'query' 
    from file.rb:23:in '<main>' 

然而,如果我正在从一个不存在的表的选择,我得到了同样的事情:

/Users/guy/.rvm/gems/ruby-2.3.0/gems/mysql2-0.4.2/lib/mysql2/client.rb:107:in '_query': Unknown column 'db.table_dne' doesn't exist (Mysql2::Error) 
    from /Users/guy/.rvm/gems/ruby-2.3.0/gems/mysql2-0.4.2/lib/mysql2/client.rb:107:in 'block in query' 
    from /Users/guy/.rvm/gems/ruby-2.3.0/gems/mysql2-0.4.2/lib/mysql2/client.rb:106:in 'handle_interrupt' 
    from /Users/guy/.rvm/gems/ruby-2.3.0/gems/mysql2-0.4.2/lib/mysql2/client.rb:106:in 'query' 
    from file.rb:23:in '<main>' 

理想情况下,我想rescue根据控制台中出现的异常,并让用户重新输入tCPtF,而不是仅仅给出一个更一般的例外。

我看着MySQL2 documentation没有运气。

+1

异常是一个字符串。由于类没有区别,你可以分析异常消息并做任何你想做的事情。 –

+0

@ nick-roz帮助很大;但我刚刚发现分析'e.errno'会更容易。尽管你的评论确实指向了我的正确方向。 – EVAL

+0

任何时候您都不应允许不可信用户输入任何SQL。这是被黑客入侵的好方法。如果你相信用户,然后将信息呈现在列表中,则他们可以从这样的错别字中选择和/或不能注入临时查询。如果您的界面位于命令行上,那么请认真考虑将它移到可以更好地控制输入的Web窗体,或者编写并运行大量代码来验证其输入,然后将其提交到数据库。一旦命中数据库,防范恶意SQL就太迟了。您可能应该使用ORM来帮助保护您的数据库。 –

回答

1

让我们打破你的尝试:

rescue Mysql2::Error => e 
    puts e.errno 
    puts e.error 
  1. rescue使你的脚本运行
  2. Mysql2::Error => eError类和商店发生在e
  3. puts e.errnoputs错误号到控制台
  4. puts e.errorputs错误描述到控制台

有了这样的,下面begin循环应该为你工作:

begin 
    report = mysql.query(dynQ) 
    report.each {|row| puts row} 

    puts "Query Successful!" 

rescue Mysql2::Error => e 

    if e.errno === 1146 
    puts e.error 

    tF = db + "." 
    puts "Now re-enter the `table` to select `FROM`:" 
    tF << gets.chomp! 
    elsif e.errno === 1054 
    puts e.error 

    puts "Please re-nter all `table`.`column` pairs separated by, ', '." 
    tCP = gets.chomp!.split(", ") 

    dynQ = "SELECT " 
    tCP.each {|pair| dynQ << (db + "." + pair + ", ") } 
    else 
# puts e.errno 
    puts e.error 

     puts "Please re-nter all `table`.`column` pairs separated by, ', '." 
    tCP = gets.chomp!.split(", ") 

    dynQ = "SELECT " 
    tCP.each {|pair| dynQ << (db + "." + pair + ", ") } 

    tF = db + "." 
    puts "Now re-enter the `table` to select `FROM`:" 
    tF << gets.chomp! 
    end 

    dynQ = dynQ.chop!.chop! + " FROM " + tF + " LIMIT 10;" 

    retry 
end