#!/usr/bin/env ruby # msqlm.rb: written by itacchi (DATE Ken) 2000- # That's sample program for Ruby/mSQL. # msqlm.rb is a `msql' clone. require 'getopts' require 'tempfile' require 'msql' class OptionError < StandardError; end class InputError < StandardError; end class MsqlResult def to_table str = "" separator = ' +' length = Hash.new each_field do |field| name = field.name case field.type when MsqlField::REAL_TYPE length[name] = name.size length[name] = 12 if length[name] < 12 when MsqlField::INT_TYPE, MsqlField::UINT_TYPE, MsqlField::MONEY_TYPE, MsqlField::TIME_TYPE length[name] = name.size length[name] = 8 if length[name] < 8 when MsqlField::DATE_TYPE length[name] = name.size length[name] = 11 if length[name] < 11 when MsqlField::CHAR_TYPE, MsqlField::TEXT_TYPE length[name] = name.size > field.length ? name.size : field.length end separator += '-' * length[name] + '-+' end separator += "\n" str = separator field_seek 0 str += ' |' each_field do |field| name = field.name str += " #{name}" str += ' ' * (length[name] - name.size) str += '|' end str += "\n" + separator field_seek 0 each_row do |row| str += ' |' each_field_with_index do |field, i| name = field.name if row[i] str += " #{row[i]}" + ' ' * (length[name] - row[i].size) else str += " NULL" + ' ' * (length[name] - 4) end str += '|' end str += "\n" field_seek 0 end str += separator + "\n\n" end end class MsqlMonitor def initialize(host, database) @client = Msql::connect(host) @client.select_db(database) @message = "" @query_string = "" end attr_reader :message, :query_string def add_query(str) @query_string += str end def clear_query @query_string = "" end def edit_query tmp = Tempfile::new('msql') editor = ENV['VISUAL'] or ENV['EDITOR'] if not editor case RUBY_PLATFORM when /win32/ editor = "edit" when /cygwin/ editor = "vim" else editor = "vi" end end tmp.puts @query_string tmp.close system "#{editor} #{tmp.path}" tmp.open @query_string = tmp.read tmp.close(true) end def handle_query if @query_string.size == 0 raise MsqlError, "No query specified !!\n" end begin res = @client.query @query_string rescue MsqlError return @message = "ERROR: #{$!}\n\n" end @message = "\nQuery OK. #{res} row(s) modified or retrieved.\n\n" result = @client.store_result @message += result.to_table if result end end class MsqlMonitorView def initialize(host, database) @monitor = MsqlMonitor.new(host, database) end def run is_in_string = false prompt = true new_query = false print "Welcome to the miniSQL monitor. Type \\h for help.\n\n" print "\nmSQL > " STDOUT.flush while line = STDIN.gets while line.size > 0 if is_in_string case line # in literal (such as 'LITERAL') when /\A.*\'/ # go out @monitor.add_query($& + ' ') is_in_string = false else @monitor.add_query line break end else case line when /\A#/ # skip comment break when /\A\n/ if prompt @monitor.add_query $& print " -> " end prompt = true when /\A\s+/ # skip space when /\A\\h/ help @monitor.clear_query print "\nmSQL > " prompt = false new_query = true when /\A\\g/ @monitor.handle_query print @monitor.message print "\nmSQL > " prompt = false new_query = true when /\A\\e/ @monitor.edit_query print "Query buffer\n" print "------------\n" print "#{@monitor.query_string}\n[continue]\n" prompt = false when /\A\\q/ print "\n\nBye!\n\n" return when /\A\\p/ print "\nQuery buffer\n" print "------------\n" print "#{@monitor.query_string}\n[continue]\n" print " -> " prompt = false when /\A\\./ print "\n\nUnknown command.\n\n" print "\nmSQL > " prompt = false new_query = true when /\A\'.*\'/ # literal if new_query @monitor.clear_query new_query = false end @monitor.add_query($& + ' ') when /\A\'[^\']*\Z/ # into literal is_in_string = true if new_query @monitor.clear_query new_query = false end @monitor.add_query $& when /\A[\w;,'\(\)=_<>\*]+/ if new_query @monitor.clear_query new_query = false end prompt = true @monitor.add_query($&+' ') when /\A.*/ raise InputError,"ERROR: illegal charactor \"#{$&}\"\n\n" end end line = $' end end print "\nBye!\n\n" end private def help print "\n\nMiniSQL Help!\n\n" print "The following commands are available :- \n\n" print "\t\\q Quit\n" print "\t\\g Go (Send query to database)\n" print "\t\\e Edit (Edit previous query)\n" print "\t\\p Print (Print the query buffer)\n" end end # print usage def usage STDERR.print "\n\nUsage : msql [-f conf_file] [-h host] database\n\n" end # --- main process # parse option opts = getopts(nil, "h:", "f:") # parse database name database = ARGV.shift host = $OPT_h conf = $OPT_f begin print "\n" # illegal option or not specified database raise OptionError unless opts and database # too many args... raise OptionError if ARGV.size != 0 # when option -f exists, load specified config file if conf Msql::load_config_file(conf) end # create mSQL interactive monitor instance msqlm = MsqlMonitorView.new(host, database) # monitor run msqlm.run rescue OptionError usage end