From f4c326e24a53e2739ee18d077035ef488d02dfcc Mon Sep 17 00:00:00 2001 From: Mike Dalessio Date: Fri, 19 Apr 2024 16:05:51 -0400 Subject: [PATCH] fix: Database#execute_batch properly handles non-ASCII strings Fix a regression in v2.0.0 that caused `Database#execute_batch` to raise an encoding exception when passed some non-ASCII strings. As a result of this fix, `Database#prepare` now ensures the "remainder" string will always be encoded as UTF-8. Closes #524 --- CHANGELOG.md | 1 + ext/sqlite3/statement.c | 2 +- test/test_database.rb | 18 ++++++++++++++++++ 3 files changed, 20 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e6219586..3897d1c9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,7 @@ ### Fixed - Raise an exception if `Database#execute`, `#execute_batch`, or `#query` are passed multiple bind parameters that are not in an Array. In v2.0.0 these methods would silently swallow additional arguments. [#527] @flavorjones +- Fixed a regression in v2.0.0 that caused `Database#execute_batch` to raise an encoding exception when passed some non-ascii strings. As a result of this fix, `Database#prepare` now ensures the "remainder" string will always be encoded as UTF-8. [#524] @flavorjones ## 2.0.0 / 2024-04-17 diff --git a/ext/sqlite3/statement.c b/ext/sqlite3/statement.c index 29bb2779..cb65efb7 100644 --- a/ext/sqlite3/statement.c +++ b/ext/sqlite3/statement.c @@ -72,7 +72,7 @@ prepare(VALUE self, VALUE db, VALUE sql) CHECK(db_ctx->db, status); timespecclear(&db_ctx->stmt_deadline); - return rb_str_new2(tail); + return rb_utf8_str_new_cstr(tail); } /* call-seq: stmt.close diff --git a/test/test_database.rb b/test/test_database.rb index 363286e7..6662eab9 100644 --- a/test/test_database.rb +++ b/test/test_database.rb @@ -326,6 +326,24 @@ def test_block_prepare_does_not_double_close assert_equal :foo, r end + def test_prepare_batch_split + db = SQLite3::Database.new(":memory:") + s1 = db.prepare("select 'asdf'; select 'qwer'; select 'côté'") + + assert_equal " select 'qwer'; select 'côté'", s1.remainder + assert_equal Encoding::UTF_8, s1.remainder.encoding + + s2 = db.prepare(s1.remainder) + + assert_equal " select 'côté'", s2.remainder + assert_equal Encoding::UTF_8, s2.remainder.encoding + + s3 = db.prepare(s2.remainder) + + assert_equal "", s3.remainder + assert_equal Encoding::UTF_8, s3.remainder.encoding + end + def test_total_changes db = SQLite3::Database.new(":memory:") db.execute("create table foo ( a integer primary key, b text )")