mysql2 0.2.24 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.gitignore +12 -0
- data/.rspec +2 -0
- data/.rvmrc +1 -0
- data/CHANGELOG.md +148 -0
- data/Gemfile +3 -0
- data/README.rdoc +257 -0
- data/Rakefile +5 -0
- data/benchmark/active_record.rb +51 -0
- data/benchmark/active_record_threaded.rb +42 -0
- data/benchmark/allocations.rb +33 -0
- data/benchmark/escape.rb +36 -0
- data/benchmark/query_with_mysql_casting.rb +80 -0
- data/benchmark/query_without_mysql_casting.rb +47 -0
- data/benchmark/sequel.rb +37 -0
- data/benchmark/setup_db.rb +119 -0
- data/benchmark/threaded.rb +44 -0
- data/ext/mysql2/client.c +272 -849
- data/ext/mysql2/client.h +12 -27
- data/ext/mysql2/extconf.rb +14 -72
- data/ext/mysql2/mysql2_ext.h +4 -7
- data/ext/mysql2/result.c +123 -319
- data/ext/mysql2/result.h +1 -4
- data/lib/active_record/connection_adapters/em_mysql2_adapter.rb +64 -0
- data/lib/active_record/fiber_patches.rb +104 -0
- data/lib/mysql2.rb +5 -20
- data/lib/mysql2/client.rb +200 -50
- data/lib/mysql2/em.rb +3 -13
- data/lib/mysql2/em_fiber.rb +31 -0
- data/lib/mysql2/error.rb +6 -71
- data/lib/mysql2/version.rb +2 -2
- data/mysql2.gemspec +32 -0
- data/spec/em/em_fiber_spec.rb +22 -0
- data/spec/em/em_spec.rb +9 -74
- data/spec/mysql2/client_spec.rb +126 -593
- data/spec/mysql2/error_spec.rb +44 -58
- data/spec/mysql2/result_spec.rb +85 -257
- data/spec/spec_helper.rb +3 -24
- data/tasks/benchmarks.rake +20 -0
- data/tasks/compile.rake +71 -0
- data/tasks/rspec.rake +16 -0
- data/tasks/vendor_mysql.rake +40 -0
- metadata +179 -92
- checksums.yaml +0 -7
- data/README.md +0 -524
- data/ext/mysql2/infile.c +0 -122
- data/ext/mysql2/infile.h +0 -1
- data/ext/mysql2/mysql_enc_name_to_ruby.h +0 -168
- data/ext/mysql2/mysql_enc_to_ruby.h +0 -246
- data/ext/mysql2/wait_for_single_fd.h +0 -36
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +0 -635
- data/lib/arel/engines/sql/compilers/mysql2_compiler.rb +0 -11
- data/lib/mysql2/console.rb +0 -5
- data/spec/configuration.yml.example +0 -17
- data/spec/my.cnf.example +0 -9
- data/spec/test_data +0 -1
- data/support/mysql_enc_to_ruby.rb +0 -82
- data/support/ruby_enc_to_mysql.rb +0 -61
data/ext/mysql2/client.h
CHANGED
@@ -1,30 +1,24 @@
|
|
1
1
|
#ifndef MYSQL2_CLIENT_H
|
2
2
|
#define MYSQL2_CLIENT_H
|
3
3
|
|
4
|
-
#ifndef HAVE_RB_THREAD_CALL_WITHOUT_GVL
|
5
|
-
#ifdef HAVE_RB_THREAD_BLOCKING_REGION
|
6
|
-
|
7
|
-
/* emulate rb_thread_call_without_gvl with rb_thread_blocking_region */
|
8
|
-
#define rb_thread_call_without_gvl(func, data1, ubf, data2) \
|
9
|
-
rb_thread_blocking_region((rb_blocking_function_t *)func, data1, ubf, data2)
|
10
|
-
|
11
|
-
#else /* ! HAVE_RB_THREAD_BLOCKING_REGION */
|
12
4
|
/*
|
13
|
-
* partial emulation of the
|
5
|
+
* partial emulation of the 1.9 rb_thread_blocking_region under 1.8,
|
14
6
|
* this is enough for dealing with blocking I/O functions in the
|
15
7
|
* presence of threads.
|
16
8
|
*/
|
9
|
+
#ifndef HAVE_RB_THREAD_BLOCKING_REGION
|
17
10
|
|
18
11
|
#include <rubysig.h>
|
19
12
|
#define RUBY_UBF_IO ((rb_unblock_function_t *)-1)
|
20
13
|
typedef void rb_unblock_function_t(void *);
|
21
|
-
|
22
|
-
|
23
|
-
|
14
|
+
typedef VALUE rb_blocking_function_t(void *);
|
15
|
+
static VALUE
|
16
|
+
rb_thread_blocking_region(
|
17
|
+
rb_blocking_function_t *func, void *data1,
|
24
18
|
RB_MYSQL_UNUSED rb_unblock_function_t *ubf,
|
25
19
|
RB_MYSQL_UNUSED void *data2)
|
26
20
|
{
|
27
|
-
|
21
|
+
VALUE rv;
|
28
22
|
|
29
23
|
TRAP_BEG;
|
30
24
|
rv = func(data1);
|
@@ -34,23 +28,14 @@ rb_thread_call_without_gvl(
|
|
34
28
|
}
|
35
29
|
|
36
30
|
#endif /* ! HAVE_RB_THREAD_BLOCKING_REGION */
|
37
|
-
|
31
|
+
|
32
|
+
void init_mysql2_client();
|
38
33
|
|
39
34
|
typedef struct {
|
40
35
|
VALUE encoding;
|
41
|
-
|
42
|
-
|
43
|
-
int reconnect_enabled;
|
44
|
-
unsigned int connect_timeout;
|
45
|
-
int active;
|
46
|
-
int connected;
|
47
|
-
int initialized;
|
48
|
-
int refcount;
|
49
|
-
int freed;
|
36
|
+
char active;
|
37
|
+
char closed;
|
50
38
|
MYSQL *client;
|
51
39
|
} mysql_client_wrapper;
|
52
40
|
|
53
|
-
|
54
|
-
void decr_mysql2_client(mysql_client_wrapper *wrapper);
|
55
|
-
|
56
|
-
#endif
|
41
|
+
#endif
|
data/ext/mysql2/extconf.rb
CHANGED
@@ -5,14 +5,8 @@ def asplode lib
|
|
5
5
|
abort "-----\n#{lib} is missing. please check your installation of mysql and try again.\n-----"
|
6
6
|
end
|
7
7
|
|
8
|
-
# 2.0-only
|
9
|
-
have_header('ruby/thread.h') && have_func('rb_thread_call_without_gvl', 'ruby/thread.h')
|
10
|
-
|
11
8
|
# 1.9-only
|
12
9
|
have_func('rb_thread_blocking_region')
|
13
|
-
have_func('rb_wait_for_single_fd')
|
14
|
-
have_func('rb_hash_dup')
|
15
|
-
have_func('rb_intern3')
|
16
10
|
|
17
11
|
# borrowed from mysqlplus
|
18
12
|
# http://github.com/oldmoe/mysqlplus/blob/master/ext/extconf.rb
|
@@ -22,7 +16,6 @@ dirs = ENV['PATH'].split(File::PATH_SEPARATOR) + %w[
|
|
22
16
|
/opt/local/mysql
|
23
17
|
/opt/local/lib/mysql5
|
24
18
|
/usr
|
25
|
-
/usr/mysql
|
26
19
|
/usr/local
|
27
20
|
/usr/local/mysql
|
28
21
|
/usr/local/mysql-*
|
@@ -31,39 +24,20 @@ dirs = ENV['PATH'].split(File::PATH_SEPARATOR) + %w[
|
|
31
24
|
|
32
25
|
GLOB = "{#{dirs.join(',')}}/{mysql_config,mysql_config5}"
|
33
26
|
|
34
|
-
|
35
|
-
inc, lib = dir_config('mysql')
|
36
|
-
|
37
|
-
|
38
|
-
# https://bugs.ruby-lang.org/projects/ruby-trunk/repository/revisions/39717
|
39
|
-
# do not properly search for lib directories, and must be corrected
|
40
|
-
unless lib && lib[-3, 3] == 'lib'
|
41
|
-
@libdir_basename = 'lib'
|
42
|
-
inc, lib = dir_config('mysql')
|
43
|
-
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-----"
|
47
|
-
rpath_dir = lib
|
48
|
-
elsif mc = (with_config('mysql-config') || Dir[GLOB].first)
|
49
|
-
# If the user has provided a --with-mysql-config argument, we must respect it or fail.
|
50
|
-
# If the user gave --with-mysql-config with no argument means we should try to find it.
|
27
|
+
if RUBY_PLATFORM =~ /mswin|mingw/
|
28
|
+
inc, lib = dir_config('mysql')
|
29
|
+
exit 1 unless have_library("libmysql")
|
30
|
+
elsif mc = (with_config('mysql-config') || Dir[GLOB].first) then
|
51
31
|
mc = Dir[GLOB].first if mc == true
|
52
|
-
|
53
|
-
abort "-----\nCannot execute mysql_config at #{mc}\n-----" unless File.executable?(mc)
|
54
|
-
warn "-----\nUsing mysql_config at #{mc}\n-----"
|
55
|
-
ver = `#{mc} --version`.chomp.to_f
|
56
|
-
includes = `#{mc} --include`.chomp
|
32
|
+
cflags = `#{mc} --cflags`.chomp
|
57
33
|
exit 1 if $? != 0
|
58
34
|
libs = `#{mc} --libs_r`.chomp
|
59
|
-
|
60
|
-
if ver >= 5.5 || libs.empty?
|
35
|
+
if libs.empty?
|
61
36
|
libs = `#{mc} --libs`.chomp
|
62
37
|
end
|
63
38
|
exit 1 if $? != 0
|
64
|
-
$
|
39
|
+
$CPPFLAGS += ' ' + cflags
|
65
40
|
$libs = libs + " " + $libs
|
66
|
-
rpath_dir = libs
|
67
41
|
else
|
68
42
|
inc, lib = dir_config('mysql', '/usr/local')
|
69
43
|
libs = ['m', 'z', 'socket', 'nsl', 'mygcc']
|
@@ -71,16 +45,11 @@ else
|
|
71
45
|
exit 1 if libs.empty?
|
72
46
|
have_library(libs.shift)
|
73
47
|
end
|
74
|
-
rpath_dir = lib
|
75
|
-
end
|
76
|
-
|
77
|
-
if RUBY_PLATFORM =~ /mswin|mingw/
|
78
|
-
exit 1 unless have_library('libmysql')
|
79
48
|
end
|
80
49
|
|
81
|
-
if have_header('mysql.h')
|
50
|
+
if have_header('mysql.h') then
|
82
51
|
prefix = nil
|
83
|
-
elsif have_header('mysql/mysql.h')
|
52
|
+
elsif have_header('mysql/mysql.h') then
|
84
53
|
prefix = 'mysql'
|
85
54
|
else
|
86
55
|
asplode 'mysql.h'
|
@@ -91,40 +60,13 @@ end
|
|
91
60
|
asplode h unless have_header h
|
92
61
|
end
|
93
62
|
|
94
|
-
|
95
|
-
|
96
|
-
gcc_flags = ' -Wall -funroll-loops'
|
97
|
-
if try_link('int main() {return 0;}', gcc_flags)
|
98
|
-
$CFLAGS << gcc_flags
|
63
|
+
unless RUBY_PLATFORM =~ /mswin/ or RUBY_PLATFORM =~ /sparc/
|
64
|
+
$CFLAGS << ' -Wall -funroll-loops'
|
99
65
|
end
|
66
|
+
# $CFLAGS << ' -O0 -ggdb3 -Wextra'
|
100
67
|
|
101
|
-
|
102
|
-
|
103
|
-
abort "-----\nOption --with-mysql-rpath must have an argument\n-----"
|
104
|
-
when false
|
105
|
-
warn "-----\nOption --with-mysql-rpath has been disabled at your request\n-----"
|
106
|
-
when String
|
107
|
-
# The user gave us a value so use it
|
108
|
-
rpath_flags = " -Wl,-rpath,#{explicit_rpath}"
|
109
|
-
warn "-----\nSetting mysql rpath to #{explicit_rpath}\n-----"
|
110
|
-
$LDFLAGS << rpath_flags
|
111
|
-
else
|
112
|
-
if libdir = rpath_dir[%r{(-L)?(/[^ ]+)}, 2]
|
113
|
-
rpath_flags = " -Wl,-rpath,#{libdir}"
|
114
|
-
if RbConfig::CONFIG["RPATHFLAG"].to_s.empty? && try_link('int main() {return 0;}', rpath_flags)
|
115
|
-
# Usually Ruby sets RPATHFLAG the right way for each system, but not on OS X.
|
116
|
-
warn "-----\nSetting rpath to #{libdir}\n-----"
|
117
|
-
$LDFLAGS << rpath_flags
|
118
|
-
else
|
119
|
-
if RbConfig::CONFIG["RPATHFLAG"].to_s.empty?
|
120
|
-
# If we got here because try_link failed, warn the user
|
121
|
-
warn "-----\nDon't know how to set rpath on your system, if MySQL libraries are not in path mysql2 may not load\n-----"
|
122
|
-
end
|
123
|
-
# Make sure that LIBPATH gets set if we didn't explicitly set the rpath.
|
124
|
-
warn "-----\nSetting libpath to #{libdir}\n-----"
|
125
|
-
$LIBPATH << libdir unless $LIBPATH.include?(libdir)
|
126
|
-
end
|
127
|
-
end
|
68
|
+
if hard_mysql_path = $libs[%r{-L(/[^ ]+)}, 1]
|
69
|
+
$LDFLAGS << " -Wl,-rpath,#{hard_mysql_path}"
|
128
70
|
end
|
129
71
|
|
130
72
|
create_makefile('mysql2/mysql2')
|
data/ext/mysql2/mysql2_ext.h
CHANGED
@@ -1,11 +1,12 @@
|
|
1
1
|
#ifndef MYSQL2_EXT
|
2
2
|
#define MYSQL2_EXT
|
3
3
|
|
4
|
-
|
5
|
-
|
6
|
-
|
4
|
+
// tell rbx not to use it's caching compat layer
|
5
|
+
// by doing this we're making a promize to RBX that
|
6
|
+
// we'll never modify the pointers we get back from RSTRING_PTR
|
7
7
|
#define RSTRING_NOT_MODIFIED
|
8
8
|
#include <ruby.h>
|
9
|
+
#include <fcntl.h>
|
9
10
|
|
10
11
|
#ifndef HAVE_UINT
|
11
12
|
#define HAVE_UINT
|
@@ -28,9 +29,6 @@ typedef unsigned int uint;
|
|
28
29
|
#ifdef HAVE_RUBY_ENCODING_H
|
29
30
|
#include <ruby/encoding.h>
|
30
31
|
#endif
|
31
|
-
#ifdef HAVE_RUBY_THREAD_H
|
32
|
-
#include <ruby/thread.h>
|
33
|
-
#endif
|
34
32
|
|
35
33
|
#if defined(__GNUC__) && (__GNUC__ >= 3)
|
36
34
|
#define RB_MYSQL_UNUSED __attribute__ ((unused))
|
@@ -40,6 +38,5 @@ typedef unsigned int uint;
|
|
40
38
|
|
41
39
|
#include <client.h>
|
42
40
|
#include <result.h>
|
43
|
-
#include <infile.h>
|
44
41
|
|
45
42
|
#endif
|
data/ext/mysql2/result.c
CHANGED
@@ -1,62 +1,28 @@
|
|
1
1
|
#include <mysql2_ext.h>
|
2
2
|
|
3
|
-
#include <stdint.h>
|
4
|
-
|
5
|
-
#include "mysql_enc_to_ruby.h"
|
6
|
-
|
7
3
|
#ifdef HAVE_RUBY_ENCODING_H
|
8
4
|
static rb_encoding *binaryEncoding;
|
9
5
|
#endif
|
10
6
|
|
11
|
-
#
|
12
|
-
/* on 64bit platforms we can handle dates way outside 2038-01-19T03:14:07
|
13
|
-
*
|
14
|
-
* (9999*31557600) + (12*2592000) + (31*86400) + (11*3600) + (59*60) + 59
|
15
|
-
*/
|
16
|
-
#define MYSQL2_MAX_TIME 315578267999ULL
|
17
|
-
#else
|
18
|
-
/**
|
19
|
-
* On 32bit platforms the maximum date the Time class can handle is 2038-01-19T03:14:07
|
20
|
-
* 2038 years + 1 month + 19 days + 3 hours + 14 minutes + 7 seconds = 64318634047 seconds
|
21
|
-
*
|
22
|
-
* (2038*31557600) + (1*2592000) + (19*86400) + (3*3600) + (14*60) + 7
|
23
|
-
*/
|
24
|
-
#define MYSQL2_MAX_TIME 64318634047ULL
|
25
|
-
#endif
|
7
|
+
#define MYSQL2_MAX_YEAR 2058
|
26
8
|
|
27
|
-
#
|
28
|
-
/*
|
29
|
-
|
30
|
-
* (0*31557600) + (1*2592000) + (1*86400) + (0*3600) + (0*60) + 0
|
31
|
-
*/
|
32
|
-
#define MYSQL2_MIN_TIME 2678400ULL
|
33
|
-
#elif SIZEOF_INT < SIZEOF_LONG /* 64bit Ruby 1.8 */
|
34
|
-
/* 0139-1-1 00:00:00 UTC
|
35
|
-
*
|
36
|
-
* (139*31557600) + (1*2592000) + (1*86400) + (0*3600) + (0*60) + 0
|
37
|
-
*/
|
38
|
-
#define MYSQL2_MIN_TIME 4389184800ULL
|
39
|
-
#elif defined(NEGATIVE_TIME_T)
|
40
|
-
/* 1901-12-13 20:45:52 UTC : The oldest time in 32-bit signed time_t.
|
41
|
-
*
|
42
|
-
* (1901*31557600) + (12*2592000) + (13*86400) + (20*3600) + (45*60) + 52
|
43
|
-
*/
|
44
|
-
#define MYSQL2_MIN_TIME 60023299552ULL
|
9
|
+
#ifdef NEGATIVE_TIME_T
|
10
|
+
/* 1901-12-13 20:45:52 UTC : The oldest time in 32-bit signed time_t. */
|
11
|
+
#define MYSQL2_MIN_YEAR 1902
|
45
12
|
#else
|
46
|
-
/* 1970-01-01 00:00:
|
47
|
-
|
48
|
-
* (1970*31557600) + (1*2592000) + (1*86400) + (0*3600) + (0*60) + 1
|
49
|
-
*/
|
50
|
-
#define MYSQL2_MIN_TIME 62171150401ULL
|
13
|
+
/* 1970-01-01 00:00:00 UTC : The Unix epoch - the oldest time in portable time_t. */
|
14
|
+
#define MYSQL2_MIN_YEAR 1970
|
51
15
|
#endif
|
52
16
|
|
53
17
|
static VALUE cMysql2Result;
|
54
18
|
static VALUE cBigDecimal, cDate, cDateTime;
|
55
19
|
static VALUE opt_decimal_zero, opt_float_zero, opt_time_year, opt_time_month, opt_utc_offset;
|
56
20
|
extern VALUE mMysql2, cMysql2Client, cMysql2Error;
|
57
|
-
static
|
21
|
+
static VALUE intern_encoding_from_charset;
|
22
|
+
static ID intern_new, intern_utc, intern_local, intern_encoding_from_charset_code,
|
23
|
+
intern_localtime, intern_local_offset, intern_civil, intern_new_offset;
|
58
24
|
static VALUE sym_symbolize_keys, sym_as, sym_array, sym_database_timezone, sym_application_timezone,
|
59
|
-
sym_local, sym_utc, sym_cast_booleans, sym_cache_rows
|
25
|
+
sym_local, sym_utc, sym_cast_booleans, sym_cache_rows;
|
60
26
|
static ID intern_merge;
|
61
27
|
|
62
28
|
static void rb_mysql_result_mark(void * wrapper) {
|
@@ -65,29 +31,22 @@ static void rb_mysql_result_mark(void * wrapper) {
|
|
65
31
|
rb_gc_mark(w->fields);
|
66
32
|
rb_gc_mark(w->rows);
|
67
33
|
rb_gc_mark(w->encoding);
|
68
|
-
rb_gc_mark(w->client);
|
69
34
|
}
|
70
35
|
}
|
71
36
|
|
72
37
|
/* this may be called manually or during GC */
|
73
38
|
static void rb_mysql_result_free_result(mysql2_result_wrapper * wrapper) {
|
74
39
|
if (wrapper && wrapper->resultFreed != 1) {
|
75
|
-
/* FIXME: this may call flush_use_result, which can hit the socket */
|
76
40
|
mysql_free_result(wrapper->result);
|
77
41
|
wrapper->resultFreed = 1;
|
78
42
|
}
|
79
43
|
}
|
80
44
|
|
81
45
|
/* this is called during GC */
|
82
|
-
static void rb_mysql_result_free(void *
|
83
|
-
mysql2_result_wrapper *
|
84
|
-
|
85
|
-
|
86
|
-
// If the GC gets to client first it will be nil
|
87
|
-
if (wrapper->client != Qnil) {
|
88
|
-
decr_mysql2_client(wrapper->client_wrapper);
|
89
|
-
}
|
90
|
-
|
46
|
+
static void rb_mysql_result_free(void * wrapper) {
|
47
|
+
mysql2_result_wrapper * w = wrapper;
|
48
|
+
/* FIXME: this may call flush_use_result, which can hit the socket */
|
49
|
+
rb_mysql_result_free_result(w);
|
91
50
|
xfree(wrapper);
|
92
51
|
}
|
93
52
|
|
@@ -96,10 +55,10 @@ static void rb_mysql_result_free(void *ptr) {
|
|
96
55
|
* reliable way for us to tell this so we'll always release the GVL
|
97
56
|
* to be safe
|
98
57
|
*/
|
99
|
-
static
|
58
|
+
static VALUE nogvl_fetch_row(void *ptr) {
|
100
59
|
MYSQL_RES *result = ptr;
|
101
60
|
|
102
|
-
return mysql_fetch_row(result);
|
61
|
+
return (VALUE)mysql_fetch_row(result);
|
103
62
|
}
|
104
63
|
|
105
64
|
static VALUE rb_mysql_result_fetch_field(VALUE self, unsigned int idx, short int symbolize_keys) {
|
@@ -122,14 +81,10 @@ static VALUE rb_mysql_result_fetch_field(VALUE self, unsigned int idx, short int
|
|
122
81
|
|
123
82
|
field = mysql_fetch_field_direct(wrapper->result, idx);
|
124
83
|
if (symbolize_keys) {
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
VALUE colStr;
|
130
|
-
colStr = rb_str_new(field->name, field->name_length);
|
131
|
-
rb_field = ID2SYM(rb_to_id(colStr));
|
132
|
-
#endif
|
84
|
+
char buf[field->name_length+1];
|
85
|
+
memcpy(buf, field->name, field->name_length);
|
86
|
+
buf[field->name_length] = 0;
|
87
|
+
rb_field = ID2SYM(rb_intern(buf));
|
133
88
|
} else {
|
134
89
|
rb_field = rb_str_new(field->name, field->name_length);
|
135
90
|
#ifdef HAVE_RUBY_ENCODING_H
|
@@ -145,56 +100,11 @@ static VALUE rb_mysql_result_fetch_field(VALUE self, unsigned int idx, short int
|
|
145
100
|
return rb_field;
|
146
101
|
}
|
147
102
|
|
148
|
-
|
149
|
-
static VALUE mysql2_set_field_string_encoding(VALUE val, MYSQL_FIELD field, rb_encoding *default_internal_enc, rb_encoding *conn_enc) {
|
150
|
-
/* if binary flag is set, respect it's wishes */
|
151
|
-
if (field.flags & BINARY_FLAG && field.charsetnr == 63) {
|
152
|
-
rb_enc_associate(val, binaryEncoding);
|
153
|
-
} else if (!field.charsetnr) {
|
154
|
-
/* MySQL 4.x may not provide an encoding, binary will get the bytes through */
|
155
|
-
rb_enc_associate(val, binaryEncoding);
|
156
|
-
} else {
|
157
|
-
/* lookup the encoding configured on this field */
|
158
|
-
const char *enc_name;
|
159
|
-
int enc_index;
|
160
|
-
|
161
|
-
enc_name = mysql2_mysql_enc_to_rb[field.charsetnr-1];
|
162
|
-
if (enc_name != NULL) {
|
163
|
-
/* use the field encoding we were able to match */
|
164
|
-
enc_index = rb_enc_find_index(enc_name);
|
165
|
-
rb_enc_set_index(val, enc_index);
|
166
|
-
} else {
|
167
|
-
/* otherwise fall-back to the connection's encoding */
|
168
|
-
rb_enc_associate(val, conn_enc);
|
169
|
-
}
|
170
|
-
|
171
|
-
if (default_internal_enc) {
|
172
|
-
val = rb_str_export_to_enc(val, default_internal_enc);
|
173
|
-
}
|
174
|
-
}
|
175
|
-
return val;
|
176
|
-
}
|
177
|
-
#endif
|
178
|
-
|
179
|
-
/* Interpret microseconds digits left-aligned in fixed-width field.
|
180
|
-
* e.g. 10.123 seconds means 10 seconds and 123000 microseconds,
|
181
|
-
* because the microseconds are to the right of the decimal point.
|
182
|
-
*/
|
183
|
-
static unsigned int msec_char_to_uint(char *msec_char, size_t len)
|
184
|
-
{
|
185
|
-
int i;
|
186
|
-
for (i = 0; i < (len - 1); i++) {
|
187
|
-
if (msec_char[i] == '\0') {
|
188
|
-
msec_char[i] = '0';
|
189
|
-
}
|
190
|
-
}
|
191
|
-
return (unsigned int)strtoul(msec_char, NULL, 10);
|
192
|
-
}
|
193
|
-
|
194
|
-
static VALUE rb_mysql_result_fetch_row(VALUE self, ID db_timezone, ID app_timezone, int symbolizeKeys, int asArray, int castBool, int cast, MYSQL_FIELD * fields) {
|
103
|
+
static VALUE rb_mysql_result_fetch_row(VALUE self, ID db_timezone, ID app_timezone, int symbolizeKeys, int asArray, int castBool) {
|
195
104
|
VALUE rowVal;
|
196
105
|
mysql2_result_wrapper * wrapper;
|
197
106
|
MYSQL_ROW row;
|
107
|
+
MYSQL_FIELD * fields = NULL;
|
198
108
|
unsigned int i = 0;
|
199
109
|
unsigned long * fieldLengths;
|
200
110
|
void * ptr;
|
@@ -210,7 +120,7 @@ static VALUE rb_mysql_result_fetch_row(VALUE self, ID db_timezone, ID app_timezo
|
|
210
120
|
#endif
|
211
121
|
|
212
122
|
ptr = wrapper->result;
|
213
|
-
row = (MYSQL_ROW)
|
123
|
+
row = (MYSQL_ROW)rb_thread_blocking_region(nogvl_fetch_row, ptr, RUBY_UBF_IO, 0);
|
214
124
|
if (row == NULL) {
|
215
125
|
return Qnil;
|
216
126
|
}
|
@@ -220,6 +130,7 @@ static VALUE rb_mysql_result_fetch_row(VALUE self, ID db_timezone, ID app_timezo
|
|
220
130
|
} else {
|
221
131
|
rowVal = rb_hash_new();
|
222
132
|
}
|
133
|
+
fields = mysql_fetch_fields(wrapper->result);
|
223
134
|
fieldLengths = mysql_fetch_lengths(wrapper->result);
|
224
135
|
if (wrapper->fields == Qnil) {
|
225
136
|
wrapper->numberOfFields = mysql_num_fields(wrapper->result);
|
@@ -230,53 +141,35 @@ static VALUE rb_mysql_result_fetch_row(VALUE self, ID db_timezone, ID app_timezo
|
|
230
141
|
VALUE field = rb_mysql_result_fetch_field(self, i, symbolizeKeys);
|
231
142
|
if (row[i]) {
|
232
143
|
VALUE val = Qnil;
|
233
|
-
|
234
|
-
|
235
|
-
if(!cast) {
|
236
|
-
if (type == MYSQL_TYPE_NULL) {
|
237
|
-
val = Qnil;
|
238
|
-
} else {
|
239
|
-
val = rb_str_new(row[i], fieldLengths[i]);
|
240
|
-
#ifdef HAVE_RUBY_ENCODING_H
|
241
|
-
val = mysql2_set_field_string_encoding(val, fields[i], default_internal_enc, conn_enc);
|
242
|
-
#endif
|
243
|
-
}
|
244
|
-
} else {
|
245
|
-
switch(type) {
|
246
|
-
case MYSQL_TYPE_NULL: /* NULL-type field */
|
144
|
+
switch(fields[i].type) {
|
145
|
+
case MYSQL_TYPE_NULL: // NULL-type field
|
247
146
|
val = Qnil;
|
248
147
|
break;
|
249
|
-
case MYSQL_TYPE_BIT:
|
250
|
-
|
251
|
-
val = *row[i] == 1 ? Qtrue : Qfalse;
|
252
|
-
}else{
|
253
|
-
val = rb_str_new(row[i], fieldLengths[i]);
|
254
|
-
}
|
148
|
+
case MYSQL_TYPE_BIT: // BIT field (MySQL 5.0.3 and up)
|
149
|
+
val = rb_str_new(row[i], fieldLengths[i]);
|
255
150
|
break;
|
256
|
-
case MYSQL_TYPE_TINY:
|
151
|
+
case MYSQL_TYPE_TINY: // TINYINT field
|
257
152
|
if (castBool && fields[i].length == 1) {
|
258
|
-
val = *row[i]
|
153
|
+
val = *row[i] == '1' ? Qtrue : Qfalse;
|
259
154
|
break;
|
260
155
|
}
|
261
|
-
case MYSQL_TYPE_SHORT:
|
262
|
-
case MYSQL_TYPE_LONG:
|
263
|
-
case MYSQL_TYPE_INT24:
|
264
|
-
case MYSQL_TYPE_LONGLONG:
|
265
|
-
case MYSQL_TYPE_YEAR:
|
156
|
+
case MYSQL_TYPE_SHORT: // SMALLINT field
|
157
|
+
case MYSQL_TYPE_LONG: // INTEGER field
|
158
|
+
case MYSQL_TYPE_INT24: // MEDIUMINT field
|
159
|
+
case MYSQL_TYPE_LONGLONG: // BIGINT field
|
160
|
+
case MYSQL_TYPE_YEAR: // YEAR field
|
266
161
|
val = rb_cstr2inum(row[i], 10);
|
267
162
|
break;
|
268
|
-
case MYSQL_TYPE_DECIMAL:
|
269
|
-
case MYSQL_TYPE_NEWDECIMAL:
|
270
|
-
if (
|
271
|
-
val = rb_cstr2inum(row[i], 10);
|
272
|
-
} else if (strtod(row[i], NULL) == 0.000000){
|
163
|
+
case MYSQL_TYPE_DECIMAL: // DECIMAL or NUMERIC field
|
164
|
+
case MYSQL_TYPE_NEWDECIMAL: // Precision math DECIMAL or NUMERIC field (MySQL 5.0.3 and up)
|
165
|
+
if (strtod(row[i], NULL) == 0.000000){
|
273
166
|
val = rb_funcall(cBigDecimal, intern_new, 1, opt_decimal_zero);
|
274
167
|
}else{
|
275
168
|
val = rb_funcall(cBigDecimal, intern_new, 1, rb_str_new(row[i], fieldLengths[i]));
|
276
169
|
}
|
277
170
|
break;
|
278
|
-
case MYSQL_TYPE_FLOAT:
|
279
|
-
case MYSQL_TYPE_DOUBLE: {
|
171
|
+
case MYSQL_TYPE_FLOAT: // FLOAT field
|
172
|
+
case MYSQL_TYPE_DOUBLE: { // DOUBLE or REAL field
|
280
173
|
double column_to_double;
|
281
174
|
column_to_double = strtod(row[i], NULL);
|
282
175
|
if (column_to_double == 0.000000){
|
@@ -286,69 +179,50 @@ static VALUE rb_mysql_result_fetch_row(VALUE self, ID db_timezone, ID app_timezo
|
|
286
179
|
}
|
287
180
|
break;
|
288
181
|
}
|
289
|
-
case MYSQL_TYPE_TIME: {
|
290
|
-
int tokens;
|
291
|
-
|
292
|
-
|
293
|
-
|
294
|
-
tokens = sscanf(row[i], "%2u:%2u:%2u.%6s", &hour, &min, &sec, msec_char);
|
295
|
-
if (tokens < 3) {
|
296
|
-
val = Qnil;
|
297
|
-
break;
|
298
|
-
}
|
299
|
-
msec = msec_char_to_uint(msec_char, sizeof(msec_char));
|
300
|
-
val = rb_funcall(rb_cTime, db_timezone, 6, opt_time_year, opt_time_month, opt_time_month, UINT2NUM(hour), UINT2NUM(min), UINT2NUM(sec), UINT2NUM(msec));
|
182
|
+
case MYSQL_TYPE_TIME: { // TIME field
|
183
|
+
int hour, min, sec, tokens;
|
184
|
+
tokens = sscanf(row[i], "%2d:%2d:%2d", &hour, &min, &sec);
|
185
|
+
val = rb_funcall(rb_cTime, db_timezone, 6, opt_time_year, opt_time_month, opt_time_month, INT2NUM(hour), INT2NUM(min), INT2NUM(sec));
|
301
186
|
if (!NIL_P(app_timezone)) {
|
302
187
|
if (app_timezone == intern_local) {
|
303
188
|
val = rb_funcall(val, intern_localtime, 0);
|
304
|
-
} else {
|
189
|
+
} else { // utc
|
305
190
|
val = rb_funcall(val, intern_utc, 0);
|
306
191
|
}
|
307
192
|
}
|
308
193
|
break;
|
309
194
|
}
|
310
|
-
case MYSQL_TYPE_TIMESTAMP:
|
311
|
-
case MYSQL_TYPE_DATETIME: {
|
312
|
-
int tokens;
|
313
|
-
|
314
|
-
|
315
|
-
uint64_t seconds;
|
316
|
-
|
317
|
-
tokens = sscanf(row[i], "%4u-%2u-%2u %2u:%2u:%2u.%6s", &year, &month, &day, &hour, &min, &sec, msec_char);
|
318
|
-
if (tokens < 6) { /* msec might be empty */
|
319
|
-
val = Qnil;
|
320
|
-
break;
|
321
|
-
}
|
322
|
-
seconds = (year*31557600ULL) + (month*2592000ULL) + (day*86400ULL) + (hour*3600ULL) + (min*60ULL) + sec;
|
323
|
-
|
324
|
-
if (seconds == 0) {
|
195
|
+
case MYSQL_TYPE_TIMESTAMP: // TIMESTAMP field
|
196
|
+
case MYSQL_TYPE_DATETIME: { // DATETIME field
|
197
|
+
int year, month, day, hour, min, sec, tokens;
|
198
|
+
tokens = sscanf(row[i], "%4d-%2d-%2d %2d:%2d:%2d", &year, &month, &day, &hour, &min, &sec);
|
199
|
+
if (year+month+day+hour+min+sec == 0) {
|
325
200
|
val = Qnil;
|
326
201
|
} else {
|
327
202
|
if (month < 1 || day < 1) {
|
328
|
-
rb_raise(cMysql2Error, "Invalid date
|
203
|
+
rb_raise(cMysql2Error, "Invalid date: %s", row[i]);
|
329
204
|
val = Qnil;
|
330
205
|
} else {
|
331
|
-
if (
|
206
|
+
if (year < MYSQL2_MIN_YEAR || year+month+day > MYSQL2_MAX_YEAR) { // use DateTime instead
|
332
207
|
VALUE offset = INT2NUM(0);
|
333
208
|
if (db_timezone == intern_local) {
|
334
209
|
offset = rb_funcall(cMysql2Client, intern_local_offset, 0);
|
335
210
|
}
|
336
|
-
val = rb_funcall(cDateTime, intern_civil, 7,
|
211
|
+
val = rb_funcall(cDateTime, intern_civil, 7, INT2NUM(year), INT2NUM(month), INT2NUM(day), INT2NUM(hour), INT2NUM(min), INT2NUM(sec), offset);
|
337
212
|
if (!NIL_P(app_timezone)) {
|
338
213
|
if (app_timezone == intern_local) {
|
339
214
|
offset = rb_funcall(cMysql2Client, intern_local_offset, 0);
|
340
215
|
val = rb_funcall(val, intern_new_offset, 1, offset);
|
341
|
-
} else {
|
216
|
+
} else { // utc
|
342
217
|
val = rb_funcall(val, intern_new_offset, 1, opt_utc_offset);
|
343
218
|
}
|
344
219
|
}
|
345
220
|
} else {
|
346
|
-
|
347
|
-
val = rb_funcall(rb_cTime, db_timezone, 7, UINT2NUM(year), UINT2NUM(month), UINT2NUM(day), UINT2NUM(hour), UINT2NUM(min), UINT2NUM(sec), UINT2NUM(msec));
|
221
|
+
val = rb_funcall(rb_cTime, db_timezone, 6, INT2NUM(year), INT2NUM(month), INT2NUM(day), INT2NUM(hour), INT2NUM(min), INT2NUM(sec));
|
348
222
|
if (!NIL_P(app_timezone)) {
|
349
223
|
if (app_timezone == intern_local) {
|
350
224
|
val = rb_funcall(val, intern_localtime, 0);
|
351
|
-
} else {
|
225
|
+
} else { // utc
|
352
226
|
val = rb_funcall(val, intern_utc, 0);
|
353
227
|
}
|
354
228
|
}
|
@@ -357,23 +231,18 @@ static VALUE rb_mysql_result_fetch_row(VALUE self, ID db_timezone, ID app_timezo
|
|
357
231
|
}
|
358
232
|
break;
|
359
233
|
}
|
360
|
-
case MYSQL_TYPE_DATE:
|
361
|
-
case MYSQL_TYPE_NEWDATE: {
|
362
|
-
int tokens;
|
363
|
-
|
364
|
-
tokens = sscanf(row[i], "%4u-%2u-%2u", &year, &month, &day);
|
365
|
-
if (tokens < 3) {
|
366
|
-
val = Qnil;
|
367
|
-
break;
|
368
|
-
}
|
234
|
+
case MYSQL_TYPE_DATE: // DATE field
|
235
|
+
case MYSQL_TYPE_NEWDATE: { // Newer const used > 5.0
|
236
|
+
int year, month, day, tokens;
|
237
|
+
tokens = sscanf(row[i], "%4d-%2d-%2d", &year, &month, &day);
|
369
238
|
if (year+month+day == 0) {
|
370
239
|
val = Qnil;
|
371
240
|
} else {
|
372
241
|
if (month < 1 || day < 1) {
|
373
|
-
rb_raise(cMysql2Error, "Invalid date
|
242
|
+
rb_raise(cMysql2Error, "Invalid date: %s", row[i]);
|
374
243
|
val = Qnil;
|
375
244
|
} else {
|
376
|
-
val = rb_funcall(cDate, intern_new, 3,
|
245
|
+
val = rb_funcall(cDate, intern_new, 3, INT2NUM(year), INT2NUM(month), INT2NUM(day));
|
377
246
|
}
|
378
247
|
}
|
379
248
|
break;
|
@@ -384,17 +253,33 @@ static VALUE rb_mysql_result_fetch_row(VALUE self, ID db_timezone, ID app_timezo
|
|
384
253
|
case MYSQL_TYPE_BLOB:
|
385
254
|
case MYSQL_TYPE_VAR_STRING:
|
386
255
|
case MYSQL_TYPE_VARCHAR:
|
387
|
-
case MYSQL_TYPE_STRING:
|
388
|
-
case MYSQL_TYPE_SET:
|
389
|
-
case MYSQL_TYPE_ENUM:
|
390
|
-
case MYSQL_TYPE_GEOMETRY:
|
256
|
+
case MYSQL_TYPE_STRING: // CHAR or BINARY field
|
257
|
+
case MYSQL_TYPE_SET: // SET field
|
258
|
+
case MYSQL_TYPE_ENUM: // ENUM field
|
259
|
+
case MYSQL_TYPE_GEOMETRY: // Spatial fielda
|
391
260
|
default:
|
392
261
|
val = rb_str_new(row[i], fieldLengths[i]);
|
393
262
|
#ifdef HAVE_RUBY_ENCODING_H
|
394
|
-
|
263
|
+
// if binary flag is set, respect it's wishes
|
264
|
+
if (fields[i].flags & BINARY_FLAG && fields[i].charsetnr == 63) {
|
265
|
+
rb_enc_associate(val, binaryEncoding);
|
266
|
+
} else {
|
267
|
+
// lookup the encoding configured on this field
|
268
|
+
VALUE new_encoding = rb_funcall(cMysql2Client, intern_encoding_from_charset_code, 1, INT2NUM(fields[i].charsetnr));
|
269
|
+
if (new_encoding != Qnil) {
|
270
|
+
// use the field encoding we were able to match
|
271
|
+
rb_encoding *enc = rb_to_encoding(new_encoding);
|
272
|
+
rb_enc_associate(val, enc);
|
273
|
+
} else {
|
274
|
+
// otherwise fall-back to the connection's encoding
|
275
|
+
rb_enc_associate(val, conn_enc);
|
276
|
+
}
|
277
|
+
if (default_internal_enc) {
|
278
|
+
val = rb_str_export_to_enc(val, default_internal_enc);
|
279
|
+
}
|
280
|
+
}
|
395
281
|
#endif
|
396
282
|
break;
|
397
|
-
}
|
398
283
|
}
|
399
284
|
if (asArray) {
|
400
285
|
rb_ary_push(rowVal, val);
|
@@ -421,7 +306,6 @@ static VALUE rb_mysql_result_fetch_fields(VALUE self) {
|
|
421
306
|
GetMysql2Result(self, wrapper);
|
422
307
|
|
423
308
|
defaults = rb_iv_get(self, "@query_options");
|
424
|
-
Check_Type(defaults, T_HASH);
|
425
309
|
if (rb_hash_aref(defaults, sym_symbolize_keys) == Qtrue) {
|
426
310
|
symbolizeKeys = 1;
|
427
311
|
}
|
@@ -445,14 +329,11 @@ static VALUE rb_mysql_result_each(int argc, VALUE * argv, VALUE self) {
|
|
445
329
|
ID db_timezone, app_timezone, dbTz, appTz;
|
446
330
|
mysql2_result_wrapper * wrapper;
|
447
331
|
unsigned long i;
|
448
|
-
|
449
|
-
int symbolizeKeys = 0, asArray = 0, castBool = 0, cacheRows = 1, cast = 1, streaming = 0;
|
450
|
-
MYSQL_FIELD * fields = NULL;
|
332
|
+
int symbolizeKeys = 0, asArray = 0, castBool = 0, cacheRows = 1;
|
451
333
|
|
452
334
|
GetMysql2Result(self, wrapper);
|
453
335
|
|
454
336
|
defaults = rb_iv_get(self, "@query_options");
|
455
|
-
Check_Type(defaults, T_HASH);
|
456
337
|
if (rb_scan_args(argc, argv, "01&", &opts, &block) == 1) {
|
457
338
|
opts = rb_funcall(defaults, intern_merge, 1, opts);
|
458
339
|
} else {
|
@@ -475,18 +356,6 @@ static VALUE rb_mysql_result_each(int argc, VALUE * argv, VALUE self) {
|
|
475
356
|
cacheRows = 0;
|
476
357
|
}
|
477
358
|
|
478
|
-
if (rb_hash_aref(opts, sym_cast) == Qfalse) {
|
479
|
-
cast = 0;
|
480
|
-
}
|
481
|
-
|
482
|
-
if(rb_hash_aref(opts, sym_stream) == Qtrue) {
|
483
|
-
streaming = 1;
|
484
|
-
}
|
485
|
-
|
486
|
-
if(streaming && cacheRows) {
|
487
|
-
rb_warn("cacheRows is ignored if streaming is true");
|
488
|
-
}
|
489
|
-
|
490
359
|
dbTz = rb_hash_aref(opts, sym_database_timezone);
|
491
360
|
if (dbTz == sym_local) {
|
492
361
|
db_timezone = intern_local;
|
@@ -509,111 +378,56 @@ static VALUE rb_mysql_result_each(int argc, VALUE * argv, VALUE self) {
|
|
509
378
|
}
|
510
379
|
|
511
380
|
if (wrapper->lastRowProcessed == 0) {
|
512
|
-
|
513
|
-
|
514
|
-
/* until we've finished fetching all rows */
|
515
|
-
wrapper->numberOfRows = 0;
|
381
|
+
wrapper->numberOfRows = mysql_num_rows(wrapper->result);
|
382
|
+
if (wrapper->numberOfRows == 0) {
|
516
383
|
wrapper->rows = rb_ary_new();
|
517
|
-
|
518
|
-
wrapper->numberOfRows = mysql_num_rows(wrapper->result);
|
519
|
-
if (wrapper->numberOfRows == 0) {
|
520
|
-
wrapper->rows = rb_ary_new();
|
521
|
-
return wrapper->rows;
|
522
|
-
}
|
523
|
-
wrapper->rows = rb_ary_new2(wrapper->numberOfRows);
|
384
|
+
return wrapper->rows;
|
524
385
|
}
|
386
|
+
wrapper->rows = rb_ary_new2(wrapper->numberOfRows);
|
525
387
|
}
|
526
388
|
|
527
|
-
if (
|
528
|
-
|
529
|
-
|
530
|
-
|
531
|
-
|
532
|
-
|
533
|
-
do {
|
534
|
-
row = rb_mysql_result_fetch_row(self, db_timezone, app_timezone, symbolizeKeys, asArray, castBool, cast, fields);
|
535
|
-
|
536
|
-
if (block != Qnil && row != Qnil) {
|
537
|
-
rb_yield(row);
|
538
|
-
wrapper->lastRowProcessed++;
|
539
|
-
}
|
540
|
-
} while(row != Qnil);
|
541
|
-
|
542
|
-
rb_mysql_result_free_result(wrapper);
|
543
|
-
|
544
|
-
wrapper->numberOfRows = wrapper->lastRowProcessed;
|
545
|
-
wrapper->streamingComplete = 1;
|
546
|
-
|
547
|
-
// Check for errors, the connection might have gone out from under us
|
548
|
-
// mysql_error returns an empty string if there is no error
|
549
|
-
errstr = mysql_error(wrapper->client_wrapper->client);
|
550
|
-
if (errstr[0]) {
|
551
|
-
rb_raise(cMysql2Error, "%s", errstr);
|
552
|
-
}
|
553
|
-
} else {
|
554
|
-
rb_raise(cMysql2Error, "You have already fetched all the rows for this query and streaming is true. (to reiterate you must requery).");
|
389
|
+
if (cacheRows && wrapper->lastRowProcessed == wrapper->numberOfRows) {
|
390
|
+
// we've already read the entire dataset from the C result into our
|
391
|
+
// internal array. Lets hand that over to the user since it's ready to go
|
392
|
+
for (i = 0; i < wrapper->numberOfRows; i++) {
|
393
|
+
rb_yield(rb_ary_entry(wrapper->rows, i));
|
555
394
|
}
|
556
395
|
} else {
|
557
|
-
|
558
|
-
|
559
|
-
|
560
|
-
|
561
|
-
|
562
|
-
|
563
|
-
|
564
|
-
|
565
|
-
|
566
|
-
|
567
|
-
|
568
|
-
for (i = 0; i < wrapper->numberOfRows; i++) {
|
569
|
-
VALUE row;
|
570
|
-
if (cacheRows && i < rowsProcessed) {
|
571
|
-
row = rb_ary_entry(wrapper->rows, i);
|
572
|
-
} else {
|
573
|
-
row = rb_mysql_result_fetch_row(self, db_timezone, app_timezone, symbolizeKeys, asArray, castBool, cast, fields);
|
574
|
-
if (cacheRows) {
|
575
|
-
rb_ary_store(wrapper->rows, i, row);
|
576
|
-
}
|
577
|
-
wrapper->lastRowProcessed++;
|
578
|
-
}
|
579
|
-
|
580
|
-
if (row == Qnil) {
|
581
|
-
/* we don't need the mysql C dataset around anymore, peace it */
|
582
|
-
rb_mysql_result_free_result(wrapper);
|
583
|
-
return Qnil;
|
584
|
-
}
|
585
|
-
|
586
|
-
if (block != Qnil) {
|
587
|
-
rb_yield(row);
|
396
|
+
unsigned long rowsProcessed = 0;
|
397
|
+
rowsProcessed = RARRAY_LEN(wrapper->rows);
|
398
|
+
for (i = 0; i < wrapper->numberOfRows; i++) {
|
399
|
+
VALUE row;
|
400
|
+
if (cacheRows && i < rowsProcessed) {
|
401
|
+
row = rb_ary_entry(wrapper->rows, i);
|
402
|
+
} else {
|
403
|
+
row = rb_mysql_result_fetch_row(self, db_timezone, app_timezone, symbolizeKeys, asArray, castBool);
|
404
|
+
if (cacheRows) {
|
405
|
+
rb_ary_store(wrapper->rows, i, row);
|
588
406
|
}
|
407
|
+
wrapper->lastRowProcessed++;
|
589
408
|
}
|
590
|
-
|
591
|
-
|
409
|
+
|
410
|
+
if (row == Qnil) {
|
411
|
+
// we don't need the mysql C dataset around anymore, peace it
|
592
412
|
rb_mysql_result_free_result(wrapper);
|
413
|
+
return Qnil;
|
593
414
|
}
|
415
|
+
|
416
|
+
if (block != Qnil) {
|
417
|
+
rb_yield(row);
|
418
|
+
}
|
419
|
+
}
|
420
|
+
if (wrapper->lastRowProcessed == wrapper->numberOfRows) {
|
421
|
+
// we don't need the mysql C dataset around anymore, peace it
|
422
|
+
rb_mysql_result_free_result(wrapper);
|
594
423
|
}
|
595
424
|
}
|
596
425
|
|
597
426
|
return wrapper->rows;
|
598
427
|
}
|
599
428
|
|
600
|
-
static VALUE rb_mysql_result_count(VALUE self) {
|
601
|
-
mysql2_result_wrapper *wrapper;
|
602
|
-
|
603
|
-
GetMysql2Result(self, wrapper);
|
604
|
-
if(wrapper->resultFreed) {
|
605
|
-
if (wrapper->streamingComplete){
|
606
|
-
return LONG2NUM(wrapper->numberOfRows);
|
607
|
-
} else {
|
608
|
-
return LONG2NUM(RARRAY_LEN(wrapper->rows));
|
609
|
-
}
|
610
|
-
} else {
|
611
|
-
return INT2FIX(mysql_num_rows(wrapper->result));
|
612
|
-
}
|
613
|
-
}
|
614
|
-
|
615
429
|
/* Mysql2::Result */
|
616
|
-
VALUE rb_mysql_result_to_obj(
|
430
|
+
VALUE rb_mysql_result_to_obj(MYSQL_RES * r) {
|
617
431
|
VALUE obj;
|
618
432
|
mysql2_result_wrapper * wrapper;
|
619
433
|
obj = Data_Make_Struct(cMysql2Result, mysql2_result_wrapper, rb_mysql_result_mark, rb_mysql_result_free, wrapper);
|
@@ -624,16 +438,8 @@ VALUE rb_mysql_result_to_obj(VALUE client, VALUE encoding, VALUE options, MYSQL_
|
|
624
438
|
wrapper->result = r;
|
625
439
|
wrapper->fields = Qnil;
|
626
440
|
wrapper->rows = Qnil;
|
627
|
-
wrapper->encoding =
|
628
|
-
wrapper->streamingComplete = 0;
|
629
|
-
wrapper->client = client;
|
630
|
-
wrapper->client_wrapper = DATA_PTR(client);
|
631
|
-
wrapper->client_wrapper->refcount++;
|
632
|
-
|
441
|
+
wrapper->encoding = Qnil;
|
633
442
|
rb_obj_call_init(obj, 0, NULL);
|
634
|
-
|
635
|
-
rb_iv_set(obj, "@query_options", options);
|
636
|
-
|
637
443
|
return obj;
|
638
444
|
}
|
639
445
|
|
@@ -645,8 +451,9 @@ void init_mysql2_result() {
|
|
645
451
|
cMysql2Result = rb_define_class_under(mMysql2, "Result", rb_cObject);
|
646
452
|
rb_define_method(cMysql2Result, "each", rb_mysql_result_each, -1);
|
647
453
|
rb_define_method(cMysql2Result, "fields", rb_mysql_result_fetch_fields, 0);
|
648
|
-
|
649
|
-
|
454
|
+
|
455
|
+
intern_encoding_from_charset = rb_intern("encoding_from_charset");
|
456
|
+
intern_encoding_from_charset_code = rb_intern("encoding_from_charset_code");
|
650
457
|
|
651
458
|
intern_new = rb_intern("new");
|
652
459
|
intern_utc = rb_intern("utc");
|
@@ -666,12 +473,9 @@ void init_mysql2_result() {
|
|
666
473
|
sym_database_timezone = ID2SYM(rb_intern("database_timezone"));
|
667
474
|
sym_application_timezone = ID2SYM(rb_intern("application_timezone"));
|
668
475
|
sym_cache_rows = ID2SYM(rb_intern("cache_rows"));
|
669
|
-
sym_cast = ID2SYM(rb_intern("cast"));
|
670
|
-
sym_stream = ID2SYM(rb_intern("stream"));
|
671
|
-
sym_name = ID2SYM(rb_intern("name"));
|
672
476
|
|
673
477
|
opt_decimal_zero = rb_str_new2("0.0");
|
674
|
-
rb_global_variable(&opt_decimal_zero);
|
478
|
+
rb_global_variable(&opt_decimal_zero); //never GC
|
675
479
|
opt_float_zero = rb_float_new((double)0);
|
676
480
|
rb_global_variable(&opt_float_zero);
|
677
481
|
opt_time_year = INT2NUM(2000);
|