Skip to content

Commit be3a0bb

Browse files
committed
Fix encoding for values passed to custom functions
Fixes: 218
1 parent 44ab2aa commit be3a0bb

File tree

2 files changed

+44
-12
lines changed

2 files changed

+44
-12
lines changed

ext/sqlite3/database.c

Lines changed: 14 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -277,32 +277,34 @@ last_insert_row_id(VALUE self)
277277
VALUE
278278
sqlite3val2rb(sqlite3_value *val)
279279
{
280+
VALUE rb_val;
281+
280282
switch (sqlite3_value_type(val)) {
281283
case SQLITE_INTEGER:
282-
return LL2NUM(sqlite3_value_int64(val));
284+
rb_val = LL2NUM(sqlite3_value_int64(val));
283285
break;
284286
case SQLITE_FLOAT:
285-
return rb_float_new(sqlite3_value_double(val));
287+
rb_val = rb_float_new(sqlite3_value_double(val));
286288
break;
287-
case SQLITE_TEXT:
288-
return rb_str_new2((const char *)sqlite3_value_text(val));
289+
case SQLITE_TEXT: {
290+
rb_val = rb_utf8_str_new_cstr((const char *)sqlite3_value_text(val));
291+
rb_obj_freeze(rb_val);
289292
break;
293+
}
290294
case SQLITE_BLOB: {
291-
/* Sqlite warns calling sqlite3_value_bytes may invalidate pointer from sqlite3_value_blob,
292-
so we explicitly get the length before getting blob pointer.
293-
Note that rb_str_new apparently create string with ASCII-8BIT (BINARY) encoding,
294-
which is what we want, as blobs are binary
295-
*/
296295
int len = sqlite3_value_bytes(val);
297-
return rb_str_new((const char *)sqlite3_value_blob(val), len);
296+
rb_val = rb_str_new((const char *)sqlite3_value_blob(val), len);
297+
rb_obj_freeze(rb_val);
298298
break;
299299
}
300300
case SQLITE_NULL:
301-
return Qnil;
301+
rb_val = Qnil;
302302
break;
303303
default:
304-
rb_raise(rb_eRuntimeError, "bad type"); /* FIXME */
304+
rb_raise(rb_eRuntimeError, "bad type");
305305
}
306+
307+
return rb_val;
306308
}
307309

308310
void

test/test_database.rb

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,36 @@ def teardown
1515
@db.close unless @db.closed?
1616
end
1717

18+
def test_custom_function_encoding
19+
@db.execute("CREATE TABLE
20+
sourceTable(
21+
sourceData TEXT);")
22+
@db.execute("INSERT INTO sourceTable
23+
VALUES ('abcde');")
24+
25+
@db.create_function("GetCopy", 1) { |func, value|
26+
func.result = value
27+
}
28+
29+
@db.transaction { |t|
30+
t.execute("CREATE TABLE
31+
afterTable(
32+
beforeData TEXT,
33+
afterData TEXT);".squeeze(" "))
34+
35+
t.execute("INSERT INTO afterTable
36+
SELECT
37+
sourceData,
38+
GetCopy(sourceData)
39+
FROM sourceTable;")
40+
}
41+
42+
assert_equal(1, @db.get_first_value("SELECT 1
43+
FROM afterTable
44+
WHERE beforeData = afterData
45+
LIMIT 1;"))
46+
end
47+
1848
def test_segv
1949
assert_raises { SQLite3::Database.new 1 } # rubocop:disable Minitest/UnspecifiedException
2050
end

0 commit comments

Comments
 (0)