From 8aec02df63b0d423034d155a50ab7021ecea2854 Mon Sep 17 00:00:00 2001 From: Aaron Stone Date: Wed, 9 Apr 2014 23:25:23 -0700 Subject: [PATCH 1/3] Separate out connect options from query options --- lib/mysql2/client.rb | 60 +++++++++++++++++++++++++------------------- 1 file changed, 34 insertions(+), 26 deletions(-) diff --git a/lib/mysql2/client.rb b/lib/mysql2/client.rb index 2481efd1c..5dd825570 100644 --- a/lib/mysql2/client.rb +++ b/lib/mysql2/client.rb @@ -1,45 +1,48 @@ module Mysql2 class Client - attr_reader :query_options, :read_timeout + attr_reader :connect_options, :query_options, :read_timeout + + VALID_CONNECT_KEYS = [:connect_flags, :connect_timeout, :encoding, :default_file, :default_group, :read_timeout, :write_timeout, :secure_auth, :init_command, :reconnect, :local_infile] + @@default_connect_options = { + :connect_flags => REMEMBER_OPTIONS | LONG_PASSWORD | LONG_FLAG | TRANSACTIONS | PROTOCOL_41 | SECURE_CONNECTION, + :connect_timeout => 120, # Set default connect_timeout to avoid unlimited retries from signal interruption + :encoding => 'utf8' + } + + VALID_QUERY_KEYS = [:as, :async, :cast_booleans, :symbolize_keys, :database_timezone, :application_timezone, :cache_rows, :cast] @@default_query_options = { - :as => :hash, # the type of object you want each row back as; also supports :array (an array of values) - :async => false, # don't wait for a result after sending the query, you'll have to monitor the socket yourself then eventually call Mysql2::Client#async_result - :cast_booleans => false, # cast tinyint(1) fields as true/false in ruby - :symbolize_keys => false, # return field names as symbols instead of strings - :database_timezone => :local, # timezone Mysql2 will assume datetime objects are stored in - :application_timezone => nil, # timezone Mysql2 will convert to before handing the object back to the caller - :cache_rows => true, # tells Mysql2 to use it's internal row cache for results - :connect_flags => REMEMBER_OPTIONS | LONG_PASSWORD | LONG_FLAG | TRANSACTIONS | PROTOCOL_41 | SECURE_CONNECTION, - :cast => true, - :default_file => nil, - :default_group => nil + :as => :hash, # the type of object you want each row back as; also supports :array (an array of values) + :async => false, # don't wait for a result after sending the query, you'll have to monitor the socket yourself then eventually call Mysql2::Client#async_result + :cast_booleans => false, # cast tinyint(1) fields as true/false in ruby + :symbolize_keys => false, # return field names as symbols instead of strings + :database_timezone => :local, # timezone Mysql2 will assume datetime objects are stored in + :application_timezone => nil, # timezone Mysql2 will convert to before handing the object back to the caller + :cache_rows => true, # tells Mysql2 to use it's internal row cache for results + :cast => true # cast result fields to corresponding Ruby data types } def initialize(opts = {}) - opts = Mysql2::Util.key_hash_as_symbols( opts ) - @read_timeout = nil - @query_options = @@default_query_options.dup - @query_options.merge! opts + opts = Mysql2::Util.key_hash_as_symbols(opts) + @read_timeout = nil # by default don't timeout on read + @connect_options = @@default_connect_options.merge Hash[ opts.select { |k, v| VALID_CONNECT_KEYS.include? k } ] + @query_options = @@default_query_options.merge Hash[ opts.select { |k, v| VALID_QUERY_KEYS.include? k } ] initialize_ext - # Set default connect_timeout to avoid unlimited retries from signal interruption - opts[:connect_timeout] = 120 unless opts.key?(:connect_timeout) - [:reconnect, :connect_timeout, :local_infile, :read_timeout, :write_timeout, :default_file, :default_group, :secure_auth, :init_command].each do |key| - next unless opts.key?(key) + next unless @connect_options.key?(key) case key when :reconnect, :local_infile, :secure_auth - send(:"#{key}=", !!opts[key]) + send(:"#{key}=", !!@connect_options[key]) when :connect_timeout, :read_timeout, :write_timeout - send(:"#{key}=", opts[key].to_i) + send(:"#{key}=", @connect_options[key].to_i) else - send(:"#{key}=", opts[key]) + send(:"#{key}=", @connect_options[key]) end end - # force the encoding to utf8 - self.charset_name = opts[:encoding] || 'utf8' + # force the encoding to utf8 even if set to nil + self.charset_name = @connect_options[:encoding] || 'utf8' ssl_options = opts.values_at(:sslkey, :sslcert, :sslca, :sslcapath, :sslcipher) ssl_set(*ssl_options) if ssl_options.any? @@ -57,7 +60,7 @@ def initialize(opts = {}) port = opts[:port] database = opts[:database] || opts[:dbname] || opts[:db] socket = opts[:socket] || opts[:sock] - flags = opts[:flags] ? opts[:flags] | @query_options[:connect_flags] : @query_options[:connect_flags] + flags = opts[:flags] ? opts[:flags] | @connect_options[:connect_flags] : @connect_options[:connect_flags] # Correct the data types before passing these values down to the C level user = user.to_s unless user.nil? @@ -66,10 +69,15 @@ def initialize(opts = {}) port = port.to_i unless port.nil? database = database.to_s unless database.nil? socket = socket.to_s unless socket.nil? + flags = flags.to_i # if nil then 0 connect user, pass, host, port, database, socket, flags end + def self.default_connect_options + @@default_connect_options + end + def self.default_query_options @@default_query_options end From 11ba7015c195dd95dfc75b245915f813e4c9b6e7 Mon Sep 17 00:00:00 2001 From: Aaron Stone Date: Mon, 23 Feb 2015 18:13:55 -0800 Subject: [PATCH 2/3] Remove deprecated connection options, raise instead of warn if they are used --- lib/mysql2/client.rb | 33 +++++++++++++-------------------- 1 file changed, 13 insertions(+), 20 deletions(-) diff --git a/lib/mysql2/client.rb b/lib/mysql2/client.rb index 5dd825570..0ed1acc2b 100644 --- a/lib/mysql2/client.rb +++ b/lib/mysql2/client.rb @@ -47,29 +47,22 @@ def initialize(opts = {}) ssl_options = opts.values_at(:sslkey, :sslcert, :sslca, :sslcapath, :sslcipher) ssl_set(*ssl_options) if ssl_options.any? - if [:user,:pass,:hostname,:dbname,:db,:sock].any?{|k| @query_options.has_key?(k) } - warn "============= WARNING FROM mysql2 =============" - warn "The options :user, :pass, :hostname, :dbname, :db, and :sock will be deprecated at some point in the future." - warn "Instead, please use :username, :password, :host, :port, :database, :socket, :flags for the options." - warn "============= END WARNING FROM mysql2 =========" + if [:user, :pass, :hostname, :dbname, :db, :sock].any? { |k| @connect_options.has_key? k } + raise <<-DEPR +The options :user, :pass, :hostname, :dbname, :db, :sock are removed. +Please use :username, :password, :host, :port, :database, :socket instead. +DEPR end - user = opts[:username] || opts[:user] - pass = opts[:password] || opts[:pass] - host = opts[:host] || opts[:hostname] - port = opts[:port] - database = opts[:database] || opts[:dbname] || opts[:db] - socket = opts[:socket] || opts[:sock] - flags = opts[:flags] ? opts[:flags] | @connect_options[:connect_flags] : @connect_options[:connect_flags] - # Correct the data types before passing these values down to the C level - user = user.to_s unless user.nil? - pass = pass.to_s unless pass.nil? - host = host.to_s unless host.nil? - port = port.to_i unless port.nil? - database = database.to_s unless database.nil? - socket = socket.to_s unless socket.nil? - flags = flags.to_i # if nil then 0 + user = opts[:username].to_s unless opts[:username].nil? + pass = opts[:password].to_s unless opts[:password].nil? + host = opts[:host].to_s unless opts[:host].nil? + port = opts[:port].to_i unless opts[:port].nil? + database = opts[:database].to_s unless opts[:database].nil? + socket = opts[:socket].to_s unless opts[:socket].nil? + flags = opts[:flags] ? opts[:flags] | @connect_options[:connect_flags] : @connect_options[:connect_flags] + flags ||= 0 # if nil then 0 connect user, pass, host, port, database, socket, flags end From 2f48f3a40a5974f881c25fc151f2a309c8e8eaee Mon Sep 17 00:00:00 2001 From: Aaron Stone Date: Thu, 11 Jun 2015 22:11:10 -0700 Subject: [PATCH 3/3] Move @@default_..._options to class methods to avoid @@ semantics Recommended in #596 --- ext/mysql2/client.c | 4 ++-- lib/mysql2/client.rb | 37 +++++++++++++++++-------------------- 2 files changed, 19 insertions(+), 22 deletions(-) diff --git a/ext/mysql2/client.c b/ext/mysql2/client.c index a6accbaff..563f89a76 100644 --- a/ext/mysql2/client.c +++ b/ext/mysql2/client.c @@ -639,8 +639,8 @@ static VALUE rb_mysql_client_abandon_results(VALUE self) { /* call-seq: * client.query(sql, options = {}) * - * Query the database with +sql+, with optional +options+. For the possible - * options, see @@default_query_options on the Mysql2::Client class. + * Query the database with +sql+, with optional +options+. + * For available options, see VALID_QUERY_KEYS in the Mysql2::Client class. */ static VALUE rb_query(VALUE self, VALUE sql, VALUE current) { #ifndef _WIN32 diff --git a/lib/mysql2/client.rb b/lib/mysql2/client.rb index 0ed1acc2b..679fc21cd 100644 --- a/lib/mysql2/client.rb +++ b/lib/mysql2/client.rb @@ -3,29 +3,13 @@ class Client attr_reader :connect_options, :query_options, :read_timeout VALID_CONNECT_KEYS = [:connect_flags, :connect_timeout, :encoding, :default_file, :default_group, :read_timeout, :write_timeout, :secure_auth, :init_command, :reconnect, :local_infile] - @@default_connect_options = { - :connect_flags => REMEMBER_OPTIONS | LONG_PASSWORD | LONG_FLAG | TRANSACTIONS | PROTOCOL_41 | SECURE_CONNECTION, - :connect_timeout => 120, # Set default connect_timeout to avoid unlimited retries from signal interruption - :encoding => 'utf8' - } - VALID_QUERY_KEYS = [:as, :async, :cast_booleans, :symbolize_keys, :database_timezone, :application_timezone, :cache_rows, :cast] - @@default_query_options = { - :as => :hash, # the type of object you want each row back as; also supports :array (an array of values) - :async => false, # don't wait for a result after sending the query, you'll have to monitor the socket yourself then eventually call Mysql2::Client#async_result - :cast_booleans => false, # cast tinyint(1) fields as true/false in ruby - :symbolize_keys => false, # return field names as symbols instead of strings - :database_timezone => :local, # timezone Mysql2 will assume datetime objects are stored in - :application_timezone => nil, # timezone Mysql2 will convert to before handing the object back to the caller - :cache_rows => true, # tells Mysql2 to use it's internal row cache for results - :cast => true # cast result fields to corresponding Ruby data types - } def initialize(opts = {}) opts = Mysql2::Util.key_hash_as_symbols(opts) @read_timeout = nil # by default don't timeout on read - @connect_options = @@default_connect_options.merge Hash[ opts.select { |k, v| VALID_CONNECT_KEYS.include? k } ] - @query_options = @@default_query_options.merge Hash[ opts.select { |k, v| VALID_QUERY_KEYS.include? k } ] + @connect_options = self.class.default_connect_options.merge Hash[ opts.select { |k, v| VALID_CONNECT_KEYS.include? k } ] + @query_options = self.class.default_query_options.merge Hash[ opts.select { |k, v| VALID_QUERY_KEYS.include? k } ] initialize_ext @@ -68,11 +52,24 @@ def initialize(opts = {}) end def self.default_connect_options - @@default_connect_options + @default_connect_options ||= { + :connect_flags => REMEMBER_OPTIONS | LONG_PASSWORD | LONG_FLAG | TRANSACTIONS | PROTOCOL_41 | SECURE_CONNECTION, + :connect_timeout => 120, # Set default connect_timeout to avoid unlimited retries from signal interruption + :encoding => 'utf8', + } end def self.default_query_options - @@default_query_options + @default_query_options ||= { + :as => :hash, # the type of object you want each row back as; also supports :array (an array of values) + :async => false, # don't wait for a result after sending the query, you'll have to monitor the socket yourself then eventually call Mysql2::Client#async_result + :cast_booleans => false, # cast tinyint(1) fields as true/false in ruby + :symbolize_keys => false, # return field names as symbols instead of strings + :database_timezone => :local, # timezone Mysql2 will assume datetime objects are stored in + :application_timezone => nil, # timezone Mysql2 will convert to before handing the object back to the caller + :cache_rows => true, # tells Mysql2 to use it's internal row cache for results + :cast => true, # cast result fields to corresponding Ruby data types + } end if Thread.respond_to?(:handle_interrupt)