@@ -789,46 +789,68 @@ static void rb_mysql_row_query_options(VALUE opts, ID *db_timezone, ID *app_time
789789 }
790790}
791791
792- static VALUE rb_mysql_result_element (VALUE self , VALUE seek ) {
792+ static VALUE rb_mysql_result_element (int argc , VALUE * argv , VALUE self ) {
793793 result_each_args args ;
794794 MYSQL_FIELD * fields = NULL ;
795- long offset ;
796795 ID db_timezone , app_timezone ;
796+ VALUE seek , count , row , rows ;
797+ long i , c_seek , c_count = 0 ;
797798 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 );
799800
800801 GET_RESULT (self );
801802
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 );
803806
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 ;
806824 }
807825
808- opts = rb_iv_get (self , "@query_options" );
809826 rb_mysql_row_query_options (opts , & db_timezone , & app_timezone , & symbolizeKeys , & asArray , & castBool , & cast , & cacheRows );
810827
811828 if (wrapper -> is_streaming ) {
812829 rb_raise (cMysql2Error , "Element reference operator #[] cannot be used in streaming mode." );
813830 }
814831
832+ if (!wrapper -> numberOfRows ) {
833+ wrapper -> numberOfRows = mysql_num_rows (wrapper -> result );
834+ }
835+
815836 /* 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 ;
818839 }
819840
820841 /* negative offset was too big */
821- if (offset < 0 ) {
842+ if (c_seek < 0 ) {
822843 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); */
824845 }
825846
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); */
829851 }
830852
831- mysql_data_seek (wrapper -> result , offset );
853+ mysql_data_seek (wrapper -> result , c_seek );
832854
833855 // Backward compat
834856 args .symbolizeKeys = symbolizeKeys ;
@@ -838,15 +860,30 @@ static VALUE rb_mysql_result_element(VALUE self, VALUE seek) {
838860 args .cast = cast ;
839861 args .db_timezone = db_timezone ;
840862 args .app_timezone = app_timezone ;
841- args .block_given = Qnil ;
863+ args .block_given = block ;
842864
843865 if (wrapper -> stmt ) {
844866 fetch_row_func = rb_mysql_result_fetch_row_stmt ;
845867 } else {
846868 fetch_row_func = rb_mysql_result_fetch_row ;
847869 }
848870
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 ;
850887}
851888
852889static VALUE rb_mysql_result_each_ (VALUE self ,
@@ -1042,7 +1079,7 @@ void init_mysql2_result() {
10421079 cDateTime = rb_const_get (rb_cObject , rb_intern ("DateTime" ));
10431080
10441081 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 );
10461083 rb_define_method (cMysql2Result , "each" , rb_mysql_result_each , -1 );
10471084 rb_define_method (cMysql2Result , "fields" , rb_mysql_result_fetch_fields , 0 );
10481085 rb_define_method (cMysql2Result , "count" , rb_mysql_result_count , 0 );
0 commit comments