lib/baza/drivers/mysql.rb in baza-0.0.19 vs lib/baza/drivers/mysql.rb in baza-0.0.20

- old
+ new

@@ -1,220 +1,127 @@ -class Baza::Driver::Mysql < Baza::BaseSqlDriver - path = "#{File.dirname(__FILE__)}/mysql" - - autoload :Table, "#{path}/table" - autoload :Tables, "#{path}/tables" - autoload :Column, "#{path}/column" - autoload :Columns, "#{path}/columns" - autoload :Index, "#{path}/index" - autoload :Indexes, "#{path}/indexes" - autoload :Result, "#{path}/result" - autoload :UnbufferedResult, "#{path}/unbuffered_result" - autoload :Sqlspecs, "#{path}/sqlspecs" - - attr_reader :conn - - def self.from_object(args) - raise 'Mysql does not support auth extraction' if args[:object].class.name == 'Mysql' - end - - def initialize(baza) - super - - @opts = @baza.opts - - require 'monitor' - @mutex = Monitor.new - - if baza.opts[:conn] - @conn = baza.opts[:conn] - else - if @opts[:encoding] - @encoding = @opts[:encoding] - else - @encoding = 'utf8' - end - - if @baza.opts.key?(:port) - @port = @baza.opts[:port].to_i - else - @port = 3306 - end - - reconnect - end - end - - #This method handels the closing of statements and results for the Java MySQL-mode. - def java_mysql_resultset_killer(id) - data = @java_rs_data[id] - return nil unless data - - data[:res].close - data[:stmt].close - @java_rs_data.delete(id) - end - - #Cleans the wref-map holding the tables. - def clean - tables.clean if tables - end - - #Respawns the connection to the MySQL-database. - def reconnect - @mutex.synchronize do - require 'mysql' unless ::Object.const_defined?(:Mysql) - @conn = ::Mysql.real_connect(@baza.opts[:host], @baza.opts[:user], @baza.opts[:pass], @baza.opts[:db], @port) - query("SET NAMES '#{self.esc(@encoding)}'") if @encoding - end - end - - #Executes a query and returns the result. - def query(str) - str = str.to_s - str = str.force_encoding("UTF-8") if @encoding == "utf8" and str.respond_to?(:force_encoding) - tries = 0 - - begin - tries += 1 - @mutex.synchronize do - return Baza::Driver::Mysql::Result.new(self, @conn.query(str)) - end - rescue => e - if tries <= 3 - if e.message == "MySQL server has gone away" || e.message == "closed MySQL connection" or e.message == "Can't connect to local MySQL server through socket" - sleep 0.5 - reconnect - retry - elsif e.message.include?("No operations allowed after connection closed") or e.message == "This connection is still waiting for a result, try again once you have the result" or e.message == "Lock wait timeout exceeded; try restarting transaction" - reconnect - retry - end - end - - raise e - end - end - - #Executes an unbuffered query and returns the result that can be used to access the data. - def query_ubuf(str) - @mutex.synchronize do - @conn.query_with_result = false - return Baza::Driver::Mysql::UnbufferedResult.new(@conn, @opts, @conn.query(str)) - end - end - - #Escapes a string to be safe to use in a query. - def escape_alternative(string) - return @conn.escape_string(string.to_s) - end - - #Returns the last inserted ID for the connection. - def last_id - @mutex.synchronize { return @conn.insert_id.to_i } - end - - #Closes the connection threadsafe. - def close - @mutex.synchronize { @conn.close } - end - - #Destroyes the connection. - def destroy - @conn = nil - @baza = nil - @mutex = nil - @subtype = nil - @encoding = nil - @query_args = nil - @port = nil - end - - #Inserts multiple rows in a table. Can return the inserted IDs if asked to in arguments. - def insert_multi(tablename, arr_hashes, args = nil) - sql = "INSERT INTO `#{tablename}` (" - - first = true - if args && args[:keys] - keys = args[:keys] - elsif arr_hashes.first.is_a?(Hash) - keys = arr_hashes.first.keys - else - raise "Could not figure out keys." - end - - keys.each do |col_name| - sql << "," unless first - first = false if first - sql << "`#{self.esc_col(col_name)}`" - end - - sql << ") VALUES (" - - first = true - arr_hashes.each do |hash| - if first - first = false - else - sql << "),(" - end - - first_key = true - if hash.is_a?(Array) - hash.each do |val| - if first_key - first_key = false - else - sql << "," - end - - sql << @baza.sqlval(val) - end - else - hash.each do |key, val| - if first_key - first_key = false - else - sql << "," - end - - sql << @baza.sqlval(val) - end - end - end - - sql << ")" - - return sql if args && args[:return_sql] - - self.query(sql) - - if args && args[:return_id] - first_id = self.last_id - raise "Invalid ID: #{first_id}" if first_id.to_i <= 0 - ids = [first_id] - 1.upto(arr_hashes.length - 1) do |count| - ids << first_id + count - end - - ids_length = ids.length - arr_hashes_length = arr_hashes.length - raise "Invalid length (#{ids_length}, #{arr_hashes_length})." unless ids_length == arr_hashes_length - - return ids - else - return nil - end - end - - def transaction - @baza.q("START TRANSACTION") - - begin - yield @baza - @baza.q("COMMIT") - rescue - @baza.q("ROLLBACK") - raise - end - end -end +class Baza::Driver::Mysql < Baza::MysqlBaseDriver + path = "#{File.dirname(__FILE__)}/mysql" + + autoload :Database, "#{path}/database" + autoload :Databases, "#{path}/databases" + autoload :Table, "#{path}/table" + autoload :Tables, "#{path}/tables" + autoload :Column, "#{path}/column" + autoload :Columns, "#{path}/columns" + autoload :Index, "#{path}/index" + autoload :Indexes, "#{path}/indexes" + autoload :Result, "#{path}/result" + autoload :UnbufferedResult, "#{path}/unbuffered_result" + autoload :Sqlspecs, "#{path}/sqlspecs" + + attr_reader :conn + + def self.from_object(args) + raise "Mysql does not support auth extraction" if args[:object].class.name == "Mysql" + end + + def initialize(baza) + super + + @opts = @baza.opts + + require "monitor" + @mutex = Monitor.new + + if baza.opts[:conn] + @conn = baza.opts[:conn] + else + if @opts[:encoding] + @encoding = @opts[:encoding] + else + @encoding = "utf8" + end + + if @baza.opts.key?(:port) + @port = @baza.opts[:port].to_i + else + @port = 3306 + end + + reconnect + end + end + + # Cleans the wref-map holding the tables. + def clean + tables.clean if tables + end + + # Respawns the connection to the MySQL-database. + def reconnect + @mutex.synchronize do + require "mysql" unless ::Object.const_defined?(:Mysql) + @conn = ::Mysql.real_connect(@baza.opts[:host], @baza.opts[:user], @baza.opts[:pass], @baza.opts[:db], @port) + query("SET NAMES '#{esc(@encoding)}'") if @encoding + end + end + + # Executes a query and returns the result. + def query(str) + str = str.to_s + str = str.force_encoding("UTF-8") if @encoding == "utf8" && str.respond_to?(:force_encoding) + tries = 0 + + begin + tries += 1 + @mutex.synchronize do + return Baza::Driver::Mysql::Result.new(self, @conn.query(str)) + end + rescue => e + if tries <= 3 + if e.message == "MySQL server has gone away" || e.message == "closed MySQL connection" || e.message == "Can't connect to local MySQL server through socket" + sleep 0.5 + reconnect + retry + elsif e.message.include?("No operations allowed after connection closed") || e.message == "This connection is still waiting for a result, try again once you have the result" || e.message == "Lock wait timeout exceeded; try restarting transaction" + reconnect + retry + end + end + + raise e + end + end + + # Executes an unbuffered query and returns the result that can be used to access the data. + def query_ubuf(str) + @mutex.synchronize do + @conn.query_with_result = false + return Baza::Driver::Mysql::UnbufferedResult.new(@conn, @opts, @conn.query(str)) + end + end + + # Escapes a string to be safe to use in a query. + def escape_alternative(string) + @conn.escape_string(string.to_s) + end + + # Returns the last inserted ID for the connection. + def last_id + @mutex.synchronize { return @conn.insert_id.to_i } + end + + # Closes the connection threadsafe. + def close + @mutex.synchronize { @conn.close } + end + + # Destroyes the connection. + def destroy + @conn = nil + @baza = nil + @mutex = nil + @subtype = nil + @encoding = nil + @query_args = nil + @port = nil + end + + def supports_multiple_databases? + true + end +end