Skip to content

Commit f9005a2

Browse files
committed
fix wrongly tagged encoding when inserting and selecting UTF16LE encoded values
1 parent 6e1bd33 commit f9005a2

File tree

3 files changed

+51
-7
lines changed

3 files changed

+51
-7
lines changed

ext/sqlite3/sqlite3_ruby.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
#ifdef HAVE_RUBY_ENCODING_H
2020
#include <ruby/encoding.h>
2121

22+
#define USASCII_P(_obj) (rb_enc_get_index(_obj) == rb_usascii_encindex())
2223
#define UTF8_P(_obj) (rb_enc_get_index(_obj) == rb_utf8_encindex())
2324
#define UTF16_LE_P(_obj) (rb_enc_get_index(_obj) == rb_enc_find_index("UTF-16LE"))
2425
#define UTF16_BE_P(_obj) (rb_enc_get_index(_obj) == rb_enc_find_index("UTF-16BE"))

ext/sqlite3/statement.c

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -156,7 +156,7 @@ static VALUE step(VALUE self)
156156
(long)sqlite3_column_bytes(stmt, i)
157157
);
158158
#ifdef HAVE_RUBY_ENCODING_H
159-
rb_enc_associate_index(str, enc_index);
159+
rb_enc_associate_index(str, rb_utf8_encindex());
160160
if(internal_encoding)
161161
str = rb_str_export_to_enc(str, internal_encoding);
162162
#endif
@@ -238,22 +238,32 @@ static VALUE bind_param(VALUE self, VALUE key, VALUE value)
238238
SQLITE_TRANSIENT
239239
);
240240
} else {
241+
242+
241243
#ifdef HAVE_RUBY_ENCODING_H
242-
if(!UTF8_P(value)) {
243-
VALUE db = rb_iv_get(self, "@connection");
244-
VALUE encoding = rb_funcall(db, rb_intern("encoding"), 0);
245-
rb_encoding * enc = rb_to_encoding(encoding);
246-
value = rb_str_export_to_enc(value, enc);
244+
if (UTF16_LE_P(value)) {
245+
status = sqlite3_bind_text16(
246+
ctx->st,
247+
index,
248+
(const char *)StringValuePtr(value),
249+
(int)RSTRING_LEN(value),
250+
SQLITE_TRANSIENT
251+
);
252+
} else {
253+
if (!UTF8_P(value) || !USASCII_P(value)) {
254+
value = rb_str_encode(value, rb_enc_from_encoding(rb_utf8_encoding()), 0, Qnil);
247255
}
248256
#endif
249-
250257
status = sqlite3_bind_text(
251258
ctx->st,
252259
index,
253260
(const char *)StringValuePtr(value),
254261
(int)RSTRING_LEN(value),
255262
SQLITE_TRANSIENT
256263
);
264+
#ifdef HAVE_RUBY_ENCODING_H
265+
}
266+
#endif
257267
}
258268
break;
259269
case T_BIGNUM:

test/test_encoding.rb

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,39 @@ def setup
1111
@db.execute(@create);
1212
end
1313

14+
def test_select_encoding_on_utf_16
15+
str = "foo"
16+
db = SQLite3::Database.new(':memory:'.encode('UTF-16LE'))
17+
db.execute @create
18+
db.execute "insert into ex (id, data) values (1, \"#{str}\")"
19+
20+
stmt = db.prepare 'select * from ex where data = ?'
21+
['US-ASCII', 'UTF-16LE', 'EUC-JP', 'UTF-8'].each do |enc|
22+
stmt.bind_param 1, str.encode(enc)
23+
assert_equal 1, stmt.to_a.length
24+
stmt.reset!
25+
end
26+
end
27+
28+
def test_insert_encoding
29+
str = "foo"
30+
db = SQLite3::Database.new(':memory:'.encode('UTF-16LE'))
31+
db.execute @create
32+
stmt = db.prepare @insert
33+
34+
['US-ASCII', 'UTF-16LE', 'UTF-16BE', 'EUC-JP', 'UTF-8'].each_with_index do |enc,i|
35+
str2 = str.encode(enc)
36+
stmt.bind_param 1, i
37+
stmt.bind_param 2, str.encode(enc)
38+
stmt.to_a
39+
stmt.reset!
40+
end
41+
42+
db.execute('select data from ex').flatten.each do |s|
43+
assert_equal str, s
44+
end
45+
end
46+
1447
def test_default_internal_is_honored
1548
warn_before = $-w
1649
$-w = false

0 commit comments

Comments
 (0)