do_mysql 0.9.11 → 0.9.12
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/LICENSE +1 -1
- data/Manifest.txt +15 -4
- data/Rakefile +7 -122
- data/ext/do_mysql_ext/do_mysql_ext.c +154 -99
- data/ext/do_mysql_ext/extconf.rb +1 -0
- data/lib/do_mysql.rb +5 -2
- data/lib/do_mysql/version.rb +1 -1
- data/spec/command_spec.rb +9 -0
- data/spec/connection_spec.rb +19 -0
- data/spec/encoding_spec.rb +8 -0
- data/spec/lib/rspec_immediate_feedback_formatter.rb +3 -0
- data/spec/reader_spec.rb +8 -0
- data/spec/result_spec.rb +9 -0
- data/spec/spec_helper.rb +38 -47
- data/spec/typecast/array_spec.rb +8 -0
- data/spec/typecast/bigdecimal_spec.rb +9 -0
- data/spec/typecast/boolean_spec.rb +9 -0
- data/spec/typecast/byte_array_spec.rb +8 -0
- data/spec/typecast/class_spec.rb +8 -0
- data/spec/typecast/date_spec.rb +9 -0
- data/spec/typecast/datetime_spec.rb +9 -0
- data/spec/typecast/float_spec.rb +9 -0
- data/spec/typecast/integer_spec.rb +8 -0
- data/spec/typecast/nil_spec.rb +10 -0
- data/spec/typecast/range_spec.rb +8 -0
- data/spec/typecast/string_spec.rb +8 -0
- data/spec/typecast/time_spec.rb +8 -0
- data/tasks/gem.rake +60 -0
- data/tasks/install.rake +15 -0
- data/tasks/native.rake +31 -0
- data/tasks/release.rake +75 -0
- data/tasks/retrieve.rake +67 -0
- data/tasks/spec.rake +18 -0
- metadata +72 -40
- data/.gitignore +0 -0
- data/buildfile +0 -27
- data/ext-java/src/main/java/DoMysqlExtService.java +0 -23
- data/ext-java/src/main/java/do_mysql/MySqlDriverDefinition.java +0 -22
- data/ext/.gitignore +0 -2
- data/spec/integration/do_mysql_spec.rb +0 -341
- data/spec/integration/logging_spec.rb +0 -52
- data/spec/integration/quoting_spec.rb +0 -45
- data/spec/spec.opts +0 -2
- data/spec/unit/transaction_spec.rb +0 -35
data/LICENSE
CHANGED
@@ -17,4 +17,4 @@ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
17
17
|
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
18
|
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
19
|
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
-
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/Manifest.txt
CHANGED
@@ -13,9 +13,20 @@ ext/do_mysql_ext/extconf.rb
|
|
13
13
|
lib/do_mysql.rb
|
14
14
|
lib/do_mysql/transaction.rb
|
15
15
|
lib/do_mysql/version.rb
|
16
|
-
spec/
|
17
|
-
spec/
|
18
|
-
spec/
|
16
|
+
spec/command_spec.rb
|
17
|
+
spec/connection_spec.rb
|
18
|
+
spec/reader_spec.rb
|
19
|
+
spec/result_spec.rb
|
19
20
|
spec/spec.opts
|
20
21
|
spec/spec_helper.rb
|
21
|
-
spec/
|
22
|
+
spec/typecast/bigdecimal_spec.rb
|
23
|
+
spec/typecast/boolean_spec.rb
|
24
|
+
spec/typecast/byte_array_spec.rb
|
25
|
+
spec/typecast/class_spec.rb
|
26
|
+
spec/typecast/date_spec.rb
|
27
|
+
spec/typecast/datetime_spec.rb
|
28
|
+
spec/typecast/float_spec.rb
|
29
|
+
spec/typecast/integer_spec.rb
|
30
|
+
spec/typecast/nil_spec.rb
|
31
|
+
spec/typecast/string_spec.rb
|
32
|
+
spec/typecast/time_spec.rb
|
data/Rakefile
CHANGED
@@ -1,131 +1,16 @@
|
|
1
|
-
require 'pathname'
|
2
1
|
require 'rubygems'
|
3
|
-
require '
|
4
|
-
require '
|
2
|
+
require 'rake'
|
3
|
+
require 'rake/clean'
|
5
4
|
|
5
|
+
require 'pathname'
|
6
|
+
require 'lib/do_mysql/version'
|
6
7
|
|
7
8
|
ROOT = Pathname(__FILE__).dirname.expand_path
|
8
9
|
JRUBY = RUBY_PLATFORM =~ /java/
|
9
10
|
WINDOWS = Gem.win_platform?
|
10
11
|
SUDO = (WINDOWS || JRUBY) ? '' : ('sudo' unless ENV['SUDOLESS'])
|
12
|
+
BINARY_VERSION = '5.0.77'
|
11
13
|
|
12
|
-
|
13
|
-
EMAIL = "d.bussink@gmail.com"
|
14
|
-
GEM_NAME = "do_mysql"
|
15
|
-
GEM_VERSION = DataObjects::Mysql::VERSION
|
16
|
-
GEM_DEPENDENCIES = if JRUBY
|
17
|
-
[["data_objects", GEM_VERSION], ["do_jdbc", GEM_VERSION], ["jdbc-mysql", ">=5.0.4"]]
|
18
|
-
else
|
19
|
-
[["data_objects", GEM_VERSION]]
|
20
|
-
end
|
21
|
-
GEM_CLEAN = ['**/*.{o,so,bundle,jar,log,a,gem,dSYM,obj,pdb,lib,def,exp,DS_Store}',
|
22
|
-
'ext/Makefile', 'ext-java/target']
|
23
|
-
GEM_EXTRAS = if JRUBY
|
24
|
-
{
|
25
|
-
:has_rdoc => false,
|
26
|
-
:platform => 'java'
|
27
|
-
}
|
28
|
-
else
|
29
|
-
{
|
30
|
-
:has_rdoc => false,
|
31
|
-
:extensions => 'ext/do_mysql_ext/extconf.rb'
|
32
|
-
}
|
33
|
-
end
|
34
|
-
|
35
|
-
PROJECT_NAME = "dorb"
|
36
|
-
PROJECT_URL = "http://rubyforge.org/projects/dorb"
|
37
|
-
PROJECT_DESCRIPTION = PROJECT_SUMMARY = "A DataObject.rb driver for MySQL"
|
38
|
-
|
39
|
-
|
40
|
-
# RCov is run by default, except on the JRuby platform, or if NO_RCOV env is true
|
41
|
-
RUN_RCOV = JRUBY ? false : (ENV.has_key?('NO_RCOV') ? ENV['NO_RCOV'] != 'true' : true)
|
42
|
-
|
43
|
-
if (tasks_dir = ROOT.parent + 'tasks').directory?
|
44
|
-
require tasks_dir + 'hoe'
|
45
|
-
require tasks_dir + 'ext_helper_java'
|
46
|
-
|
47
|
-
setup_java_extension "#{GEM_NAME}_ext", HOE.spec
|
48
|
-
end
|
49
|
-
|
50
|
-
if JRUBY
|
51
|
-
HOE.spec.files += ['lib/do_mysql_ext.jar']
|
52
|
-
HOE.spec.require_paths = Dir['lib']
|
53
|
-
end
|
54
|
-
|
55
|
-
# compile the extension
|
56
|
-
if JRUBY
|
57
|
-
Rake::Task['compile:jruby'].invoke
|
58
|
-
else
|
59
|
-
begin
|
60
|
-
gem('rake-compiler')
|
61
|
-
require 'rake/extensiontask'
|
62
|
-
Rake::ExtensionTask.new('do_mysql_ext', HOE.spec)
|
63
|
-
rescue LoadError
|
64
|
-
warn "To cross-compile, install rake-compiler (gem install rake-compiler)"
|
65
|
-
if tasks_dir.directory?
|
66
|
-
require tasks_dir + 'ext_helper'
|
67
|
-
setup_c_extension('do_mysql_ext', HOE.spec)
|
68
|
-
end
|
69
|
-
end
|
70
|
-
end
|
71
|
-
|
72
|
-
def sudo_gem(cmd)
|
73
|
-
sh "#{SUDO} #{RUBY} -S gem #{cmd}", :verbose => false
|
74
|
-
end
|
75
|
-
|
76
|
-
# Installation
|
77
|
-
|
78
|
-
desc "Install #{GEM_NAME} #{GEM_VERSION}"
|
79
|
-
task :install => [ :package ] do
|
80
|
-
sudo_gem "install pkg/#{GEM_NAME}-#{GEM_VERSION} --no-update-sources"
|
81
|
-
end
|
82
|
-
|
83
|
-
desc "Uninstall #{GEM_NAME} #{GEM_VERSION}"
|
84
|
-
task :uninstall => [ :clobber ] do
|
85
|
-
sudo_gem "uninstall #{GEM_NAME} -v#{GEM_VERSION} -I -x"
|
86
|
-
end
|
87
|
-
|
88
|
-
# Specs
|
89
|
-
|
90
|
-
desc 'Run specifications'
|
91
|
-
Spec::Rake::SpecTask.new(:spec) do |t|
|
92
|
-
t.spec_opts << '--format' << 'specdoc' << '--colour'
|
93
|
-
t.spec_opts << '--loadby' << 'random'
|
94
|
-
t.spec_files = Pathname.glob(ENV['FILES'] || 'spec/**/*_spec.rb').map { |f| f.to_s }
|
95
|
-
|
96
|
-
begin
|
97
|
-
t.rcov = RUN_RCOV
|
98
|
-
t.rcov_opts << '--exclude' << 'spec'
|
99
|
-
t.rcov_opts << '--text-summary'
|
100
|
-
t.rcov_opts << '--sort' << 'coverage' << '--sort-reverse'
|
101
|
-
rescue Exception
|
102
|
-
# rcov not installed
|
103
|
-
end
|
104
|
-
end
|
105
|
-
|
106
|
-
namespace :ci do
|
107
|
-
|
108
|
-
task :prepare do
|
109
|
-
rm_rf ROOT + "ci"
|
110
|
-
mkdir_p ROOT + "ci"
|
111
|
-
mkdir_p ROOT + "ci/doc"
|
112
|
-
mkdir_p ROOT + "ci/cyclomatic"
|
113
|
-
mkdir_p ROOT + "ci/token"
|
114
|
-
end
|
115
|
-
|
116
|
-
task :publish do
|
117
|
-
out = ENV['CC_BUILD_ARTIFACTS'] || "out"
|
118
|
-
mkdir_p out unless File.directory? out
|
119
|
-
|
120
|
-
mv "ci/rspec_report.html", "#{out}/rspec_report.html"
|
121
|
-
mv "ci/coverage", "#{out}/coverage"
|
122
|
-
end
|
123
|
-
|
124
|
-
task :spec => :prepare do
|
125
|
-
Rake::Task[:spec].invoke
|
126
|
-
mv ROOT + "coverage", ROOT + "ci/coverage"
|
127
|
-
end
|
128
|
-
|
129
|
-
end
|
14
|
+
Dir['tasks/*.rake'].each { |f| import f }
|
130
15
|
|
131
|
-
|
16
|
+
CLEAN.include(%w[ {tmp,pkg}/ **/*.{o,so,bundle,jar,log,a,gem,dSYM,obj,pdb,exp,DS_Store,rbc,db} ext/do_mysql_ext/Makefile ext-java/target ])
|
@@ -3,7 +3,6 @@
|
|
3
3
|
#include <math.h>
|
4
4
|
#include <ctype.h>
|
5
5
|
#include <time.h>
|
6
|
-
#include <my_global.h>
|
7
6
|
#include <mysql.h>
|
8
7
|
#include <errmsg.h>
|
9
8
|
#include <mysqld_error.h>
|
@@ -29,8 +28,10 @@
|
|
29
28
|
#endif
|
30
29
|
|
31
30
|
#ifdef _WIN32
|
31
|
+
#define cCommand_execute cCommand_execute_sync
|
32
32
|
#define do_int64 signed __int64
|
33
33
|
#else
|
34
|
+
#define cCommand_execute cCommand_execute_async
|
34
35
|
#define do_int64 signed long long int
|
35
36
|
#endif
|
36
37
|
|
@@ -40,7 +41,6 @@ static ID ID_TO_F;
|
|
40
41
|
static ID ID_TO_S;
|
41
42
|
static ID ID_TO_TIME;
|
42
43
|
static ID ID_NEW;
|
43
|
-
static ID ID_NEW_RATIONAL;
|
44
44
|
static ID ID_NEW_DATE;
|
45
45
|
static ID ID_CONST_GET;
|
46
46
|
static ID ID_RATIONAL;
|
@@ -51,6 +51,9 @@ static ID ID_LOGGER;
|
|
51
51
|
static ID ID_DEBUG;
|
52
52
|
static ID ID_LEVEL;
|
53
53
|
|
54
|
+
// Reference to Extlib module
|
55
|
+
static VALUE mExtlib;
|
56
|
+
|
54
57
|
// References to DataObjects base classes
|
55
58
|
static VALUE mDO;
|
56
59
|
static VALUE cDO_Quoting;
|
@@ -63,6 +66,7 @@ static VALUE cDO_Reader;
|
|
63
66
|
static VALUE rb_cDate;
|
64
67
|
static VALUE rb_cDateTime;
|
65
68
|
static VALUE rb_cBigDecimal;
|
69
|
+
static VALUE rb_cByteArray;
|
66
70
|
|
67
71
|
// Classes that we'll build in Init
|
68
72
|
static VALUE mDOMysql;
|
@@ -71,61 +75,44 @@ static VALUE cCommand;
|
|
71
75
|
static VALUE cResult;
|
72
76
|
static VALUE cReader;
|
73
77
|
static VALUE eMysqlError;
|
78
|
+
static VALUE eArgumentError;
|
74
79
|
|
75
80
|
// Figures out what we should cast a given mysql field type to
|
76
81
|
static VALUE infer_ruby_type(MYSQL_FIELD *field) {
|
77
|
-
|
78
|
-
char* ruby_type;
|
79
|
-
|
80
82
|
switch(field->type) {
|
81
|
-
case MYSQL_TYPE_NULL:
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
case MYSQL_TYPE_TINY: {
|
86
|
-
ruby_type = "TrueClass";
|
87
|
-
break;
|
88
|
-
}
|
83
|
+
case MYSQL_TYPE_NULL:
|
84
|
+
return Qnil;
|
85
|
+
case MYSQL_TYPE_TINY:
|
86
|
+
return rb_cTrueClass;
|
89
87
|
case MYSQL_TYPE_BIT:
|
90
88
|
case MYSQL_TYPE_SHORT:
|
91
89
|
case MYSQL_TYPE_LONG:
|
92
90
|
case MYSQL_TYPE_INT24:
|
93
91
|
case MYSQL_TYPE_LONGLONG:
|
94
|
-
case MYSQL_TYPE_YEAR:
|
95
|
-
|
96
|
-
|
97
|
-
}
|
92
|
+
case MYSQL_TYPE_YEAR:
|
93
|
+
return rb_cInteger;
|
94
|
+
case MYSQL_TYPE_NEWDECIMAL:
|
98
95
|
case MYSQL_TYPE_DECIMAL:
|
99
|
-
|
100
|
-
ruby_type = "BigDecimal";
|
101
|
-
break;
|
102
|
-
}
|
96
|
+
return rb_cBigDecimal;
|
103
97
|
case MYSQL_TYPE_FLOAT:
|
104
|
-
case MYSQL_TYPE_DOUBLE:
|
105
|
-
|
106
|
-
break;
|
107
|
-
}
|
98
|
+
case MYSQL_TYPE_DOUBLE:
|
99
|
+
return rb_cFloat;
|
108
100
|
case MYSQL_TYPE_TIMESTAMP:
|
109
|
-
case MYSQL_TYPE_DATETIME:
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
case MYSQL_TYPE_TIME: {
|
114
|
-
ruby_type = "DateTime";
|
115
|
-
break;
|
116
|
-
}
|
101
|
+
case MYSQL_TYPE_DATETIME:
|
102
|
+
return rb_cDateTime;
|
103
|
+
case MYSQL_TYPE_TIME:
|
104
|
+
return rb_cDateTime;
|
117
105
|
case MYSQL_TYPE_DATE:
|
118
|
-
case MYSQL_TYPE_NEWDATE:
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
106
|
+
case MYSQL_TYPE_NEWDATE:
|
107
|
+
return rb_cDate;
|
108
|
+
case MYSQL_TYPE_TINY_BLOB:
|
109
|
+
case MYSQL_TYPE_MEDIUM_BLOB:
|
110
|
+
case MYSQL_TYPE_LONG_BLOB:
|
111
|
+
case MYSQL_TYPE_BLOB:
|
112
|
+
return rb_cByteArray;
|
113
|
+
default:
|
114
|
+
return rb_cString;
|
126
115
|
}
|
127
|
-
|
128
|
-
return rb_str_new2(ruby_type);
|
129
116
|
}
|
130
117
|
|
131
118
|
// Find the greatest common denominator and reduce the provided numerator and denominator.
|
@@ -185,7 +172,7 @@ static VALUE parse_date(const char *date) {
|
|
185
172
|
|
186
173
|
static VALUE parse_time(const char *date) {
|
187
174
|
|
188
|
-
int year, month, day, hour, min, sec, usec;
|
175
|
+
int year, month, day, hour, min, sec, usec, tokens;
|
189
176
|
char subsec[7];
|
190
177
|
|
191
178
|
if (0 != strchr(date, '.')) {
|
@@ -193,7 +180,12 @@ static VALUE parse_time(const char *date) {
|
|
193
180
|
sscanf(date, "%4d-%2d-%2d %2d:%2d:%2d.%s", &year, &month, &day, &hour, &min, &sec, subsec);
|
194
181
|
sscanf(subsec, "%d", &usec);
|
195
182
|
} else {
|
196
|
-
sscanf(date, "%4d-%2d-%2d %2d:%2d:%2d", &year, &month, &day, &hour, &min, &sec);
|
183
|
+
tokens = sscanf(date, "%4d-%2d-%2d %2d:%2d:%2d", &year, &month, &day, &hour, &min, &sec);
|
184
|
+
if (tokens == 3) {
|
185
|
+
hour = 0;
|
186
|
+
min = 0;
|
187
|
+
sec = 0;
|
188
|
+
}
|
197
189
|
usec = 0;
|
198
190
|
}
|
199
191
|
|
@@ -240,9 +232,14 @@ static VALUE parse_date_time(const char *date) {
|
|
240
232
|
} else if ((max_tokens - 1) == tokens_read) {
|
241
233
|
// We read the Date and Time, but no Minute Offset
|
242
234
|
minute_offset = 0;
|
243
|
-
} else if (tokens_read == 3) {
|
244
|
-
|
245
|
-
|
235
|
+
} else if (tokens_read == 3 || tokens_read >= (max_tokens - 3)) {
|
236
|
+
if (tokens_read == 3) {
|
237
|
+
hour = 0;
|
238
|
+
min = 0;
|
239
|
+
hour_offset = 0;
|
240
|
+
minute_offset = 0;
|
241
|
+
sec = 0;
|
242
|
+
}
|
246
243
|
// We read the Date and Time, default to the current locale's offset
|
247
244
|
|
248
245
|
// Get localtime
|
@@ -298,31 +295,40 @@ static VALUE parse_date_time(const char *date) {
|
|
298
295
|
}
|
299
296
|
|
300
297
|
// Convert C-string to a Ruby instance of Ruby type "type"
|
301
|
-
static VALUE typecast(const char*
|
302
|
-
|
298
|
+
static VALUE typecast(const char *value, long length, const VALUE type) {
|
299
|
+
|
300
|
+
if(NULL == value) {
|
303
301
|
return Qnil;
|
302
|
+
}
|
304
303
|
|
305
|
-
if (
|
306
|
-
return rb_funcall(rb_cObject, rb_intern("full_const_get"), 1, TAINTED_STRING(value, length));
|
307
|
-
} else if ( strcmp(type, "Integer") == 0 || strcmp(type, "Fixnum") == 0 || strcmp(type, "Bignum") == 0 ) {
|
304
|
+
if (type == rb_cInteger) {
|
308
305
|
return rb_cstr2inum(value, 10);
|
309
|
-
} else if (
|
306
|
+
} else if (type == rb_cString) {
|
310
307
|
return TAINTED_STRING(value, length);
|
311
|
-
} else if (
|
308
|
+
} else if (type == rb_cFloat) {
|
312
309
|
return rb_float_new(rb_cstr_to_dbl(value, Qfalse));
|
313
|
-
} else if (
|
310
|
+
} else if (type == rb_cBigDecimal) {
|
314
311
|
return rb_funcall(rb_cBigDecimal, ID_NEW, 1, TAINTED_STRING(value, length));
|
315
|
-
} else if (
|
316
|
-
return (0 == value || 0 == strcmp("0", value)) ? Qfalse : Qtrue;
|
317
|
-
} else if (0 == strcmp("Date", type)) {
|
312
|
+
} else if (type == rb_cDate) {
|
318
313
|
return parse_date(value);
|
319
|
-
} else if (
|
314
|
+
} else if (type == rb_cDateTime) {
|
320
315
|
return parse_date_time(value);
|
321
|
-
} else if (
|
316
|
+
} else if (type == rb_cTime) {
|
322
317
|
return parse_time(value);
|
318
|
+
} else if (type == rb_cTrueClass) {
|
319
|
+
return (0 == value || 0 == strcmp("0", value)) ? Qfalse : Qtrue;
|
320
|
+
} else if (type == rb_cByteArray) {
|
321
|
+
return rb_funcall(rb_cByteArray, ID_NEW, 1, TAINTED_STRING(value, length));
|
322
|
+
} else if (type == rb_cClass) {
|
323
|
+
return rb_funcall(rb_cObject, rb_intern("full_const_get"), 1, TAINTED_STRING(value, length));
|
324
|
+
} else if (type == rb_cObject) {
|
325
|
+
return rb_marshal_load(rb_str_new(value, length));
|
326
|
+
} else if (type == rb_cNilClass) {
|
327
|
+
return Qnil;
|
323
328
|
} else {
|
324
329
|
return TAINTED_STRING(value, length);
|
325
330
|
}
|
331
|
+
|
326
332
|
}
|
327
333
|
|
328
334
|
static void data_objects_debug(VALUE string, struct timeval* start) {
|
@@ -341,9 +347,6 @@ static void data_objects_debug(VALUE string, struct timeval* start) {
|
|
341
347
|
gettimeofday(&stop, NULL);
|
342
348
|
|
343
349
|
duration = (stop.tv_sec - start->tv_sec) * 1000000 + stop.tv_usec - start->tv_usec;
|
344
|
-
if(stop.tv_usec < start->tv_usec) {
|
345
|
-
duration += 1000000;
|
346
|
-
}
|
347
350
|
|
348
351
|
snprintf(total_time, 32, "%.6f", duration / 1000000.0);
|
349
352
|
message = (char *)calloc(length + strlen(total_time) + 4, sizeof(char));
|
@@ -379,6 +382,29 @@ static char * get_uri_option(VALUE query_hash, char * key) {
|
|
379
382
|
return value;
|
380
383
|
}
|
381
384
|
|
385
|
+
#ifdef _WIN32
|
386
|
+
static MYSQL_RES* cCommand_execute_sync(VALUE self, MYSQL* db, VALUE query) {
|
387
|
+
int retval;
|
388
|
+
struct timeval start;
|
389
|
+
char* str = RSTRING_PTR(query);
|
390
|
+
int len = RSTRING_LEN(query);
|
391
|
+
|
392
|
+
VALUE connection = rb_iv_get(self, "@connection");
|
393
|
+
|
394
|
+
if(mysql_ping(db) && mysql_errno(db) == CR_SERVER_GONE_ERROR) {
|
395
|
+
CHECK_AND_RAISE(mysql_errno(db), "Mysql server has gone away. \
|
396
|
+
Please report this issue to the Datamapper project. \
|
397
|
+
Specify your at least your MySQL version when filing a ticket");
|
398
|
+
}
|
399
|
+
gettimeofday(&start, NULL);
|
400
|
+
retval = mysql_real_query(db, str, len);
|
401
|
+
CHECK_AND_RAISE(retval, str);
|
402
|
+
|
403
|
+
data_objects_debug(query, &start);
|
404
|
+
|
405
|
+
return mysql_store_result(db);
|
406
|
+
}
|
407
|
+
#else
|
382
408
|
static MYSQL_RES* cCommand_execute_async(VALUE self, MYSQL* db, VALUE query) {
|
383
409
|
int socket_fd;
|
384
410
|
int retval;
|
@@ -427,6 +453,7 @@ static MYSQL_RES* cCommand_execute_async(VALUE self, MYSQL* db, VALUE query) {
|
|
427
453
|
|
428
454
|
return mysql_store_result(db);
|
429
455
|
}
|
456
|
+
#endif
|
430
457
|
|
431
458
|
static VALUE cConnection_initialize(VALUE self, VALUE uri) {
|
432
459
|
VALUE r_host, r_user, r_password, r_path, r_query, r_port;
|
@@ -508,8 +535,10 @@ static VALUE cConnection_initialize(VALUE self, VALUE uri) {
|
|
508
535
|
raise_mysql_error(Qnil, db, -1, NULL);
|
509
536
|
}
|
510
537
|
|
538
|
+
#ifdef MYSQL_OPT_RECONNECT
|
511
539
|
my_bool reconnect = 1;
|
512
540
|
mysql_options(db, MYSQL_OPT_RECONNECT, &reconnect);
|
541
|
+
#endif
|
513
542
|
|
514
543
|
// Set the connections character set
|
515
544
|
encoding_error = mysql_set_character_set(db, encoding);
|
@@ -518,8 +547,8 @@ static VALUE cConnection_initialize(VALUE self, VALUE uri) {
|
|
518
547
|
}
|
519
548
|
|
520
549
|
// Disable sql_auto_is_null
|
521
|
-
|
522
|
-
|
550
|
+
cCommand_execute(self, db, rb_str_new2("SET sql_auto_is_null = 0"));
|
551
|
+
cCommand_execute(self, db, rb_str_new2("SET SESSION sql_mode = 'ANSI,NO_AUTO_VALUE_ON_ZERO,NO_DIR_IN_CREATE,NO_ENGINE_SUBSTITUTION,NO_UNSIGNED_SUBTRACTION,TRADITIONAL'"));
|
523
552
|
|
524
553
|
rb_iv_set(self, "@uri", uri);
|
525
554
|
rb_iv_set(self, "@connection", Data_Wrap_Struct(rb_cObject, 0, 0, db));
|
@@ -570,12 +599,32 @@ static VALUE cConnection_dispose(VALUE self) {
|
|
570
599
|
Accepts an array of Ruby types (Fixnum, Float, String, etc...) and turns them
|
571
600
|
into Ruby-strings so we can easily typecast later
|
572
601
|
*/
|
573
|
-
static VALUE cCommand_set_types(VALUE
|
602
|
+
static VALUE cCommand_set_types(int argc, VALUE *argv, VALUE self) {
|
574
603
|
VALUE type_strings = rb_ary_new();
|
575
|
-
|
604
|
+
VALUE array = rb_ary_new();
|
605
|
+
|
606
|
+
int i, j;
|
607
|
+
|
608
|
+
for ( i = 0; i < argc; i++) {
|
609
|
+
rb_ary_push(array, argv[i]);
|
610
|
+
}
|
576
611
|
|
577
612
|
for (i = 0; i < RARRAY_LEN(array); i++) {
|
578
|
-
|
613
|
+
VALUE entry = rb_ary_entry(array, i);
|
614
|
+
if(TYPE(entry) == T_CLASS) {
|
615
|
+
rb_ary_push(type_strings, entry);
|
616
|
+
} else if (TYPE(entry) == T_ARRAY) {
|
617
|
+
for (j = 0; j < RARRAY_LEN(entry); j++) {
|
618
|
+
VALUE sub_entry = rb_ary_entry(entry, j);
|
619
|
+
if(TYPE(sub_entry) == T_CLASS) {
|
620
|
+
rb_ary_push(type_strings, sub_entry);
|
621
|
+
} else {
|
622
|
+
rb_raise(eArgumentError, "Invalid type given");
|
623
|
+
}
|
624
|
+
}
|
625
|
+
} else {
|
626
|
+
rb_raise(eArgumentError, "Invalid type given");
|
627
|
+
}
|
579
628
|
}
|
580
629
|
|
581
630
|
rb_iv_set(self, "@field_types", type_strings);
|
@@ -583,23 +632,23 @@ static VALUE cCommand_set_types(VALUE self, VALUE array) {
|
|
583
632
|
return array;
|
584
633
|
}
|
585
634
|
|
586
|
-
VALUE
|
635
|
+
VALUE cConnection_quote_time(VALUE self, VALUE value) {
|
587
636
|
return rb_funcall(value, ID_STRFTIME, 1, RUBY_STRING("'%Y-%m-%d %H:%M:%S'"));
|
588
637
|
}
|
589
638
|
|
590
639
|
|
591
|
-
VALUE
|
640
|
+
VALUE cConnection_quote_date_time(VALUE self, VALUE value) {
|
592
641
|
// TODO: Support non-local dates. we need to call #new_offset on the date to be
|
593
642
|
// quoted and pass in the current locale's date offset (self.new_offset((hours * 3600).to_r / 86400)
|
594
643
|
return rb_funcall(value, ID_STRFTIME, 1, RUBY_STRING("'%Y-%m-%d %H:%M:%S'"));
|
595
644
|
}
|
596
645
|
|
597
|
-
VALUE
|
646
|
+
VALUE cConnection_quote_date(VALUE self, VALUE value) {
|
598
647
|
return rb_funcall(value, ID_STRFTIME, 1, RUBY_STRING("'%Y-%m-%d'"));
|
599
648
|
}
|
600
649
|
|
601
|
-
static VALUE
|
602
|
-
MYSQL *db = DATA_PTR(rb_iv_get(
|
650
|
+
static VALUE cConnection_quote_string(VALUE self, VALUE string) {
|
651
|
+
MYSQL *db = DATA_PTR(rb_iv_get(self, "@connection"));
|
603
652
|
const char *source = RSTRING_PTR(string);
|
604
653
|
int source_len = RSTRING_LEN(string);
|
605
654
|
char *escaped;
|
@@ -624,14 +673,14 @@ static VALUE cCommand_quote_string(VALUE self, VALUE string) {
|
|
624
673
|
|
625
674
|
static VALUE build_query_from_args(VALUE klass, int count, VALUE *args) {
|
626
675
|
VALUE query = rb_iv_get(klass, "@text");
|
627
|
-
|
628
|
-
|
629
|
-
|
630
|
-
|
631
|
-
|
632
|
-
}
|
633
|
-
query = rb_funcall(klass, ID_ESCAPE_SQL, 1, array);
|
676
|
+
|
677
|
+
int i;
|
678
|
+
VALUE array = rb_ary_new();
|
679
|
+
for ( i = 0; i < count; i++) {
|
680
|
+
rb_ary_push(array, (VALUE)args[i]);
|
634
681
|
}
|
682
|
+
query = rb_funcall(klass, ID_ESCAPE_SQL, 1, array);
|
683
|
+
|
635
684
|
return query;
|
636
685
|
}
|
637
686
|
|
@@ -643,13 +692,14 @@ static VALUE cCommand_execute_non_query(int argc, VALUE *argv, VALUE self) {
|
|
643
692
|
my_ulonglong affected_rows;
|
644
693
|
VALUE connection = rb_iv_get(self, "@connection");
|
645
694
|
VALUE mysql_connection = rb_iv_get(connection, "@connection");
|
646
|
-
if (Qnil == mysql_connection)
|
695
|
+
if (Qnil == mysql_connection) {
|
647
696
|
rb_raise(eMysqlError, "This connection has already been closed.");
|
697
|
+
}
|
648
698
|
|
649
699
|
MYSQL *db = DATA_PTR(mysql_connection);
|
650
700
|
query = build_query_from_args(self, argc, argv);
|
651
701
|
|
652
|
-
response =
|
702
|
+
response = cCommand_execute(self, db, query);
|
653
703
|
|
654
704
|
affected_rows = mysql_affected_rows(db);
|
655
705
|
mysql_free_result(response);
|
@@ -681,7 +731,7 @@ static VALUE cCommand_execute_reader(int argc, VALUE *argv, VALUE self) {
|
|
681
731
|
|
682
732
|
query = build_query_from_args(self, argc, argv);
|
683
733
|
|
684
|
-
response =
|
734
|
+
response = cCommand_execute(self, db, query);
|
685
735
|
|
686
736
|
if (!response) {
|
687
737
|
return Qnil;
|
@@ -704,7 +754,7 @@ static VALUE cCommand_execute_reader(int argc, VALUE *argv, VALUE self) {
|
|
704
754
|
// Whoops... wrong number of types passed to set_types. Close the reader and raise
|
705
755
|
// and error
|
706
756
|
rb_funcall(reader, rb_intern("close"), 0);
|
707
|
-
rb_raise(
|
757
|
+
rb_raise(eArgumentError, "Field-count mismatch. Expected %ld fields, but the query yielded %d", RARRAY_LEN(field_types), field_count);
|
708
758
|
}
|
709
759
|
|
710
760
|
for(i = 0; i < field_count; i++) {
|
@@ -753,34 +803,35 @@ static VALUE cReader_close(VALUE self) {
|
|
753
803
|
static VALUE cReader_next(VALUE self) {
|
754
804
|
// Get the reader from the instance variable, maybe refactor this?
|
755
805
|
VALUE reader_container = rb_iv_get(self, "@reader");
|
756
|
-
VALUE
|
806
|
+
VALUE field_types, field_type, row;
|
757
807
|
|
758
808
|
MYSQL_RES *reader;
|
759
809
|
MYSQL_ROW result;
|
760
810
|
unsigned long *lengths;
|
761
811
|
|
762
812
|
int i;
|
763
|
-
const char *field_type;
|
764
813
|
|
765
|
-
if (Qnil == reader_container)
|
814
|
+
if (Qnil == reader_container) {
|
766
815
|
return Qfalse;
|
816
|
+
}
|
767
817
|
|
768
818
|
reader = DATA_PTR(reader_container);
|
769
819
|
|
770
820
|
// The Meat
|
771
|
-
|
821
|
+
field_types = rb_iv_get(self, "@field_types");
|
772
822
|
row = rb_ary_new();
|
773
|
-
result =
|
823
|
+
result = mysql_fetch_row(reader);
|
774
824
|
lengths = mysql_fetch_lengths(reader);
|
775
825
|
|
776
826
|
rb_iv_set(self, "@state", result ? Qtrue : Qfalse);
|
777
827
|
|
778
|
-
if (!result)
|
779
|
-
return
|
828
|
+
if (!result) {
|
829
|
+
return Qfalse;
|
830
|
+
}
|
780
831
|
|
781
832
|
for (i = 0; i < reader->field_count; i++) {
|
782
833
|
// The field_type data could be cached in a c-array
|
783
|
-
field_type =
|
834
|
+
field_type = rb_ary_entry(field_types, i);
|
784
835
|
rb_ary_push(row, typecast(result[i], lengths[i], field_type));
|
785
836
|
}
|
786
837
|
|
@@ -841,6 +892,10 @@ void Init_do_mysql_ext() {
|
|
841
892
|
rb_cDateTime = RUBY_CLASS("DateTime");
|
842
893
|
rb_cBigDecimal = RUBY_CLASS("BigDecimal");
|
843
894
|
|
895
|
+
// Get references to the Extlib module
|
896
|
+
mExtlib = CONST_GET(rb_mKernel, "Extlib");
|
897
|
+
rb_cByteArray = CONST_GET(mExtlib, "ByteArray");
|
898
|
+
|
844
899
|
// Get references to the DataObjects module and its classes
|
845
900
|
mDO = CONST_GET(rb_mKernel, "DataObjects");
|
846
901
|
cDO_Quoting = CONST_GET(mDO, "Quoting");
|
@@ -852,6 +907,7 @@ void Init_do_mysql_ext() {
|
|
852
907
|
// Top Level Module that all the classes live under
|
853
908
|
mDOMysql = rb_define_module_under(mDO, "Mysql");
|
854
909
|
|
910
|
+
eArgumentError = CONST_GET(rb_mKernel, "ArgumentError");
|
855
911
|
eMysqlError = rb_define_class("MysqlError", rb_eStandardError);
|
856
912
|
|
857
913
|
cConnection = DRIVER_CLASS("Connection", cDO_Connection);
|
@@ -859,16 +915,15 @@ void Init_do_mysql_ext() {
|
|
859
915
|
rb_define_method(cConnection, "using_socket?", cConnection_is_using_socket, 0);
|
860
916
|
rb_define_method(cConnection, "character_set", cConnection_character_set , 0);
|
861
917
|
rb_define_method(cConnection, "dispose", cConnection_dispose, 0);
|
918
|
+
rb_define_method(cConnection, "quote_string", cConnection_quote_string, 1);
|
919
|
+
rb_define_method(cConnection, "quote_date", cConnection_quote_date, 1);
|
920
|
+
rb_define_method(cConnection, "quote_time", cConnection_quote_time, 1);
|
921
|
+
rb_define_method(cConnection, "quote_datetime", cConnection_quote_date_time, 1);
|
862
922
|
|
863
923
|
cCommand = DRIVER_CLASS("Command", cDO_Command);
|
864
|
-
|
865
|
-
rb_define_method(cCommand, "set_types", cCommand_set_types, 1);
|
924
|
+
rb_define_method(cCommand, "set_types", cCommand_set_types, -1);
|
866
925
|
rb_define_method(cCommand, "execute_non_query", cCommand_execute_non_query, -1);
|
867
926
|
rb_define_method(cCommand, "execute_reader", cCommand_execute_reader, -1);
|
868
|
-
rb_define_method(cCommand, "quote_string", cCommand_quote_string, 1);
|
869
|
-
rb_define_method(cCommand, "quote_date", cCommand_quote_date, 1);
|
870
|
-
rb_define_method(cCommand, "quote_time", cCommand_quote_time, 1);
|
871
|
-
rb_define_method(cCommand, "quote_datetime", cCommand_quote_date_time, 1);
|
872
927
|
|
873
928
|
// Non-Query result
|
874
929
|
cResult = DRIVER_CLASS("Result", cDO_Result);
|