mysql_blob_streaming 1.1.3
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/README.markdown +24 -0
- data/ext/mysql_blob_streaming/extconf.rb +23 -0
- data/ext/mysql_blob_streaming/mysql_blob_streaming.c +98 -0
- data/lib/mysql_blob_streaming.rb +1 -0
- metadata +85 -0
data/README.markdown
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
# A blob streaming extension for the native Ruby-MySQL adaptor.
|
2
|
+
|
3
|
+
It provides the module MysqlBlobStreaming, which gives the adaptor the ability
|
4
|
+
of streaming blobs right out of the MySQL database.
|
5
|
+
|
6
|
+
(c) 2008-2012 Infopark AG. See MIT-LICENSE for licensing details.
|
7
|
+
|
8
|
+
## Dependencies
|
9
|
+
|
10
|
+
* Ruby-headers
|
11
|
+
* MySQL-headers
|
12
|
+
* [Native Ruby-MySQL adaptor](http://www.tmtm.org/en/mysql/ruby)
|
13
|
+
|
14
|
+
## Building
|
15
|
+
|
16
|
+
gem build mysql_blob_streaming.gemspec
|
17
|
+
|
18
|
+
## Installation
|
19
|
+
|
20
|
+
Install it like any other Gem:
|
21
|
+
|
22
|
+
gem install mysql_blob_streaming-X.X.X.gem
|
23
|
+
|
24
|
+
Run it with root privileges if needed.
|
@@ -0,0 +1,23 @@
|
|
1
|
+
require "mkmf"
|
2
|
+
|
3
|
+
additional_mysql_include_dirs = [
|
4
|
+
'/usr/local/mysql/include',
|
5
|
+
'/usr/include/mysql']
|
6
|
+
additional_mysql_lib_dirs = additional_mysql_include_dirs.map{
|
7
|
+
|d| d.sub('include', 'lib')}
|
8
|
+
|
9
|
+
find_header('mysql.h', *additional_mysql_include_dirs)
|
10
|
+
find_header('errmsg.h', *additional_mysql_include_dirs)
|
11
|
+
find_library('mysqlclient', nil, *additional_mysql_lib_dirs)
|
12
|
+
|
13
|
+
# --no-undefined forces us to link against libruby
|
14
|
+
def remove_no_undefined(ldflags)
|
15
|
+
ldflags.gsub("-Wl,--no-undefined", "")
|
16
|
+
end
|
17
|
+
|
18
|
+
with_ldflags("#{remove_no_undefined($LDFLAGS)}") { true }
|
19
|
+
|
20
|
+
# Do NOT link against libruby
|
21
|
+
$LIBRUBYARG = ""
|
22
|
+
|
23
|
+
create_makefile("mysql_blob_streaming/mysql_blob_streaming")
|
@@ -0,0 +1,98 @@
|
|
1
|
+
#include <ruby.h>
|
2
|
+
#include <stdlib.h>
|
3
|
+
|
4
|
+
#include <mysql.h>
|
5
|
+
#include <errmsg.h>
|
6
|
+
|
7
|
+
struct mysql_stmt {
|
8
|
+
MYSQL_STMT *stmt;
|
9
|
+
char closed;
|
10
|
+
struct {
|
11
|
+
int n;
|
12
|
+
MYSQL_BIND *bind;
|
13
|
+
unsigned long *length;
|
14
|
+
MYSQL_TIME *buffer;
|
15
|
+
} param;
|
16
|
+
struct {
|
17
|
+
int n;
|
18
|
+
MYSQL_BIND *bind;
|
19
|
+
my_bool *is_null;
|
20
|
+
unsigned long *length;
|
21
|
+
} result;
|
22
|
+
MYSQL_RES *res;
|
23
|
+
};
|
24
|
+
|
25
|
+
|
26
|
+
static void store_buffer(struct mysql_stmt *s, int offset_index, VALUE obj)
|
27
|
+
{
|
28
|
+
int status = mysql_stmt_fetch_column(s->stmt, s->result.bind, 0, offset_index);
|
29
|
+
if (status != 0) {
|
30
|
+
rb_raise(rb_eRuntimeError, "Fetching column failed");
|
31
|
+
}
|
32
|
+
if (!s->result.is_null[0]) {
|
33
|
+
if (s->result.bind[0].buffer_type == MYSQL_TYPE_BLOB) {
|
34
|
+
rb_funcall(obj, rb_intern("handle_data"), 1, rb_str_new(s->result.bind[0].buffer,
|
35
|
+
s->result.bind[0].buffer_length));
|
36
|
+
} else {
|
37
|
+
rb_raise(rb_eRuntimeError, "wrong buffer_type (must be: MYSQL_TYPE_BLOB): %d",
|
38
|
+
s->result.bind[0].buffer_type);
|
39
|
+
}
|
40
|
+
}
|
41
|
+
}
|
42
|
+
|
43
|
+
|
44
|
+
static int determine_blob_length(struct mysql_stmt *s)
|
45
|
+
{
|
46
|
+
s->result.bind[0].buffer_length = 0;
|
47
|
+
if (mysql_stmt_bind_result(s->stmt, s->result.bind) != 0) {
|
48
|
+
rb_raise(rb_eRuntimeError, "Could not determine the blob length: bind failed");
|
49
|
+
}
|
50
|
+
int status = mysql_stmt_fetch(s->stmt);
|
51
|
+
// MYSQL_DATA_TRUNCATED is returned if MYSQL_REPORT_DATA_TRUNCATION connection option is set
|
52
|
+
if (status != 0 && status != MYSQL_DATA_TRUNCATED) {
|
53
|
+
rb_raise(rb_eRuntimeError, "Could not determine the blob length: fetch failed");
|
54
|
+
}
|
55
|
+
return *s->result.bind[0].length;
|
56
|
+
}
|
57
|
+
|
58
|
+
|
59
|
+
static VALUE stmt_fetch_and_write(VALUE obj, VALUE rb_buffer_length)
|
60
|
+
{
|
61
|
+
int buffer_length = FIX2INT(rb_buffer_length);
|
62
|
+
|
63
|
+
if (buffer_length == 0) {
|
64
|
+
return 0;
|
65
|
+
}
|
66
|
+
if (buffer_length < 0) {
|
67
|
+
rb_raise(rb_eRuntimeError, "buffer size must be integer >= 0");
|
68
|
+
}
|
69
|
+
|
70
|
+
struct mysql_stmt *s = DATA_PTR(obj);
|
71
|
+
int blob_length = determine_blob_length(s);
|
72
|
+
|
73
|
+
s->result.bind[0].buffer_length = buffer_length;
|
74
|
+
if (blob_length <= s->result.bind[0].buffer_length) {
|
75
|
+
s->result.bind[0].buffer_length = blob_length;
|
76
|
+
store_buffer(s, 0, obj);
|
77
|
+
} else {
|
78
|
+
long loops = abs(blob_length / s->result.bind[0].buffer_length);
|
79
|
+
long i;
|
80
|
+
for (i = 0; i < loops; ++i) {
|
81
|
+
store_buffer(s, i * s->result.bind[0].buffer_length, obj);
|
82
|
+
}
|
83
|
+
int old_bufflen = s->result.bind[0].buffer_length;
|
84
|
+
int new_bufflen = blob_length % s->result.bind[0].buffer_length;
|
85
|
+
if (new_bufflen) {
|
86
|
+
s->result.bind[0].buffer_length = new_bufflen;
|
87
|
+
store_buffer(s, loops * old_bufflen, obj);
|
88
|
+
}
|
89
|
+
}
|
90
|
+
return Qnil;
|
91
|
+
}
|
92
|
+
|
93
|
+
|
94
|
+
void Init_mysql_blob_streaming()
|
95
|
+
{
|
96
|
+
VALUE rb_mMysqlBlobStreaming = rb_define_module("MysqlBlobStreaming");
|
97
|
+
rb_define_method(rb_mMysqlBlobStreaming, "stream", stmt_fetch_and_write, 1);
|
98
|
+
}
|
@@ -0,0 +1 @@
|
|
1
|
+
require "mysql_blob_streaming/mysql_blob_streaming"
|
metadata
ADDED
@@ -0,0 +1,85 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: mysql_blob_streaming
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
hash: 21
|
5
|
+
prerelease:
|
6
|
+
segments:
|
7
|
+
- 1
|
8
|
+
- 1
|
9
|
+
- 3
|
10
|
+
version: 1.1.3
|
11
|
+
platform: ruby
|
12
|
+
authors:
|
13
|
+
- Infopark AG
|
14
|
+
autorequire:
|
15
|
+
bindir: bin
|
16
|
+
cert_chain: []
|
17
|
+
|
18
|
+
date: 2012-07-12 00:00:00 Z
|
19
|
+
dependencies:
|
20
|
+
- !ruby/object:Gem::Dependency
|
21
|
+
name: mysql
|
22
|
+
prerelease: false
|
23
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
24
|
+
none: false
|
25
|
+
requirements:
|
26
|
+
- - ">="
|
27
|
+
- !ruby/object:Gem::Version
|
28
|
+
hash: 13
|
29
|
+
segments:
|
30
|
+
- 2
|
31
|
+
- 7
|
32
|
+
version: "2.7"
|
33
|
+
type: :runtime
|
34
|
+
version_requirements: *id001
|
35
|
+
description: " This GEM is required by the Infopark Rails Connector (RC) when using MySQL.\n"
|
36
|
+
email: info@infopark.de
|
37
|
+
executables: []
|
38
|
+
|
39
|
+
extensions:
|
40
|
+
- ext/mysql_blob_streaming/extconf.rb
|
41
|
+
extra_rdoc_files:
|
42
|
+
- README.markdown
|
43
|
+
files:
|
44
|
+
- lib/mysql_blob_streaming.rb
|
45
|
+
- ext/mysql_blob_streaming/mysql_blob_streaming.c
|
46
|
+
- ext/mysql_blob_streaming/extconf.rb
|
47
|
+
- README.markdown
|
48
|
+
homepage: http://www.infopark.de/
|
49
|
+
licenses: []
|
50
|
+
|
51
|
+
post_install_message:
|
52
|
+
rdoc_options:
|
53
|
+
- --main
|
54
|
+
- README.markdown
|
55
|
+
require_paths:
|
56
|
+
- lib
|
57
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
58
|
+
none: false
|
59
|
+
requirements:
|
60
|
+
- - ">="
|
61
|
+
- !ruby/object:Gem::Version
|
62
|
+
hash: 57
|
63
|
+
segments:
|
64
|
+
- 1
|
65
|
+
- 8
|
66
|
+
- 7
|
67
|
+
version: 1.8.7
|
68
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
69
|
+
none: false
|
70
|
+
requirements:
|
71
|
+
- - ">="
|
72
|
+
- !ruby/object:Gem::Version
|
73
|
+
hash: 3
|
74
|
+
segments:
|
75
|
+
- 0
|
76
|
+
version: "0"
|
77
|
+
requirements:
|
78
|
+
- Infopark Rails Connector (RC)
|
79
|
+
rubyforge_project:
|
80
|
+
rubygems_version: 1.8.21
|
81
|
+
signing_key:
|
82
|
+
specification_version: 3
|
83
|
+
summary: A blob streaming extension for the native Ruby-MySQL adapter
|
84
|
+
test_files: []
|
85
|
+
|