From 3c67c7be1eb133bf220eaf8ed871a9580f78d8c8 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 | 7 +++++++ ext/sqlite3/statement.c | 2 +- test/test_database.rb | 18 ++++++++++++++++++ 3 files changed, 26 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 400a7855..7eb5ba7e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,12 @@ # sqlite3-ruby Changelog +## next / unreleased + +### Fixed + +- 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 This is a major release which contains some breaking changes, primarily the removal of 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 )")