Skip to content

Commit

Permalink
Feature request brianmario#130: add element reference operator #[] to…
Browse files Browse the repository at this point in the history
… Mysql2::Result using mysql_data_seek.
  • Loading branch information
sodabrew committed Jul 16, 2013
1 parent 2eb4a8f commit 0ed17f8
Show file tree
Hide file tree
Showing 2 changed files with 77 additions and 0 deletions.
46 changes: 46 additions & 0 deletions ext/mysql2/result.c
Expand Up @@ -470,6 +470,51 @@ static void rb_mysql_row_query_options(VALUE opts, ID *db_timezone, ID *app_time
}
}

static VALUE rb_mysql_result_element(VALUE self, VALUE seek) {
VALUE row, opts;
ID db_timezone, app_timezone;
long offset;
int symbolizeKeys = 0, asArray = 0, castBool = 0, cacheRows = 1, cast = 1, streaming = 0;
mysql2_result_wrapper * wrapper;

GetMysql2Result(self, wrapper);

offset = NUM2LONG(seek);

if (!wrapper->numberOfRows) {
wrapper->numberOfRows = mysql_num_rows(wrapper->result);
}

opts = rb_iv_get(self, "@query_options");
rb_mysql_row_query_options(opts, &db_timezone, &app_timezone, &symbolizeKeys, &asArray, &castBool, &cast, &streaming, &cacheRows);

if (streaming) {
rb_raise(cMysql2Error, "Element reference operator #[] cannot be used in streaming mode.");
}

/* count back from the end if passed a negative number */
if (offset < 0) {
offset = wrapper->numberOfRows + offset;
}

/* negative offset was too big */
if (offset < 0) {
return Qnil;
/* rb_raise(cMysql2Error, "Out of range: offset %ld is beyond %lu rows (offset begins at 0).", offset, wrapper->numberOfRows); */
}

if (wrapper->numberOfRows <= (unsigned long)offset) {
return Qnil;
/* rb_raise(cMysql2Error, "Out of range: offset %ld is beyond %lu rows (offset begins at 0).", offset, wrapper->numberOfRows); */
}

mysql_data_seek(wrapper->result, offset);

row = rb_mysql_result_fetch_row(self, db_timezone, app_timezone, symbolizeKeys, asArray, castBool, cast);

return row;
}

static VALUE rb_mysql_result_each(int argc, VALUE * argv, VALUE self) {
VALUE defaults, opts, block;
ID db_timezone, app_timezone;
Expand Down Expand Up @@ -613,6 +658,7 @@ void init_mysql2_result() {
cDateTime = rb_const_get(rb_cObject, rb_intern("DateTime"));

cMysql2Result = rb_define_class_under(mMysql2, "Result", rb_cObject);
rb_define_method(cMysql2Result, "[]", rb_mysql_result_element, 1);
rb_define_method(cMysql2Result, "each", rb_mysql_result_each, -1);
rb_define_method(cMysql2Result, "fields", rb_mysql_result_fetch_fields, 0);
rb_define_method(cMysql2Result, "count", rb_mysql_result_count, 0);
Expand Down
31 changes: 31 additions & 0 deletions spec/mysql2/result_spec.rb
Expand Up @@ -123,6 +123,37 @@
end
end

context "#[]" do
it "should return results when accessed by [offset]" do
result = @client.query "SELECT 1 UNION SELECT 2"
result[1][result.fields.first].should eql(2)
result[0][result.fields.first].should eql(1)
end

it "should return results when accessed by negative [offset]" do
result = @client.query "SELECT 1 UNION SELECT 2"
result[-1][result.fields.first].should eql(2)
result[-2][result.fields.first].should eql(1)
end

it "should return nil if we use too large [offset]" do
result = @client.query "SELECT 1 UNION SELECT 2"
result[2].should be_nil
result[200].should be_nil
end

it "should return nil if we use too negative [offset]" do
result = @client.query "SELECT 1 UNION SELECT 2"
result[-3].should be_nil
result[-300].should be_nil
end

it "should throw an exception if we use an [offset] in streaming mode" do
result = @client.query "SELECT 1 UNION SELECT 2", :stream => true
expect { result[0] }.to raise_exception(Mysql2::Error)
end
end

context "#fields" do
before(:each) do
@client.query "USE test"
Expand Down

0 comments on commit 0ed17f8

Please sign in to comment.