mysql2 0.3.18 → 0.4.2

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.
Files changed (48) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +1 -0
  3. data/LICENSE +21 -0
  4. data/README.md +63 -12
  5. data/examples/eventmachine.rb +1 -1
  6. data/examples/threaded.rb +4 -6
  7. data/ext/mysql2/client.c +170 -175
  8. data/ext/mysql2/client.h +21 -1
  9. data/ext/mysql2/extconf.rb +95 -35
  10. data/ext/mysql2/infile.c +2 -2
  11. data/ext/mysql2/mysql2_ext.c +1 -0
  12. data/ext/mysql2/mysql2_ext.h +5 -6
  13. data/ext/mysql2/mysql_enc_name_to_ruby.h +2 -2
  14. data/ext/mysql2/mysql_enc_to_ruby.h +25 -22
  15. data/ext/mysql2/result.c +494 -132
  16. data/ext/mysql2/result.h +12 -6
  17. data/ext/mysql2/statement.c +494 -0
  18. data/ext/mysql2/statement.h +19 -0
  19. data/lib/mysql2/client.rb +68 -22
  20. data/lib/mysql2/console.rb +1 -1
  21. data/lib/mysql2/em.rb +5 -6
  22. data/lib/mysql2/error.rb +18 -27
  23. data/lib/mysql2/field.rb +3 -0
  24. data/lib/mysql2/statement.rb +17 -0
  25. data/lib/mysql2/version.rb +1 -1
  26. data/lib/mysql2.rb +38 -18
  27. data/spec/em/em_spec.rb +21 -21
  28. data/spec/mysql2/client_spec.rb +393 -351
  29. data/spec/mysql2/error_spec.rb +37 -36
  30. data/spec/mysql2/result_spec.rb +213 -208
  31. data/spec/mysql2/statement_spec.rb +684 -0
  32. data/spec/spec_helper.rb +7 -0
  33. data/spec/ssl/ca-cert.pem +17 -0
  34. data/spec/ssl/ca-key.pem +27 -0
  35. data/spec/ssl/ca.cnf +22 -0
  36. data/spec/ssl/cert.cnf +22 -0
  37. data/spec/ssl/client-cert.pem +17 -0
  38. data/spec/ssl/client-key.pem +27 -0
  39. data/spec/ssl/client-req.pem +15 -0
  40. data/spec/ssl/gen_certs.sh +48 -0
  41. data/spec/ssl/pkcs8-client-key.pem +28 -0
  42. data/spec/ssl/pkcs8-server-key.pem +28 -0
  43. data/spec/ssl/server-cert.pem +17 -0
  44. data/spec/ssl/server-key.pem +27 -0
  45. data/spec/ssl/server-req.pem +15 -0
  46. data/support/mysql_enc_to_ruby.rb +7 -8
  47. data/support/ruby_enc_to_mysql.rb +1 -1
  48. metadata +41 -46
data/ext/mysql2/client.h CHANGED
@@ -50,7 +50,27 @@ typedef struct {
50
50
  MYSQL *client;
51
51
  } mysql_client_wrapper;
52
52
 
53
- void init_mysql2_client();
53
+ #define REQUIRE_CONNECTED(wrapper) \
54
+ REQUIRE_INITIALIZED(wrapper) \
55
+ if (!wrapper->connected && !wrapper->reconnect_enabled) { \
56
+ rb_raise(cMysql2Error, "closed MySQL connection"); \
57
+ }
58
+
59
+ void rb_mysql_client_set_active_thread(VALUE self);
60
+
61
+ #define MARK_CONN_INACTIVE(conn) do {\
62
+ wrapper->active_thread = Qnil; \
63
+ } while(0)
64
+
65
+ #define GET_CLIENT(self) \
66
+ mysql_client_wrapper *wrapper; \
67
+ Data_Get_Struct(self, mysql_client_wrapper, wrapper);
68
+
69
+ void init_mysql2_client(void);
54
70
  void decr_mysql2_client(mysql_client_wrapper *wrapper);
55
71
 
56
72
  #endif
73
+
74
+ #ifndef HAVE_RB_HASH_DUP
75
+ VALUE rb_hash_dup(VALUE other);
76
+ #endif
@@ -1,8 +1,15 @@
1
1
  # encoding: UTF-8
2
2
  require 'mkmf'
3
+ require 'English'
3
4
 
4
- def asplode lib
5
- abort "-----\n#{lib} is missing. please check your installation of mysql and try again.\n-----"
5
+ def asplode(lib)
6
+ if RUBY_PLATFORM =~ /mingw|mswin/
7
+ abort "-----\n#{lib} is missing. Check your installation of MySQL or Connector/C, and try again.\n-----"
8
+ elsif RUBY_PLATFORM =~ /darwin/
9
+ abort "-----\n#{lib} is missing. You may need to 'brew install mysql' or 'port install mysql', and try again.\n-----"
10
+ else
11
+ abort "-----\n#{lib} is missing. You may need to 'apt-get install libmysqlclient-dev' or 'yum install mysql-devel', and try again.\n-----"
12
+ end
6
13
  end
7
14
 
8
15
  # 2.0-only
@@ -16,7 +23,7 @@ have_func('rb_intern3')
16
23
 
17
24
  # borrowed from mysqlplus
18
25
  # http://github.com/oldmoe/mysqlplus/blob/master/ext/extconf.rb
19
- dirs = ENV['PATH'].split(File::PATH_SEPARATOR) + %w[
26
+ dirs = ENV.fetch('PATH').split(File::PATH_SEPARATOR) + %w(
20
27
  /opt
21
28
  /opt/local
22
29
  /opt/local/mysql
@@ -27,13 +34,15 @@ dirs = ENV['PATH'].split(File::PATH_SEPARATOR) + %w[
27
34
  /usr/local/mysql
28
35
  /usr/local/mysql-*
29
36
  /usr/local/lib/mysql5*
30
- ].map{|dir| "#{dir}/bin" }
37
+ /usr/local/opt/mysql5*
38
+ ).map { |dir| dir << '/bin' }
31
39
 
32
- GLOB = "{#{dirs.join(',')}}/{mysql_config,mysql_config5}"
40
+ GLOB = "{#{dirs.join(',')}}/{mysql_config,mysql_config5,mariadb_config}"
33
41
 
34
42
  # If the user has provided a --with-mysql-dir argument, we must respect it or fail.
35
43
  inc, lib = dir_config('mysql')
36
44
  if inc && lib
45
+ # TODO: Remove when 2.0.0 is the minimum supported version
37
46
  # Ruby versions not incorporating the mkmf fix at
38
47
  # https://bugs.ruby-lang.org/projects/ruby-trunk/repository/revisions/39717
39
48
  # do not properly search for lib directories, and must be corrected
@@ -41,37 +50,33 @@ if inc && lib
41
50
  @libdir_basename = 'lib'
42
51
  inc, lib = dir_config('mysql')
43
52
  end
44
- abort "-----\nCannot find include dir(s) #{inc}\n-----" unless inc && inc.split(File::PATH_SEPARATOR).any?{|dir| File.directory?(dir)}
45
- abort "-----\nCannot find library dir(s) #{lib}\n-----" unless lib && lib.split(File::PATH_SEPARATOR).any?{|dir| File.directory?(dir)}
46
- warn "-----\nUsing --with-mysql-dir=#{File.dirname inc}\n-----"
53
+ abort "-----\nCannot find include dir(s) #{inc}\n-----" unless inc && inc.split(File::PATH_SEPARATOR).any? { |dir| File.directory?(dir) }
54
+ abort "-----\nCannot find library dir(s) #{lib}\n-----" unless lib && lib.split(File::PATH_SEPARATOR).any? { |dir| File.directory?(dir) }
55
+ warn "-----\nUsing --with-mysql-dir=#{File.dirname inc}\n-----"
47
56
  rpath_dir = lib
48
- elsif mc = (with_config('mysql-config') || Dir[GLOB].first)
57
+ elsif (mc = (with_config('mysql-config') || Dir[GLOB].first))
49
58
  # If the user has provided a --with-mysql-config argument, we must respect it or fail.
50
59
  # If the user gave --with-mysql-config with no argument means we should try to find it.
51
60
  mc = Dir[GLOB].first if mc == true
52
- abort "-----\nCannot find mysql_config at #{mc}\n-----" unless mc && File.exists?(mc)
61
+ abort "-----\nCannot find mysql_config at #{mc}\n-----" unless mc && File.exist?(mc)
53
62
  abort "-----\nCannot execute mysql_config at #{mc}\n-----" unless File.executable?(mc)
54
- warn "-----\nUsing mysql_config at #{mc}\n-----"
63
+ warn "-----\nUsing mysql_config at #{mc}\n-----"
55
64
  ver = `#{mc} --version`.chomp.to_f
56
65
  includes = `#{mc} --include`.chomp
57
- exit 1 if $? != 0
66
+ abort unless $CHILD_STATUS.success?
58
67
  libs = `#{mc} --libs_r`.chomp
59
68
  # MySQL 5.5 and above already have re-entrant code in libmysqlclient (no _r).
60
- if ver >= 5.5 || libs.empty?
61
- libs = `#{mc} --libs`.chomp
62
- end
63
- exit 1 if $? != 0
69
+ libs = `#{mc} --libs`.chomp if ver >= 5.5 || libs.empty?
70
+ abort unless $CHILD_STATUS.success?
64
71
  $INCFLAGS += ' ' + includes
65
72
  $libs = libs + " " + $libs
66
73
  rpath_dir = libs
67
74
  else
68
- inc, lib = dir_config('mysql', '/usr/local')
69
- libs = ['m', 'z', 'socket', 'nsl', 'mygcc']
70
- while not find_library('mysqlclient', 'mysql_query', lib, "#{lib}/mysql") do
71
- exit 1 if libs.empty?
72
- have_library(libs.shift)
73
- end
74
- rpath_dir = lib
75
+ _, usr_local_lib = dir_config('mysql', '/usr/local')
76
+
77
+ asplode("mysql client") unless find_library('mysqlclient', 'mysql_query', usr_local_lib, "#{usr_local_lib}/mysql")
78
+
79
+ rpath_dir = usr_local_lib
75
80
  end
76
81
 
77
82
  if have_header('mysql.h')
@@ -82,16 +87,71 @@ else
82
87
  asplode 'mysql.h'
83
88
  end
84
89
 
85
- %w{ errmsg.h mysqld_error.h }.each do |h|
90
+ %w(errmsg.h mysqld_error.h).each do |h|
86
91
  header = [prefix, h].compact.join '/'
87
- asplode h unless have_header h
92
+ asplode h unless have_header header
93
+ end
94
+
95
+ # This is our wishlist. We use whichever flags work on the host.
96
+ # -Wall and -Wextra are included by default.
97
+ wishlist = [
98
+ '-Weverything',
99
+ '-Wno-bad-function-cast', # rb_thread_call_without_gvl returns void * that we cast to VALUE
100
+ '-Wno-conditional-uninitialized', # false positive in client.c
101
+ '-Wno-covered-switch-default', # result.c -- enum_field_types (when fully covered, e.g. mysql 5.5)
102
+ '-Wno-declaration-after-statement', # GET_CLIENT followed by GET_STATEMENT in statement.c
103
+ '-Wno-disabled-macro-expansion', # rubby :(
104
+ '-Wno-documentation-unknown-command', # rubby :(
105
+ '-Wno-missing-field-initializers', # gperf generates bad code
106
+ '-Wno-missing-variable-declarations', # missing symbols due to ruby native ext initialization
107
+ '-Wno-padded', # mysql :(
108
+ '-Wno-reserved-id-macro', # rubby :(
109
+ '-Wno-sign-conversion', # gperf generates bad code
110
+ '-Wno-static-in-inline', # gperf generates bad code
111
+ '-Wno-switch-enum', # result.c -- enum_field_types (when not fully covered, e.g. mysql 5.6+)
112
+ '-Wno-undef', # rubinius :(
113
+ '-Wno-unreachable-code', # rubby :(
114
+ '-Wno-used-but-marked-unused', # rubby :(
115
+ ]
116
+
117
+ usable_flags = wishlist.select do |flag|
118
+ try_link('int main() {return 0;}', "-Werror #{flag}")
88
119
  end
89
120
 
90
- # These gcc style flags are also supported by clang and xcode compilers,
91
- # so we'll use a does-it-work test instead of an is-it-gcc test.
92
- gcc_flags = ' -Wall -funroll-loops'
93
- if try_link('int main() {return 0;}', gcc_flags)
94
- $CFLAGS << gcc_flags
121
+ $CFLAGS << ' ' << usable_flags.join(' ')
122
+
123
+ enabled_sanitizers = disabled_sanitizers = []
124
+ # Specify a commna-separated list of sanitizers, or try them all by default
125
+ sanitizers = with_config('sanitize')
126
+ case sanitizers
127
+ when true
128
+ # Try them all, turn on whatever we can
129
+ enabled_sanitizers = %w(address cfi integer memory thread undefined).select do |s|
130
+ try_link('int main() {return 0;}', "-Werror -fsanitize=#{s}")
131
+ end
132
+ abort "-----\nCould not enable any sanitizers!\n-----" if enabled_sanitizers.empty?
133
+ when String
134
+ # Figure out which sanitizers are supported
135
+ enabled_sanitizers, disabled_sanitizers = sanitizers.split(',').partition do |s|
136
+ try_link('int main() {return 0;}', "-Werror -fsanitize=#{s}")
137
+ end
138
+ end
139
+
140
+ unless disabled_sanitizers.empty?
141
+ abort "-----\nCould not enable requested sanitizers: #{disabled_sanitizers.join(',')}\n-----"
142
+ end
143
+
144
+ unless enabled_sanitizers.empty?
145
+ warn "-----\nEnabling sanitizers: #{enabled_sanitizers.join(',')}\n-----"
146
+ enabled_sanitizers.each do |s|
147
+ # address sanitizer requires runtime support
148
+ if s == 'address' # rubocop:disable Style/IfUnlessModifier
149
+ have_library('asan') || $LDFLAGS << ' -fsanitize=address'
150
+ end
151
+ $CFLAGS << " -fsanitize=#{s}"
152
+ end
153
+ # Options for line numbers in backtraces
154
+ $CFLAGS << ' -g -fno-omit-frame-pointer'
95
155
  end
96
156
 
97
157
  if RUBY_PLATFORM =~ /mswin|mingw/
@@ -102,7 +162,7 @@ if RUBY_PLATFORM =~ /mswin|mingw/
102
162
  # Use rake to rebuild only if these files change
103
163
  deffile = File.expand_path('../../../support/libmysql.def', __FILE__)
104
164
  libfile = File.expand_path(File.join(rpath_dir, 'libmysql.lib'))
105
- file 'libmysql.a' => [deffile, libfile] do |t|
165
+ file 'libmysql.a' => [deffile, libfile] do
106
166
  when_writing 'building libmysql.a' do
107
167
  # Ruby kindly shows us where dllwrap is, but that tool does more than we want.
108
168
  # Maybe in the future Ruby could provide RbConfig::CONFIG['DLLTOOL'] directly.
@@ -119,8 +179,8 @@ if RUBY_PLATFORM =~ /mswin|mingw/
119
179
 
120
180
  # Make sure the generated interface library works (if cross-compiling, trust without verifying)
121
181
  unless RbConfig::CONFIG['host_os'] =~ /mswin|mingw/
122
- abort "-----\nCannot find libmysql.a\n----" unless have_library('libmysql')
123
- abort "-----\nCannot link to libmysql.a (my_init)\n----" unless have_func('my_init')
182
+ abort "-----\nCannot find libmysql.a\n-----" unless have_library('libmysql')
183
+ abort "-----\nCannot link to libmysql.a (my_init)\n-----" unless have_func('my_init')
124
184
  end
125
185
 
126
186
  # Vendor libmysql.dll
@@ -129,7 +189,7 @@ if RUBY_PLATFORM =~ /mswin|mingw/
129
189
 
130
190
  vendordll = File.join(vendordir, 'libmysql.dll')
131
191
  dllfile = File.expand_path(File.join(rpath_dir, 'libmysql.dll'))
132
- file vendordll => [dllfile, vendordir] do |t|
192
+ file vendordll => [dllfile, vendordir] do
133
193
  when_writing 'copying libmysql.dll' do
134
194
  cp dllfile, vendordll
135
195
  end
@@ -155,7 +215,7 @@ else
155
215
  warn "-----\nSetting mysql rpath to #{explicit_rpath}\n-----"
156
216
  $LDFLAGS << rpath_flags
157
217
  else
158
- if libdir = rpath_dir[%r{(-L)?(/[^ ]+)}, 2]
218
+ if (libdir = rpath_dir[%r{(-L)?(/[^ ]+)}, 2])
159
219
  rpath_flags = " -Wl,-rpath,#{libdir}"
160
220
  if RbConfig::CONFIG["RPATHFLAG"].to_s.empty? && try_link('int main() {return 0;}', rpath_flags)
161
221
  # Usually Ruby sets RPATHFLAG the right way for each system, but not on OS X.
data/ext/mysql2/infile.c CHANGED
@@ -56,7 +56,7 @@ mysql2_local_infile_init(void **ptr, const char *filename, void *userdata)
56
56
  * < 0 error
57
57
  */
58
58
  static int
59
- mysql2_local_infile_read(void *ptr, char *buf, uint buf_len)
59
+ mysql2_local_infile_read(void *ptr, char *buf, unsigned int buf_len)
60
60
  {
61
61
  int count;
62
62
  mysql2_local_infile_data *data = (mysql2_local_infile_data *)ptr;
@@ -95,7 +95,7 @@ mysql2_local_infile_end(void *ptr)
95
95
  * Error message number (see http://dev.mysql.com/doc/refman/5.0/en/error-messages-client.html)
96
96
  */
97
97
  static int
98
- mysql2_local_infile_error(void *ptr, char *error_msg, uint error_msg_len)
98
+ mysql2_local_infile_error(void *ptr, char *error_msg, unsigned int error_msg_len)
99
99
  {
100
100
  mysql2_local_infile_data *data = (mysql2_local_infile_data *) ptr;
101
101
 
@@ -9,4 +9,5 @@ void Init_mysql2() {
9
9
 
10
10
  init_mysql2_client();
11
11
  init_mysql2_result();
12
+ init_mysql2_statement();
12
13
  }
@@ -1,18 +1,14 @@
1
1
  #ifndef MYSQL2_EXT
2
2
  #define MYSQL2_EXT
3
3
 
4
+ void Init_mysql2(void);
5
+
4
6
  /* tell rbx not to use it's caching compat layer
5
7
  by doing this we're making a promise to RBX that
6
8
  we'll never modify the pointers we get back from RSTRING_PTR */
7
9
  #define RSTRING_NOT_MODIFIED
8
10
  #include <ruby.h>
9
11
 
10
- #ifndef HAVE_UINT
11
- #define HAVE_UINT
12
- typedef unsigned short ushort;
13
- typedef unsigned int uint;
14
- #endif
15
-
16
12
  #ifdef HAVE_MYSQL_H
17
13
  #include <mysql.h>
18
14
  #include <mysql_com.h>
@@ -33,12 +29,15 @@ typedef unsigned int uint;
33
29
  #endif
34
30
 
35
31
  #if defined(__GNUC__) && (__GNUC__ >= 3)
32
+ #define RB_MYSQL_NORETURN __attribute__ ((noreturn))
36
33
  #define RB_MYSQL_UNUSED __attribute__ ((unused))
37
34
  #else
35
+ #define RB_MYSQL_NORETURN
38
36
  #define RB_MYSQL_UNUSED
39
37
  #endif
40
38
 
41
39
  #include <client.h>
40
+ #include <statement.h>
42
41
  #include <result.h>
43
42
  #include <infile.h>
44
43
 
@@ -1,4 +1,4 @@
1
- /* C code produced by gperf version 3.0.3 */
1
+ /* C code produced by gperf version 3.0.4 */
2
2
  /* Command-line: gperf */
3
3
  /* Computed positions: -k'1,3,$' */
4
4
 
@@ -78,7 +78,7 @@ mysql2_mysql_enc_name_to_rb_hash (str, len)
78
78
 
79
79
  #ifdef __GNUC__
80
80
  __inline
81
- #ifdef __GNUC_STDC_INLINE__
81
+ #if defined __GNUC_STDC_INLINE__ || defined __GNUC_GNU_INLINE__
82
82
  __attribute__ ((__gnu_inline__))
83
83
  #endif
84
84
  #endif
@@ -1,4 +1,4 @@
1
- const char *mysql2_mysql_enc_to_rb[] = {
1
+ static const char *mysql2_mysql_enc_to_rb[] = {
2
2
  "Big5",
3
3
  "ISO-8859-2",
4
4
  NULL,
@@ -54,13 +54,13 @@ const char *mysql2_mysql_enc_to_rb[] = {
54
54
  "macRoman",
55
55
  "UTF-16",
56
56
  "UTF-16",
57
- NULL,
57
+ "",
58
58
  "Windows-1256",
59
59
  "Windows-1257",
60
60
  "Windows-1257",
61
61
  "UTF-32",
62
62
  "UTF-32",
63
- NULL,
63
+ "",
64
64
  "ASCII-8BIT",
65
65
  NULL,
66
66
  "US-ASCII",
@@ -119,10 +119,10 @@ const char *mysql2_mysql_enc_to_rb[] = {
119
119
  "UTF-16",
120
120
  "UTF-16",
121
121
  "UTF-16",
122
- NULL,
123
- NULL,
124
- NULL,
125
- NULL,
122
+ "UTF-16",
123
+ "UTF-16",
124
+ "UTF-16",
125
+ "UTF-16",
126
126
  NULL,
127
127
  NULL,
128
128
  NULL,
@@ -146,6 +146,10 @@ const char *mysql2_mysql_enc_to_rb[] = {
146
146
  "UTF-16BE",
147
147
  "UTF-16BE",
148
148
  "UTF-16BE",
149
+ "UTF-16BE",
150
+ "UTF-16BE",
151
+ "UTF-16BE",
152
+ "UTF-16BE",
149
153
  NULL,
150
154
  NULL,
151
155
  NULL,
@@ -153,11 +157,11 @@ const char *mysql2_mysql_enc_to_rb[] = {
153
157
  NULL,
154
158
  NULL,
155
159
  NULL,
156
- NULL,
157
- NULL,
158
- NULL,
159
- NULL,
160
- NULL,
160
+ "UTF-16BE",
161
+ "UTF-32",
162
+ "UTF-32",
163
+ "UTF-32",
164
+ "UTF-32",
161
165
  "UTF-32",
162
166
  "UTF-32",
163
167
  "UTF-32",
@@ -178,10 +182,6 @@ const char *mysql2_mysql_enc_to_rb[] = {
178
182
  "UTF-32",
179
183
  "UTF-32",
180
184
  "UTF-32",
181
- NULL,
182
- NULL,
183
- NULL,
184
- NULL,
185
185
  NULL,
186
186
  NULL,
187
187
  NULL,
@@ -210,6 +210,10 @@ const char *mysql2_mysql_enc_to_rb[] = {
210
210
  "UTF-8",
211
211
  "UTF-8",
212
212
  "UTF-8",
213
+ "UTF-8",
214
+ "UTF-8",
215
+ "UTF-8",
216
+ "UTF-8",
213
217
  NULL,
214
218
  NULL,
215
219
  NULL,
@@ -217,11 +221,11 @@ const char *mysql2_mysql_enc_to_rb[] = {
217
221
  NULL,
218
222
  NULL,
219
223
  NULL,
220
- NULL,
221
- NULL,
222
- NULL,
223
- NULL,
224
- NULL,
224
+ "UTF-8",
225
+ "UTF-8",
226
+ "UTF-8",
227
+ "UTF-8",
228
+ "UTF-8",
225
229
  "UTF-8",
226
230
  "UTF-8",
227
231
  "UTF-8",
@@ -243,4 +247,3 @@ const char *mysql2_mysql_enc_to_rb[] = {
243
247
  "UTF-8",
244
248
  "UTF-8"
245
249
  };
246
-