]>
Commit | Line | Data |
---|---|---|
91a672d8 JR |
1 | commit b7e4613559f0a741935ad375f07f9411c2107bb7 |
2 | Author: Loren Segal <lsegal@soen.ca> | |
3 | Date: Fri Nov 6 22:07:00 2009 -0500 | |
4 | ||
5 | Add basic encoding aware logic. Convert all data to default external encoding | |
6 | ||
7 | diff --git a/extconf.rb b/extconf.rb | |
8 | index f31633e..9f3f57c 100644 | |
9 | --- a/extconf.rb | |
10 | +++ b/extconf.rb | |
11 | @@ -109,4 +108,6 @@ File.open('error_const.h', 'w') do |f| | |
12 | end | |
13 | end | |
14 | ||
15 | +$CPPFLAGS += " -DRUBY19" if RUBY_VERSION =~ /1.9/ | |
16 | + | |
17 | create_makefile("mysql") | |
18 | diff --git a/mysql.c b/mysql.c | |
19 | index 9c4515e..91570af 100644 | |
20 | --- a/mysql.c | |
21 | +++ b/mysql.c | |
22 | @@ -16,6 +16,32 @@ | |
23 | #define rb_str_set_len(str, length) (RSTRING_LEN(str) = (length)) | |
24 | #endif | |
25 | ||
26 | +#ifdef RUBY19 | |
27 | +#include <ruby/encoding.h> | |
28 | +#define DEFAULT_ENCODING (rb_enc_get(rb_enc_default_external())) | |
29 | +#else | |
30 | +#define DEFAULT_ENCODING NULL | |
31 | +#define rb_enc_str_new(ptr, len, enc) rb_str_new(ptr, len) | |
32 | +#endif | |
33 | + | |
34 | +VALUE | |
35 | +rb_enc_tainted_str_new(const char *ptr, long len) | |
36 | +{ | |
37 | + VALUE str = rb_enc_str_new(ptr, len, DEFAULT_ENCODING); | |
38 | + | |
39 | + OBJ_TAINT(str); | |
40 | + return str; | |
41 | +} | |
42 | + | |
43 | +VALUE | |
44 | +rb_enc_tainted_str_new2(const char *ptr) | |
45 | +{ | |
46 | + VALUE str = rb_enc_str_new(ptr, strlen(ptr), DEFAULT_ENCODING); | |
47 | + | |
48 | + OBJ_TAINT(str); | |
49 | + return str; | |
50 | +} | |
51 | + | |
52 | #ifdef HAVE_MYSQL_H | |
53 | #include <mysql.h> | |
54 | #include <errmsg.h> | |
55 | @@ -180,7 +206,7 @@ static void mysql_raise(MYSQL* m) | |
56 | VALUE e = rb_exc_new2(eMysql, mysql_error(m)); | |
57 | rb_iv_set(e, "errno", INT2FIX(mysql_errno(m))); | |
58 | #if MYSQL_VERSION_ID >= 40101 | |
59 | - rb_iv_set(e, "sqlstate", rb_tainted_str_new2(mysql_sqlstate(m))); | |
60 | + rb_iv_set(e, "sqlstate", rb_enc_tainted_str_new2(mysql_sqlstate(m))); | |
61 | #endif | |
62 | rb_exc_raise(e); | |
63 | } | |
64 | @@ -207,9 +233,9 @@ static VALUE make_field_obj(MYSQL_FIELD* f) | |
65 | if (f == NULL) | |
66 | return Qnil; | |
67 | obj = rb_obj_alloc(cMysqlField); | |
68 | - rb_iv_set(obj, "name", f->name? rb_str_freeze(rb_tainted_str_new2(f->name)): Qnil); | |
69 | - rb_iv_set(obj, "table", f->table? rb_str_freeze(rb_tainted_str_new2(f->table)): Qnil); | |
70 | - rb_iv_set(obj, "def", f->def? rb_str_freeze(rb_tainted_str_new2(f->def)): Qnil); | |
71 | + rb_iv_set(obj, "name", f->name? rb_str_freeze(rb_enc_tainted_str_new2(f->name)): Qnil); | |
72 | + rb_iv_set(obj, "table", f->table? rb_str_freeze(rb_enc_tainted_str_new2(f->table)): Qnil); | |
73 | + rb_iv_set(obj, "def", f->def? rb_str_freeze(rb_enc_tainted_str_new2(f->def)): Qnil); | |
74 | rb_iv_set(obj, "type", INT2NUM(f->type)); | |
75 | rb_iv_set(obj, "length", INT2NUM(f->length)); | |
76 | rb_iv_set(obj, "max_length", INT2NUM(f->max_length)); | |
77 | @@ -290,7 +316,7 @@ static VALUE escape_string(VALUE klass, VALUE str) | |
78 | { | |
79 | VALUE ret; | |
80 | Check_Type(str, T_STRING); | |
81 | - ret = rb_str_new(0, (RSTRING_LEN(str))*2+1); | |
82 | + ret = rb_enc_str_new(0, (RSTRING_LEN(str))*2+1, DEFAULT_ENCODING); | |
83 | rb_str_set_len(ret, mysql_escape_string(RSTRING_PTR(ret), RSTRING_PTR(str), RSTRING_LEN(str))); | |
84 | return ret; | |
85 | } | |
86 | @@ -298,7 +324,7 @@ static VALUE escape_string(VALUE klass, VALUE str) | |
87 | /* client_info() */ | |
88 | static VALUE client_info(VALUE klass) | |
89 | { | |
90 | - return rb_tainted_str_new2(mysql_get_client_info()); | |
91 | + return rb_enc_tainted_str_new2(mysql_get_client_info()); | |
92 | } | |
93 | ||
94 | #if MYSQL_VERSION_ID >= 32332 | |
95 | @@ -428,7 +454,7 @@ static VALUE real_escape_string(VALUE obj, VALUE str) | |
96 | MYSQL* m = GetHandler(obj); | |
97 | VALUE ret; | |
98 | Check_Type(str, T_STRING); | |
99 | - ret = rb_str_new(0, (RSTRING_LEN(str))*2+1); | |
100 | + ret = rb_enc_str_new(0, (RSTRING_LEN(str))*2+1, DEFAULT_ENCODING); | |
101 | rb_str_set_len(ret, mysql_real_escape_string(m, RSTRING_PTR(ret), RSTRING_PTR(str), RSTRING_LEN(str))); | |
102 | return ret; | |
103 | } | |
104 | @@ -467,7 +493,7 @@ static VALUE change_user(int argc, VALUE* argv, VALUE obj) | |
105 | /* character_set_name() */ | |
106 | static VALUE character_set_name(VALUE obj) | |
107 | { | |
108 | - return rb_tainted_str_new2(mysql_character_set_name(GetHandler(obj))); | |
109 | + return rb_enc_tainted_str_new2(mysql_character_set_name(GetHandler(obj))); | |
110 | } | |
111 | #endif | |
112 | ||
113 | @@ -532,7 +558,7 @@ static VALUE field_count(VALUE obj) | |
114 | /* host_info() */ | |
115 | static VALUE host_info(VALUE obj) | |
116 | { | |
117 | - return rb_tainted_str_new2(mysql_get_host_info(GetHandler(obj))); | |
118 | + return rb_enc_tainted_str_new2(mysql_get_host_info(GetHandler(obj))); | |
119 | } | |
120 | ||
121 | /* proto_info() */ | |
122 | @@ -544,14 +570,14 @@ static VALUE proto_info(VALUE obj) | |
123 | /* server_info() */ | |
124 | static VALUE server_info(VALUE obj) | |
125 | { | |
126 | - return rb_tainted_str_new2(mysql_get_server_info(GetHandler(obj))); | |
127 | + return rb_enc_tainted_str_new2(mysql_get_server_info(GetHandler(obj))); | |
128 | } | |
129 | ||
130 | /* info() */ | |
131 | static VALUE info(VALUE obj) | |
132 | { | |
133 | const char* p = mysql_info(GetHandler(obj)); | |
134 | - return p? rb_tainted_str_new2(p): Qnil; | |
135 | + return p? rb_enc_tainted_str_new2(p): Qnil; | |
136 | } | |
137 | ||
138 | /* insert_id() */ | |
139 | @@ -586,7 +612,7 @@ static VALUE list_dbs(int argc, VALUE* argv, VALUE obj) | |
140 | n = mysql_num_rows(res); | |
141 | ret = rb_ary_new2(n); | |
142 | for (i=0; i<n; i++) | |
143 | - rb_ary_store(ret, i, rb_tainted_str_new2(mysql_fetch_row(res)[0])); | |
144 | + rb_ary_store(ret, i, rb_enc_tainted_str_new2(mysql_fetch_row(res)[0])); | |
145 | mysql_free_result(res); | |
146 | return ret; | |
147 | } | |
148 | @@ -631,7 +657,7 @@ static VALUE list_tables(int argc, VALUE* argv, VALUE obj) | |
149 | n = mysql_num_rows(res); | |
150 | ret = rb_ary_new2(n); | |
151 | for (i=0; i<n; i++) | |
152 | - rb_ary_store(ret, i, rb_tainted_str_new2(mysql_fetch_row(res)[0])); | |
153 | + rb_ary_store(ret, i, rb_enc_tainted_str_new2(mysql_fetch_row(res)[0])); | |
154 | mysql_free_result(res); | |
155 | return ret; | |
156 | } | |
157 | @@ -695,7 +721,7 @@ static VALUE my_stat(VALUE obj) | |
158 | const char* s = mysql_stat(m); | |
159 | if (s == NULL) | |
160 | mysql_raise(m); | |
161 | - return rb_tainted_str_new2(s); | |
162 | + return rb_enc_tainted_str_new2(s); | |
163 | } | |
164 | ||
165 | /* store_result() */ | |
166 | @@ -862,7 +888,7 @@ static VALUE set_server_option(VALUE obj, VALUE option) | |
167 | static VALUE sqlstate(VALUE obj) | |
168 | { | |
169 | MYSQL *m = GetHandler(obj); | |
170 | - return rb_tainted_str_new2(mysql_sqlstate(m)); | |
171 | + return rb_enc_tainted_str_new2(mysql_sqlstate(m)); | |
172 | } | |
173 | #endif | |
174 | ||
175 | @@ -1027,7 +1053,7 @@ static VALUE fetch_row(VALUE obj) | |
176 | return Qnil; | |
177 | ary = rb_ary_new2(n); | |
178 | for (i=0; i<n; i++) | |
179 | - rb_ary_store(ary, i, row[i]? rb_tainted_str_new(row[i], lengths[i]): Qnil); | |
180 | + rb_ary_store(ary, i, row[i]? rb_enc_tainted_str_new(row[i], lengths[i]): Qnil); | |
181 | return ary; | |
182 | } | |
183 | ||
184 | @@ -1051,7 +1077,7 @@ static VALUE fetch_hash2(VALUE obj, VALUE with_table) | |
185 | if (colname == Qnil) { | |
186 | colname = rb_ary_new2(n); | |
187 | for (i=0; i<n; i++) { | |
188 | - VALUE s = rb_tainted_str_new2(fields[i].name); | |
189 | + VALUE s = rb_enc_tainted_str_new2(fields[i].name); | |
190 | rb_obj_freeze(s); | |
191 | rb_ary_store(colname, i, s); | |
192 | } | |
193 | @@ -1064,7 +1090,7 @@ static VALUE fetch_hash2(VALUE obj, VALUE with_table) | |
194 | colname = rb_ary_new2(n); | |
195 | for (i=0; i<n; i++) { | |
196 | int len = strlen(fields[i].table)+strlen(fields[i].name)+1; | |
197 | - VALUE s = rb_tainted_str_new(NULL, len); | |
198 | + VALUE s = rb_enc_tainted_str_new(NULL, len); | |
199 | snprintf(RSTRING_PTR(s), len+1, "%s.%s", fields[i].table, fields[i].name); | |
200 | rb_obj_freeze(s); | |
201 | rb_ary_store(colname, i, s); | |
202 | @@ -1074,7 +1100,7 @@ static VALUE fetch_hash2(VALUE obj, VALUE with_table) | |
203 | } | |
204 | } | |
205 | for (i=0; i<n; i++) { | |
206 | - rb_hash_aset(hash, rb_ary_entry(colname, i), row[i]? rb_tainted_str_new(row[i], lengths[i]): Qnil); | |
207 | + rb_hash_aset(hash, rb_ary_entry(colname, i), row[i]? rb_enc_tainted_str_new(row[i], lengths[i]): Qnil); | |
208 | } | |
209 | return hash; | |
210 | } | |
211 | @@ -1196,7 +1222,7 @@ static VALUE field_hash(VALUE obj) | |
212 | static VALUE field_inspect(VALUE obj) | |
213 | { | |
214 | VALUE n = rb_iv_get(obj, "name"); | |
215 | - VALUE s = rb_str_new(0, RSTRING_LEN(n) + 16); | |
216 | + VALUE s = rb_enc_str_new(0, RSTRING_LEN(n) + 16, DEFAULT_ENCODING); | |
217 | sprintf(RSTRING_PTR(s), "#<Mysql::Field:%s>", RSTRING_PTR(n)); | |
218 | return s; | |
219 | } | |
220 | @@ -1255,7 +1281,7 @@ static void mysql_stmt_raise(MYSQL_STMT* s) | |
221 | { | |
222 | VALUE e = rb_exc_new2(eMysql, mysql_stmt_error(s)); | |
223 | rb_iv_set(e, "errno", INT2FIX(mysql_stmt_errno(s))); | |
224 | - rb_iv_set(e, "sqlstate", rb_tainted_str_new2(mysql_stmt_sqlstate(s))); | |
225 | + rb_iv_set(e, "sqlstate", rb_enc_tainted_str_new2(mysql_stmt_sqlstate(s))); | |
226 | rb_exc_raise(e); | |
227 | } | |
228 | ||
229 | @@ -1571,7 +1597,7 @@ static VALUE stmt_fetch(VALUE obj) | |
230 | case MYSQL_TYPE_NEWDECIMAL: | |
231 | case MYSQL_TYPE_BIT: | |
232 | #endif | |
233 | - v = rb_tainted_str_new(s->result.bind[i].buffer, s->result.length[i]); | |
234 | + v = rb_enc_tainted_str_new(s->result.bind[i].buffer, s->result.length[i]); | |
235 | break; | |
236 | default: | |
237 | rb_raise(rb_eTypeError, "unknown buffer_type: %d", s->result.bind[i].buffer_type); | |
238 | @@ -1760,7 +1786,7 @@ static VALUE stmt_send_long_data(VALUE obj, VALUE col, VALUE data) | |
239 | static VALUE stmt_sqlstate(VALUE obj) | |
240 | { | |
241 | struct mysql_stmt* s = DATA_PTR(obj); | |
242 | - return rb_tainted_str_new2(mysql_stmt_sqlstate(s->stmt)); | |
243 | + return rb_enc_tainted_str_new2(mysql_stmt_sqlstate(s->stmt)); | |
244 | } | |
245 | ||
246 | /*------------------------------- | |
247 | diff --git a/test.rb b/test.rb | |
248 | index 92151e0..f11939c 100644 | |
249 | --- a/test.rb | |
250 | +++ b/test.rb | |
251 | @@ -1196,7 +1196,9 @@ class TC_MysqlStmt2 < Test::Unit::TestCase | |
252 | @s.execute | |
253 | assert_equal([nil], @s.fetch) | |
254 | assert_equal([""], @s.fetch) | |
255 | - assert_equal(["abc"], @s.fetch) | |
256 | + row = @s.fetch | |
257 | + assert_equal(Encoding.default_external, row[0].encoding) if RUBY_VERSION =~ /1.9/ | |
258 | + assert_equal(["abc"], row) | |
259 | assert_equal(["def"], @s.fetch) | |
260 | assert_equal(["abc"], @s.fetch) | |
261 | assert_equal(["def"], @s.fetch) | |
262 | @@ -1233,6 +1235,7 @@ class TC_MysqlStmt2 < Test::Unit::TestCase | |
263 | case c | |
264 | when 0 | |
265 | assert_equal([1,"abc",Mysql::Time.new(1970,12,24,23,59,05)], a) | |
266 | + assert_equal(Encoding.default_external, a[1].encoding) if RUBY_VERSION =~ /1.9/ | |
267 | when 1 | |
268 | assert_equal([2,"def",Mysql::Time.new(2112,9,3,12,34,56)], a) | |
269 | when 2 |