@@ -789,46 +789,68 @@ static void rb_mysql_row_query_options(VALUE opts, ID *db_timezone, ID *app_time
789
789
}
790
790
}
791
791
792
- static VALUE rb_mysql_result_element (VALUE self , VALUE seek ) {
792
+ static VALUE rb_mysql_result_element (int argc , VALUE * argv , VALUE self ) {
793
793
result_each_args args ;
794
794
MYSQL_FIELD * fields = NULL ;
795
- long offset ;
796
795
ID db_timezone , app_timezone ;
796
+ VALUE seek , count , row , rows ;
797
+ long i , c_seek , c_count = 0 ;
797
798
int symbolizeKeys , asArray , castBool , cacheRows , cast ;
798
- VALUE opts , (* fetch_row_func )(VALUE , MYSQL_FIELD * fields , const result_each_args * args );
799
+ VALUE defaults , block , opts , (* fetch_row_func )(VALUE , MYSQL_FIELD * fields , const result_each_args * args );
799
800
800
801
GET_RESULT (self );
801
802
802
- offset = NUM2LONG (seek );
803
+ defaults = rb_iv_get (self , "@query_options" );
804
+ Check_Type (defaults , T_HASH );
805
+ rb_scan_args (argc , argv , "12&" , & seek , & count , & opts , & block );
803
806
804
- if (!wrapper -> numberOfRows ) {
805
- wrapper -> numberOfRows = mysql_num_rows (wrapper -> result );
807
+ /* If the second arg is a hash, it's the opts and there's no count */
808
+ if (TYPE (count ) == T_HASH ) {
809
+ opts = count ;
810
+ count = Qnil ;
811
+ }
812
+
813
+ c_seek = NUM2LONG (seek );
814
+ if (!NIL_P (count )) {
815
+ c_count = NUM2LONG (count );
816
+ /* Special case: ary[x, 0] returns []*/
817
+ if (!c_count ) return rb_ary_new ();
818
+ }
819
+
820
+ if (!NIL_P (opts )) {
821
+ opts = rb_funcall (defaults , intern_merge , 1 , opts );
822
+ } else {
823
+ opts = defaults ;
806
824
}
807
825
808
- opts = rb_iv_get (self , "@query_options" );
809
826
rb_mysql_row_query_options (opts , & db_timezone , & app_timezone , & symbolizeKeys , & asArray , & castBool , & cast , & cacheRows );
810
827
811
828
if (wrapper -> is_streaming ) {
812
829
rb_raise (cMysql2Error , "Element reference operator #[] cannot be used in streaming mode." );
813
830
}
814
831
832
+ if (!wrapper -> numberOfRows ) {
833
+ wrapper -> numberOfRows = mysql_num_rows (wrapper -> result );
834
+ }
835
+
815
836
/* count back from the end if passed a negative number */
816
- if (offset < 0 ) {
817
- offset = wrapper -> numberOfRows + offset ;
837
+ if (c_seek < 0 ) {
838
+ c_seek = wrapper -> numberOfRows + c_seek ;
818
839
}
819
840
820
841
/* negative offset was too big */
821
- if (offset < 0 ) {
842
+ if (c_seek < 0 ) {
822
843
return Qnil ;
823
- /* rb_raise(cMysql2Error, "Out of range: offset %ld is beyond %lu rows (offset begins at 0).", offset , wrapper->numberOfRows); */
844
+ /* rb_raise(cMysql2Error, "Out of range: offset %ld is beyond %lu rows (offset begins at 0).", c_seek , wrapper->numberOfRows); */
824
845
}
825
846
826
- if (wrapper -> numberOfRows <= (unsigned long )offset ) {
827
- return Qnil ;
828
- /* rb_raise(cMysql2Error, "Out of range: offset %ld is beyond %lu rows (offset begins at 0).", offset, wrapper->numberOfRows); */
847
+ if (wrapper -> numberOfRows <= (unsigned long )c_seek ) {
848
+ if (!c_count ) return Qnil ;
849
+ else return rb_ary_new ();
850
+ /* rb_raise(cMysql2Error, "Out of range: offset %ld is beyond %lu rows (offset begins at 0).", c_seek, wrapper->numberOfRows); */
829
851
}
830
852
831
- mysql_data_seek (wrapper -> result , offset );
853
+ mysql_data_seek (wrapper -> result , c_seek );
832
854
833
855
// Backward compat
834
856
args .symbolizeKeys = symbolizeKeys ;
@@ -838,15 +860,30 @@ static VALUE rb_mysql_result_element(VALUE self, VALUE seek) {
838
860
args .cast = cast ;
839
861
args .db_timezone = db_timezone ;
840
862
args .app_timezone = app_timezone ;
841
- args .block_given = Qnil ;
863
+ args .block_given = block ;
842
864
843
865
if (wrapper -> stmt ) {
844
866
fetch_row_func = rb_mysql_result_fetch_row_stmt ;
845
867
} else {
846
868
fetch_row_func = rb_mysql_result_fetch_row ;
847
869
}
848
870
849
- return fetch_row_func (self , fields , & args );
871
+ if (!c_count ) {
872
+ return fetch_row_func (self , fields , & args );
873
+ }
874
+
875
+ /* given ary = [1, 2, 3] then ary[1, 100] returns [2, 3] */
876
+ if ((unsigned long )(c_seek + c_count ) > wrapper -> numberOfRows ) {
877
+ c_count = wrapper -> numberOfRows - c_seek ;
878
+ }
879
+
880
+ /* return an array! */
881
+ rows = rb_ary_new2 (c_count );
882
+ for (i = 0 ; i < c_count ; i ++ ) {
883
+ row = fetch_row_func (self , fields , & args );
884
+ rb_ary_store (rows , i , row );
885
+ }
886
+ return rows ;
850
887
}
851
888
852
889
static VALUE rb_mysql_result_each_ (VALUE self ,
@@ -1042,7 +1079,7 @@ void init_mysql2_result() {
1042
1079
cDateTime = rb_const_get (rb_cObject , rb_intern ("DateTime" ));
1043
1080
1044
1081
cMysql2Result = rb_define_class_under (mMysql2 , "Result" , rb_cObject );
1045
- rb_define_method (cMysql2Result , "[]" , rb_mysql_result_element , 1 );
1082
+ rb_define_method (cMysql2Result , "[]" , rb_mysql_result_element , - 1 );
1046
1083
rb_define_method (cMysql2Result , "each" , rb_mysql_result_each , -1 );
1047
1084
rb_define_method (cMysql2Result , "fields" , rb_mysql_result_fetch_fields , 0 );
1048
1085
rb_define_method (cMysql2Result , "count" , rb_mysql_result_count , 0 );
0 commit comments