mysql2_bigint 0.2.6.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/CHANGELOG.md +120 -0
- data/Gemfile +3 -0
- data/MIT-LICENSE +20 -0
- data/README.rdoc +248 -0
- data/Rakefile +5 -0
- data/benchmark/active_record.rb +51 -0
- data/benchmark/allocations.rb +33 -0
- data/benchmark/escape.rb +36 -0
- data/benchmark/query_with_mysql_casting.rb +80 -0
- data/benchmark/query_without_mysql_casting.rb +47 -0
- data/benchmark/sequel.rb +37 -0
- data/benchmark/setup_db.rb +119 -0
- data/examples/eventmachine.rb +21 -0
- data/examples/threaded.rb +20 -0
- data/ext/mysql2/client.c +768 -0
- data/ext/mysql2/client.h +41 -0
- data/ext/mysql2/extconf.rb +69 -0
- data/ext/mysql2/mysql2_ext.c +12 -0
- data/ext/mysql2/mysql2_ext.h +38 -0
- data/ext/mysql2/result.c +488 -0
- data/ext/mysql2/result.h +20 -0
- data/lib/active_record/connection_adapters/em_mysql2_adapter.rb +64 -0
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +654 -0
- data/lib/active_record/fiber_patches.rb +104 -0
- data/lib/arel/engines/sql/compilers/mysql2_compiler.rb +11 -0
- data/lib/mysql2.rb +16 -0
- data/lib/mysql2/client.rb +240 -0
- data/lib/mysql2/em.rb +37 -0
- data/lib/mysql2/em_fiber.rb +31 -0
- data/lib/mysql2/error.rb +15 -0
- data/lib/mysql2/result.rb +5 -0
- data/lib/mysql2/version.rb +3 -0
- data/lib/mysql2_bigint.rb +1 -0
- data/mysql2_bigint.gemspec +32 -0
- data/spec/em/em_fiber_spec.rb +22 -0
- data/spec/em/em_spec.rb +49 -0
- data/spec/mysql2/client_spec.rb +385 -0
- data/spec/mysql2/error_spec.rb +25 -0
- data/spec/mysql2/result_spec.rb +328 -0
- data/spec/rcov.opts +3 -0
- data/spec/spec_helper.rb +66 -0
- data/tasks/benchmarks.rake +20 -0
- data/tasks/compile.rake +53 -0
- data/tasks/rspec.rake +16 -0
- data/tasks/vendor_mysql.rake +41 -0
- metadata +199 -0
| @@ -0,0 +1,33 @@ | |
| 1 | 
            +
            # encoding: UTF-8
         | 
| 2 | 
            +
            $LOAD_PATH.unshift File.expand_path(File.dirname(__FILE__) + '/../lib')
         | 
| 3 | 
            +
             | 
| 4 | 
            +
            raise Mysql2::Mysql2Error.new("GC allocation benchmarks only supported on Ruby 1.9!") unless RUBY_VERSION =~ /1\.9/
         | 
| 5 | 
            +
             | 
| 6 | 
            +
            require 'rubygems'
         | 
| 7 | 
            +
            require 'benchmark'
         | 
| 8 | 
            +
            require 'active_record'
         | 
| 9 | 
            +
             | 
| 10 | 
            +
            ActiveRecord::Base.default_timezone = :local
         | 
| 11 | 
            +
            ActiveRecord::Base.time_zone_aware_attributes = true
         | 
| 12 | 
            +
             | 
| 13 | 
            +
            class Mysql2Model < ActiveRecord::Base
         | 
| 14 | 
            +
              set_table_name :mysql2_test
         | 
| 15 | 
            +
            end
         | 
| 16 | 
            +
             | 
| 17 | 
            +
            def bench_allocations(feature, iterations = 10, &blk)
         | 
| 18 | 
            +
              puts "GC overhead for #{feature}"
         | 
| 19 | 
            +
              Mysql2Model.establish_connection(:adapter => 'mysql2', :database => 'test')
         | 
| 20 | 
            +
              GC::Profiler.clear
         | 
| 21 | 
            +
              GC::Profiler.enable
         | 
| 22 | 
            +
              iterations.times{ blk.call }
         | 
| 23 | 
            +
              GC::Profiler.report(STDOUT)
         | 
| 24 | 
            +
              GC::Profiler.disable
         | 
| 25 | 
            +
            end
         | 
| 26 | 
            +
             | 
| 27 | 
            +
            bench_allocations('coercion') do
         | 
| 28 | 
            +
              Mysql2Model.all(:limit => 1000).each{ |r|
         | 
| 29 | 
            +
                r.attributes.keys.each{ |k|
         | 
| 30 | 
            +
                  r.send(k.to_sym)
         | 
| 31 | 
            +
                }
         | 
| 32 | 
            +
              }
         | 
| 33 | 
            +
            end
         | 
    
        data/benchmark/escape.rb
    ADDED
    
    | @@ -0,0 +1,36 @@ | |
| 1 | 
            +
            # encoding: UTF-8
         | 
| 2 | 
            +
            $LOAD_PATH.unshift File.expand_path(File.dirname(__FILE__) + '/../lib')
         | 
| 3 | 
            +
             | 
| 4 | 
            +
            require 'rubygems'
         | 
| 5 | 
            +
            require 'benchmark'
         | 
| 6 | 
            +
            require 'mysql'
         | 
| 7 | 
            +
            require 'mysql2'
         | 
| 8 | 
            +
            require 'do_mysql'
         | 
| 9 | 
            +
             | 
| 10 | 
            +
            def run_escape_benchmarks(str, number_of = 1000)
         | 
| 11 | 
            +
              Benchmark.bmbm do |x|
         | 
| 12 | 
            +
                mysql = Mysql.new("localhost", "root")
         | 
| 13 | 
            +
                x.report "Mysql #{str.inspect}" do
         | 
| 14 | 
            +
                  number_of.times do
         | 
| 15 | 
            +
                    mysql.quote str
         | 
| 16 | 
            +
                  end
         | 
| 17 | 
            +
                end
         | 
| 18 | 
            +
             | 
| 19 | 
            +
                mysql2 = Mysql2::Client.new(:host => "localhost", :username => "root")
         | 
| 20 | 
            +
                x.report "Mysql2 #{str.inspect}" do
         | 
| 21 | 
            +
                  number_of.times do
         | 
| 22 | 
            +
                    mysql2.escape str
         | 
| 23 | 
            +
                  end
         | 
| 24 | 
            +
                end
         | 
| 25 | 
            +
             | 
| 26 | 
            +
                do_mysql = DataObjects::Connection.new("mysql://localhost/test")
         | 
| 27 | 
            +
                x.report "do_mysql #{str.inspect}" do
         | 
| 28 | 
            +
                  number_of.times do
         | 
| 29 | 
            +
                    do_mysql.quote_string str
         | 
| 30 | 
            +
                  end
         | 
| 31 | 
            +
                end
         | 
| 32 | 
            +
              end
         | 
| 33 | 
            +
            end
         | 
| 34 | 
            +
             | 
| 35 | 
            +
            run_escape_benchmarks "abc'def\"ghi\0jkl%mno"
         | 
| 36 | 
            +
            run_escape_benchmarks "clean string"
         | 
| @@ -0,0 +1,80 @@ | |
| 1 | 
            +
            # encoding: UTF-8
         | 
| 2 | 
            +
            $LOAD_PATH.unshift File.expand_path(File.dirname(__FILE__) + '/../lib')
         | 
| 3 | 
            +
             | 
| 4 | 
            +
            require 'rubygems'
         | 
| 5 | 
            +
            require 'benchmark'
         | 
| 6 | 
            +
            require 'mysql'
         | 
| 7 | 
            +
            require 'mysql2'
         | 
| 8 | 
            +
            require 'do_mysql'
         | 
| 9 | 
            +
             | 
| 10 | 
            +
            number_of = 100
         | 
| 11 | 
            +
            database = 'test'
         | 
| 12 | 
            +
            sql = "SELECT * FROM mysql2_test LIMIT 100"
         | 
| 13 | 
            +
             | 
| 14 | 
            +
            class Mysql
         | 
| 15 | 
            +
              include Enumerable
         | 
| 16 | 
            +
            end
         | 
| 17 | 
            +
             | 
| 18 | 
            +
            def mysql_cast(type, value)
         | 
| 19 | 
            +
              case type
         | 
| 20 | 
            +
                when Mysql::Field::TYPE_NULL
         | 
| 21 | 
            +
                  nil
         | 
| 22 | 
            +
                when Mysql::Field::TYPE_TINY, Mysql::Field::TYPE_SHORT, Mysql::Field::TYPE_LONG,
         | 
| 23 | 
            +
                     Mysql::Field::TYPE_INT24, Mysql::Field::TYPE_LONGLONG, Mysql::Field::TYPE_YEAR
         | 
| 24 | 
            +
                  value.to_i
         | 
| 25 | 
            +
                when Mysql::Field::TYPE_DECIMAL, Mysql::Field::TYPE_NEWDECIMAL
         | 
| 26 | 
            +
                  BigDecimal.new(value)
         | 
| 27 | 
            +
                when Mysql::Field::TYPE_DOUBLE, Mysql::Field::TYPE_FLOAT
         | 
| 28 | 
            +
                  value.to_f
         | 
| 29 | 
            +
                when Mysql::Field::TYPE_DATE
         | 
| 30 | 
            +
                  Date.parse(value)
         | 
| 31 | 
            +
                when Mysql::Field::TYPE_TIME, Mysql::Field::TYPE_DATETIME, Mysql::Field::TYPE_TIMESTAMP
         | 
| 32 | 
            +
                  Time.parse(value)
         | 
| 33 | 
            +
                when Mysql::Field::TYPE_BLOB, Mysql::Field::TYPE_BIT, Mysql::Field::TYPE_STRING,
         | 
| 34 | 
            +
                     Mysql::Field::TYPE_VAR_STRING, Mysql::Field::TYPE_CHAR, Mysql::Field::TYPE_SET
         | 
| 35 | 
            +
                     Mysql::Field::TYPE_ENUM
         | 
| 36 | 
            +
                  value
         | 
| 37 | 
            +
                else
         | 
| 38 | 
            +
                  value
         | 
| 39 | 
            +
              end
         | 
| 40 | 
            +
            end
         | 
| 41 | 
            +
             | 
| 42 | 
            +
            Benchmark.bmbm do |x|
         | 
| 43 | 
            +
              mysql2 = Mysql2::Client.new(:host => "localhost", :username => "root")
         | 
| 44 | 
            +
              mysql2.query "USE #{database}"
         | 
| 45 | 
            +
              x.report "Mysql2" do
         | 
| 46 | 
            +
                number_of.times do
         | 
| 47 | 
            +
                  mysql2_result = mysql2.query sql, :symbolize_keys => true
         | 
| 48 | 
            +
                  mysql2_result.each do |res|
         | 
| 49 | 
            +
                    # puts res.inspect
         | 
| 50 | 
            +
                  end
         | 
| 51 | 
            +
                end
         | 
| 52 | 
            +
              end
         | 
| 53 | 
            +
             | 
| 54 | 
            +
              mysql = Mysql.new("localhost", "root")
         | 
| 55 | 
            +
              mysql.query "USE #{database}"
         | 
| 56 | 
            +
              x.report "Mysql" do
         | 
| 57 | 
            +
                number_of.times do
         | 
| 58 | 
            +
                  mysql_result = mysql.query sql
         | 
| 59 | 
            +
                  fields = mysql_result.fetch_fields
         | 
| 60 | 
            +
                  mysql_result.each do |row|
         | 
| 61 | 
            +
                    row_hash = {}
         | 
| 62 | 
            +
                    row.each_with_index do |f, j|
         | 
| 63 | 
            +
                      row_hash[fields[j].name.to_sym] = mysql_cast(fields[j].type, row[j])
         | 
| 64 | 
            +
                    end
         | 
| 65 | 
            +
                    # puts row_hash.inspect
         | 
| 66 | 
            +
                  end
         | 
| 67 | 
            +
                end
         | 
| 68 | 
            +
              end
         | 
| 69 | 
            +
             | 
| 70 | 
            +
              do_mysql = DataObjects::Connection.new("mysql://localhost/#{database}")
         | 
| 71 | 
            +
              command = do_mysql.create_command sql
         | 
| 72 | 
            +
              x.report "do_mysql" do
         | 
| 73 | 
            +
                number_of.times do
         | 
| 74 | 
            +
                  do_result = command.execute_reader
         | 
| 75 | 
            +
                  do_result.each do |res|
         | 
| 76 | 
            +
                    # puts res.inspect
         | 
| 77 | 
            +
                  end
         | 
| 78 | 
            +
                end
         | 
| 79 | 
            +
              end
         | 
| 80 | 
            +
            end
         | 
| @@ -0,0 +1,47 @@ | |
| 1 | 
            +
            # encoding: UTF-8
         | 
| 2 | 
            +
            $LOAD_PATH.unshift File.expand_path(File.dirname(__FILE__) + '/../lib')
         | 
| 3 | 
            +
             | 
| 4 | 
            +
            require 'rubygems'
         | 
| 5 | 
            +
            require 'benchmark'
         | 
| 6 | 
            +
            require 'mysql'
         | 
| 7 | 
            +
            require 'mysql2'
         | 
| 8 | 
            +
            require 'do_mysql'
         | 
| 9 | 
            +
             | 
| 10 | 
            +
            number_of = 100
         | 
| 11 | 
            +
            database = 'test'
         | 
| 12 | 
            +
            sql = "SELECT * FROM mysql2_test LIMIT 100"
         | 
| 13 | 
            +
             | 
| 14 | 
            +
            Benchmark.bmbm do |x|
         | 
| 15 | 
            +
              mysql2 = Mysql2::Client.new(:host => "localhost", :username => "root")
         | 
| 16 | 
            +
              mysql2.query "USE #{database}"
         | 
| 17 | 
            +
              x.report "Mysql2" do
         | 
| 18 | 
            +
                number_of.times do
         | 
| 19 | 
            +
                  mysql2_result = mysql2.query sql, :symbolize_keys => true
         | 
| 20 | 
            +
                  mysql2_result.each do |res|
         | 
| 21 | 
            +
                    # puts res.inspect
         | 
| 22 | 
            +
                  end
         | 
| 23 | 
            +
                end
         | 
| 24 | 
            +
              end
         | 
| 25 | 
            +
             | 
| 26 | 
            +
              mysql = Mysql.new("localhost", "root")
         | 
| 27 | 
            +
              mysql.query "USE #{database}"
         | 
| 28 | 
            +
              x.report "Mysql" do
         | 
| 29 | 
            +
                number_of.times do
         | 
| 30 | 
            +
                  mysql_result = mysql.query sql
         | 
| 31 | 
            +
                  mysql_result.each_hash do |res|
         | 
| 32 | 
            +
                    # puts res.inspect
         | 
| 33 | 
            +
                  end
         | 
| 34 | 
            +
                end
         | 
| 35 | 
            +
              end
         | 
| 36 | 
            +
             | 
| 37 | 
            +
              do_mysql = DataObjects::Connection.new("mysql://localhost/#{database}")
         | 
| 38 | 
            +
              command = DataObjects::Mysql::Command.new do_mysql, sql
         | 
| 39 | 
            +
              x.report "do_mysql" do
         | 
| 40 | 
            +
                number_of.times do
         | 
| 41 | 
            +
                  do_result = command.execute_reader
         | 
| 42 | 
            +
                  do_result.each do |res|
         | 
| 43 | 
            +
                    # puts res.inspect
         | 
| 44 | 
            +
                  end
         | 
| 45 | 
            +
                end
         | 
| 46 | 
            +
              end
         | 
| 47 | 
            +
            end
         | 
    
        data/benchmark/sequel.rb
    ADDED
    
    | @@ -0,0 +1,37 @@ | |
| 1 | 
            +
            # encoding: UTF-8
         | 
| 2 | 
            +
            $LOAD_PATH.unshift File.expand_path(File.dirname(__FILE__) + '/../lib')
         | 
| 3 | 
            +
             | 
| 4 | 
            +
            require 'rubygems'
         | 
| 5 | 
            +
            require 'benchmark'
         | 
| 6 | 
            +
            require 'mysql2'
         | 
| 7 | 
            +
            require 'sequel'
         | 
| 8 | 
            +
            require 'sequel/adapters/do'
         | 
| 9 | 
            +
             | 
| 10 | 
            +
            number_of = 10
         | 
| 11 | 
            +
            mysql2_opts = "mysql2://localhost/test"
         | 
| 12 | 
            +
            mysql_opts = "mysql://localhost/test"
         | 
| 13 | 
            +
            do_mysql_opts = "do:mysql://localhost/test"
         | 
| 14 | 
            +
             | 
| 15 | 
            +
            class Mysql2Model < Sequel::Model(Sequel.connect(mysql2_opts)[:mysql2_test]); end
         | 
| 16 | 
            +
            class MysqlModel < Sequel::Model(Sequel.connect(mysql_opts)[:mysql2_test]); end
         | 
| 17 | 
            +
            class DOMysqlModel < Sequel::Model(Sequel.connect(do_mysql_opts)[:mysql2_test]); end
         | 
| 18 | 
            +
             | 
| 19 | 
            +
            Benchmark.bmbm do |x|
         | 
| 20 | 
            +
              x.report "Mysql2" do
         | 
| 21 | 
            +
                number_of.times do
         | 
| 22 | 
            +
                  Mysql2Model.limit(1000).all
         | 
| 23 | 
            +
                end
         | 
| 24 | 
            +
              end
         | 
| 25 | 
            +
             | 
| 26 | 
            +
              x.report "do:mysql" do
         | 
| 27 | 
            +
                number_of.times do
         | 
| 28 | 
            +
                  DOMysqlModel.limit(1000).all
         | 
| 29 | 
            +
                end
         | 
| 30 | 
            +
              end
         | 
| 31 | 
            +
             | 
| 32 | 
            +
              x.report "Mysql" do
         | 
| 33 | 
            +
                number_of.times do
         | 
| 34 | 
            +
                  MysqlModel.limit(1000).all
         | 
| 35 | 
            +
                end
         | 
| 36 | 
            +
              end
         | 
| 37 | 
            +
            end
         | 
| @@ -0,0 +1,119 @@ | |
| 1 | 
            +
            # encoding: UTF-8
         | 
| 2 | 
            +
            $LOAD_PATH.unshift File.expand_path(File.dirname(__FILE__) + '/../lib')
         | 
| 3 | 
            +
             | 
| 4 | 
            +
            # This script is for generating psudo-random data into a single table consisting of nearly every
         | 
| 5 | 
            +
            # data type MySQL 5.1 supports.
         | 
| 6 | 
            +
            #
         | 
| 7 | 
            +
            # It's meant to be used with the query.rb benchmark script (or others in the future)
         | 
| 8 | 
            +
             | 
| 9 | 
            +
            require 'mysql2'
         | 
| 10 | 
            +
            require 'rubygems'
         | 
| 11 | 
            +
            require 'faker'
         | 
| 12 | 
            +
             | 
| 13 | 
            +
            num = ENV['NUM'] && ENV['NUM'].to_i || 10_000
         | 
| 14 | 
            +
             | 
| 15 | 
            +
            create_table_sql = %[
         | 
| 16 | 
            +
              CREATE TABLE IF NOT EXISTS mysql2_test (
         | 
| 17 | 
            +
                null_test VARCHAR(10),
         | 
| 18 | 
            +
                bit_test BIT,
         | 
| 19 | 
            +
                tiny_int_test TINYINT,
         | 
| 20 | 
            +
                small_int_test SMALLINT,
         | 
| 21 | 
            +
                medium_int_test MEDIUMINT,
         | 
| 22 | 
            +
                int_test INT,
         | 
| 23 | 
            +
                big_int_test BIGINT,
         | 
| 24 | 
            +
                float_test FLOAT(10,3),
         | 
| 25 | 
            +
                float_zero_test FLOAT(10,3),
         | 
| 26 | 
            +
                double_test DOUBLE(10,3),
         | 
| 27 | 
            +
                decimal_test DECIMAL(10,3),
         | 
| 28 | 
            +
                decimal_zero_test DECIMAL(10,3),
         | 
| 29 | 
            +
                date_test DATE,
         | 
| 30 | 
            +
                date_time_test DATETIME,
         | 
| 31 | 
            +
                timestamp_test TIMESTAMP,
         | 
| 32 | 
            +
                time_test TIME,
         | 
| 33 | 
            +
                year_test YEAR(4),
         | 
| 34 | 
            +
                char_test CHAR(10),
         | 
| 35 | 
            +
                varchar_test VARCHAR(10),
         | 
| 36 | 
            +
                binary_test BINARY(10),
         | 
| 37 | 
            +
                varbinary_test VARBINARY(10),
         | 
| 38 | 
            +
                tiny_blob_test TINYBLOB,
         | 
| 39 | 
            +
                tiny_text_test TINYTEXT,
         | 
| 40 | 
            +
                blob_test BLOB,
         | 
| 41 | 
            +
                text_test TEXT,
         | 
| 42 | 
            +
                medium_blob_test MEDIUMBLOB,
         | 
| 43 | 
            +
                medium_text_test MEDIUMTEXT,
         | 
| 44 | 
            +
                long_blob_test LONGBLOB,
         | 
| 45 | 
            +
                long_text_test LONGTEXT,
         | 
| 46 | 
            +
                enum_test ENUM('val1', 'val2'),
         | 
| 47 | 
            +
                set_test SET('val1', 'val2')
         | 
| 48 | 
            +
              ) DEFAULT CHARSET=utf8
         | 
| 49 | 
            +
            ]
         | 
| 50 | 
            +
             | 
| 51 | 
            +
            # connect to localhost by default, pass options as needed
         | 
| 52 | 
            +
            @client = Mysql2::Client.new :host => "localhost", :username => "root", :database => "test"
         | 
| 53 | 
            +
             | 
| 54 | 
            +
            @client.query create_table_sql
         | 
| 55 | 
            +
             | 
| 56 | 
            +
            def insert_record(args)
         | 
| 57 | 
            +
              insert_sql = "
         | 
| 58 | 
            +
                INSERT INTO mysql2_test (
         | 
| 59 | 
            +
                  null_test, bit_test, tiny_int_test, small_int_test, medium_int_test, int_test, big_int_test,
         | 
| 60 | 
            +
                  float_test, float_zero_test, double_test, decimal_test, decimal_zero_test, date_test, date_time_test, timestamp_test, time_test,
         | 
| 61 | 
            +
                  year_test, char_test, varchar_test, binary_test, varbinary_test, tiny_blob_test,
         | 
| 62 | 
            +
                  tiny_text_test, blob_test, text_test, medium_blob_test, medium_text_test,
         | 
| 63 | 
            +
                  long_blob_test, long_text_test, enum_test, set_test
         | 
| 64 | 
            +
                )
         | 
| 65 | 
            +
             | 
| 66 | 
            +
                VALUES (
         | 
| 67 | 
            +
                  NULL, #{args[:bit_test]}, #{args[:tiny_int_test]}, #{args[:small_int_test]}, #{args[:medium_int_test]}, #{args[:int_test]}, #{args[:big_int_test]},
         | 
| 68 | 
            +
                  #{args[:float_test]}, #{args[:float_zero_test]}, #{args[:double_test]}, #{args[:decimal_test]}, #{args[:decimal_zero_test]}, '#{args[:date_test]}', '#{args[:date_time_test]}', '#{args[:timestamp_test]}', '#{args[:time_test]}',
         | 
| 69 | 
            +
                  #{args[:year_test]}, '#{args[:char_test]}', '#{args[:varchar_test]}', '#{args[:binary_test]}', '#{args[:varbinary_test]}', '#{args[:tiny_blob_test]}',
         | 
| 70 | 
            +
                  '#{args[:tiny_text_test]}', '#{args[:blob_test]}', '#{args[:text_test]}', '#{args[:medium_blob_test]}', '#{args[:medium_text_test]}',
         | 
| 71 | 
            +
                  '#{args[:long_blob_test]}', '#{args[:long_text_test]}', '#{args[:enum_test]}', '#{args[:set_test]}'
         | 
| 72 | 
            +
                )
         | 
| 73 | 
            +
              "
         | 
| 74 | 
            +
              @client.query insert_sql
         | 
| 75 | 
            +
            end
         | 
| 76 | 
            +
             | 
| 77 | 
            +
            puts "Creating #{num} records"
         | 
| 78 | 
            +
            num.times do |n|
         | 
| 79 | 
            +
              five_words = Faker::Lorem.words(rand(5))
         | 
| 80 | 
            +
              twenty5_paragraphs = Faker::Lorem.paragraphs(rand(25))
         | 
| 81 | 
            +
              insert_record(
         | 
| 82 | 
            +
                :bit_test => 1,
         | 
| 83 | 
            +
                :tiny_int_test => rand(128),
         | 
| 84 | 
            +
                :small_int_test => rand(32767),
         | 
| 85 | 
            +
                :medium_int_test => rand(8388607),
         | 
| 86 | 
            +
                :int_test => rand(2147483647),
         | 
| 87 | 
            +
                :big_int_test => rand(9223372036854775807),
         | 
| 88 | 
            +
                :float_test => rand(32767)/1.87,
         | 
| 89 | 
            +
                :float_zero_test => 0.0,
         | 
| 90 | 
            +
                :double_test => rand(8388607)/1.87,
         | 
| 91 | 
            +
                :decimal_test => rand(8388607)/1.87,
         | 
| 92 | 
            +
                :decimal_zero_test => 0,
         | 
| 93 | 
            +
                :date_test => '2010-4-4',
         | 
| 94 | 
            +
                :date_time_test => '2010-4-4 11:44:00',
         | 
| 95 | 
            +
                :timestamp_test => '2010-4-4 11:44:00',
         | 
| 96 | 
            +
                :time_test => '11:44:00',
         | 
| 97 | 
            +
                :year_test => Time.now.year,
         | 
| 98 | 
            +
                :char_test => five_words,
         | 
| 99 | 
            +
                :varchar_test => five_words,
         | 
| 100 | 
            +
                :binary_test => five_words,
         | 
| 101 | 
            +
                :varbinary_test => five_words,
         | 
| 102 | 
            +
                :tiny_blob_test => five_words,
         | 
| 103 | 
            +
                :tiny_text_test => Faker::Lorem.paragraph(rand(5)),
         | 
| 104 | 
            +
                :blob_test => twenty5_paragraphs,
         | 
| 105 | 
            +
                :text_test => twenty5_paragraphs,
         | 
| 106 | 
            +
                :medium_blob_test => twenty5_paragraphs,
         | 
| 107 | 
            +
                :medium_text_test => twenty5_paragraphs,
         | 
| 108 | 
            +
                :long_blob_test => twenty5_paragraphs,
         | 
| 109 | 
            +
                :long_text_test => twenty5_paragraphs,
         | 
| 110 | 
            +
                :enum_test => ['val1', 'val2'].rand,
         | 
| 111 | 
            +
                :set_test => ['val1', 'val2', 'val1,val2'].rand
         | 
| 112 | 
            +
              )
         | 
| 113 | 
            +
              if n % 100 == 0
         | 
| 114 | 
            +
                $stdout.putc '.'
         | 
| 115 | 
            +
                $stdout.flush
         | 
| 116 | 
            +
              end
         | 
| 117 | 
            +
            end
         | 
| 118 | 
            +
            puts
         | 
| 119 | 
            +
            puts "Done"
         | 
| @@ -0,0 +1,21 @@ | |
| 1 | 
            +
            # encoding: utf-8
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            $LOAD_PATH.unshift 'lib'
         | 
| 4 | 
            +
             | 
| 5 | 
            +
            require 'rubygems'
         | 
| 6 | 
            +
            require 'eventmachine'
         | 
| 7 | 
            +
            require 'mysql2/em'
         | 
| 8 | 
            +
             | 
| 9 | 
            +
            EM.run do
         | 
| 10 | 
            +
              client1 = Mysql2::EM::Client.new
         | 
| 11 | 
            +
              defer1 = client1.query "SELECT sleep(3) as first_query"
         | 
| 12 | 
            +
              defer1.callback do |result|
         | 
| 13 | 
            +
                puts "Result: #{result.to_a.inspect}"
         | 
| 14 | 
            +
              end
         | 
| 15 | 
            +
             | 
| 16 | 
            +
              client2 = Mysql2::EM::Client.new
         | 
| 17 | 
            +
              defer2 = client2.query "SELECT sleep(1) second_query"
         | 
| 18 | 
            +
              defer2.callback do |result|
         | 
| 19 | 
            +
                puts "Result: #{result.to_a.inspect}"
         | 
| 20 | 
            +
              end
         | 
| 21 | 
            +
            end
         | 
| @@ -0,0 +1,20 @@ | |
| 1 | 
            +
            # encoding: utf-8
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            $LOAD_PATH.unshift 'lib'
         | 
| 4 | 
            +
            require 'mysql2'
         | 
| 5 | 
            +
            require 'timeout'
         | 
| 6 | 
            +
             | 
| 7 | 
            +
            threads = []
         | 
| 8 | 
            +
            # Should never exceed worst case 3.5 secs across all 20 threads
         | 
| 9 | 
            +
            Timeout.timeout(3.5) do
         | 
| 10 | 
            +
              20.times do
         | 
| 11 | 
            +
                threads << Thread.new do
         | 
| 12 | 
            +
                  overhead = rand(3)
         | 
| 13 | 
            +
                  puts ">> thread #{Thread.current.object_id} query, #{overhead} sec overhead"
         | 
| 14 | 
            +
                  # 3 second overhead per query
         | 
| 15 | 
            +
                  Mysql2::Client.new(:host => "localhost", :username => "root").query("SELECT sleep(#{overhead}) as result")
         | 
| 16 | 
            +
                  puts "<< thread #{Thread.current.object_id} result, #{overhead} sec overhead"
         | 
| 17 | 
            +
                end
         | 
| 18 | 
            +
              end
         | 
| 19 | 
            +
              threads.each{|t| t.join }
         | 
| 20 | 
            +
            end
         | 
    
        data/ext/mysql2/client.c
    ADDED
    
    | @@ -0,0 +1,768 @@ | |
| 1 | 
            +
            #include <mysql2_ext.h>
         | 
| 2 | 
            +
            #include <client.h>
         | 
| 3 | 
            +
            #include <errno.h>
         | 
| 4 | 
            +
             | 
| 5 | 
            +
            VALUE cMysql2Client;
         | 
| 6 | 
            +
            extern VALUE mMysql2, cMysql2Error;
         | 
| 7 | 
            +
            static VALUE intern_encoding_from_charset;
         | 
| 8 | 
            +
            static ID sym_id, sym_version, sym_async, sym_symbolize_keys, sym_as, sym_array;
         | 
| 9 | 
            +
            static ID intern_merge, intern_error_number_eql, intern_sql_state_eql;
         | 
| 10 | 
            +
             | 
| 11 | 
            +
            #define REQUIRE_OPEN_DB(wrapper) \
         | 
| 12 | 
            +
              if(wrapper->closed) { \
         | 
| 13 | 
            +
                rb_raise(cMysql2Error, "closed MySQL connection"); \
         | 
| 14 | 
            +
              }
         | 
| 15 | 
            +
             | 
| 16 | 
            +
            #define MARK_CONN_INACTIVE(conn) \
         | 
| 17 | 
            +
              wrapper->active = 0
         | 
| 18 | 
            +
             | 
| 19 | 
            +
            #define GET_CLIENT(self) \
         | 
| 20 | 
            +
              mysql_client_wrapper *wrapper; \
         | 
| 21 | 
            +
              Data_Get_Struct(self, mysql_client_wrapper, wrapper)
         | 
| 22 | 
            +
             | 
| 23 | 
            +
            /*
         | 
| 24 | 
            +
             * used to pass all arguments to mysql_real_connect while inside
         | 
| 25 | 
            +
             * rb_thread_blocking_region
         | 
| 26 | 
            +
             */
         | 
| 27 | 
            +
            struct nogvl_connect_args {
         | 
| 28 | 
            +
              MYSQL *mysql;
         | 
| 29 | 
            +
              const char *host;
         | 
| 30 | 
            +
              const char *user;
         | 
| 31 | 
            +
              const char *passwd;
         | 
| 32 | 
            +
              const char *db;
         | 
| 33 | 
            +
              unsigned int port;
         | 
| 34 | 
            +
              const char *unix_socket;
         | 
| 35 | 
            +
              unsigned long client_flag;
         | 
| 36 | 
            +
            };
         | 
| 37 | 
            +
             | 
| 38 | 
            +
            /*
         | 
| 39 | 
            +
             * used to pass all arguments to mysql_send_query while inside
         | 
| 40 | 
            +
             * rb_thread_blocking_region
         | 
| 41 | 
            +
             */
         | 
| 42 | 
            +
            struct nogvl_send_query_args {
         | 
| 43 | 
            +
              MYSQL *mysql;
         | 
| 44 | 
            +
              VALUE sql;
         | 
| 45 | 
            +
            };
         | 
| 46 | 
            +
             | 
| 47 | 
            +
            /*
         | 
| 48 | 
            +
             * non-blocking mysql_*() functions that we won't be wrapping since
         | 
| 49 | 
            +
             * they do not appear to hit the network nor issue any interruptible
         | 
| 50 | 
            +
             * or blocking system calls.
         | 
| 51 | 
            +
             *
         | 
| 52 | 
            +
             * - mysql_affected_rows()
         | 
| 53 | 
            +
             * - mysql_error()
         | 
| 54 | 
            +
             * - mysql_fetch_fields()
         | 
| 55 | 
            +
             * - mysql_fetch_lengths() - calls cli_fetch_lengths or emb_fetch_lengths
         | 
| 56 | 
            +
             * - mysql_field_count()
         | 
| 57 | 
            +
             * - mysql_get_client_info()
         | 
| 58 | 
            +
             * - mysql_get_client_version()
         | 
| 59 | 
            +
             * - mysql_get_server_info()
         | 
| 60 | 
            +
             * - mysql_get_server_version()
         | 
| 61 | 
            +
             * - mysql_insert_id()
         | 
| 62 | 
            +
             * - mysql_num_fields()
         | 
| 63 | 
            +
             * - mysql_num_rows()
         | 
| 64 | 
            +
             * - mysql_options()
         | 
| 65 | 
            +
             * - mysql_real_escape_string()
         | 
| 66 | 
            +
             * - mysql_ssl_set()
         | 
| 67 | 
            +
             */
         | 
| 68 | 
            +
             | 
| 69 | 
            +
            static void rb_mysql_client_mark(void * wrapper) {
         | 
| 70 | 
            +
              mysql_client_wrapper * w = wrapper;
         | 
| 71 | 
            +
              if (w) {
         | 
| 72 | 
            +
                rb_gc_mark(w->encoding);
         | 
| 73 | 
            +
              }
         | 
| 74 | 
            +
            }
         | 
| 75 | 
            +
             | 
| 76 | 
            +
            static VALUE rb_raise_mysql2_error(MYSQL *client) {
         | 
| 77 | 
            +
              VALUE e = rb_exc_new2(cMysql2Error, mysql_error(client));
         | 
| 78 | 
            +
              rb_funcall(e, intern_error_number_eql, 1, UINT2NUM(mysql_errno(client)));
         | 
| 79 | 
            +
              rb_funcall(e, intern_sql_state_eql, 1, rb_tainted_str_new2(mysql_sqlstate(client)));
         | 
| 80 | 
            +
              rb_exc_raise(e);
         | 
| 81 | 
            +
              return Qnil;
         | 
| 82 | 
            +
            }
         | 
| 83 | 
            +
             | 
| 84 | 
            +
            static VALUE nogvl_init(void *ptr) {
         | 
| 85 | 
            +
              MYSQL *client;
         | 
| 86 | 
            +
             | 
| 87 | 
            +
              /* may initialize embedded server and read /etc/services off disk */
         | 
| 88 | 
            +
              client = mysql_init((MYSQL *)ptr);
         | 
| 89 | 
            +
              return client ? Qtrue : Qfalse;
         | 
| 90 | 
            +
            }
         | 
| 91 | 
            +
             | 
| 92 | 
            +
            static VALUE nogvl_connect(void *ptr) {
         | 
| 93 | 
            +
              struct nogvl_connect_args *args = ptr;
         | 
| 94 | 
            +
              MYSQL *client;
         | 
| 95 | 
            +
             | 
| 96 | 
            +
              do {
         | 
| 97 | 
            +
                client = mysql_real_connect(args->mysql, args->host,
         | 
| 98 | 
            +
                                            args->user, args->passwd,
         | 
| 99 | 
            +
                                            args->db, args->port, args->unix_socket,
         | 
| 100 | 
            +
                                            args->client_flag);
         | 
| 101 | 
            +
              } while (! client && errno == EINTR && (errno = 0) == 0);
         | 
| 102 | 
            +
             | 
| 103 | 
            +
              return client ? Qtrue : Qfalse;
         | 
| 104 | 
            +
            }
         | 
| 105 | 
            +
             | 
| 106 | 
            +
            static VALUE nogvl_close(void *ptr) {
         | 
| 107 | 
            +
              mysql_client_wrapper *wrapper;
         | 
| 108 | 
            +
            #ifndef _WIN32
         | 
| 109 | 
            +
              int flags;
         | 
| 110 | 
            +
            #endif
         | 
| 111 | 
            +
              wrapper = ptr;
         | 
| 112 | 
            +
              if (!wrapper->closed) {
         | 
| 113 | 
            +
                wrapper->closed = 1;
         | 
| 114 | 
            +
             | 
| 115 | 
            +
                /*
         | 
| 116 | 
            +
                 * we'll send a QUIT message to the server, but that message is more of a
         | 
| 117 | 
            +
                 * formality than a hard requirement since the socket is getting shutdown
         | 
| 118 | 
            +
                 * anyways, so ensure the socket write does not block our interpreter
         | 
| 119 | 
            +
                 *
         | 
| 120 | 
            +
                 *
         | 
| 121 | 
            +
                 * if the socket is dead we have no chance of blocking,
         | 
| 122 | 
            +
                 * so ignore any potential fcntl errors since they don't matter
         | 
| 123 | 
            +
                 */
         | 
| 124 | 
            +
            #ifndef _WIN32
         | 
| 125 | 
            +
                flags = fcntl(wrapper->client->net.fd, F_GETFL);
         | 
| 126 | 
            +
                if (flags > 0 && !(flags & O_NONBLOCK))
         | 
| 127 | 
            +
                  fcntl(wrapper->client->net.fd, F_SETFL, flags | O_NONBLOCK);
         | 
| 128 | 
            +
            #else
         | 
| 129 | 
            +
                u_long iMode;
         | 
| 130 | 
            +
                iMode = 1;
         | 
| 131 | 
            +
                ioctlsocket(wrapper->client->net.fd, FIONBIO, &iMode);
         | 
| 132 | 
            +
            #endif
         | 
| 133 | 
            +
             | 
| 134 | 
            +
                mysql_close(wrapper->client);
         | 
| 135 | 
            +
                free(wrapper->client);
         | 
| 136 | 
            +
              }
         | 
| 137 | 
            +
             | 
| 138 | 
            +
              return Qnil;
         | 
| 139 | 
            +
            }
         | 
| 140 | 
            +
             | 
| 141 | 
            +
            static void rb_mysql_client_free(void * ptr) {
         | 
| 142 | 
            +
              mysql_client_wrapper *wrapper = (mysql_client_wrapper *)ptr;
         | 
| 143 | 
            +
             | 
| 144 | 
            +
              nogvl_close(wrapper);
         | 
| 145 | 
            +
             | 
| 146 | 
            +
              xfree(ptr);
         | 
| 147 | 
            +
            }
         | 
| 148 | 
            +
             | 
| 149 | 
            +
            static VALUE allocate(VALUE klass) {
         | 
| 150 | 
            +
              VALUE obj;
         | 
| 151 | 
            +
              mysql_client_wrapper * wrapper;
         | 
| 152 | 
            +
              obj = Data_Make_Struct(klass, mysql_client_wrapper, rb_mysql_client_mark, rb_mysql_client_free, wrapper);
         | 
| 153 | 
            +
              wrapper->encoding = Qnil;
         | 
| 154 | 
            +
              wrapper->active = 0;
         | 
| 155 | 
            +
              wrapper->closed = 1;
         | 
| 156 | 
            +
              wrapper->client = (MYSQL*)malloc(sizeof(MYSQL));
         | 
| 157 | 
            +
              return obj;
         | 
| 158 | 
            +
            }
         | 
| 159 | 
            +
             | 
| 160 | 
            +
            static VALUE rb_connect(VALUE self, VALUE user, VALUE pass, VALUE host, VALUE port, VALUE database, VALUE socket, VALUE flags) {
         | 
| 161 | 
            +
              struct nogvl_connect_args args;
         | 
| 162 | 
            +
              GET_CLIENT(self);
         | 
| 163 | 
            +
             | 
| 164 | 
            +
              args.host = NIL_P(host) ? "localhost" : StringValuePtr(host);
         | 
| 165 | 
            +
              args.unix_socket = NIL_P(socket) ? NULL : StringValuePtr(socket);
         | 
| 166 | 
            +
              args.port = NIL_P(port) ? 3306 : NUM2INT(port);
         | 
| 167 | 
            +
              args.user = NIL_P(user) ? NULL : StringValuePtr(user);
         | 
| 168 | 
            +
              args.passwd = NIL_P(pass) ? NULL : StringValuePtr(pass);
         | 
| 169 | 
            +
              args.db = NIL_P(database) ? NULL : StringValuePtr(database);
         | 
| 170 | 
            +
              args.mysql = wrapper->client;
         | 
| 171 | 
            +
              args.client_flag = NUM2ULONG(flags);
         | 
| 172 | 
            +
             | 
| 173 | 
            +
              if (rb_thread_blocking_region(nogvl_connect, &args, RUBY_UBF_IO, 0) == Qfalse) {
         | 
| 174 | 
            +
                // unable to connect
         | 
| 175 | 
            +
                return rb_raise_mysql2_error(wrapper->client);
         | 
| 176 | 
            +
              }
         | 
| 177 | 
            +
             | 
| 178 | 
            +
              return self;
         | 
| 179 | 
            +
            }
         | 
| 180 | 
            +
             | 
| 181 | 
            +
            /*
         | 
| 182 | 
            +
             * Immediately disconnect from the server, normally the garbage collector
         | 
| 183 | 
            +
             * will disconnect automatically when a connection is no longer needed.
         | 
| 184 | 
            +
             * Explicitly closing this will free up server resources sooner than waiting
         | 
| 185 | 
            +
             * for the garbage collector.
         | 
| 186 | 
            +
             */
         | 
| 187 | 
            +
            static VALUE rb_mysql_client_close(VALUE self) {
         | 
| 188 | 
            +
              GET_CLIENT(self);
         | 
| 189 | 
            +
             | 
| 190 | 
            +
              if (!wrapper->closed) {
         | 
| 191 | 
            +
                rb_thread_blocking_region(nogvl_close, wrapper, RUBY_UBF_IO, 0);
         | 
| 192 | 
            +
              }
         | 
| 193 | 
            +
             | 
| 194 | 
            +
              return Qnil;
         | 
| 195 | 
            +
            }
         | 
| 196 | 
            +
             | 
| 197 | 
            +
            /*
         | 
| 198 | 
            +
             * mysql_send_query is unlikely to block since most queries are small
         | 
| 199 | 
            +
             * enough to fit in a socket buffer, but sometimes large UPDATE and
         | 
| 200 | 
            +
             * INSERTs will cause the process to block
         | 
| 201 | 
            +
             */
         | 
| 202 | 
            +
            static VALUE nogvl_send_query(void *ptr) {
         | 
| 203 | 
            +
              struct nogvl_send_query_args *args = ptr;
         | 
| 204 | 
            +
              int rv;
         | 
| 205 | 
            +
              const char *sql = StringValuePtr(args->sql);
         | 
| 206 | 
            +
              long sql_len = RSTRING_LEN(args->sql);
         | 
| 207 | 
            +
             | 
| 208 | 
            +
              rv = mysql_send_query(args->mysql, sql, sql_len);
         | 
| 209 | 
            +
             | 
| 210 | 
            +
              return rv == 0 ? Qtrue : Qfalse;
         | 
| 211 | 
            +
            }
         | 
| 212 | 
            +
             | 
| 213 | 
            +
            /*
         | 
| 214 | 
            +
             * even though we did rb_thread_select before calling this, a large
         | 
| 215 | 
            +
             * response can overflow the socket buffers and cause us to eventually
         | 
| 216 | 
            +
             * block while calling mysql_read_query_result
         | 
| 217 | 
            +
             */
         | 
| 218 | 
            +
            static VALUE nogvl_read_query_result(void *ptr) {
         | 
| 219 | 
            +
              MYSQL * client = ptr;
         | 
| 220 | 
            +
              my_bool res = mysql_read_query_result(client);
         | 
| 221 | 
            +
             | 
| 222 | 
            +
              return res == 0 ? Qtrue : Qfalse;
         | 
| 223 | 
            +
            }
         | 
| 224 | 
            +
             | 
| 225 | 
            +
            /* mysql_store_result may (unlikely) read rows off the socket */
         | 
| 226 | 
            +
            static VALUE nogvl_store_result(void *ptr) {
         | 
| 227 | 
            +
              MYSQL * client = ptr;
         | 
| 228 | 
            +
              return (VALUE)mysql_store_result(client);
         | 
| 229 | 
            +
            }
         | 
| 230 | 
            +
             | 
| 231 | 
            +
            static VALUE rb_mysql_client_async_result(VALUE self) {
         | 
| 232 | 
            +
              MYSQL_RES * result;
         | 
| 233 | 
            +
              VALUE resultObj;
         | 
| 234 | 
            +
            #ifdef HAVE_RUBY_ENCODING_H
         | 
| 235 | 
            +
              mysql2_result_wrapper * result_wrapper;
         | 
| 236 | 
            +
            #endif
         | 
| 237 | 
            +
              GET_CLIENT(self);
         | 
| 238 | 
            +
             | 
| 239 | 
            +
              REQUIRE_OPEN_DB(wrapper);
         | 
| 240 | 
            +
              if (rb_thread_blocking_region(nogvl_read_query_result, wrapper->client, RUBY_UBF_IO, 0) == Qfalse) {
         | 
| 241 | 
            +
                // an error occurred, mark this connection inactive
         | 
| 242 | 
            +
                MARK_CONN_INACTIVE(self);
         | 
| 243 | 
            +
                return rb_raise_mysql2_error(wrapper->client);
         | 
| 244 | 
            +
              }
         | 
| 245 | 
            +
             | 
| 246 | 
            +
              result = (MYSQL_RES *)rb_thread_blocking_region(nogvl_store_result, wrapper->client, RUBY_UBF_IO, 0);
         | 
| 247 | 
            +
             | 
| 248 | 
            +
              // we have our result, mark this connection inactive
         | 
| 249 | 
            +
              MARK_CONN_INACTIVE(self);
         | 
| 250 | 
            +
             | 
| 251 | 
            +
              if (result == NULL) {
         | 
| 252 | 
            +
                if (mysql_field_count(wrapper->client) != 0) {
         | 
| 253 | 
            +
                  rb_raise_mysql2_error(wrapper->client);
         | 
| 254 | 
            +
                }
         | 
| 255 | 
            +
                return Qnil;
         | 
| 256 | 
            +
              }
         | 
| 257 | 
            +
             | 
| 258 | 
            +
              resultObj = rb_mysql_result_to_obj(result);
         | 
| 259 | 
            +
              // pass-through query options for result construction later
         | 
| 260 | 
            +
              rb_iv_set(resultObj, "@query_options", rb_funcall(rb_iv_get(self, "@query_options"), rb_intern("dup"), 0));
         | 
| 261 | 
            +
             | 
| 262 | 
            +
            #ifdef HAVE_RUBY_ENCODING_H
         | 
| 263 | 
            +
              GetMysql2Result(resultObj, result_wrapper);
         | 
| 264 | 
            +
              result_wrapper->encoding = wrapper->encoding;
         | 
| 265 | 
            +
            #endif
         | 
| 266 | 
            +
              return resultObj;
         | 
| 267 | 
            +
            }
         | 
| 268 | 
            +
             | 
| 269 | 
            +
            static VALUE rb_mysql_client_query(int argc, VALUE * argv, VALUE self) {
         | 
| 270 | 
            +
              struct nogvl_send_query_args args;
         | 
| 271 | 
            +
              fd_set fdset;
         | 
| 272 | 
            +
              int fd, retval;
         | 
| 273 | 
            +
              int async = 0;
         | 
| 274 | 
            +
              VALUE opts, defaults, read_timeout;
         | 
| 275 | 
            +
            #ifdef HAVE_RUBY_ENCODING_H
         | 
| 276 | 
            +
              rb_encoding *conn_enc;
         | 
| 277 | 
            +
            #endif
         | 
| 278 | 
            +
              struct timeval tv;
         | 
| 279 | 
            +
              struct timeval* tvp;
         | 
| 280 | 
            +
              long int sec;
         | 
| 281 | 
            +
              VALUE result;
         | 
| 282 | 
            +
              GET_CLIENT(self);
         | 
| 283 | 
            +
             | 
| 284 | 
            +
              REQUIRE_OPEN_DB(wrapper);
         | 
| 285 | 
            +
              args.mysql = wrapper->client;
         | 
| 286 | 
            +
             | 
| 287 | 
            +
              // see if this connection is still waiting on a result from a previous query
         | 
| 288 | 
            +
              if (wrapper->active == 0) {
         | 
| 289 | 
            +
                // mark this connection active
         | 
| 290 | 
            +
                wrapper->active = 1;
         | 
| 291 | 
            +
              } else {
         | 
| 292 | 
            +
                rb_raise(cMysql2Error, "This connection is still waiting for a result, try again once you have the result");
         | 
| 293 | 
            +
              }
         | 
| 294 | 
            +
             | 
| 295 | 
            +
              defaults = rb_iv_get(self, "@query_options");
         | 
| 296 | 
            +
              if (rb_scan_args(argc, argv, "11", &args.sql, &opts) == 2) {
         | 
| 297 | 
            +
                opts = rb_funcall(defaults, intern_merge, 1, opts);
         | 
| 298 | 
            +
                rb_iv_set(self, "@query_options", opts);
         | 
| 299 | 
            +
             | 
| 300 | 
            +
                if (rb_hash_aref(opts, sym_async) == Qtrue) {
         | 
| 301 | 
            +
                  async = 1;
         | 
| 302 | 
            +
                }
         | 
| 303 | 
            +
              } else {
         | 
| 304 | 
            +
                opts = defaults;
         | 
| 305 | 
            +
              }
         | 
| 306 | 
            +
             | 
| 307 | 
            +
              Check_Type(args.sql, T_STRING);
         | 
| 308 | 
            +
            #ifdef HAVE_RUBY_ENCODING_H
         | 
| 309 | 
            +
              conn_enc = rb_to_encoding(wrapper->encoding);
         | 
| 310 | 
            +
              // ensure the string is in the encoding the connection is expecting
         | 
| 311 | 
            +
              args.sql = rb_str_export_to_enc(args.sql, conn_enc);
         | 
| 312 | 
            +
            #endif
         | 
| 313 | 
            +
             | 
| 314 | 
            +
              if (rb_thread_blocking_region(nogvl_send_query, &args, RUBY_UBF_IO, 0) == Qfalse) {
         | 
| 315 | 
            +
                // an error occurred, we're not active anymore
         | 
| 316 | 
            +
                MARK_CONN_INACTIVE(self);
         | 
| 317 | 
            +
                return rb_raise_mysql2_error(wrapper->client);
         | 
| 318 | 
            +
              }
         | 
| 319 | 
            +
             | 
| 320 | 
            +
              read_timeout = rb_iv_get(self, "@read_timeout");
         | 
| 321 | 
            +
             | 
| 322 | 
            +
              tvp = NULL;
         | 
| 323 | 
            +
              if (!NIL_P(read_timeout)) {
         | 
| 324 | 
            +
                Check_Type(read_timeout, T_FIXNUM);
         | 
| 325 | 
            +
                tvp = &tv;
         | 
| 326 | 
            +
                sec = FIX2INT(read_timeout);
         | 
| 327 | 
            +
                // TODO: support partial seconds?
         | 
| 328 | 
            +
                // also, this check is here for sanity, we also check up in Ruby
         | 
| 329 | 
            +
                if (sec >= 0) {
         | 
| 330 | 
            +
                  tvp->tv_sec = sec;
         | 
| 331 | 
            +
                } else {
         | 
| 332 | 
            +
                  rb_raise(cMysql2Error, "read_timeout must be a positive integer, you passed %ld", sec);
         | 
| 333 | 
            +
                }
         | 
| 334 | 
            +
                tvp->tv_usec = 0;
         | 
| 335 | 
            +
              }
         | 
| 336 | 
            +
             | 
| 337 | 
            +
              if (!async) {
         | 
| 338 | 
            +
                // the below code is largely from do_mysql
         | 
| 339 | 
            +
                // http://github.com/datamapper/do
         | 
| 340 | 
            +
                fd = wrapper->client->net.fd;
         | 
| 341 | 
            +
                for(;;) {
         | 
| 342 | 
            +
                  int fd_set_fd = fd;
         | 
| 343 | 
            +
             | 
| 344 | 
            +
            #ifdef _WIN32
         | 
| 345 | 
            +
                  WSAPROTOCOL_INFO wsa_pi;
         | 
| 346 | 
            +
                  // dupicate the SOCKET from libmysql
         | 
| 347 | 
            +
                  int r = WSADuplicateSocket(fd, GetCurrentProcessId(), &wsa_pi);
         | 
| 348 | 
            +
                  SOCKET s = WSASocket(wsa_pi.iAddressFamily, wsa_pi.iSocketType, wsa_pi.iProtocol, &wsa_pi, 0, 0);
         | 
| 349 | 
            +
                  // create the CRT fd so ruby can get back to the SOCKET
         | 
| 350 | 
            +
                  fd_set_fd = _open_osfhandle(s, O_RDWR|O_BINARY);
         | 
| 351 | 
            +
            #endif
         | 
| 352 | 
            +
             | 
| 353 | 
            +
                  FD_ZERO(&fdset);
         | 
| 354 | 
            +
                  FD_SET(fd_set_fd, &fdset);
         | 
| 355 | 
            +
             | 
| 356 | 
            +
                  retval = rb_thread_select(fd_set_fd + 1, &fdset, NULL, NULL, tvp);
         | 
| 357 | 
            +
             | 
| 358 | 
            +
            #ifdef _WIN32
         | 
| 359 | 
            +
                  // cleanup the CRT fd
         | 
| 360 | 
            +
                  _close(fd_set_fd);
         | 
| 361 | 
            +
                  // cleanup the duplicated SOCKET
         | 
| 362 | 
            +
                  closesocket(s);
         | 
| 363 | 
            +
            #endif
         | 
| 364 | 
            +
             | 
| 365 | 
            +
                  if (retval == 0) {
         | 
| 366 | 
            +
                    rb_raise(cMysql2Error, "Timeout waiting for a response from the last query. (waited %d seconds)", FIX2INT(read_timeout));
         | 
| 367 | 
            +
                  }
         | 
| 368 | 
            +
             | 
| 369 | 
            +
                  if (retval < 0) {
         | 
| 370 | 
            +
                    rb_sys_fail(0);
         | 
| 371 | 
            +
                  }
         | 
| 372 | 
            +
             | 
| 373 | 
            +
                  if (retval > 0) {
         | 
| 374 | 
            +
                    break;
         | 
| 375 | 
            +
                  }
         | 
| 376 | 
            +
                }
         | 
| 377 | 
            +
             | 
| 378 | 
            +
                result = rb_mysql_client_async_result(self);
         | 
| 379 | 
            +
             | 
| 380 | 
            +
                return result;
         | 
| 381 | 
            +
              } else {
         | 
| 382 | 
            +
                return Qnil;
         | 
| 383 | 
            +
              }
         | 
| 384 | 
            +
            }
         | 
| 385 | 
            +
             | 
| 386 | 
            +
            static VALUE rb_mysql_client_escape(VALUE self, VALUE str) {
         | 
| 387 | 
            +
              VALUE newStr;
         | 
| 388 | 
            +
              unsigned long newLen, oldLen;
         | 
| 389 | 
            +
            #ifdef HAVE_RUBY_ENCODING_H
         | 
| 390 | 
            +
              rb_encoding *default_internal_enc;
         | 
| 391 | 
            +
              rb_encoding *conn_enc;
         | 
| 392 | 
            +
            #endif
         | 
| 393 | 
            +
              GET_CLIENT(self);
         | 
| 394 | 
            +
             | 
| 395 | 
            +
              REQUIRE_OPEN_DB(wrapper);
         | 
| 396 | 
            +
              Check_Type(str, T_STRING);
         | 
| 397 | 
            +
            #ifdef HAVE_RUBY_ENCODING_H
         | 
| 398 | 
            +
              default_internal_enc = rb_default_internal_encoding();
         | 
| 399 | 
            +
              conn_enc = rb_to_encoding(wrapper->encoding);
         | 
| 400 | 
            +
              // ensure the string is in the encoding the connection is expecting
         | 
| 401 | 
            +
              str = rb_str_export_to_enc(str, conn_enc);
         | 
| 402 | 
            +
            #endif
         | 
| 403 | 
            +
             | 
| 404 | 
            +
              oldLen = RSTRING_LEN(str);
         | 
| 405 | 
            +
              newStr = rb_str_new(0, oldLen*2+1);
         | 
| 406 | 
            +
             | 
| 407 | 
            +
              newLen = mysql_real_escape_string(wrapper->client, RSTRING_PTR(newStr), StringValuePtr(str), oldLen);
         | 
| 408 | 
            +
              if (newLen == oldLen) {
         | 
| 409 | 
            +
                // no need to return a new ruby string if nothing changed
         | 
| 410 | 
            +
                return str;
         | 
| 411 | 
            +
              } else {
         | 
| 412 | 
            +
                rb_str_resize(newStr, newLen);
         | 
| 413 | 
            +
            #ifdef HAVE_RUBY_ENCODING_H
         | 
| 414 | 
            +
                rb_enc_associate(newStr, conn_enc);
         | 
| 415 | 
            +
                if (default_internal_enc) {
         | 
| 416 | 
            +
                  newStr = rb_str_export_to_enc(newStr, default_internal_enc);
         | 
| 417 | 
            +
                }
         | 
| 418 | 
            +
            #endif
         | 
| 419 | 
            +
                return newStr;
         | 
| 420 | 
            +
              }
         | 
| 421 | 
            +
            }
         | 
| 422 | 
            +
             | 
| 423 | 
            +
            static VALUE rb_mysql_client_info(VALUE self) {
         | 
| 424 | 
            +
              VALUE version, client_info;
         | 
| 425 | 
            +
            #ifdef HAVE_RUBY_ENCODING_H
         | 
| 426 | 
            +
              rb_encoding *default_internal_enc;
         | 
| 427 | 
            +
              rb_encoding *conn_enc;
         | 
| 428 | 
            +
            #endif
         | 
| 429 | 
            +
              GET_CLIENT(self);
         | 
| 430 | 
            +
              version = rb_hash_new();
         | 
| 431 | 
            +
             | 
| 432 | 
            +
            #ifdef HAVE_RUBY_ENCODING_H
         | 
| 433 | 
            +
              default_internal_enc = rb_default_internal_encoding();
         | 
| 434 | 
            +
              conn_enc = rb_to_encoding(wrapper->encoding);
         | 
| 435 | 
            +
            #endif
         | 
| 436 | 
            +
             | 
| 437 | 
            +
              rb_hash_aset(version, sym_id, LONG2NUM(mysql_get_client_version()));
         | 
| 438 | 
            +
              client_info = rb_str_new2(mysql_get_client_info());
         | 
| 439 | 
            +
            #ifdef HAVE_RUBY_ENCODING_H
         | 
| 440 | 
            +
              rb_enc_associate(client_info, conn_enc);
         | 
| 441 | 
            +
              if (default_internal_enc) {
         | 
| 442 | 
            +
                client_info = rb_str_export_to_enc(client_info, default_internal_enc);
         | 
| 443 | 
            +
              }
         | 
| 444 | 
            +
            #endif
         | 
| 445 | 
            +
              rb_hash_aset(version, sym_version, client_info);
         | 
| 446 | 
            +
              return version;
         | 
| 447 | 
            +
            }
         | 
| 448 | 
            +
             | 
| 449 | 
            +
            static VALUE rb_mysql_client_server_info(VALUE self) {
         | 
| 450 | 
            +
              VALUE version, server_info;
         | 
| 451 | 
            +
            #ifdef HAVE_RUBY_ENCODING_H
         | 
| 452 | 
            +
              rb_encoding *default_internal_enc;
         | 
| 453 | 
            +
              rb_encoding *conn_enc;
         | 
| 454 | 
            +
            #endif
         | 
| 455 | 
            +
              GET_CLIENT(self);
         | 
| 456 | 
            +
             | 
| 457 | 
            +
              REQUIRE_OPEN_DB(wrapper);
         | 
| 458 | 
            +
            #ifdef HAVE_RUBY_ENCODING_H
         | 
| 459 | 
            +
              default_internal_enc = rb_default_internal_encoding();
         | 
| 460 | 
            +
              conn_enc = rb_to_encoding(wrapper->encoding);
         | 
| 461 | 
            +
            #endif
         | 
| 462 | 
            +
             | 
| 463 | 
            +
              version = rb_hash_new();
         | 
| 464 | 
            +
              rb_hash_aset(version, sym_id, LONG2FIX(mysql_get_server_version(wrapper->client)));
         | 
| 465 | 
            +
              server_info = rb_str_new2(mysql_get_server_info(wrapper->client));
         | 
| 466 | 
            +
            #ifdef HAVE_RUBY_ENCODING_H
         | 
| 467 | 
            +
              rb_enc_associate(server_info, conn_enc);
         | 
| 468 | 
            +
              if (default_internal_enc) {
         | 
| 469 | 
            +
                server_info = rb_str_export_to_enc(server_info, default_internal_enc);
         | 
| 470 | 
            +
              }
         | 
| 471 | 
            +
            #endif
         | 
| 472 | 
            +
              rb_hash_aset(version, sym_version, server_info);
         | 
| 473 | 
            +
              return version;
         | 
| 474 | 
            +
            }
         | 
| 475 | 
            +
             | 
| 476 | 
            +
            static VALUE rb_mysql_client_socket(VALUE self) {
         | 
| 477 | 
            +
              GET_CLIENT(self);
         | 
| 478 | 
            +
              REQUIRE_OPEN_DB(wrapper);
         | 
| 479 | 
            +
              return INT2NUM(wrapper->client->net.fd);
         | 
| 480 | 
            +
            }
         | 
| 481 | 
            +
             | 
| 482 | 
            +
            static VALUE rb_mysql_client_last_id(VALUE self) {
         | 
| 483 | 
            +
              GET_CLIENT(self);
         | 
| 484 | 
            +
              REQUIRE_OPEN_DB(wrapper);
         | 
| 485 | 
            +
              return ULL2NUM(mysql_insert_id(wrapper->client));
         | 
| 486 | 
            +
            }
         | 
| 487 | 
            +
             | 
| 488 | 
            +
            static VALUE rb_mysql_client_affected_rows(VALUE self) {
         | 
| 489 | 
            +
              my_ulonglong retVal;
         | 
| 490 | 
            +
              GET_CLIENT(self);
         | 
| 491 | 
            +
             | 
| 492 | 
            +
              REQUIRE_OPEN_DB(wrapper);
         | 
| 493 | 
            +
              retVal = mysql_affected_rows(wrapper->client);
         | 
| 494 | 
            +
              if (retVal == (my_ulonglong)-1) {
         | 
| 495 | 
            +
                rb_raise_mysql2_error(wrapper->client);
         | 
| 496 | 
            +
              }
         | 
| 497 | 
            +
              return ULL2NUM(retVal);
         | 
| 498 | 
            +
            }
         | 
| 499 | 
            +
             | 
| 500 | 
            +
            static VALUE rb_mysql_client_thread_id(VALUE self) {
         | 
| 501 | 
            +
              unsigned long retVal;
         | 
| 502 | 
            +
              GET_CLIENT(self);
         | 
| 503 | 
            +
             | 
| 504 | 
            +
              REQUIRE_OPEN_DB(wrapper);
         | 
| 505 | 
            +
              retVal = mysql_thread_id(wrapper->client);
         | 
| 506 | 
            +
              return ULL2NUM(retVal);
         | 
| 507 | 
            +
            }
         | 
| 508 | 
            +
             | 
| 509 | 
            +
            static VALUE rb_mysql_client_ping(VALUE self) {
         | 
| 510 | 
            +
              unsigned long retVal;
         | 
| 511 | 
            +
              GET_CLIENT(self);
         | 
| 512 | 
            +
             | 
| 513 | 
            +
              retVal = mysql_ping(wrapper->client);
         | 
| 514 | 
            +
              if (retVal == 0) {
         | 
| 515 | 
            +
                return Qtrue;
         | 
| 516 | 
            +
              } else {
         | 
| 517 | 
            +
                return Qfalse;
         | 
| 518 | 
            +
              }
         | 
| 519 | 
            +
            }
         | 
| 520 | 
            +
             | 
| 521 | 
            +
            static VALUE set_reconnect(VALUE self, VALUE value) {
         | 
| 522 | 
            +
              my_bool reconnect;
         | 
| 523 | 
            +
              GET_CLIENT(self);
         | 
| 524 | 
            +
             | 
| 525 | 
            +
              if(!NIL_P(value)) {
         | 
| 526 | 
            +
                reconnect = value == Qfalse ? 0 : 1;
         | 
| 527 | 
            +
             | 
| 528 | 
            +
                /* set default reconnect behavior */
         | 
| 529 | 
            +
                if (mysql_options(wrapper->client, MYSQL_OPT_RECONNECT, &reconnect)) {
         | 
| 530 | 
            +
                  /* TODO: warning - unable to set reconnect behavior */
         | 
| 531 | 
            +
                  rb_warn("%s\n", mysql_error(wrapper->client));
         | 
| 532 | 
            +
                }
         | 
| 533 | 
            +
              }
         | 
| 534 | 
            +
              return value;
         | 
| 535 | 
            +
            }
         | 
| 536 | 
            +
             | 
| 537 | 
            +
            static VALUE set_connect_timeout(VALUE self, VALUE value) {
         | 
| 538 | 
            +
              unsigned int connect_timeout = 0;
         | 
| 539 | 
            +
              GET_CLIENT(self);
         | 
| 540 | 
            +
             | 
| 541 | 
            +
              if(!NIL_P(value)) {
         | 
| 542 | 
            +
                connect_timeout = NUM2INT(value);
         | 
| 543 | 
            +
                if(0 == connect_timeout) return value;
         | 
| 544 | 
            +
             | 
| 545 | 
            +
                /* set default connection timeout behavior */
         | 
| 546 | 
            +
                if (mysql_options(wrapper->client, MYSQL_OPT_CONNECT_TIMEOUT, &connect_timeout)) {
         | 
| 547 | 
            +
                  /* TODO: warning - unable to set connection timeout */
         | 
| 548 | 
            +
                  rb_warn("%s\n", mysql_error(wrapper->client));
         | 
| 549 | 
            +
                }
         | 
| 550 | 
            +
              }
         | 
| 551 | 
            +
              return value;
         | 
| 552 | 
            +
            }
         | 
| 553 | 
            +
             | 
| 554 | 
            +
            static VALUE set_charset_name(VALUE self, VALUE value) {
         | 
| 555 | 
            +
              char * charset_name;
         | 
| 556 | 
            +
            #ifdef HAVE_RUBY_ENCODING_H
         | 
| 557 | 
            +
              VALUE new_encoding;
         | 
| 558 | 
            +
            #endif
         | 
| 559 | 
            +
              GET_CLIENT(self);
         | 
| 560 | 
            +
             | 
| 561 | 
            +
            #ifdef HAVE_RUBY_ENCODING_H
         | 
| 562 | 
            +
              new_encoding = rb_funcall(cMysql2Client, intern_encoding_from_charset, 1, value);
         | 
| 563 | 
            +
              if (new_encoding == Qnil) {
         | 
| 564 | 
            +
                rb_raise(cMysql2Error, "Unsupported charset: '%s'", RSTRING_PTR(value));
         | 
| 565 | 
            +
              } else {
         | 
| 566 | 
            +
                if (wrapper->encoding == Qnil) {
         | 
| 567 | 
            +
                  wrapper->encoding = new_encoding;
         | 
| 568 | 
            +
                }
         | 
| 569 | 
            +
              }
         | 
| 570 | 
            +
            #endif
         | 
| 571 | 
            +
             | 
| 572 | 
            +
              charset_name = StringValuePtr(value);
         | 
| 573 | 
            +
             | 
| 574 | 
            +
              if (mysql_options(wrapper->client, MYSQL_SET_CHARSET_NAME, charset_name)) {
         | 
| 575 | 
            +
                /* TODO: warning - unable to set charset */
         | 
| 576 | 
            +
                rb_warn("%s\n", mysql_error(wrapper->client));
         | 
| 577 | 
            +
              }
         | 
| 578 | 
            +
             | 
| 579 | 
            +
              return value;
         | 
| 580 | 
            +
            }
         | 
| 581 | 
            +
             | 
| 582 | 
            +
            static VALUE set_ssl_options(VALUE self, VALUE key, VALUE cert, VALUE ca, VALUE capath, VALUE cipher) {
         | 
| 583 | 
            +
              GET_CLIENT(self);
         | 
| 584 | 
            +
             | 
| 585 | 
            +
              if(!NIL_P(ca) || !NIL_P(key)) {
         | 
| 586 | 
            +
                mysql_ssl_set(wrapper->client,
         | 
| 587 | 
            +
                    NIL_P(key) ? NULL : StringValuePtr(key),
         | 
| 588 | 
            +
                    NIL_P(cert) ? NULL : StringValuePtr(cert),
         | 
| 589 | 
            +
                    NIL_P(ca) ? NULL : StringValuePtr(ca),
         | 
| 590 | 
            +
                    NIL_P(capath) ? NULL : StringValuePtr(capath),
         | 
| 591 | 
            +
                    NIL_P(cipher) ? NULL : StringValuePtr(cipher));
         | 
| 592 | 
            +
              }
         | 
| 593 | 
            +
             | 
| 594 | 
            +
              return self;
         | 
| 595 | 
            +
            }
         | 
| 596 | 
            +
             | 
| 597 | 
            +
            static VALUE init_connection(VALUE self) {
         | 
| 598 | 
            +
              GET_CLIENT(self);
         | 
| 599 | 
            +
             | 
| 600 | 
            +
              if (rb_thread_blocking_region(nogvl_init, wrapper->client, RUBY_UBF_IO, 0) == Qfalse) {
         | 
| 601 | 
            +
                /* TODO: warning - not enough memory? */
         | 
| 602 | 
            +
                return rb_raise_mysql2_error(wrapper->client);
         | 
| 603 | 
            +
              }
         | 
| 604 | 
            +
             | 
| 605 | 
            +
              wrapper->closed = 0;
         | 
| 606 | 
            +
              return self;
         | 
| 607 | 
            +
            }
         | 
| 608 | 
            +
             | 
| 609 | 
            +
            void init_mysql2_client() {
         | 
| 610 | 
            +
              // verify the libmysql we're about to use was the version we were built against
         | 
| 611 | 
            +
              // https://github.com/luislavena/mysql-gem/commit/a600a9c459597da0712f70f43736e24b484f8a99
         | 
| 612 | 
            +
              int i;
         | 
| 613 | 
            +
              int dots = 0;
         | 
| 614 | 
            +
              const char *lib = mysql_get_client_info();
         | 
| 615 | 
            +
              for (i = 0; lib[i] != 0 && MYSQL_SERVER_VERSION[i] != 0; i++) {
         | 
| 616 | 
            +
                if (lib[i] == '.') {
         | 
| 617 | 
            +
                  dots++;
         | 
| 618 | 
            +
                          // we only compare MAJOR and MINOR
         | 
| 619 | 
            +
                  if (dots == 2) break;
         | 
| 620 | 
            +
                }
         | 
| 621 | 
            +
                if (lib[i] != MYSQL_SERVER_VERSION[i]) {
         | 
| 622 | 
            +
                  rb_raise(rb_eRuntimeError, "Incorrect MySQL client library version! This gem was compiled for %s but the client library is %s.", MYSQL_SERVER_VERSION, lib);
         | 
| 623 | 
            +
                  return;
         | 
| 624 | 
            +
                }
         | 
| 625 | 
            +
              }
         | 
| 626 | 
            +
             | 
| 627 | 
            +
              cMysql2Client = rb_define_class_under(mMysql2, "Client", rb_cObject);
         | 
| 628 | 
            +
             | 
| 629 | 
            +
              rb_define_alloc_func(cMysql2Client, allocate);
         | 
| 630 | 
            +
             | 
| 631 | 
            +
              rb_define_method(cMysql2Client, "close", rb_mysql_client_close, 0);
         | 
| 632 | 
            +
              rb_define_method(cMysql2Client, "query", rb_mysql_client_query, -1);
         | 
| 633 | 
            +
              rb_define_method(cMysql2Client, "escape", rb_mysql_client_escape, 1);
         | 
| 634 | 
            +
              rb_define_method(cMysql2Client, "info", rb_mysql_client_info, 0);
         | 
| 635 | 
            +
              rb_define_method(cMysql2Client, "server_info", rb_mysql_client_server_info, 0);
         | 
| 636 | 
            +
              rb_define_method(cMysql2Client, "socket", rb_mysql_client_socket, 0);
         | 
| 637 | 
            +
              rb_define_method(cMysql2Client, "async_result", rb_mysql_client_async_result, 0);
         | 
| 638 | 
            +
              rb_define_method(cMysql2Client, "last_id", rb_mysql_client_last_id, 0);
         | 
| 639 | 
            +
              rb_define_method(cMysql2Client, "affected_rows", rb_mysql_client_affected_rows, 0);
         | 
| 640 | 
            +
              rb_define_method(cMysql2Client, "thread_id", rb_mysql_client_thread_id, 0);
         | 
| 641 | 
            +
              rb_define_method(cMysql2Client, "ping", rb_mysql_client_ping, 0);
         | 
| 642 | 
            +
             | 
| 643 | 
            +
              rb_define_private_method(cMysql2Client, "reconnect=", set_reconnect, 1);
         | 
| 644 | 
            +
              rb_define_private_method(cMysql2Client, "connect_timeout=", set_connect_timeout, 1);
         | 
| 645 | 
            +
              rb_define_private_method(cMysql2Client, "charset_name=", set_charset_name, 1);
         | 
| 646 | 
            +
              rb_define_private_method(cMysql2Client, "ssl_set", set_ssl_options, 5);
         | 
| 647 | 
            +
              rb_define_private_method(cMysql2Client, "init_connection", init_connection, 0);
         | 
| 648 | 
            +
              rb_define_private_method(cMysql2Client, "connect", rb_connect, 7);
         | 
| 649 | 
            +
             | 
| 650 | 
            +
              intern_encoding_from_charset = rb_intern("encoding_from_charset");
         | 
| 651 | 
            +
             | 
| 652 | 
            +
              sym_id              = ID2SYM(rb_intern("id"));
         | 
| 653 | 
            +
              sym_version         = ID2SYM(rb_intern("version"));
         | 
| 654 | 
            +
              sym_async           = ID2SYM(rb_intern("async"));
         | 
| 655 | 
            +
              sym_symbolize_keys  = ID2SYM(rb_intern("symbolize_keys"));
         | 
| 656 | 
            +
              sym_as              = ID2SYM(rb_intern("as"));
         | 
| 657 | 
            +
              sym_array           = ID2SYM(rb_intern("array"));
         | 
| 658 | 
            +
             | 
| 659 | 
            +
              intern_merge = rb_intern("merge");
         | 
| 660 | 
            +
              intern_error_number_eql = rb_intern("error_number=");
         | 
| 661 | 
            +
              intern_sql_state_eql = rb_intern("sql_state=");
         | 
| 662 | 
            +
             | 
| 663 | 
            +
            #ifdef CLIENT_LONG_PASSWORD
         | 
| 664 | 
            +
              rb_const_set(cMysql2Client, rb_intern("LONG_PASSWORD"),
         | 
| 665 | 
            +
                  INT2NUM(CLIENT_LONG_PASSWORD));
         | 
| 666 | 
            +
            #endif
         | 
| 667 | 
            +
             | 
| 668 | 
            +
            #ifdef CLIENT_FOUND_ROWS
         | 
| 669 | 
            +
              rb_const_set(cMysql2Client, rb_intern("FOUND_ROWS"),
         | 
| 670 | 
            +
                  INT2NUM(CLIENT_FOUND_ROWS));
         | 
| 671 | 
            +
            #endif
         | 
| 672 | 
            +
             | 
| 673 | 
            +
            #ifdef CLIENT_LONG_FLAG
         | 
| 674 | 
            +
              rb_const_set(cMysql2Client, rb_intern("LONG_FLAG"),
         | 
| 675 | 
            +
                  INT2NUM(CLIENT_LONG_FLAG));
         | 
| 676 | 
            +
            #endif
         | 
| 677 | 
            +
             | 
| 678 | 
            +
            #ifdef CLIENT_CONNECT_WITH_DB
         | 
| 679 | 
            +
              rb_const_set(cMysql2Client, rb_intern("CONNECT_WITH_DB"),
         | 
| 680 | 
            +
                  INT2NUM(CLIENT_CONNECT_WITH_DB));
         | 
| 681 | 
            +
            #endif
         | 
| 682 | 
            +
             | 
| 683 | 
            +
            #ifdef CLIENT_NO_SCHEMA
         | 
| 684 | 
            +
              rb_const_set(cMysql2Client, rb_intern("NO_SCHEMA"),
         | 
| 685 | 
            +
                  INT2NUM(CLIENT_NO_SCHEMA));
         | 
| 686 | 
            +
            #endif
         | 
| 687 | 
            +
             | 
| 688 | 
            +
            #ifdef CLIENT_COMPRESS
         | 
| 689 | 
            +
              rb_const_set(cMysql2Client, rb_intern("COMPRESS"), INT2NUM(CLIENT_COMPRESS));
         | 
| 690 | 
            +
            #endif
         | 
| 691 | 
            +
             | 
| 692 | 
            +
            #ifdef CLIENT_ODBC
         | 
| 693 | 
            +
              rb_const_set(cMysql2Client, rb_intern("ODBC"), INT2NUM(CLIENT_ODBC));
         | 
| 694 | 
            +
            #endif
         | 
| 695 | 
            +
             | 
| 696 | 
            +
            #ifdef CLIENT_LOCAL_FILES
         | 
| 697 | 
            +
              rb_const_set(cMysql2Client, rb_intern("LOCAL_FILES"),
         | 
| 698 | 
            +
                  INT2NUM(CLIENT_LOCAL_FILES));
         | 
| 699 | 
            +
            #endif
         | 
| 700 | 
            +
             | 
| 701 | 
            +
            #ifdef CLIENT_IGNORE_SPACE
         | 
| 702 | 
            +
              rb_const_set(cMysql2Client, rb_intern("IGNORE_SPACE"),
         | 
| 703 | 
            +
                  INT2NUM(CLIENT_IGNORE_SPACE));
         | 
| 704 | 
            +
            #endif
         | 
| 705 | 
            +
             | 
| 706 | 
            +
            #ifdef CLIENT_PROTOCOL_41
         | 
| 707 | 
            +
              rb_const_set(cMysql2Client, rb_intern("PROTOCOL_41"),
         | 
| 708 | 
            +
                  INT2NUM(CLIENT_PROTOCOL_41));
         | 
| 709 | 
            +
            #endif
         | 
| 710 | 
            +
             | 
| 711 | 
            +
            #ifdef CLIENT_INTERACTIVE
         | 
| 712 | 
            +
              rb_const_set(cMysql2Client, rb_intern("INTERACTIVE"),
         | 
| 713 | 
            +
                  INT2NUM(CLIENT_INTERACTIVE));
         | 
| 714 | 
            +
            #endif
         | 
| 715 | 
            +
             | 
| 716 | 
            +
            #ifdef CLIENT_SSL
         | 
| 717 | 
            +
              rb_const_set(cMysql2Client, rb_intern("SSL"), INT2NUM(CLIENT_SSL));
         | 
| 718 | 
            +
            #endif
         | 
| 719 | 
            +
             | 
| 720 | 
            +
            #ifdef CLIENT_IGNORE_SIGPIPE
         | 
| 721 | 
            +
              rb_const_set(cMysql2Client, rb_intern("IGNORE_SIGPIPE"),
         | 
| 722 | 
            +
                  INT2NUM(CLIENT_IGNORE_SIGPIPE));
         | 
| 723 | 
            +
            #endif
         | 
| 724 | 
            +
             | 
| 725 | 
            +
            #ifdef CLIENT_TRANSACTIONS
         | 
| 726 | 
            +
              rb_const_set(cMysql2Client, rb_intern("TRANSACTIONS"),
         | 
| 727 | 
            +
                  INT2NUM(CLIENT_TRANSACTIONS));
         | 
| 728 | 
            +
            #endif
         | 
| 729 | 
            +
             | 
| 730 | 
            +
            #ifdef CLIENT_RESERVED
         | 
| 731 | 
            +
              rb_const_set(cMysql2Client, rb_intern("RESERVED"), INT2NUM(CLIENT_RESERVED));
         | 
| 732 | 
            +
            #endif
         | 
| 733 | 
            +
             | 
| 734 | 
            +
            #ifdef CLIENT_SECURE_CONNECTION
         | 
| 735 | 
            +
              rb_const_set(cMysql2Client, rb_intern("SECURE_CONNECTION"),
         | 
| 736 | 
            +
                  INT2NUM(CLIENT_SECURE_CONNECTION));
         | 
| 737 | 
            +
            #endif
         | 
| 738 | 
            +
             | 
| 739 | 
            +
            #ifdef CLIENT_MULTI_STATEMENTS
         | 
| 740 | 
            +
              rb_const_set(cMysql2Client, rb_intern("MULTI_STATEMENTS"),
         | 
| 741 | 
            +
                  INT2NUM(CLIENT_MULTI_STATEMENTS));
         | 
| 742 | 
            +
            #endif
         | 
| 743 | 
            +
             | 
| 744 | 
            +
            #ifdef CLIENT_PS_MULTI_RESULTS
         | 
| 745 | 
            +
              rb_const_set(cMysql2Client, rb_intern("PS_MULTI_RESULTS"),
         | 
| 746 | 
            +
                  INT2NUM(CLIENT_PS_MULTI_RESULTS));
         | 
| 747 | 
            +
            #endif
         | 
| 748 | 
            +
             | 
| 749 | 
            +
            #ifdef CLIENT_SSL_VERIFY_SERVER_CERT
         | 
| 750 | 
            +
              rb_const_set(cMysql2Client, rb_intern("SSL_VERIFY_SERVER_CERT"),
         | 
| 751 | 
            +
                  INT2NUM(CLIENT_SSL_VERIFY_SERVER_CERT));
         | 
| 752 | 
            +
            #endif
         | 
| 753 | 
            +
             | 
| 754 | 
            +
            #ifdef CLIENT_REMEMBER_OPTIONS
         | 
| 755 | 
            +
              rb_const_set(cMysql2Client, rb_intern("REMEMBER_OPTIONS"),
         | 
| 756 | 
            +
                  INT2NUM(CLIENT_REMEMBER_OPTIONS));
         | 
| 757 | 
            +
            #endif
         | 
| 758 | 
            +
             | 
| 759 | 
            +
            #ifdef CLIENT_ALL_FLAGS
         | 
| 760 | 
            +
              rb_const_set(cMysql2Client, rb_intern("ALL_FLAGS"),
         | 
| 761 | 
            +
                  INT2NUM(CLIENT_ALL_FLAGS));
         | 
| 762 | 
            +
            #endif
         | 
| 763 | 
            +
             | 
| 764 | 
            +
            #ifdef CLIENT_BASIC_FLAGS
         | 
| 765 | 
            +
              rb_const_set(cMysql2Client, rb_intern("BASIC_FLAGS"),
         | 
| 766 | 
            +
                  INT2NUM(CLIENT_BASIC_FLAGS));
         | 
| 767 | 
            +
            #endif
         | 
| 768 | 
            +
            }
         |