@@ -470,49 +470,81 @@ static void rb_mysql_row_query_options(VALUE opts, ID *db_timezone, ID *app_time
470470 }
471471}
472472
473- static VALUE rb_mysql_result_element (VALUE self , VALUE seek ) {
474- VALUE row , opts ;
473+ static VALUE rb_mysql_result_element (int argc , VALUE * argv , VALUE self ) {
474+ VALUE seek , count , defaults , opts ;
475+ VALUE row , rows ;
475476 ID db_timezone , app_timezone ;
476- long offset ;
477+ long i , c_seek , c_count = 0 ;
477478 int symbolizeKeys = 0 , asArray = 0 , castBool = 0 , cacheRows = 1 , cast = 1 , streaming = 0 ;
478479 mysql2_result_wrapper * wrapper ;
479480
480481 GetMysql2Result (self , wrapper );
481482
482- offset = NUM2LONG (seek );
483+ rb_scan_args (argc , argv , "12" , & seek , & count , & opts );
484+ /* If the second arg is a hash, it's the opts and there's no count */
485+ if (TYPE (count ) == T_HASH ) {
486+ opts = count ;
487+ count = Qnil ;
488+ }
483489
484- if (!wrapper -> numberOfRows ) {
485- wrapper -> numberOfRows = mysql_num_rows (wrapper -> result );
490+ c_seek = NUM2LONG (seek );
491+ if (!NIL_P (count )) {
492+ c_count = NUM2LONG (count );
493+ /* Special case: ary[x, 0] returns []*/
494+ if (!c_count ) return rb_ary_new ();
486495 }
487496
488- opts = rb_iv_get (self , "@query_options" );
497+ defaults = rb_iv_get (self , "@query_options" );
498+ if (!NIL_P (opts )) {
499+ opts = rb_funcall (defaults , intern_merge , 1 , opts );
500+ } else {
501+ opts = defaults ;
502+ }
489503 rb_mysql_row_query_options (opts , & db_timezone , & app_timezone , & symbolizeKeys , & asArray , & castBool , & cast , & streaming , & cacheRows );
490504
491505 if (streaming ) {
492506 rb_raise (cMysql2Error , "Element reference operator #[] cannot be used in streaming mode." );
493507 }
494508
509+ if (!wrapper -> numberOfRows ) {
510+ wrapper -> numberOfRows = mysql_num_rows (wrapper -> result );
511+ }
512+
495513 /* count back from the end if passed a negative number */
496- if (offset < 0 ) {
497- offset = wrapper -> numberOfRows + offset ;
514+ if (c_seek < 0 ) {
515+ c_seek = wrapper -> numberOfRows + c_seek ;
498516 }
499517
500518 /* negative offset was too big */
501- if (offset < 0 ) {
519+ if (c_seek < 0 ) {
502520 return Qnil ;
503- /* rb_raise(cMysql2Error, "Out of range: offset %ld is beyond %lu rows (offset begins at 0).", offset , wrapper->numberOfRows); */
521+ /* rb_raise(cMysql2Error, "Out of range: offset %ld is beyond %lu rows (offset begins at 0).", c_seek , wrapper->numberOfRows); */
504522 }
505523
506- if (wrapper -> numberOfRows <= (unsigned long )offset ) {
507- return Qnil ;
508- /* rb_raise(cMysql2Error, "Out of range: offset %ld is beyond %lu rows (offset begins at 0).", offset, wrapper->numberOfRows); */
524+ if (wrapper -> numberOfRows <= (unsigned long )c_seek ) {
525+ if (!c_count ) return Qnil ;
526+ else return rb_ary_new ();
527+ /* rb_raise(cMysql2Error, "Out of range: offset %ld is beyond %lu rows (offset begins at 0).", c_seek, wrapper->numberOfRows); */
509528 }
510529
511- mysql_data_seek (wrapper -> result , offset );
530+ mysql_data_seek (wrapper -> result , c_seek );
512531
513- row = rb_mysql_result_fetch_row (self , db_timezone , app_timezone , symbolizeKeys , asArray , castBool , cast );
532+ if (!c_count ) {
533+ return rb_mysql_result_fetch_row (self , db_timezone , app_timezone , symbolizeKeys , asArray , castBool , cast );
534+ }
535+
536+ /* given ary = [1, 2, 3] then ary[1, 100] returns [2, 3] */
537+ if ((unsigned long )(c_seek + c_count ) > wrapper -> numberOfRows ) {
538+ c_count = wrapper -> numberOfRows - c_seek ;
539+ }
514540
515- return row ;
541+ /* return an array! */
542+ rows = rb_ary_new2 (c_count );
543+ for (i = 0 ; i < c_count ; i ++ ) {
544+ row = rb_mysql_result_fetch_row (self , db_timezone , app_timezone , symbolizeKeys , asArray , castBool , cast );
545+ rb_ary_store (rows , i , row );
546+ }
547+ return rows ;
516548}
517549
518550static VALUE rb_mysql_result_each (int argc , VALUE * argv , VALUE self ) {
@@ -658,7 +690,7 @@ void init_mysql2_result() {
658690 cDateTime = rb_const_get (rb_cObject , rb_intern ("DateTime" ));
659691
660692 cMysql2Result = rb_define_class_under (mMysql2 , "Result" , rb_cObject );
661- rb_define_method (cMysql2Result , "[]" , rb_mysql_result_element , 1 );
693+ rb_define_method (cMysql2Result , "[]" , rb_mysql_result_element , - 1 );
662694 rb_define_method (cMysql2Result , "each" , rb_mysql_result_each , -1 );
663695 rb_define_method (cMysql2Result , "fields" , rb_mysql_result_fetch_fields , 0 );
664696 rb_define_method (cMysql2Result , "count" , rb_mysql_result_count , 0 );
0 commit comments