Skip to content

Commit

Permalink
Merge pull request brianmario#673 from jeremy/statement-close
Browse files Browse the repository at this point in the history
Support prepared_statement.close
  • Loading branch information
sodabrew committed Sep 13, 2015
2 parents de7c375 + c43aa2b commit 9886c94
Show file tree
Hide file tree
Showing 3 changed files with 39 additions and 4 deletions.
3 changes: 1 addition & 2 deletions ext/mysql2/client.c
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
VALUE cMysql2Client;
extern VALUE mMysql2, cMysql2Error;
static VALUE sym_id, sym_version, sym_header_version, sym_async, sym_symbolize_keys, sym_as, sym_array, sym_stream;
static ID intern_brackets, intern_new, intern_merge, intern_merge_bang, intern_new_with_args;
static ID intern_brackets, intern_merge, intern_merge_bang, intern_new_with_args;

#ifndef HAVE_RB_HASH_DUP
VALUE rb_hash_dup(VALUE other) {
Expand Down Expand Up @@ -1293,7 +1293,6 @@ void init_mysql2_client() {
sym_stream = ID2SYM(rb_intern("stream"));

intern_brackets = rb_intern("[]");
intern_new = rb_intern("new");
intern_merge = rb_intern("merge");
intern_merge_bang = rb_intern("merge!");
intern_new_with_args = rb_intern("new_with_args");
Expand Down
27 changes: 25 additions & 2 deletions ext/mysql2/statement.c
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@ static VALUE intern_usec, intern_sec, intern_min, intern_hour, intern_day, inter

#define GET_STATEMENT(self) \
mysql_stmt_wrapper *stmt_wrapper; \
Data_Get_Struct(self, mysql_stmt_wrapper, stmt_wrapper);
Data_Get_Struct(self, mysql_stmt_wrapper, stmt_wrapper); \
if (!stmt_wrapper->stmt) { rb_raise(cMysql2Error, "Invalid statement handle"); }


static void rb_mysql_stmt_mark(void * ptr) {
Expand All @@ -17,6 +18,14 @@ static void rb_mysql_stmt_mark(void * ptr) {
rb_gc_mark(stmt_wrapper->client);
}

static void *nogvl_stmt_close(void *ptr) {
mysql_stmt_wrapper *stmt_wrapper = (mysql_stmt_wrapper *)ptr;
if (stmt_wrapper->stmt) {
mysql_stmt_close(stmt_wrapper->stmt);
stmt_wrapper->stmt = NULL;
}
}

static void rb_mysql_stmt_free(void * ptr) {
mysql_stmt_wrapper* stmt_wrapper = (mysql_stmt_wrapper *)ptr;
decr_mysql2_stmt(stmt_wrapper);
Expand All @@ -26,7 +35,7 @@ void decr_mysql2_stmt(mysql_stmt_wrapper *stmt_wrapper) {
stmt_wrapper->refcount--;

if (stmt_wrapper->refcount == 0) {
mysql_stmt_close(stmt_wrapper->stmt);
nogvl_stmt_close(stmt_wrapper);
xfree(stmt_wrapper);
}
}
Expand Down Expand Up @@ -442,6 +451,19 @@ static VALUE rb_mysql_stmt_affected_rows(VALUE self) {
return ULL2NUM(affected);
}

/* call-seq:
* stmt.close
*
* Explicitly closing this will free up server resources immediately rather
* than waiting for the garbage collector. Useful if you're managing your
* own prepared statement cache.
*/
static VALUE rb_mysql_stmt_close(VALUE self) {
GET_STATEMENT(self);
rb_thread_call_without_gvl(nogvl_stmt_close, stmt_wrapper, RUBY_UBF_IO, 0);
return Qnil;
}

void init_mysql2_statement() {
cMysql2Statement = rb_define_class_under(mMysql2, "Statement", rb_cObject);

Expand All @@ -451,6 +473,7 @@ void init_mysql2_statement() {
rb_define_method(cMysql2Statement, "fields", fields, 0);
rb_define_method(cMysql2Statement, "last_id", rb_mysql_stmt_last_id, 0);
rb_define_method(cMysql2Statement, "affected_rows", rb_mysql_stmt_affected_rows, 0);
rb_define_method(cMysql2Statement, "close", rb_mysql_stmt_close, 0);

sym_stream = ID2SYM(rb_intern("stream"));

Expand Down
13 changes: 13 additions & 0 deletions spec/mysql2/statement_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -664,4 +664,17 @@
expect(stmt.affected_rows).to eq 1
end
end

context 'close' do
it 'should free server resources' do
stmt = @client.prepare 'SELECT 1'
expect(stmt.close).to eq nil
end

it 'should raise an error on subsequent execution' do
stmt = @client.prepare 'SELECT 1'
stmt.close
expect { stmt.execute }.to raise_error(Mysql2::Error, /Invalid statement handle/)
end
end
end

0 comments on commit 9886c94

Please sign in to comment.