Skip to content

Commit 34a958f

Browse files
committed
Feature request #130: add element reference operator #[] to Mysql2::Result using mysql_data_seek.
1 parent cef4bf9 commit 34a958f

File tree

2 files changed

+77
-0
lines changed

2 files changed

+77
-0
lines changed

ext/mysql2/result.c

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -475,6 +475,51 @@ static void rb_mysql_row_query_options(VALUE opts, ID *db_timezone, ID *app_time
475475
}
476476
}
477477

478+
static VALUE rb_mysql_result_element(VALUE self, VALUE seek) {
479+
VALUE row, opts;
480+
ID db_timezone, app_timezone;
481+
long offset;
482+
int symbolizeKeys, asArray, castBool, cacheRows, cast;
483+
mysql2_result_wrapper * wrapper;
484+
485+
GetMysql2Result(self, wrapper);
486+
487+
offset = NUM2LONG(seek);
488+
489+
if (!wrapper->numberOfRows) {
490+
wrapper->numberOfRows = mysql_num_rows(wrapper->result);
491+
}
492+
493+
opts = rb_iv_get(self, "@query_options");
494+
rb_mysql_row_query_options(opts, &db_timezone, &app_timezone, &symbolizeKeys, &asArray, &castBool, &cast, &cacheRows);
495+
496+
if (wrapper->is_streaming) {
497+
rb_raise(cMysql2Error, "Element reference operator #[] cannot be used in streaming mode.");
498+
}
499+
500+
/* count back from the end if passed a negative number */
501+
if (offset < 0) {
502+
offset = wrapper->numberOfRows + offset;
503+
}
504+
505+
/* negative offset was too big */
506+
if (offset < 0) {
507+
return Qnil;
508+
/* rb_raise(cMysql2Error, "Out of range: offset %ld is beyond %lu rows (offset begins at 0).", offset, wrapper->numberOfRows); */
509+
}
510+
511+
if (wrapper->numberOfRows <= (unsigned long)offset) {
512+
return Qnil;
513+
/* rb_raise(cMysql2Error, "Out of range: offset %ld is beyond %lu rows (offset begins at 0).", offset, wrapper->numberOfRows); */
514+
}
515+
516+
mysql_data_seek(wrapper->result, offset);
517+
518+
row = rb_mysql_result_fetch_row(self, db_timezone, app_timezone, symbolizeKeys, asArray, castBool, cast);
519+
520+
return row;
521+
}
522+
478523
static VALUE rb_mysql_result_each(int argc, VALUE * argv, VALUE self) {
479524
VALUE defaults, opts, block;
480525
ID db_timezone, app_timezone;
@@ -634,6 +679,7 @@ void init_mysql2_result() {
634679
cDateTime = rb_const_get(rb_cObject, rb_intern("DateTime"));
635680

636681
cMysql2Result = rb_define_class_under(mMysql2, "Result", rb_cObject);
682+
rb_define_method(cMysql2Result, "[]", rb_mysql_result_element, 1);
637683
rb_define_method(cMysql2Result, "each", rb_mysql_result_each, -1);
638684
rb_define_method(cMysql2Result, "fields", rb_mysql_result_fetch_fields, 0);
639685
rb_define_method(cMysql2Result, "count", rb_mysql_result_count, 0);

spec/mysql2/result_spec.rb

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,37 @@
9090
end
9191
end
9292

93+
context "#[]" do
94+
it "should return results when accessed by [offset]" do
95+
result = @client.query "SELECT 1 UNION SELECT 2"
96+
result[1][result.fields.first].should eql(2)
97+
result[0][result.fields.first].should eql(1)
98+
end
99+
100+
it "should return results when accessed by negative [offset]" do
101+
result = @client.query "SELECT 1 UNION SELECT 2"
102+
result[-1][result.fields.first].should eql(2)
103+
result[-2][result.fields.first].should eql(1)
104+
end
105+
106+
it "should return nil if we use too large [offset]" do
107+
result = @client.query "SELECT 1 UNION SELECT 2"
108+
result[2].should be_nil
109+
result[200].should be_nil
110+
end
111+
112+
it "should return nil if we use too negative [offset]" do
113+
result = @client.query "SELECT 1 UNION SELECT 2"
114+
result[-3].should be_nil
115+
result[-300].should be_nil
116+
end
117+
118+
it "should throw an exception if we use an [offset] in streaming mode" do
119+
result = @client.query "SELECT 1 UNION SELECT 2", :stream => true
120+
expect { result[0] }.to raise_exception(Mysql2::Error)
121+
end
122+
end
123+
93124
context "#fields" do
94125
before(:each) do
95126
@test_result = @client.query("SELECT * FROM mysql2_test ORDER BY id DESC LIMIT 1")

0 commit comments

Comments
 (0)