Skip to content

Commit ea0cb80

Browse files
authored
Merge pull request #486 from sparklemotion/intern-column-names
Intern column names so we always get the same string
2 parents 85bd68d + 62c24b6 commit ea0cb80

File tree

3 files changed

+37
-2
lines changed

3 files changed

+37
-2
lines changed

ext/sqlite3/extconf.rb

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,10 @@ def configure_extension
109109

110110
abort_could_not_find(libname) unless find_library(libname, "sqlite3_libversion_number", "sqlite3.h")
111111

112+
# Truffle Ruby doesn't support this yet:
113+
# https://github.com/oracle/truffleruby/issues/3408
114+
have_func("rb_enc_interned_str_cstr")
115+
112116
# Functions defined in 1.9 but not 1.8
113117
have_func("rb_proc_arity")
114118

ext/sqlite3/statement.c

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -364,6 +364,21 @@ column_count(VALUE self)
364364
return INT2NUM(sqlite3_column_count(ctx->st));
365365
}
366366

367+
#if HAVE_RB_ENC_INTERNED_STR_CSTR
368+
static VALUE
369+
interned_utf8_cstr(const char *str)
370+
{
371+
return rb_enc_interned_str_cstr(str, rb_utf8_encoding());
372+
}
373+
#else
374+
static VALUE
375+
interned_utf8_cstr(const char *str)
376+
{
377+
VALUE rb_str = rb_utf8_str_new_cstr(str);
378+
return rb_funcall(rb_str, rb_intern("-@"), 0);
379+
}
380+
#endif
381+
367382
/* call-seq: stmt.column_name(index)
368383
*
369384
* Get the column name at +index+. 0 based.
@@ -382,8 +397,7 @@ column_name(VALUE self, VALUE index)
382397
VALUE ret = Qnil;
383398

384399
if (name) {
385-
ret = SQLITE3_UTF8_STR_NEW2(name);
386-
rb_obj_freeze(ret);
400+
ret = interned_utf8_cstr(name);
387401
}
388402
return ret;
389403
}

test/test_statement.rb

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,23 @@ def test_raises_type_error
4848
end
4949
end
5050

51+
def test_column_names_are_deduped
52+
@db.execute "CREATE TABLE 'things' ('float' float, 'int' int, 'text' blob, 'string' string, 'nil' string)"
53+
stmt = @db.prepare "SELECT float, int, text, string, nil FROM things"
54+
assert_equal ["float", "int", "text", "string", "nil"], stmt.columns
55+
columns = stmt.columns
56+
stmt.close
57+
58+
stmt = @db.prepare "SELECT float, int, text, string, nil FROM things"
59+
# Make sure this new statement returns the same interned strings
60+
stmt.columns.each_with_index do |str, i|
61+
assert_predicate columns[i], :frozen?
62+
assert_same columns[i], str
63+
end
64+
ensure
65+
stmt&.close
66+
end
67+
5168
def test_insert_duplicate_records
5269
@db.execute 'CREATE TABLE "things" ("name" varchar(20) CONSTRAINT "index_things_on_name" UNIQUE)'
5370
stmt = @db.prepare("INSERT INTO things(name) VALUES(?)")

0 commit comments

Comments
 (0)