mysql2_bigint 0.2.6.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (46) hide show
  1. data/CHANGELOG.md +120 -0
  2. data/Gemfile +3 -0
  3. data/MIT-LICENSE +20 -0
  4. data/README.rdoc +248 -0
  5. data/Rakefile +5 -0
  6. data/benchmark/active_record.rb +51 -0
  7. data/benchmark/allocations.rb +33 -0
  8. data/benchmark/escape.rb +36 -0
  9. data/benchmark/query_with_mysql_casting.rb +80 -0
  10. data/benchmark/query_without_mysql_casting.rb +47 -0
  11. data/benchmark/sequel.rb +37 -0
  12. data/benchmark/setup_db.rb +119 -0
  13. data/examples/eventmachine.rb +21 -0
  14. data/examples/threaded.rb +20 -0
  15. data/ext/mysql2/client.c +768 -0
  16. data/ext/mysql2/client.h +41 -0
  17. data/ext/mysql2/extconf.rb +69 -0
  18. data/ext/mysql2/mysql2_ext.c +12 -0
  19. data/ext/mysql2/mysql2_ext.h +38 -0
  20. data/ext/mysql2/result.c +488 -0
  21. data/ext/mysql2/result.h +20 -0
  22. data/lib/active_record/connection_adapters/em_mysql2_adapter.rb +64 -0
  23. data/lib/active_record/connection_adapters/mysql2_adapter.rb +654 -0
  24. data/lib/active_record/fiber_patches.rb +104 -0
  25. data/lib/arel/engines/sql/compilers/mysql2_compiler.rb +11 -0
  26. data/lib/mysql2.rb +16 -0
  27. data/lib/mysql2/client.rb +240 -0
  28. data/lib/mysql2/em.rb +37 -0
  29. data/lib/mysql2/em_fiber.rb +31 -0
  30. data/lib/mysql2/error.rb +15 -0
  31. data/lib/mysql2/result.rb +5 -0
  32. data/lib/mysql2/version.rb +3 -0
  33. data/lib/mysql2_bigint.rb +1 -0
  34. data/mysql2_bigint.gemspec +32 -0
  35. data/spec/em/em_fiber_spec.rb +22 -0
  36. data/spec/em/em_spec.rb +49 -0
  37. data/spec/mysql2/client_spec.rb +385 -0
  38. data/spec/mysql2/error_spec.rb +25 -0
  39. data/spec/mysql2/result_spec.rb +328 -0
  40. data/spec/rcov.opts +3 -0
  41. data/spec/spec_helper.rb +66 -0
  42. data/tasks/benchmarks.rake +20 -0
  43. data/tasks/compile.rake +53 -0
  44. data/tasks/rspec.rake +16 -0
  45. data/tasks/vendor_mysql.rake +41 -0
  46. 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
@@ -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
@@ -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
@@ -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
+ }