Class: Mysql2::Client
| Relationships & Source Files | |
| Extension / Inclusion / Inheritance Descendants | |
|
Subclasses:
|
|
| Inherits: | Object |
| Defined in: | lib/mysql2/client.rb, ext/mysql2/client.c |
Class Method Summary
- .default_query_options
-
.escape(string)
Escape
stringso that it may be used in a SQL statement. -
.info
Returns a string that represents the client library version.
- .new(opts = {}) ⇒ Client constructor
- .local_offset private
Instance Attribute Summary
-
#automatic_close=(false)
rw
Set this to
falseto leave the connection open after it is garbage collected. - #automatic_close? ⇒ Boolean rw
- #closed? ⇒ Boolean readonly
-
#more_results? ⇒ Boolean
readonly
Returns true or false if there are more results to process.
- #query_options readonly
- #read_timeout rw
-
#reconnect=(true)
writeonly
Enable or disable the automatic reconnect behavior of libmysql.
- #charset_name=(value) writeonly private
- #connect_timeout=(value) writeonly private
- #default_auth=(value) writeonly private
- #default_file=(value) writeonly private
- #default_group=(value) writeonly private
- #enable_cleartext_plugin=(value) writeonly private
- #get_server_public_key=(value) writeonly private
- #init_command=(value) writeonly private
- #local_infile=(value) writeonly private
- #read_timeout=(value) rw private
- #secure_auth=(value) writeonly private
- #ssl_mode=(setting) writeonly private
- #write_timeout=(value) writeonly private
Instance Method Summary
-
#abandon_results!
When using MULTI_STATEMENTS support, calling this will throw away any unprocessed results as fast as it can in order to put the connection back into a state where queries can be issued again.
-
#affected_rows
returns the number of rows changed, deleted, or inserted by the last statement if it was an UPDATE, DELETE, or INSERT.
-
#async_result
Returns the result for the last async issued query.
-
#close ⇒ nil
Immediately disconnect from the server; normally the garbage collector will disconnect automatically when a connection is no longer needed.
-
#database
Returns the currently selected database.
-
#encoding
Returns the encoding set on the client.
-
#escape(string)
Escape
stringso that it may be used in a SQL statement. -
#find_default_ca_path
Find any default system CA paths to handle system roots by default if stricter validation is requested and no path is provide.
- #info
-
#last_id
Returns the value generated for an AUTO_INCREMENT column by the previous INSERT or UPDATE statement.
-
#next_result
Fetch the next result set from the server.
-
#parse_connect_attrs(conn_attrs)
Set default program_name in performance_schema.session_connect_attrs and performance_schema.session_account_connect_attrs.
- #parse_flags_array(flags, initial = 0)
- #parse_ssl_mode(mode)
-
#ping
Checks whether the connection to the server is working.
-
#prepare(#) ⇒ Mysql2::Statement
Create a new prepared statement.
- #query(sql, options = {})
- #query_info
- #query_info_string
-
#select_db(name)
Causes the database specified by
nameto become the default (current) database on the connection specified by mysql. -
#server_info
Returns a string that represents the server version number.
-
#session_track
Returns information about changes to the session state on the server.
-
#set_server_option(value)
Enables or disables an option for the connection.
- #socket
- #ssl_cipher
-
#store_result
Return the next result object from a query which yielded multiple result sets.
-
#thread_id
Returns the thread ID of the current connection.
- #warning_count
-
#query(sql, options = {})
private
Query the database with
sql, with optionaloptions. - #check_and_clean_query_options private
- #connect(user, pass, host, port, database, socket, flags, conn_attrs) private
- #initialize_ext private
- #ssl_set(key, cert, ca, capath, cipher) private
Constructor Details
.new(opts = {}) ⇒ Client
# File 'lib/mysql2/client.rb', line 21
def initialize(opts = {}) raise Mysql2::Error, "Options parameter must be a Hash" unless opts.is_a? Hash opts = Mysql2::Util.key_hash_as_symbols(opts) @read_timeout = nil @query_options = self.class..dup @query_options.merge! opts initialize_ext # Set default connect_timeout to avoid unlimited retries from signal interruption opts[:connect_timeout] = 120 unless opts.key?(:connect_timeout) # TODO: stricter validation rather than silent massaging %i[reconnect connect_timeout local_infile read_timeout write_timeout default_file default_group secure_auth init_command automatic_close enable_cleartext_plugin default_auth get_server_public_key].each do |key| next unless opts.key?(key) case key when :reconnect, :local_infile, :secure_auth, :automatic_close, :enable_cleartext_plugin, :get_server_public_key send(:"#{key}=", !!opts[key]) # rubocop:disable Style/DoubleNegation when :connect_timeout, :read_timeout, :write_timeout send(:"#{key}=", Integer(opts[key])) unless opts[key].nil? else send(:"#{key}=", opts[key]) end end # force the encoding to utf8mb4 self.charset_name = opts[:encoding] || 'utf8mb4' mode = parse_ssl_mode(opts[:ssl_mode]) if opts[:ssl_mode] if (mode == SSL_MODE_VERIFY_CA || mode == SSL_MODE_VERIFY_IDENTITY) && !opts[:sslca] opts[:sslca] = find_default_ca_path end = opts.values_at(:sslkey, :sslcert, :sslca, :sslcapath, :sslcipher) ssl_set(*) if .any? || opts.key?(:sslverify) self.ssl_mode = mode if mode flags = case opts[:flags] when Array parse_flags_array(opts[:flags], @query_options[:connect_flags]) when String parse_flags_array(opts[:flags].split(' '), @query_options[:connect_flags]) when Integer @query_options[:connect_flags] | opts[:flags] else @query_options[:connect_flags] end # SSL verify is a connection flag rather than a mysql_ssl_set option flags |= SSL_VERIFY_SERVER_CERT if opts[:sslverify] 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] # 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? conn_attrs = parse_connect_attrs(opts[:connect_attrs]) connect user, pass, host, port, database, socket, flags, conn_attrs end
Class Method Details
.default_query_options
[ GitHub ]# File 'lib/mysql2/client.rb', line 5
def self. @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 its internal row cache for results connect_flags: REMEMBER_OPTIONS | LONG_PASSWORD | LONG_FLAG | TRANSACTIONS | PROTOCOL_41 | SECURE_CONNECTION | CONNECT_ATTRS, cast: true, default_file: nil, default_group: nil, } end
.escape(string)
Escape string so that it may be used in a SQL statement. Note that this escape method is not connection encoding aware. If you need encoding support use #escape instead.
# File 'ext/mysql2/client.c', line 430
static VALUE rb_mysql_client_escape(RB_MYSQL_UNUSED VALUE klass, VALUE str) {
unsigned char *newStr;
VALUE rb_str;
unsigned long newLen, oldLen;
Check_Type(str, T_STRING);
oldLen = RSTRING_LEN(str);
newStr = xmalloc(oldLen*2+1);
newLen = mysql_escape_string((char *)newStr, RSTRING_PTR(str), oldLen);
if (newLen == oldLen) {
/* no need to return a new ruby string if nothing changed */
xfree(newStr);
return str;
} else {
rb_str = rb_str_new((const char*)newStr, newLen);
rb_enc_copy(rb_str, str);
xfree(newStr);
return rb_str;
}
}
.info
Returns a string that represents the client library version.
# File 'ext/mysql2/client.c', line 1055
static VALUE rb_mysql_client_info(RB_MYSQL_UNUSED VALUE klass) {
VALUE version_info, version, header_version;
version_info = rb_hash_new();
version = rb_str_new2(mysql_get_client_info());
header_version = rb_str_new2(MYSQL_LINK_VERSION);
rb_enc_associate(version, rb_usascii_encoding());
rb_enc_associate(header_version, rb_usascii_encoding());
rb_hash_aset(version_info, sym_id, LONG2NUM(mysql_get_client_version()));
rb_hash_aset(version_info, sym_version, version);
rb_hash_aset(version_info, sym_header_version, header_version);
return version_info;
}
.local_offset (private)
[ GitHub ]# File 'lib/mysql2/client.rb', line 181
def local_offset ::Time.local(2010).utc_offset.to_r / 86400 end
Instance Attribute Details
#automatic_close=(false) (rw)
Set this to false to leave the connection open after it is garbage collected. To avoid “Aborted connection” errors on the server, explicitly call #close when the connection is no longer needed.
# File 'ext/mysql2/client.c', line 1378
static VALUE set_automatic_close(VALUE self, VALUE value) {
GET_CLIENT(self);
if (RTEST(value)) {
wrapper->automatic_close = 1;
} else {
#ifndef _WIN32
wrapper->automatic_close = 0;
#else
rb_warn("Connections are always closed by garbage collector on Windows");
#endif
}
return value;
}
#automatic_close? ⇒ Boolean (rw)
# File 'ext/mysql2/client.c', line 1364
static VALUE get_automatic_close(VALUE self) {
GET_CLIENT(self);
return wrapper->automatic_close ? Qtrue : Qfalse;
}
#charset_name=(value) (writeonly, private)
[ GitHub ]# File 'ext/mysql2/client.c', line 1441
static VALUE set_charset_name(VALUE self, VALUE value) {
char *charset_name;
const struct mysql2_mysql_enc_name_to_rb_map *mysql2rb;
rb_encoding *enc;
VALUE rb_enc;
GET_CLIENT(self);
Check_Type(value, T_STRING);
charset_name = RSTRING_PTR(value);
mysql2rb = mysql2_mysql_enc_name_to_rb(charset_name, (unsigned int)RSTRING_LEN(value));
if (mysql2rb == NULL || mysql2rb->rb_name == NULL) {
VALUE inspect = rb_inspect(value);
rb_raise(cMysql2Error, "Unsupported charset: '%s'", RSTRING_PTR(inspect));
} else {
enc = rb_enc_find(mysql2rb->rb_name);
rb_enc = rb_enc_from_encoding(enc);
wrapper->encoding = rb_enc;
}
if (mysql_options(wrapper->client, MYSQL_SET_CHARSET_NAME, charset_name)) {
/* TODO: warning - unable to set charset */
rb_warn("%s\n", mysql_error(wrapper->client));
}
return value;
}
#closed? ⇒ Boolean (readonly)
# File 'ext/mysql2/client.c', line 587
static VALUE rb_mysql_client_closed(VALUE self) {
GET_CLIENT(self);
return CONNECTED(wrapper) ? Qfalse : Qtrue;
}
#connect_timeout=(value) (writeonly, private)
[ GitHub ]# File 'ext/mysql2/client.c', line 1407
static VALUE set_connect_timeout(VALUE self, VALUE value) {
long int sec;
Check_Type(value, T_FIXNUM);
sec = FIX2INT(value);
if (sec < 0) {
rb_raise(cMysql2Error, "connect_timeout must be a positive integer, you passed %ld", sec);
}
return _mysql_client_options(self, MYSQL_OPT_CONNECT_TIMEOUT, value);
}
#default_auth=(value) (writeonly, private)
[ GitHub ]# File 'ext/mysql2/client.c', line 1530
static VALUE set_default_auth(VALUE self, VALUE value) {
#ifdef HAVE_MYSQL_DEFAULT_AUTH
return _mysql_client_options(self, MYSQL_DEFAULT_AUTH, value);
#else
rb_raise(cMysql2Error, "pluggable authentication is not available, you may need a newer MySQL client library");
#endif
}
#default_file=(value) (writeonly, private)
[ GitHub ]# File 'ext/mysql2/client.c', line 1510
static VALUE set_read_default_file(VALUE self, VALUE value) {
return _mysql_client_options(self, MYSQL_READ_DEFAULT_FILE, value);
}
#default_group=(value) (writeonly, private)
[ GitHub ]# File 'ext/mysql2/client.c', line 1514
static VALUE set_read_default_group(VALUE self, VALUE value) {
return _mysql_client_options(self, MYSQL_READ_DEFAULT_GROUP, value);
}
#enable_cleartext_plugin=(value) (writeonly, private)
[ GitHub ]# File 'ext/mysql2/client.c', line 1538
static VALUE set_enable_cleartext_plugin(VALUE self, VALUE value) {
#ifdef HAVE_CONST_MYSQL_ENABLE_CLEARTEXT_PLUGIN
return _mysql_client_options(self, MYSQL_ENABLE_CLEARTEXT_PLUGIN, value);
#else
rb_raise(cMysql2Error, "enable-cleartext-plugin is not available, you may need a newer MySQL client library");
#endif
}
#get_server_public_key=(value) (writeonly, private)
[ GitHub ]# File 'ext/mysql2/client.c', line 1522
static VALUE set_get_server_public_key(VALUE self, VALUE value) {
#ifdef HAVE_CONST_MYSQL_OPT_GET_SERVER_PUBLIC_KEY
return _mysql_client_options(self, MYSQL_OPT_GET_SERVER_PUBLIC_KEY, value);
#else
rb_raise(cMysql2Error, "get-server-public-key is not available, you may need a newer MySQL client library");
#endif
}
#init_command=(value) (writeonly, private)
[ GitHub ]# File 'ext/mysql2/client.c', line 1518
static VALUE set_init_command(VALUE self, VALUE value) {
return _mysql_client_options(self, MYSQL_INIT_COMMAND, value);
}
#local_infile=(value) (writeonly, private)
[ GitHub ]# File 'ext/mysql2/client.c', line 1403
static VALUE set_local_infile(VALUE self, VALUE value) {
return _mysql_client_options(self, MYSQL_OPT_LOCAL_INFILE, value);
}
#more_results? ⇒ Boolean (readonly)
Returns true or false if there are more results to process.
# File 'ext/mysql2/client.c', line 1266
static VALUE rb_mysql_client_more_results(VALUE self)
{
GET_CLIENT(self);
if (mysql_more_results(wrapper->client) == 0)
return Qfalse;
else
return Qtrue;
}
#query_options (readonly)
[ GitHub ]# File 'lib/mysql2/client.rb', line 3
attr_reader :, :read_timeout
#read_timeout (rw)
[ GitHub ]# File 'lib/mysql2/client.rb', line 3
attr_reader :, :read_timeout
#read_timeout=(value) (rw, private)
[ GitHub ]# File 'ext/mysql2/client.c', line 1417
static VALUE set_read_timeout(VALUE self, VALUE value) {
long int sec;
Check_Type(value, T_FIXNUM);
sec = FIX2INT(value);
if (sec < 0) {
rb_raise(cMysql2Error, "read_timeout must be a positive integer, you passed %ld", sec);
}
/* Set the instance variable here even though _mysql_client_options
might not succeed, because the timeout is used in other ways
elsewhere */
rb_ivar_set(self, intern_read_timeout, value);
return _mysql_client_options(self, MYSQL_OPT_READ_TIMEOUT, value);
}
#reconnect=(true) (writeonly)
Enable or disable the automatic reconnect behavior of libmysql. Read dev.mysql.com/doc/refman/5.5/en/auto-reconnect.html for more information.
# File 'ext/mysql2/client.c', line 1399
static VALUE set_reconnect(VALUE self, VALUE value) {
return _mysql_client_options(self, MYSQL_OPT_RECONNECT, value);
}
#secure_auth=(value) (writeonly, private)
[ GitHub ]# File 'ext/mysql2/client.c', line 1501
static VALUE set_secure_auth(VALUE self, VALUE value) {
/* This option was deprecated in MySQL 5.x and removed in MySQL 8.0 */
#ifdef MYSQL_SECURE_AUTH
return _mysql_client_options(self, MYSQL_SECURE_AUTH, value);
#else
return Qfalse;
#endif
}
#ssl_mode=(setting) (writeonly, private)
[ GitHub ]# File 'ext/mysql2/client.c', line 124
static VALUE rb_set_ssl_mode_option(VALUE self, VALUE setting) {
unsigned long version = mysql_get_client_version();
const char *version_str = mysql_get_client_info();
/* Warn about versions that are known to be incomplete; these are pretty
* ancient, we want people to upgrade if they need SSL/TLS to work
*
* MySQL 5.x before 5.6.30 -- ssl_mode introduced but not fully working until 5.6.36)
* MySQL 5.7 before 5.7.3 -- ssl_mode introduced but not fully working until 5.7.11)
*/
if ((version >= 50000 && version < 50630) || (version >= 50700 && version < 50703)) {
rb_warn("Your mysql client library version %s does not support setting ssl_mode; full support comes with 5.6.36+, 5.7.11+, 8.0+", version_str);
return Qnil;
}
/* For these versions, map from the options we're exposing to Ruby to the constant available:
* ssl_mode: :verify_identity to MYSQL_OPT_SSL_VERIFY_SERVER_CERT = 1
* ssl_mode: :required to MYSQL_OPT_SSL_ENFORCE = 1
* ssl_mode: :disabled to MYSQL_OPT_SSL_ENFORCE = 0
*/
#if defined(HAVE_CONST_MYSQL_OPT_SSL_VERIFY_SERVER_CERT) || defined(HAVE_CONST_MYSQL_OPT_SSL_ENFORCE)
GET_CLIENT(self);
int val = NUM2INT(setting);
/* Expected code path for MariaDB 10.x and MariaDB Connector/C 3.x
* Workaround code path for MySQL 5.7.3 - 5.7.10 and MySQL Connector/C 6.1.3 - 6.1.x
*/
if (version >= 100000 // MariaDB (all versions numbered 10.x)
|| (version >= 30000 && version < 40000) // MariaDB Connector/C (all versions numbered 3.x)
|| (version >= 50703 && version < 50711) // Workaround for MySQL 5.7.3 - 5.7.10
|| (version >= 60103 && version < 60200)) { // Workaround for MySQL Connector/C 6.1.3 - 6.1.x
#ifdef HAVE_CONST_MYSQL_OPT_SSL_VERIFY_SERVER_CERT
if (val == SSL_MODE_VERIFY_IDENTITY) {
my_bool b = 1;
int result = mysql_options(wrapper->client, MYSQL_OPT_SSL_VERIFY_SERVER_CERT, &b);
return INT2NUM(result);
}
#endif
#ifdef HAVE_CONST_MYSQL_OPT_SSL_ENFORCE
if (val == SSL_MODE_DISABLED || val == SSL_MODE_REQUIRED) {
my_bool b = (val == SSL_MODE_REQUIRED);
int result = mysql_options(wrapper->client, MYSQL_OPT_SSL_ENFORCE, &b);
return INT2NUM(result);
}
#endif
rb_warn("Your mysql client library version %s does not support ssl_mode %d", version_str, val);
return Qnil;
} else {
rb_warn("Your mysql client library version %s does not support ssl_mode as expected", version_str);
return Qnil;
}
#endif
/* For other versions -- known to be MySQL 5.6.36+, 5.7.11+, 8.0+
* pass the value of the argument to MYSQL_OPT_SSL_MODE -- note the code
* mapping from atoms / constants is in the MySQL::Client Ruby class
*/
#ifdef FULL_SSL_MODE_SUPPORT
GET_CLIENT(self);
int val = NUM2INT(setting);
if (val != SSL_MODE_DISABLED && val != SSL_MODE_PREFERRED && val != SSL_MODE_REQUIRED && val != SSL_MODE_VERIFY_CA && val != SSL_MODE_VERIFY_IDENTITY) {
rb_raise(cMysql2Error, "ssl_mode= takes DISABLED, PREFERRED, REQUIRED, VERIFY_CA, VERIFY_IDENTITY, you passed: %d", val );
}
int result = mysql_options(wrapper->client, MYSQL_OPT_SSL_MODE, &val);
return INT2NUM(result);
#endif
// Warn if we get this far
#ifdef NO_SSL_MODE_SUPPORT
rb_warn("Your mysql client library does not support setting ssl_mode");
return Qnil;
#endif
}
#write_timeout=(value) (writeonly, private)
[ GitHub ]# File 'ext/mysql2/client.c', line 1431
static VALUE set_write_timeout(VALUE self, VALUE value) {
long int sec;
Check_Type(value, T_FIXNUM);
sec = FIX2INT(value);
if (sec < 0) {
rb_raise(cMysql2Error, "write_timeout must be a positive integer, you passed %ld", sec);
}
return _mysql_client_options(self, MYSQL_OPT_WRITE_TIMEOUT, value);
}
Instance Method Details
#query(sql, options = {}) (private)
Query the database with sql, with optional options. For the possible options, see default_query_options on the Client class.
# File 'ext/mysql2/client.c', line 855
static VALUE rb_mysql_query(VALUE self, VALUE sql, VALUE current) {
#ifndef _WIN32
struct async_query_args async_args;
#endif
struct nogvl_send_query_args args;
GET_CLIENT(self);
REQUIRE_CONNECTED(wrapper);
args.mysql = wrapper->client;
(void)RB_GC_GUARD(current);
Check_Type(current, T_HASH);
rb_ivar_set(self, intern_current_query_options, current);
Check_Type(sql, T_STRING);
/* ensure the string is in the encoding the connection is expecting */
args.sql = rb_str_export_to_enc(sql, rb_to_encoding(wrapper->encoding));
args.sql_ptr = RSTRING_PTR(args.sql);
args.sql_len = RSTRING_LEN(args.sql);
args.wrapper = wrapper;
rb_mysql_client_set_active_fiber(self);
#ifndef _WIN32
rb_rescue2(do_send_query, (VALUE)&args, disconnect_and_raise, self, rb_eException, (VALUE)0);
(void)RB_GC_GUARD(sql);
if (rb_hash_aref(current, sym_async) == Qtrue) {
return Qnil;
} else {
async_args.fd = wrapper->client->net.fd;
async_args.self = self;
rb_rescue2(do_query, (VALUE)&async_args, disconnect_and_raise, self, rb_eException, (VALUE)0);
return rb_ensure(rb_mysql_client_async_result, self, disconnect_and_mark_inactive, self);
}
#else
do_send_query((VALUE)&args);
(void)RB_GC_GUARD(sql);
/* this will just block until the result is ready */
return rb_ensure(rb_mysql_client_async_result, self, disconnect_and_mark_inactive, self);
#endif
}
#abandon_results!
When using MULTI_STATEMENTS support, calling this will throw away any unprocessed results as fast as it can in order to put the connection back into a state where queries can be issued again.
# File 'ext/mysql2/client.c', line 827
static VALUE rb_mysql_client_abandon_results(VALUE self) {
MYSQL_RES *result;
int ret;
GET_CLIENT(self);
while (mysql_more_results(wrapper->client) == 1) {
ret = mysql_next_result(wrapper->client);
if (ret > 0) {
rb_raise_mysql2_error(wrapper);
}
result = (MYSQL_RES *)rb_thread_call_without_gvl(nogvl_store_result, wrapper, RUBY_UBF_IO, 0);
if (result != NULL) {
mysql_free_result(result);
}
}
return Qnil;
}
#affected_rows
returns the number of rows changed, deleted, or inserted by the last statement if it was an UPDATE, DELETE, or INSERT.
# File 'ext/mysql2/client.c', line 1163
static VALUE rb_mysql_client_affected_rows(VALUE self) {
uint64_t retVal;
GET_CLIENT(self);
REQUIRE_CONNECTED(wrapper);
retVal = wrapper->affected_rows;
if (retVal == (my_ulonglong)-1) {
rb_raise_mysql2_error(wrapper);
}
return ULL2NUM(retVal);
}
#async_result
Returns the result for the last async issued query.
# File 'ext/mysql2/client.c', line 660
static VALUE rb_mysql_client_async_result(VALUE self) {
MYSQL_RES * result;
VALUE resultObj;
VALUE current, is_streaming;
GET_CLIENT(self);
/* if we're not waiting on a result, do nothing */
if (NIL_P(wrapper->active_fiber))
return Qnil;
REQUIRE_CONNECTED(wrapper);
if ((VALUE)rb_thread_call_without_gvl(nogvl_read_query_result, wrapper->client, RUBY_UBF_IO, 0) == Qfalse) {
/* an error occurred, mark this connection inactive */
wrapper->active_fiber = Qnil;
rb_raise_mysql2_error(wrapper);
}
is_streaming = rb_hash_aref(rb_ivar_get(self, intern_current_query_options), sym_stream);
if (is_streaming == Qtrue) {
result = (MYSQL_RES *)rb_thread_call_without_gvl(nogvl_use_result, wrapper, RUBY_UBF_IO, 0);
} else {
result = (MYSQL_RES *)rb_thread_call_without_gvl(nogvl_store_result, wrapper, RUBY_UBF_IO, 0);
}
wrapper->affected_rows = mysql_affected_rows(wrapper->client);
if (result == NULL) {
if (mysql_errno(wrapper->client) != 0) {
wrapper->active_fiber = Qnil;
rb_raise_mysql2_error(wrapper);
}
/* no data and no error, so query was not a SELECT */
return Qnil;
}
// Duplicate the options hash and put the copy in the Result object
current = rb_hash_dup(rb_ivar_get(self, intern_current_query_options));
(void)RB_GC_GUARD(current);
Check_Type(current, T_HASH);
resultObj = rb_mysql_result_to_obj(self, wrapper->encoding, current, result, Qnil);
rb_mysql_set_server_query_flags(wrapper->client, resultObj);
return resultObj;
}
#check_and_clean_query_options (private)
[ GitHub ]# File 'lib/mysql2/client.rb', line 165
def if %i[user pass hostname dbname db sock].any? { |k| @query_options.key?(k) } warn "============= WARNING FROM mysql2 =============" warn "The options :user, :pass, :hostname, :dbname, :db, and :sock are deprecated and will be removed 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 =========" end # avoid logging sensitive data via #inspect @query_options.delete(:password) @query_options.delete(:pass) end
#close ⇒ nil
Immediately disconnect from the server; normally the garbage collector will disconnect automatically when a connection is no longer needed. Explicitly closing this will free up server resources sooner than waiting for the garbage collector.
# File 'ext/mysql2/client.c', line 572
static VALUE rb_mysql_client_close(VALUE self) {
GET_CLIENT(self);
if (wrapper->client) {
rb_thread_call_without_gvl(nogvl_close, wrapper, RUBY_UBF_IO, 0);
}
return Qnil;
}
#connect(user, pass, host, port, database, socket, flags, conn_attrs) (private)
[ GitHub ]# File 'ext/mysql2/client.c', line 510
static VALUE rb_mysql_connect(VALUE self, VALUE user, VALUE pass, VALUE host, VALUE port, VALUE database, VALUE socket, VALUE flags, VALUE conn_attrs) {
struct nogvl_connect_args args;
time_t start_time, end_time, elapsed_time, connect_timeout;
VALUE rv;
GET_CLIENT(self);
args.host = NIL_P(host) ? NULL : StringValueCStr(host);
args.unix_socket = NIL_P(socket) ? NULL : StringValueCStr(socket);
args.port = NIL_P(port) ? 0 : NUM2INT(port);
args.user = NIL_P(user) ? NULL : StringValueCStr(user);
args.passwd = NIL_P(pass) ? NULL : StringValueCStr(pass);
args.db = NIL_P(database) ? NULL : StringValueCStr(database);
args.mysql = wrapper->client;
args.client_flag = NUM2ULONG(flags);
#ifdef CLIENT_CONNECT_ATTRS
mysql_options(wrapper->client, MYSQL_OPT_CONNECT_ATTR_RESET, 0);
rb_hash_foreach(conn_attrs, opt_connect_attr_add_i, (VALUE)wrapper);
#endif
if (wrapper->connect_timeout)
time(&start_time);
rv = (VALUE) rb_thread_call_without_gvl(nogvl_connect, &args, RUBY_UBF_IO, 0);
if (rv == Qfalse) {
while (rv == Qfalse && errno == EINTR) {
if (wrapper->connect_timeout) {
time(&end_time);
/* avoid long connect timeout from system time changes */
if (end_time < start_time)
start_time = end_time;
elapsed_time = end_time - start_time;
/* avoid an early timeout due to time truncating milliseconds off the start time */
if (elapsed_time > 0)
elapsed_time--;
if (elapsed_time >= (time_t)wrapper->connect_timeout)
break;
connect_timeout = wrapper->connect_timeout - elapsed_time;
mysql_options(wrapper->client, MYSQL_OPT_CONNECT_TIMEOUT, &connect_timeout);
}
errno = 0;
rv = (VALUE) rb_thread_call_without_gvl(nogvl_connect, &args, RUBY_UBF_IO, 0);
}
/* restore the connect timeout for reconnecting */
if (wrapper->connect_timeout)
mysql_options(wrapper->client, MYSQL_OPT_CONNECT_TIMEOUT, &wrapper->connect_timeout);
if (rv == Qfalse)
rb_raise_mysql2_error(wrapper);
}
wrapper->closed = 0;
wrapper->server_version = mysql_get_server_version(wrapper->client);
return self;
}
#database
Returns the currently selected database.
The result may be stale if session_track_schema is disabled. Read dev.mysql.com/doc/refman/5.7/en/session-state-tracking.html for more information.
# File 'ext/mysql2/client.c', line 1348
static VALUE rb_mysql_client_database(VALUE self) {
GET_CLIENT(self);
char *db = wrapper->client->db;
if (!db) {
return Qnil;
}
return rb_str_new_cstr(wrapper->client->db);
}
#encoding
Returns the encoding set on the client.
# File 'ext/mysql2/client.c', line 1334
static VALUE rb_mysql_client_encoding(VALUE self) {
GET_CLIENT(self);
return wrapper->encoding;
}
#escape(string)
Escape string so that it may be used in a SQL statement.
# File 'ext/mysql2/client.c', line 906
static VALUE rb_mysql_client_real_escape(VALUE self, VALUE str) {
unsigned char *newStr;
VALUE rb_str;
unsigned long newLen, oldLen;
rb_encoding *default_internal_enc;
rb_encoding *conn_enc;
GET_CLIENT(self);
REQUIRE_CONNECTED(wrapper);
Check_Type(str, T_STRING);
default_internal_enc = rb_default_internal_encoding();
conn_enc = rb_to_encoding(wrapper->encoding);
/* ensure the string is in the encoding the connection is expecting */
str = rb_str_export_to_enc(str, conn_enc);
oldLen = RSTRING_LEN(str);
newStr = xmalloc(oldLen*2+1);
newLen = mysql_real_escape_string(wrapper->client, (char *)newStr, RSTRING_PTR(str), oldLen);
if (newLen == oldLen) {
/* no need to return a new ruby string if nothing changed */
if (default_internal_enc) {
str = rb_str_export_to_enc(str, default_internal_enc);
}
xfree(newStr);
return str;
} else {
rb_str = rb_str_new((const char*)newStr, newLen);
rb_enc_associate(rb_str, conn_enc);
if (default_internal_enc) {
rb_str = rb_str_export_to_enc(rb_str, default_internal_enc);
}
xfree(newStr);
return rb_str;
}
}
#find_default_ca_path
Find any default system CA paths to handle system roots by default if stricter validation is requested and no path is provide.
# File 'lib/mysql2/client.rb', line 123
def find_default_ca_path [ "/etc/ssl/certs/ca-certificates.crt", "/etc/pki/tls/certs/ca-bundle.crt", "/etc/ssl/ca-bundle.pem", "/etc/ssl/cert.pem", ].find { |f| File.exist?(f) } end
#info
[ GitHub ]# File 'lib/mysql2/client.rb', line 159
def info self.class.info end
#initialize_ext (private)
[ GitHub ]# File 'ext/mysql2/client.c', line 1546
static VALUE initialize_ext(VALUE self) {
GET_CLIENT(self);
if ((VALUE)rb_thread_call_without_gvl(nogvl_init, wrapper, RUBY_UBF_IO, 0) == Qfalse) {
/* TODO: warning - not enough memory? */
rb_raise_mysql2_error(wrapper);
}
wrapper->initialized = 1;
return self;
}
#last_id
Returns the value generated for an AUTO_INCREMENT column by the previous INSERT or UPDATE statement.
# File 'ext/mysql2/client.c', line 1121
static VALUE rb_mysql_client_last_id(VALUE self) {
GET_CLIENT(self);
REQUIRE_CONNECTED(wrapper);
return ULL2NUM(mysql_insert_id(wrapper->client));
}
#next_result
Fetch the next result set from the server. Returns nothing.
# File 'ext/mysql2/client.c', line 1281
static VALUE rb_mysql_client_next_result(VALUE self)
{
int ret;
GET_CLIENT(self);
ret = mysql_next_result(wrapper->client);
wrapper->affected_rows = mysql_affected_rows(wrapper->client);
if (ret > 0) {
rb_raise_mysql2_error(wrapper);
return Qfalse;
} else if (ret == 0) {
return Qtrue;
} else {
return Qfalse;
}
}
#parse_connect_attrs(conn_attrs)
Set default program_name in performance_schema.session_connect_attrs and performance_schema.session_account_connect_attrs
# File 'lib/mysql2/client.rb', line 134
def parse_connect_attrs(conn_attrs) return {} if Mysql2::Client::CONNECT_ATTRS.zero? conn_attrs ||= {} conn_attrs[:program_name] ||= $PROGRAM_NAME conn_attrs.each_with_object({}) do |(key, value), hash| hash[key.to_s] = value.to_s end end
#parse_flags_array(flags, initial = 0)
[ GitHub ]# File 'lib/mysql2/client.rb', line 106
def parse_flags_array(flags, initial = 0) flags.reduce(initial) do |memo, f| fneg = f.start_with?('-') ? f[1..-1] : nil if fneg && fneg =~ /^\w+$/ && Mysql2::Client.const_defined?(fneg) memo & ~ Mysql2::Client.const_get(fneg) elsif f && f =~ /^\w+$/ && Mysql2::Client.const_defined?(f) memo | Mysql2::Client.const_get(f) else warn "Unknown MySQL connection flag: '#{f}'" memo end end end
#parse_ssl_mode(mode)
[ GitHub ]# File 'lib/mysql2/client.rb', line 95
def parse_ssl_mode(mode) m = mode.to_s.upcase if m.start_with?('SSL_MODE_') return Mysql2::Client.const_get(m) if Mysql2::Client.const_defined?(m) else x = 'SSL_MODE_' + m return Mysql2::Client.const_get(x) if Mysql2::Client.const_defined?(x) end warn "Unknown MySQL ssl_mode flag: #{mode}" end
#ping
Checks whether the connection to the server is working. If the connection has gone down and auto-reconnect is enabled an attempt to reconnect is made. If the connection is down and auto-reconnect is disabled, ping returns an error.
# File 'ext/mysql2/client.c', line 1234
static VALUE rb_mysql_client_ping(VALUE self) {
GET_CLIENT(self);
if (!CONNECTED(wrapper)) {
return Qfalse;
} else {
return (VALUE)rb_thread_call_without_gvl(nogvl_ping, wrapper->client, RUBY_UBF_IO, 0);
}
}
#prepare(#) ⇒ Mysql2::Statement
Create a new prepared statement.
# File 'ext/mysql2/client.c', line 1562
static VALUE rb_mysql_client_prepare_statement(VALUE self, VALUE sql) {
GET_CLIENT(self);
REQUIRE_CONNECTED(wrapper);
return rb_mysql_stmt_new(self, sql);
}
#query(sql, options = {})
[ GitHub ]# File 'lib/mysql2/client.rb', line 144
def query(sql, = {}) Thread.handle_interrupt(::Mysql2::Util::TIMEOUT_ERROR_NEVER) do _query(sql, @query_options.merge()) end end
#query_info
[ GitHub ]# File 'lib/mysql2/client.rb', line 150
def query_info info = query_info_string return {} unless info info_hash = {} info.split.each_slice(2) { |s| info_hash[s[0].downcase.delete(':').to_sym] = s[1].to_i } info_hash end
#query_info_string
[ GitHub ]# File 'ext/mysql2/client.c', line 462
static VALUE rb_mysql_info(VALUE self) {
const char *info;
VALUE rb_str;
GET_CLIENT(self);
info = mysql_info(wrapper->client);
if (info == NULL) {
return Qnil;
}
rb_str = rb_str_new2(info);
rb_enc_associate(rb_str, rb_utf8_encoding());
return rb_str;
}
#select_db(name)
Causes the database specified by name to become the default (current) database on the connection specified by mysql.
# File 'ext/mysql2/client.c', line 1204
static VALUE rb_mysql_client_select_db(VALUE self, VALUE db)
{
struct nogvl_select_db_args args;
GET_CLIENT(self);
REQUIRE_CONNECTED(wrapper);
args.mysql = wrapper->client;
args.db = StringValueCStr(db);
if (rb_thread_call_without_gvl(nogvl_select_db, &args, RUBY_UBF_IO, 0) == Qfalse)
rb_raise_mysql2_error(wrapper);
return db;
}
#server_info
Returns a string that represents the server version number
# File 'ext/mysql2/client.c', line 1077
static VALUE rb_mysql_client_server_info(VALUE self) {
VALUE version, server_info;
rb_encoding *default_internal_enc;
rb_encoding *conn_enc;
GET_CLIENT(self);
REQUIRE_CONNECTED(wrapper);
default_internal_enc = rb_default_internal_encoding();
conn_enc = rb_to_encoding(wrapper->encoding);
version = rb_hash_new();
rb_hash_aset(version, sym_id, LONG2FIX(mysql_get_server_version(wrapper->client)));
server_info = rb_str_new2(mysql_get_server_info(wrapper->client));
rb_enc_associate(server_info, conn_enc);
if (default_internal_enc) {
server_info = rb_str_export_to_enc(server_info, default_internal_enc);
}
rb_hash_aset(version, sym_version, server_info);
return version;
}
#session_track
Returns information about changes to the session state on the server.
# File 'ext/mysql2/client.c', line 1132
static VALUE rb_mysql_client_session_track(VALUE self, VALUE type) {
#ifdef CLIENT_SESSION_TRACK
const char *data;
size_t length;
my_ulonglong retVal;
GET_CLIENT(self);
REQUIRE_CONNECTED(wrapper);
retVal = mysql_session_track_get_first(wrapper->client, NUM2INT(type), &data, &length);
if (retVal != 0) {
return Qnil;
}
VALUE rbAry = rb_ary_new();
VALUE rbFirst = rb_str_new(data, length);
rb_ary_push(rbAry, rbFirst);
while(mysql_session_track_get_next(wrapper->client, NUM2INT(type), &data, &length) == 0) {
VALUE rbNext = rb_str_new(data, length);
rb_ary_push(rbAry, rbNext);
}
return rbAry;
#else
return Qnil;
#endif
}
#set_server_option(value)
Enables or disables an option for the connection. Read dev.mysql.com/doc/refman/5.7/en/mysql-set-server-option.html for more information.
# File 'ext/mysql2/client.c', line 1251
static VALUE rb_mysql_client_set_server_option(VALUE self, VALUE value) {
GET_CLIENT(self);
if (mysql_set_server_option(wrapper->client, NUM2INT(value)) == 0) {
return Qtrue;
} else {
return Qfalse;
}
}
#socket
[ GitHub ]# File 'ext/mysql2/client.c', line 1110
static VALUE rb_mysql_client_socket(RB_MYSQL_UNUSED VALUE self) {
rb_raise(cMysql2Error, "Raw access to the mysql file descriptor isn't supported on Windows");
}
#ssl_cipher
[ GitHub ]# File 'ext/mysql2/client.c', line 479
static VALUE rb_mysql_get_ssl_cipher(VALUE self)
{
const char *cipher;
VALUE rb_str;
GET_CLIENT(self);
cipher = mysql_get_ssl_cipher(wrapper->client);
if (cipher == NULL) {
return Qnil;
}
rb_str = rb_str_new2(cipher);
rb_enc_associate(rb_str, rb_utf8_encoding());
return rb_str;
}
#ssl_set(key, cert, ca, capath, cipher) (private)
[ GitHub ]# File 'ext/mysql2/client.c', line 1469
static VALUE set_ssl_options(VALUE self, VALUE key, VALUE cert, VALUE ca, VALUE capath, VALUE cipher) {
GET_CLIENT(self);
#ifdef HAVE_MYSQL_SSL_SET
mysql_ssl_set(wrapper->client,
NIL_P(key) ? NULL : StringValueCStr(key),
NIL_P(cert) ? NULL : StringValueCStr(cert),
NIL_P(ca) ? NULL : StringValueCStr(ca),
NIL_P(capath) ? NULL : StringValueCStr(capath),
NIL_P(cipher) ? NULL : StringValueCStr(cipher));
#else
/* mysql 8.3 does not provide mysql_ssl_set */
if (!NIL_P(key)) {
mysql_options(wrapper->client, MYSQL_OPT_SSL_KEY, StringValueCStr(key));
}
if (!NIL_P(cert)) {
mysql_options(wrapper->client, MYSQL_OPT_SSL_CERT, StringValueCStr(cert));
}
if (!NIL_P(ca)) {
mysql_options(wrapper->client, MYSQL_OPT_SSL_CA, StringValueCStr(ca));
}
if (!NIL_P(capath)) {
mysql_options(wrapper->client, MYSQL_OPT_SSL_CAPATH, StringValueCStr(capath));
}
if (!NIL_P(cipher)) {
mysql_options(wrapper->client, MYSQL_OPT_SSL_CIPHER, StringValueCStr(cipher));
}
#endif
return self;
}
#store_result
Return the next result object from a query which yielded multiple result sets.
# File 'ext/mysql2/client.c', line 1303
static VALUE rb_mysql_client_store_result(VALUE self)
{
MYSQL_RES * result;
VALUE resultObj;
VALUE current;
GET_CLIENT(self);
result = (MYSQL_RES *)rb_thread_call_without_gvl(nogvl_store_result, wrapper, RUBY_UBF_IO, 0);
if (result == NULL) {
if (mysql_errno(wrapper->client) != 0) {
rb_raise_mysql2_error(wrapper);
}
/* no data and no error, so query was not a SELECT */
return Qnil;
}
// Duplicate the options hash and put the copy in the Result object
current = rb_hash_dup(rb_ivar_get(self, intern_current_query_options));
(void)RB_GC_GUARD(current);
Check_Type(current, T_HASH);
resultObj = rb_mysql_result_to_obj(self, wrapper->encoding, current, result, Qnil);
return resultObj;
}
#thread_id
Returns the thread ID of the current connection.
# File 'ext/mysql2/client.c', line 1180
static VALUE rb_mysql_client_thread_id(VALUE self) {
unsigned long retVal;
GET_CLIENT(self);
REQUIRE_CONNECTED(wrapper);
retVal = mysql_thread_id(wrapper->client);
return ULL2NUM(retVal);
}
#warning_count
[ GitHub ]# File 'ext/mysql2/client.c', line 453
static VALUE rb_mysql_client_warning_count(VALUE self) {
unsigned int warning_count;
GET_CLIENT(self);
warning_count = mysql_warning_count(wrapper->client);
return UINT2NUM(warning_count);
}