Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Intern column names so we always get the same string #486

Merged
merged 2 commits into from
Jan 27, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
4 changes: 4 additions & 0 deletions ext/sqlite3/extconf.rb
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,10 @@ def configure_extension

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

# Truffle Ruby doesn't support this yet:
# https://github.com/oracle/truffleruby/issues/3408
have_func("rb_enc_interned_str_cstr")

# Functions defined in 1.9 but not 1.8
have_func("rb_proc_arity")

Expand Down
18 changes: 16 additions & 2 deletions ext/sqlite3/statement.c
Original file line number Diff line number Diff line change
Expand Up @@ -364,6 +364,21 @@ column_count(VALUE self)
return INT2NUM(sqlite3_column_count(ctx->st));
}

#if HAVE_RB_ENC_INTERNED_STR_CSTR
static VALUE
interned_utf8_cstr(const char *str)
{
return rb_enc_interned_str_cstr(str, rb_utf8_encoding());
}
#else
static VALUE
interned_utf8_cstr(const char *str)
{
VALUE rb_str = rb_utf8_str_new_cstr(str);
return rb_funcall(rb_str, rb_intern("-@"), 0);
}
#endif

/* call-seq: stmt.column_name(index)
*
* Get the column name at +index+. 0 based.
Expand All @@ -382,8 +397,7 @@ column_name(VALUE self, VALUE index)
VALUE ret = Qnil;

if (name) {
ret = SQLITE3_UTF8_STR_NEW2(name);
rb_obj_freeze(ret);
ret = interned_utf8_cstr(name);
}
return ret;
}
Expand Down
17 changes: 17 additions & 0 deletions test/test_statement.rb
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,23 @@ def test_raises_type_error
end
end

def test_column_names_are_deduped
@db.execute "CREATE TABLE 'things' ('float' float, 'int' int, 'text' blob, 'string' string, 'nil' string)"
stmt = @db.prepare "SELECT float, int, text, string, nil FROM things"
assert_equal ["float", "int", "text", "string", "nil"], stmt.columns
columns = stmt.columns
stmt.close

stmt = @db.prepare "SELECT float, int, text, string, nil FROM things"
# Make sure this new statement returns the same interned strings
stmt.columns.each_with_index do |str, i|
assert_predicate columns[i], :frozen?
assert_same columns[i], str
end
ensure
stmt&.close
end

def test_insert_duplicate_records
@db.execute 'CREATE TABLE "things" ("name" varchar(20) CONSTRAINT "index_things_on_name" UNIQUE)'
stmt = @db.prepare("INSERT INTO things(name) VALUES(?)")
Expand Down