mysqlplus 0.1.1 → 0.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/README +7 -0
- data/TODO_LIST +6 -7
- data/ext/error_const.h +3 -0
- data/ext/extconf.rb +4 -2
- data/ext/mysql.c +354 -47
- data/lib/mysqlplus.rb +6 -4
- data/mysqlplus.gemspec +8 -13
- data/test/RUN_ALL_TESTS.RB +9 -0
- data/test/{test_all_hashes.rb → all_hashes_test.rb} +3 -9
- data/test/async_query_with_block_test.rb +7 -0
- data/test/connect_failure2_test.rb +22 -0
- data/test/{test_failure.rb → connect_failure_test.rb} +1 -1
- data/test/create_test_db.rb +22 -0
- data/test/gc_benchmark_test.rb +40 -0
- data/test/{test_many_requests.rb → many_requests_test.rb} +0 -1
- data/test/out_of_sync_test.rb +34 -0
- data/test/{test_parsing_while_response_is_being_read.rb → query_with_result_false_test.rb} +3 -4
- data/test/reconnected_test.rb +18 -0
- data/test/test_helper.rb +1 -2
- data/test/{test_threaded_sequel.rb → threaded_sequel_test.rb} +2 -2
- metadata +28 -12
    
        data/README
    CHANGED
    
    | @@ -29,6 +29,10 @@ An enhanced MySQL database driver. With support for async operations and threade | |
| 29 29 | 
             
              Same with other scripts that want to use it--just require 'mysqlplus' BEFORE you require 'mysql' and it will 
         | 
| 30 30 | 
             
              load the asynchronous version, then ignore the sequent require 'mysql' call.
         | 
| 31 31 |  | 
| 32 | 
            +
            == Other helpful mysql utilities:
         | 
| 33 | 
            +
              slim attributes http://slim-attributes.rubyforge.org/ boosts mysql speed by using arrays instead of hashed lookup.
         | 
| 34 | 
            +
              Hash extension gem also results in speedups when used: http://blog.chak.org/2008/02/09/speeding-up-activerecord-with-hashes-take-2/
         | 
| 35 | 
            +
             | 
| 32 36 | 
             
            === Credits
         | 
| 33 37 |  | 
| 34 38 | 
             
            Aman Gupta, for help in threading support and improved tests
         | 
| @@ -38,3 +42,6 @@ Lourens Naude for 1.9 integration help. | |
| 38 42 |  | 
| 39 43 | 
             
            === License
         | 
| 40 44 | 
             
            Ruby License, http://www.ruby-lang.org/en/LICENSE.txt.
         | 
| 45 | 
            +
             | 
| 46 | 
            +
            == Mailing list
         | 
| 47 | 
            +
            http://groups.google.com/group/never-block?hl=en
         | 
    
        data/TODO_LIST
    CHANGED
    
    | @@ -1,13 +1,12 @@ | |
| 1 1 | 
             
            TODO list:
         | 
| 2 2 |  | 
| 3 | 
            -
            Is there a quick, cheap, easy way to test for writability so we don't have to use select  | 
| 3 | 
            +
            Is there a quick, cheap, easy way to test for writability so we don't have to use select itself? Does select take any time that it's worth looking into this?
         | 
| 4 4 |  | 
| 5 | 
            -
             | 
| 5 | 
            +
            Some of the tests currently might "think" they are using the ruby select but in reality be using the C select.
         | 
| 6 6 |  | 
| 7 | 
            -
             | 
| 7 | 
            +
            gc_disabled is unused
         | 
| 8 8 |  | 
| 9 | 
            -
             | 
| 9 | 
            +
            if they call get_result twice consecutively it should blow (and maybe already does).
         | 
| 10 10 |  | 
| 11 | 
            -
             | 
| 12 | 
            -
             | 
| 13 | 
            -
            critical todo list:
         | 
| 11 | 
            +
            mingw support
         | 
| 12 | 
            +
            add slim attributes right in there :)
         | 
    
        data/ext/error_const.h
    CHANGED
    
    | @@ -533,4 +533,7 @@ | |
| 533 533 | 
             
                rb_define_mysql_const(ER_ADMIN_WRONG_MRG_TABLE);
         | 
| 534 534 | 
             
                rb_define_mysql_const(ER_TOO_HIGH_LEVEL_OF_NESTING_FOR_SELECT);
         | 
| 535 535 | 
             
                rb_define_mysql_const(ER_NAME_BECOMES_EMPTY);
         | 
| 536 | 
            +
                rb_define_mysql_const(ER_AMBIGUOUS_FIELD_TERM);
         | 
| 537 | 
            +
                rb_define_mysql_const(ER_LOAD_DATA_INVALID_COLUMN);
         | 
| 538 | 
            +
                rb_define_mysql_const(ER_LOG_PURGE_NO_FILE);
         | 
| 536 539 | 
             
                rb_define_mysql_const(ER_ERROR_LAST);
         | 
    
        data/ext/extconf.rb
    CHANGED
    
    | @@ -45,8 +45,10 @@ else | |
| 45 45 | 
             
              exit 1
         | 
| 46 46 | 
             
            end
         | 
| 47 47 |  | 
| 48 | 
            +
            # check for 1.9
         | 
| 48 49 | 
             
            if have_func('rb_thread_blocking_region') and have_macro('RUBY_UBF_IO', 'ruby.h')
         | 
| 49 | 
            -
              $ | 
| 50 | 
            +
              $CFLAGS += " -DHAVE_TBR "
         | 
| 51 | 
            +
              $CPPFLAGS << " -DHAVE_TBR "
         | 
| 50 52 | 
             
            end
         | 
| 51 53 |  | 
| 52 54 | 
             
            # make mysql constant
         | 
| @@ -85,4 +87,4 @@ File.open('error_const.h', 'w') do |f| | |
| 85 87 | 
             
              end
         | 
| 86 88 | 
             
            end
         | 
| 87 89 |  | 
| 88 | 
            -
            create_makefile("mysql")
         | 
| 90 | 
            +
            create_makefile("mysql")
         | 
    
        data/ext/mysql.c
    CHANGED
    
    | @@ -6,6 +6,7 @@ | |
| 6 6 |  | 
| 7 7 | 
             
            #include <ruby.h>
         | 
| 8 8 | 
             
            #include <errno.h>
         | 
| 9 | 
            +
            #include <stdarg.h> 
         | 
| 9 10 | 
             
            #ifndef RSTRING_PTR
         | 
| 10 11 | 
             
            #define RSTRING_PTR(str) RSTRING(str)->ptr
         | 
| 11 12 | 
             
            #endif
         | 
| @@ -60,9 +61,13 @@ struct mysql { | |
| 60 61 | 
             
                MYSQL handler;
         | 
| 61 62 | 
             
                char connection;
         | 
| 62 63 | 
             
                char query_with_result;
         | 
| 64 | 
            +
                char gc_disabled;
         | 
| 63 65 | 
             
                char blocking;
         | 
| 66 | 
            +
                int async_in_progress;
         | 
| 67 | 
            +
                char busy;
         | 
| 64 68 | 
             
            };
         | 
| 65 69 |  | 
| 70 | 
            +
            // a wrapper for mysql_res's so we can detect double frees
         | 
| 66 71 | 
             
            struct mysql_res {
         | 
| 67 72 | 
             
                MYSQL_RES* res;
         | 
| 68 73 | 
             
                char freed;
         | 
| @@ -180,7 +185,7 @@ static void mysql_raise(MYSQL* m) | |
| 180 185 | 
             
                rb_exc_raise(e);
         | 
| 181 186 | 
             
            }
         | 
| 182 187 |  | 
| 183 | 
            -
            static VALUE mysqlres2obj(MYSQL_RES* res)
         | 
| 188 | 
            +
            static VALUE mysqlres2obj(MYSQL_RES* res, VALUE gc_disabled)
         | 
| 184 189 | 
             
            {
         | 
| 185 190 | 
             
                VALUE obj;
         | 
| 186 191 | 
             
                struct mysql_res* resp;
         | 
| @@ -229,10 +234,135 @@ static VALUE init(VALUE klass) | |
| 229 234 | 
             
                mysql_init(&myp->handler);
         | 
| 230 235 | 
             
                myp->connection = Qfalse;
         | 
| 231 236 | 
             
                myp->query_with_result = Qtrue;
         | 
| 237 | 
            +
                myp->gc_disabled = Qtrue;
         | 
| 232 238 | 
             
                rb_obj_call_init(obj, 0, NULL);
         | 
| 233 239 | 
             
                return obj;
         | 
| 234 240 | 
             
            }
         | 
| 235 241 |  | 
| 242 | 
            +
            // =========== a 1.9 rb_thread_blocking_region simplifier attempt
         | 
| 243 | 
            +
            #ifdef HAVE_TBR
         | 
| 244 | 
            +
             | 
| 245 | 
            +
            typedef struct
         | 
| 246 | 
            +
            {
         | 
| 247 | 
            +
             void *func_pointer;
         | 
| 248 | 
            +
             int param_count;
         | 
| 249 | 
            +
             void *args[10];
         | 
| 250 | 
            +
            } arg_holder, *arg_holder2;
         | 
| 251 | 
            +
             | 
| 252 | 
            +
            // here's how to make  rb_thread_blocking_region much cleaner and easier
         | 
| 253 | 
            +
            // syntax: param_count+2, func_pointer to call, [RUBY_UBF_IO or RUBY_UBF_PROCESS], param1, param2...
         | 
| 254 | 
            +
            // the third parameter is the interuptor--possible values appear to be RUBY_UBF_IO or RUBY_UBF_PROCESS http://groups.google.com/group/comp.lang.ruby/browse_thread/thread/ad8c1326b2a8e404/00447b9aa15979be?lnk=raot
         | 
| 255 | 
            +
            // ex: (int) returned_this = rb_thread_blocking_region_variable_params(10, &method_name, RUBY_UBF_IO, param1, param2, param3, param4, param5, param6, param7, param8)
         | 
| 256 | 
            +
             | 
| 257 | 
            +
            static void *call_single_function_rb_thread_blocking_region(void *arg_holder_in);
         | 
| 258 | 
            +
             | 
| 259 | 
            +
            void *rb_thread_blocking_region_variable_params(int number, ...)
         | 
| 260 | 
            +
            {
         | 
| 261 | 
            +
              va_list param_pt;
         | 
| 262 | 
            +
              va_start(param_pt, number);
         | 
| 263 | 
            +
              int index;
         | 
| 264 | 
            +
              arg_holder param_storer;
         | 
| 265 | 
            +
              void *func_pointer = va_arg(param_pt, void *);
         | 
| 266 | 
            +
              void *interrupter = va_arg(param_pt, void *);
         | 
| 267 | 
            +
              param_storer.func_pointer = func_pointer;
         | 
| 268 | 
            +
              int real_param_count = number - 2;
         | 
| 269 | 
            +
              param_storer.param_count = real_param_count;
         | 
| 270 | 
            +
              for(index = 0 ; index < real_param_count ; index++) 
         | 
| 271 | 
            +
              {
         | 
| 272 | 
            +
            	void *arg = va_arg(param_pt, void *);
         | 
| 273 | 
            +
            	param_storer.args[index] = arg;
         | 
| 274 | 
            +
             | 
| 275 | 
            +
              }
         | 
| 276 | 
            +
              va_end(param_pt);
         | 
| 277 | 
            +
             | 
| 278 | 
            +
              return (void *) rb_thread_blocking_region((rb_blocking_function_t *)call_single_function_rb_thread_blocking_region, (void *) ¶m_storer, interrupter, 0);
         | 
| 279 | 
            +
             | 
| 280 | 
            +
            }
         | 
| 281 | 
            +
             | 
| 282 | 
            +
            // used internally
         | 
| 283 | 
            +
            static void * call_single_function_rb_thread_blocking_region(void *arg_holder_in)
         | 
| 284 | 
            +
            {
         | 
| 285 | 
            +
               arg_holder *params_and_func = (arg_holder *) arg_holder_in;
         | 
| 286 | 
            +
               int param_count = params_and_func->param_count;
         | 
| 287 | 
            +
               void *result;
         | 
| 288 | 
            +
               switch(param_count)
         | 
| 289 | 
            +
               {
         | 
| 290 | 
            +
               case 3:;
         | 
| 291 | 
            +
                 void * (*pt3Func)(void *, void *, void *) = params_and_func->func_pointer;
         | 
| 292 | 
            +
                 result = (*pt3Func)(params_and_func->args[0], params_and_func->args[1], params_and_func->args[2]); 
         | 
| 293 | 
            +
                 break;
         | 
| 294 | 
            +
               case 6:;
         | 
| 295 | 
            +
            	void * (*pt6Func)(void *, void *, void *, void *, void *, void *) = params_and_func->func_pointer;
         | 
| 296 | 
            +
            	result = (*pt6Func)(params_and_func->args[0], params_and_func->args[1], params_and_func->args[2], params_and_func->args[3], params_and_func->args[4], params_and_func->args[5]);
         | 
| 297 | 
            +
            	break;
         | 
| 298 | 
            +
               case 8:;
         | 
| 299 | 
            +
            	void * (*pt8Func)(void *, void *, void *, void *, void *, void *, void *, void *) = params_and_func->func_pointer;
         | 
| 300 | 
            +
            	result = (*pt8Func)(params_and_func->args[0], params_and_func->args[1], params_and_func->args[2], params_and_func->args[3], params_and_func->args[4], params_and_func->args[5], params_and_func->args[6], params_and_func->args[7]);
         | 
| 301 | 
            +
            	break;
         | 
| 302 | 
            +
               default:;
         | 
| 303 | 
            +
            	printf("UNknown param count--please add it! %d\n", param_count);
         | 
| 304 | 
            +
                    result = (void *) Qnil;
         | 
| 305 | 
            +
               }
         | 
| 306 | 
            +
             | 
| 307 | 
            +
               return result;
         | 
| 308 | 
            +
            }
         | 
| 309 | 
            +
             | 
| 310 | 
            +
            #endif
         | 
| 311 | 
            +
             | 
| 312 | 
            +
            static VALUE connection_identifier( VALUE obj )
         | 
| 313 | 
            +
            {
         | 
| 314 | 
            +
                MYSQL* m = GetHandler(obj);
         | 
| 315 | 
            +
                return mysql_thread_id( m );
         | 
| 316 | 
            +
            }
         | 
| 317 | 
            +
             | 
| 318 | 
            +
            static VALUE async_in_progress( VALUE obj )
         | 
| 319 | 
            +
            {
         | 
| 320 | 
            +
               struct mysql* m = GetMysqlStruct(obj);
         | 
| 321 | 
            +
               return ( m->async_in_progress == connection_identifier(obj) ) ? Qtrue : Qfalse;
         | 
| 322 | 
            +
            }
         | 
| 323 | 
            +
             | 
| 324 | 
            +
            static VALUE async_in_progress_set( VALUE obj, VALUE flag )
         | 
| 325 | 
            +
            {
         | 
| 326 | 
            +
                struct mysql* m = GetMysqlStruct(obj);
         | 
| 327 | 
            +
                m->async_in_progress = (flag == Qnil || flag == Qfalse) ? 0 : connection_identifier(obj);
         | 
| 328 | 
            +
                return flag; 
         | 
| 329 | 
            +
            }
         | 
| 330 | 
            +
             | 
| 331 | 
            +
            // does this actually really do anything helpful? Not sure.
         | 
| 332 | 
            +
            static void optimize_for_async( VALUE obj )
         | 
| 333 | 
            +
            {
         | 
| 334 | 
            +
                struct mysql* m = GetMysqlStruct(obj);
         | 
| 335 | 
            +
                my_bool was_blocking;
         | 
| 336 | 
            +
                vio_blocking(m->handler.net.vio, 0, &was_blocking);    
         | 
| 337 | 
            +
                m->blocking = vio_is_blocking( m->handler.net.vio );
         | 
| 338 | 
            +
             | 
| 339 | 
            +
                vio_fastsend( m->handler.net.vio );
         | 
| 340 | 
            +
                async_in_progress_set( obj, Qfalse );
         | 
| 341 | 
            +
            }
         | 
| 342 | 
            +
             | 
| 343 | 
            +
            // TODO does nothing currently
         | 
| 344 | 
            +
            static void schedule_connect(VALUE obj )
         | 
| 345 | 
            +
            {
         | 
| 346 | 
            +
            /* TODO is this old?
         | 
| 347 | 
            +
                MYSQL* m = GetHandler(obj);
         | 
| 348 | 
            +
                fd_set read;
         | 
| 349 | 
            +
             | 
| 350 | 
            +
                struct timeval tv = { tv_sec: m->options.connect_timeout, tv_usec: 0 };
         | 
| 351 | 
            +
                if (rb_thread_select(0, NULL, NULL, NULL, &tv) < 0) {
         | 
| 352 | 
            +
                  rb_raise(eMysql, "connect: timeout");
         | 
| 353 | 
            +
                }
         | 
| 354 | 
            +
            */
         | 
| 355 | 
            +
             | 
| 356 | 
            +
            /*
         | 
| 357 | 
            +
                FD_ZERO(&read);
         | 
| 358 | 
            +
                FD_SET(m->net.fd, &read);
         | 
| 359 | 
            +
             | 
| 360 | 
            +
                if (rb_thread_select(m->net.fd + 1, &read, NULL, NULL, &tv) < 0) {
         | 
| 361 | 
            +
                  rb_raise(eMysql, "connect: timeout");
         | 
| 362 | 
            +
                }
         | 
| 363 | 
            +
            */
         | 
| 364 | 
            +
            }
         | 
| 365 | 
            +
             | 
| 236 366 | 
             
            /*	real_connect(host=nil, user=nil, passwd=nil, db=nil, port=nil, sock=nil, flag=nil)	*/
         | 
| 237 367 | 
             
            static VALUE real_connect(int argc, VALUE* argv, VALUE klass)
         | 
| 238 368 | 
             
            {
         | 
| @@ -260,27 +390,28 @@ static VALUE real_connect(int argc, VALUE* argv, VALUE klass) | |
| 260 390 |  | 
| 261 391 | 
             
                obj = Data_Make_Struct(klass, struct mysql, 0, free_mysql, myp);
         | 
| 262 392 | 
             
            #if MYSQL_VERSION_ID >= 32200
         | 
| 263 | 
            -
                mysql_init(&myp->handler);
         | 
| 264 | 
            -
             | 
| 393 | 
            +
                mysql_init(&myp->handler); /* we get here */
         | 
| 394 | 
            +
            # ifdef HAVE_TBR
         | 
| 395 | 
            +
                if( (MYSQL *) rb_thread_blocking_region_variable_params(10, &mysql_real_connect, RUBY_UBF_IO, &myp->handler, h, u, p, d, pp, s, f) == NULL) 
         | 
| 396 | 
            +
            # else
         | 
| 397 | 
            +
                if(mysql_real_connect(&myp->handler, h, u, p, d, pp, s, f) == NULL)
         | 
| 398 | 
            +
            # endif
         | 
| 265 399 | 
             
            #elif MYSQL_VERSION_ID >= 32115
         | 
| 266 400 | 
             
                if (mysql_real_connect(&myp->handler, h, u, p, pp, s, f) == NULL)
         | 
| 267 401 | 
             
            #else
         | 
| 268 402 | 
             
                if (mysql_real_connect(&myp->handler, h, u, p, pp, s) == NULL)
         | 
| 269 403 | 
             
            #endif
         | 
| 270 404 | 
             
            	mysql_raise(&myp->handler);
         | 
| 271 | 
            -
             | 
| 405 | 
            +
                
         | 
| 272 406 | 
             
                myp->handler.reconnect = 0;
         | 
| 273 407 | 
             
                myp->connection = Qtrue;
         | 
| 274 408 |  | 
| 275 | 
            -
                 | 
| 276 | 
            -
             | 
| 277 | 
            -
                vio_blocking(myp->handler.net.vio, 0, &was_blocking);    
         | 
| 278 | 
            -
                myp->blocking = vio_is_blocking( myp->handler.net.vio );
         | 
| 279 | 
            -
             | 
| 280 | 
            -
                vio_fastsend( myp->handler.net.vio );
         | 
| 409 | 
            +
                optimize_for_async(obj);
         | 
| 281 410 |  | 
| 282 411 | 
             
                myp->query_with_result = Qtrue;
         | 
| 283 412 | 
             
                rb_obj_call_init(obj, argc, argv);
         | 
| 413 | 
            +
                
         | 
| 414 | 
            +
                //schedule_connect(obj);
         | 
| 284 415 |  | 
| 285 416 | 
             
                return obj;
         | 
| 286 417 | 
             
            }
         | 
| @@ -343,6 +474,9 @@ static VALUE real_connect2(int argc, VALUE* argv, VALUE obj) | |
| 343 474 | 
             
            	mysql_raise(m);
         | 
| 344 475 | 
             
                m->reconnect = 0;
         | 
| 345 476 | 
             
                GetMysqlStruct(obj)->connection = Qtrue;
         | 
| 477 | 
            +
                     
         | 
| 478 | 
            +
                optimize_for_async(obj);
         | 
| 479 | 
            +
                //schedule_connect(obj);
         | 
| 346 480 |  | 
| 347 481 | 
             
                return obj;
         | 
| 348 482 | 
             
            }
         | 
| @@ -597,7 +731,7 @@ static VALUE list_fields(int argc, VALUE* argv, VALUE obj) | |
| 597 731 | 
             
                res = mysql_list_fields(m, StringValuePtr(table), NILorSTRING(field));
         | 
| 598 732 | 
             
                if (res == NULL)
         | 
| 599 733 | 
             
            	mysql_raise(m);
         | 
| 600 | 
            -
                return mysqlres2obj(res);
         | 
| 734 | 
            +
                return mysqlres2obj(res, GetMysqlStruct(obj)->gc_disabled);
         | 
| 601 735 | 
             
            }
         | 
| 602 736 |  | 
| 603 737 | 
             
            /*	list_processes()	*/
         | 
| @@ -607,7 +741,7 @@ static VALUE list_processes(VALUE obj) | |
| 607 741 | 
             
                MYSQL_RES* res = mysql_list_processes(m);
         | 
| 608 742 | 
             
                if (res == NULL)
         | 
| 609 743 | 
             
            	mysql_raise(m);
         | 
| 610 | 
            -
                return mysqlres2obj(res);
         | 
| 744 | 
            +
                return mysqlres2obj(res, GetMysqlStruct(obj)->gc_disabled);
         | 
| 611 745 | 
             
            }
         | 
| 612 746 |  | 
| 613 747 | 
             
            /*	list_tables(table=nil)	*/
         | 
| @@ -694,14 +828,40 @@ static VALUE my_stat(VALUE obj) | |
| 694 828 | 
             
                return rb_tainted_str_new2(s);
         | 
| 695 829 | 
             
            }
         | 
| 696 830 |  | 
| 831 | 
            +
            // 1.9 friendly
         | 
| 832 | 
            +
            typedef struct
         | 
| 833 | 
            +
            {
         | 
| 834 | 
            +
             MYSQL *mysql_instance;
         | 
| 835 | 
            +
             MYSQL_RES **store_it_here;
         | 
| 836 | 
            +
             | 
| 837 | 
            +
            } mysql_result_to_here_t,
         | 
| 838 | 
            +
             *shared_stuff_p;
         | 
| 839 | 
            +
             | 
| 840 | 
            +
            static VALUE store_result_to_location(void *settings_in)
         | 
| 841 | 
            +
            {
         | 
| 842 | 
            +
               mysql_result_to_here_t *settings = (mysql_result_to_here_t *) settings_in;
         | 
| 843 | 
            +
               *(settings->store_it_here) = mysql_store_result(settings->mysql_instance); // this one line runs a good long while for very large queries 
         | 
| 844 | 
            +
               return Qnil;
         | 
| 845 | 
            +
            }
         | 
| 846 | 
            +
             | 
| 697 847 | 
             
            /*	store_result()	*/
         | 
| 698 848 | 
             
            static VALUE store_result(VALUE obj)
         | 
| 699 849 | 
             
            {
         | 
| 700 850 | 
             
                MYSQL* m = GetHandler(obj);
         | 
| 701 | 
            -
                MYSQL_RES* res =  | 
| 851 | 
            +
                MYSQL_RES* res = NULL;
         | 
| 852 | 
            +
            #ifndef HAVE_TBR
         | 
| 853 | 
            +
                res = mysql_store_result(m);
         | 
| 854 | 
            +
            #else
         | 
| 855 | 
            +
                mysql_result_to_here_t linker;
         | 
| 856 | 
            +
                linker.mysql_instance = m;
         | 
| 857 | 
            +
                linker.store_it_here = &res;
         | 
| 858 | 
            +
                rb_thread_blocking_region(store_result_to_location, (void *) &linker, RUBY_UBF_IO, 0);
         | 
| 859 | 
            +
            #endif
         | 
| 860 | 
            +
             
         | 
| 702 861 | 
             
                if (res == NULL)
         | 
| 703 862 | 
             
            	mysql_raise(m);
         | 
| 704 | 
            -
             | 
| 863 | 
            +
             | 
| 864 | 
            +
                return mysqlres2obj(res, GetMysqlStruct(obj)->gc_disabled);
         | 
| 705 865 | 
             
            }
         | 
| 706 866 |  | 
| 707 867 | 
             
            /*	thread_id()	*/
         | 
| @@ -717,7 +877,7 @@ static VALUE use_result(VALUE obj) | |
| 717 877 | 
             
                MYSQL_RES* res = mysql_use_result(m);
         | 
| 718 878 | 
             
                if (res == NULL)
         | 
| 719 879 | 
             
            	mysql_raise(m);
         | 
| 720 | 
            -
                return mysqlres2obj(res);
         | 
| 880 | 
            +
                return mysqlres2obj(res, GetMysqlStruct(obj)->gc_disabled);
         | 
| 721 881 | 
             
            }
         | 
| 722 882 |  | 
| 723 883 | 
             
            static VALUE res_free(VALUE);
         | 
| @@ -764,7 +924,7 @@ static VALUE query(VALUE obj, VALUE sql) | |
| 764 924 | 
             
            		if (mysql_field_count(m) != 0)
         | 
| 765 925 | 
             
            		    mysql_raise(m);
         | 
| 766 926 | 
             
            	    } else {
         | 
| 767 | 
            -
            		VALUE robj = mysqlres2obj(res);
         | 
| 927 | 
            +
            		VALUE robj = mysqlres2obj(res, GetMysqlStruct(obj)->gc_disabled);
         | 
| 768 928 | 
             
            		rb_ensure(rb_yield, robj, res_free, robj);
         | 
| 769 929 | 
             
            	    }
         | 
| 770 930 | 
             
            #if MYSQL_VERSION_ID >= 40101
         | 
| @@ -800,17 +960,46 @@ static VALUE socket(VALUE obj) | |
| 800 960 | 
             
                MYSQL* m = GetHandler(obj);
         | 
| 801 961 | 
             
                return INT2NUM(m->net.fd);
         | 
| 802 962 | 
             
            }
         | 
| 803 | 
            -
             | 
| 963 | 
            +
             | 
| 964 | 
            +
            /* socket_type --currently returns true or false, needs some work */
         | 
| 804 965 | 
             
            static VALUE socket_type(VALUE obj)
         | 
| 805 966 | 
             
            {
         | 
| 806 967 | 
             
                MYSQL* m = GetHandler(obj);
         | 
| 807 | 
            -
                 | 
| 808 | 
            -
             | 
| 968 | 
            +
                if(vio_description(m->net.vio))
         | 
| 969 | 
            +
            	return Qtrue; // TODO return a ruby string
         | 
| 970 | 
            +
                else
         | 
| 971 | 
            +
            	return Qnil;
         | 
| 809 972 | 
             
            }
         | 
| 810 973 |  | 
| 811 974 | 
             
            /* blocking */
         | 
| 812 975 | 
             
            static VALUE blocking(VALUE obj){
         | 
| 813 | 
            -
             | 
| 976 | 
            +
                return ( GetMysqlStruct(obj)->blocking ? Qtrue : Qfalse );
         | 
| 977 | 
            +
            }
         | 
| 978 | 
            +
             | 
| 979 | 
            +
            /* is_busy */
         | 
| 980 | 
            +
            static VALUE is_busy(VALUE obj){
         | 
| 981 | 
            +
                return ( GetMysqlStruct(obj)->busy ? Qtrue : Qfalse );
         | 
| 982 | 
            +
            }
         | 
| 983 | 
            +
             | 
| 984 | 
            +
            static VALUE is_idle(VALUE obj){
         | 
| 985 | 
            +
                return ( is_busy(obj) == Qtrue ) ? Qfalse : Qtrue;
         | 
| 986 | 
            +
            }
         | 
| 987 | 
            +
             | 
| 988 | 
            +
            /* busy(true|false) */
         | 
| 989 | 
            +
            static VALUE busy_set(VALUE obj, VALUE flag)
         | 
| 990 | 
            +
            {
         | 
| 991 | 
            +
                if (TYPE(flag) != T_TRUE && TYPE(flag) != T_FALSE)
         | 
| 992 | 
            +
                    rb_raise(rb_eTypeError, "invalid type, required true or false.");
         | 
| 993 | 
            +
                GetMysqlStruct(obj)->busy = flag;
         | 
| 994 | 
            +
                return flag;
         | 
| 995 | 
            +
            }
         | 
| 996 | 
            +
             | 
| 997 | 
            +
            static void busy( VALUE obj ){
         | 
| 998 | 
            +
                busy_set( obj, Qtrue );
         | 
| 999 | 
            +
            }
         | 
| 1000 | 
            +
             | 
| 1001 | 
            +
            static void idle( VALUE obj ){
         | 
| 1002 | 
            +
                busy_set( obj, Qfalse );
         | 
| 814 1003 | 
             
            }
         | 
| 815 1004 |  | 
| 816 1005 | 
             
            /* readable(timeout=nil) */
         | 
| @@ -825,69 +1014,177 @@ static VALUE readable( int argc, VALUE* argv, VALUE obj ) | |
| 825 1014 | 
             
                if ( NIL_P( timeout ) ){
         | 
| 826 1015 | 
             
                  timeout = m->net.read_timeout;
         | 
| 827 1016 | 
             
                }
         | 
| 828 | 
            -
             | 
| 1017 | 
            +
                // todo could do a rb_blocking_region here
         | 
| 829 1018 | 
             
                return ( vio_poll_read( m->net.vio, INT2NUM(timeout) ) == 0 ? Qtrue : Qfalse );
         | 
| 830 1019 | 
             
            }
         | 
| 831 1020 |  | 
| 1021 | 
            +
            /* retry */
         | 
| 1022 | 
            +
            static VALUE retry( VALUE obj )
         | 
| 1023 | 
            +
            {
         | 
| 1024 | 
            +
                MYSQL* m = GetHandler(obj);
         | 
| 1025 | 
            +
                return ( vio_should_retry( m->net.vio ) == 1 ? Qtrue : Qfalse );
         | 
| 1026 | 
            +
            }
         | 
| 1027 | 
            +
             | 
| 1028 | 
            +
            /* interrupted */
         | 
| 1029 | 
            +
            static VALUE interrupted( VALUE obj )
         | 
| 1030 | 
            +
            {
         | 
| 1031 | 
            +
                MYSQL* m = GetHandler(obj);
         | 
| 1032 | 
            +
                return ( vio_was_interrupted( m->net.vio ) == 1 ? Qtrue : Qfalse );
         | 
| 1033 | 
            +
            }
         | 
| 1034 | 
            +
             | 
| 1035 | 
            +
            /* reconnected */
         | 
| 1036 | 
            +
            static VALUE reconnected( VALUE obj ){
         | 
| 1037 | 
            +
                MYSQL* m = GetHandler(obj);
         | 
| 1038 | 
            +
                int current_connection_id = mysql_thread_id( m );
         | 
| 1039 | 
            +
                mysql_ping(m);
         | 
| 1040 | 
            +
                return ( current_connection_id == mysql_thread_id( m ) ) ? Qfalse : Qtrue;
         | 
| 1041 | 
            +
            }
         | 
| 1042 | 
            +
             | 
| 1043 | 
            +
            /* disable_gc(true|false) */
         | 
| 1044 | 
            +
            static VALUE disable_gc_set(VALUE obj, VALUE flag)
         | 
| 1045 | 
            +
            {
         | 
| 1046 | 
            +
                if (TYPE(flag) != T_TRUE && TYPE(flag) != T_FALSE)
         | 
| 1047 | 
            +
                    rb_raise(rb_eTypeError, "invalid type, required true or false.");
         | 
| 1048 | 
            +
                GetMysqlStruct(obj)->gc_disabled = flag;
         | 
| 1049 | 
            +
                return flag;
         | 
| 1050 | 
            +
            }
         | 
| 1051 | 
            +
             | 
| 1052 | 
            +
            /* gc_disabled */
         | 
| 1053 | 
            +
            static VALUE gc_disabled( VALUE obj ){
         | 
| 1054 | 
            +
                return GetMysqlStruct(obj)->gc_disabled ? Qtrue: Qfalse;  
         | 
| 1055 | 
            +
            }
         | 
| 1056 | 
            +
             | 
| 1057 | 
            +
            static void validate_async_query( VALUE obj )
         | 
| 1058 | 
            +
            {
         | 
| 1059 | 
            +
                if( async_in_progress(obj) == Qtrue ){
         | 
| 1060 | 
            +
                  async_in_progress_set(obj, Qfalse);
         | 
| 1061 | 
            +
                  rb_raise(eMysql, "Query out of sequence: Each call to Mysql#send_query requires a successive Mysql#get_result.");
         | 
| 1062 | 
            +
                }
         | 
| 1063 | 
            +
            }
         | 
| 1064 | 
            +
             | 
| 1065 | 
            +
            /* for testing */
         | 
| 1066 | 
            +
            static VALUE simulate_disconnect( VALUE obj )
         | 
| 1067 | 
            +
            {
         | 
| 1068 | 
            +
                MYSQL* m = GetHandler(obj); 
         | 
| 1069 | 
            +
                mysql_library_end();
         | 
| 1070 | 
            +
                return Qnil;
         | 
| 1071 | 
            +
            }
         | 
| 1072 | 
            +
             | 
| 1073 | 
            +
             | 
| 832 1074 | 
             
            /* send_query(sql) */
         | 
| 833 1075 | 
             
            static VALUE send_query(VALUE obj, VALUE sql)
         | 
| 834 1076 | 
             
            {
         | 
| 835 1077 | 
             
                MYSQL* m = GetHandler(obj);
         | 
| 836 | 
            -
             | 
| 1078 | 
            +
               
         | 
| 837 1079 | 
             
                Check_Type(sql, T_STRING);
         | 
| 838 | 
            -
             | 
| 839 | 
            -
             | 
| 1080 | 
            +
             | 
| 1081 | 
            +
                if (GetMysqlStruct(obj)->connection == Qfalse && async_in_progress(obj) == Qtrue ) {
         | 
| 1082 | 
            +
                  idle( obj );
         | 
| 1083 | 
            +
                  rb_raise(eMysql, "query: not connected");
         | 
| 840 1084 | 
             
                }
         | 
| 841 | 
            -
             | 
| 842 | 
            -
             | 
| 843 | 
            -
             | 
| 1085 | 
            +
             | 
| 1086 | 
            +
                validate_async_query(obj);
         | 
| 1087 | 
            +
             | 
| 1088 | 
            +
                if (mysql_send_query(m, RSTRING_PTR(sql), RSTRING_LEN(sql)) != 0){
         | 
| 1089 | 
            +
                  idle( obj );
         | 
| 1090 | 
            +
                  mysql_raise(m);
         | 
| 1091 | 
            +
                }
         | 
| 1092 | 
            +
                async_in_progress_set( obj, Qtrue );
         | 
| 1093 | 
            +
            	
         | 
| 1094 | 
            +
                return Qnil;
         | 
| 844 1095 | 
             
            }
         | 
| 845 1096 |  | 
| 846 | 
            -
            /*  | 
| 1097 | 
            +
            /* 
         | 
| 1098 | 
            +
              get_result
         | 
| 1099 | 
            +
              returns the mysql_result set (default) [i.e. all rows in said said]
         | 
| 1100 | 
            +
              or nil if query_with_result == false
         | 
| 1101 | 
            +
             */
         | 
| 847 1102 | 
             
            static VALUE get_result(VALUE obj)
         | 
| 848 1103 | 
             
            {
         | 
| 849 1104 | 
             
                MYSQL* m = GetHandler(obj);
         | 
| 1105 | 
            +
             | 
| 1106 | 
            +
                async_in_progress_set( obj, Qfalse );
         | 
| 1107 | 
            +
             | 
| 850 1108 | 
             
                if (GetMysqlStruct(obj)->connection == Qfalse) {
         | 
| 851 | 
            -
             | 
| 1109 | 
            +
                   idle( obj );    
         | 
| 1110 | 
            +
                   rb_raise(eMysql, "query: not connected");
         | 
| 852 1111 | 
             
                }
         | 
| 853 | 
            -
             | 
| 854 | 
            -
             | 
| 1112 | 
            +
            	if (mysql_read_query_result(m) != 0){
         | 
| 1113 | 
            +
            	   idle( obj );    
         | 
| 1114 | 
            +
             	   mysql_raise(m);
         | 
| 1115 | 
            +
            	}
         | 
| 1116 | 
            +
                
         | 
| 855 1117 | 
             
                if (GetMysqlStruct(obj)->query_with_result == Qfalse)
         | 
| 856 1118 | 
             
                  	return obj;
         | 
| 1119 | 
            +
             | 
| 857 1120 | 
             
                if (mysql_field_count(m) == 0)
         | 
| 858 | 
            -
             | 
| 1121 | 
            +
            	    return Qnil; 
         | 
| 1122 | 
            +
             | 
| 859 1123 | 
             
                return store_result(obj);
         | 
| 860 1124 | 
             
            }
         | 
| 861 1125 |  | 
| 862 | 
            -
            static void  | 
| 1126 | 
            +
            static void schedule_query(VALUE obj, VALUE timeout)
         | 
| 863 1127 | 
             
            {
         | 
| 864 1128 | 
             
                MYSQL* m = GetHandler(obj);
         | 
| 865 1129 | 
             
                fd_set read;
         | 
| 866 | 
            -
             | 
| 1130 | 
            +
                int ret;
         | 
| 1131 | 
            +
             
         | 
| 867 1132 | 
             
                timeout = ( NIL_P(timeout) ? m->net.read_timeout : INT2NUM(timeout) );
         | 
| 868 1133 |  | 
| 869 1134 | 
             
                struct timeval tv = { tv_sec: timeout, tv_usec: 0 };
         | 
| 870 1135 |  | 
| 871 | 
            -
                 | 
| 872 | 
            -
             | 
| 1136 | 
            +
                for(;;){
         | 
| 1137 | 
            +
                  FD_ZERO(&read);
         | 
| 1138 | 
            +
                  FD_SET(m->net.fd, &read);
         | 
| 1139 | 
            +
             
         | 
| 1140 | 
            +
                  ret = rb_thread_select(m->net.fd + 1, &read, NULL, NULL, &tv);
         | 
| 1141 | 
            +
                  if (ret < 0) {
         | 
| 1142 | 
            +
                    idle( obj );    
         | 
| 1143 | 
            +
                    rb_raise(eMysql, "query: timeout");
         | 
| 1144 | 
            +
                  }
         | 
| 1145 | 
            +
            	  
         | 
| 1146 | 
            +
            	  if (ret == 0) {
         | 
| 1147 | 
            +
                    continue;
         | 
| 1148 | 
            +
                  }
         | 
| 873 1149 |  | 
| 874 | 
            -
             | 
| 875 | 
            -
             | 
| 1150 | 
            +
                  if (m->status == MYSQL_STATUS_READY){
         | 
| 1151 | 
            +
                    break;
         | 
| 1152 | 
            +
                  }       
         | 
| 876 1153 | 
             
                }
         | 
| 877 1154 | 
             
            }
         | 
| 878 1155 |  | 
| 879 | 
            -
             | 
| 1156 | 
            +
            static int should_schedule_query(){
         | 
| 1157 | 
            +
                return rb_thread_alone() != 1;
         | 
| 1158 | 
            +
            }
         | 
| 1159 | 
            +
             | 
| 1160 | 
            +
            /* async_query(sql,timeout=nil)
         | 
| 1161 | 
            +
               optionally take a block
         | 
| 1162 | 
            +
             */
         | 
| 880 1163 | 
             
            static VALUE async_query(int argc, VALUE* argv, VALUE obj)
         | 
| 881 1164 | 
             
            {
         | 
| 882 | 
            -
             | 
| 1165 | 
            +
                MYSQL* m = GetHandler(obj); 
         | 
| 1166 | 
            +
                VALUE sql, timeout;
         | 
| 1167 | 
            +
             | 
| 1168 | 
            +
                rb_scan_args(argc, argv, "11", &sql, &timeout);
         | 
| 883 1169 |  | 
| 884 | 
            -
             | 
| 1170 | 
            +
                async_in_progress_set( obj, Qfalse );
         | 
| 885 1171 |  | 
| 886 | 
            -
             | 
| 1172 | 
            +
                busy(obj); 
         | 
| 887 1173 |  | 
| 888 | 
            -
             | 
| 1174 | 
            +
                send_query( obj, sql );
         | 
| 889 1175 |  | 
| 890 | 
            -
             | 
| 1176 | 
            +
                if ( should_schedule_query() ){
         | 
| 1177 | 
            +
                  schedule_query(obj, timeout);
         | 
| 1178 | 
            +
                } 
         | 
| 1179 | 
            +
             | 
| 1180 | 
            +
                if (rb_block_given_p()) {
         | 
| 1181 | 
            +
                  rb_yield( get_result(obj) );
         | 
| 1182 | 
            +
                  idle( obj );
         | 
| 1183 | 
            +
                  return obj; 
         | 
| 1184 | 
            +
                }else{
         | 
| 1185 | 
            +
                  idle( obj );
         | 
| 1186 | 
            +
                  return get_result(obj); 
         | 
| 1187 | 
            +
                }  
         | 
| 891 1188 | 
             
            }
         | 
| 892 1189 |  | 
| 893 1190 | 
             
            #if MYSQL_VERSION_ID >= 40100
         | 
| @@ -1157,7 +1454,7 @@ static VALUE fetch_row(VALUE obj) | |
| 1157 1454 | 
             
                return ary;
         | 
| 1158 1455 | 
             
            }
         | 
| 1159 1456 |  | 
| 1160 | 
            -
            /*	process_all_hashes (internal)	*/
         | 
| 1457 | 
            +
            /*	process_all_hashes (internal helper)	*/
         | 
| 1161 1458 | 
             
            static VALUE process_all_hashes(VALUE obj, VALUE with_table, int build_array, int yield)
         | 
| 1162 1459 | 
             
            {
         | 
| 1163 1460 | 
             
                MYSQL_RES* res = GetMysqlRes(obj);
         | 
| @@ -1922,7 +2219,7 @@ static VALUE stmt_result_metadata(VALUE obj) | |
| 1922 2219 | 
             
            	mysql_stmt_raise(s->stmt);
         | 
| 1923 2220 | 
             
                  return Qnil;
         | 
| 1924 2221 | 
             
                }
         | 
| 1925 | 
            -
                return mysqlres2obj(res);
         | 
| 2222 | 
            +
                return mysqlres2obj(res, Qfalse);
         | 
| 1926 2223 | 
             
            }
         | 
| 1927 2224 |  | 
| 1928 2225 | 
             
            /*	row_seek(offset)	*/
         | 
| @@ -2180,12 +2477,22 @@ void Init_mysql(void) | |
| 2180 2477 | 
             
                rb_define_method(cMysql, "query", query, 1);
         | 
| 2181 2478 | 
             
                rb_define_method(cMysql, "real_query", query, 1);
         | 
| 2182 2479 | 
             
                rb_define_method(cMysql, "c_async_query", async_query, -1);
         | 
| 2480 | 
            +
                rb_define_method(cMysql, "async_in_progress?", async_in_progress, 0);
         | 
| 2481 | 
            +
                rb_define_method(cMysql, "async_in_progress=", async_in_progress_set, 1);
         | 
| 2183 2482 | 
             
                rb_define_method(cMysql, "send_query", send_query, 1);
         | 
| 2483 | 
            +
                rb_define_method(cMysql, "simulate_disconnect", simulate_disconnect, 0);
         | 
| 2484 | 
            +
                rb_define_method(cMysql, "reconnected?", reconnected, 0);
         | 
| 2184 2485 | 
             
                rb_define_method(cMysql, "get_result", get_result, 0);
         | 
| 2185 2486 | 
             
                rb_define_method(cMysql, "readable?", readable, -1);
         | 
| 2487 | 
            +
                rb_define_method(cMysql, "retry?", retry, 0);
         | 
| 2488 | 
            +
                rb_define_method(cMysql, "interrupted?", interrupted, 0);
         | 
| 2186 2489 | 
             
                rb_define_method(cMysql, "blocking?", blocking, 0);
         | 
| 2490 | 
            +
                rb_define_method(cMysql, "gc_disabled?", gc_disabled, 0);
         | 
| 2491 | 
            +
                rb_define_method(cMysql, "disable_gc=", disable_gc_set, 1);
         | 
| 2492 | 
            +
                rb_define_method(cMysql, "busy?", is_busy, 0);
         | 
| 2493 | 
            +
                rb_define_method(cMysql, "idle?", is_idle, 0);
         | 
| 2494 | 
            +
                rb_define_method(cMysql, "busy=", busy_set, 1);
         | 
| 2187 2495 | 
             
                rb_define_method(cMysql, "socket", socket, 0);
         | 
| 2188 | 
            -
                rb_define_method(cMysql, "socket_type", socket_type, 0);
         | 
| 2189 2496 | 
             
                rb_define_method(cMysql, "refresh", refresh, 1);
         | 
| 2190 2497 | 
             
                rb_define_method(cMysql, "reload", reload, 0);
         | 
| 2191 2498 | 
             
                rb_define_method(cMysql, "select_db", select_db, 1);
         | 
    
        data/lib/mysqlplus.rb
    CHANGED
    
    | @@ -1,8 +1,10 @@ | |
| 1 | 
            -
            require 'mysql' #  | 
| 1 | 
            +
            require File.dirname(__FILE__) + '/mysql' # load our version of mysql--note
         | 
| 2 | 
            +
            # if someone does a require 'mysql' after a require 'mysqlplus' then their screen will be littered with warnings
         | 
| 3 | 
            +
            # and the "old" mysql will override the "new" mysqlplus, so be careful.
         | 
| 2 4 |  | 
| 3 5 | 
             
            #
         | 
| 4 | 
            -
            #  | 
| 5 | 
            -
            # See http://www.kitebird.com/articles/ruby-mysql.html for details, as well as the test directory within the  | 
| 6 | 
            +
            # The mysqlplus library is a  [slightly updated] fork of the Mysql class, with asynchronous capability added
         | 
| 7 | 
            +
            # See http://www.kitebird.com/articles/ruby-mysql.html for details, as well as the test directory within the gem
         | 
| 6 8 | 
             
            #
         | 
| 7 9 | 
             
            class Mysql
         | 
| 8 10 |  | 
| @@ -15,7 +17,7 @@ class Mysql | |
| 15 17 | 
             
              begin
         | 
| 16 18 | 
             
                alias_method :async_query, :c_async_query  
         | 
| 17 19 | 
             
              rescue NameError => e
         | 
| 18 | 
            -
                raise LoadError.new | 
| 20 | 
            +
                raise LoadError.new("error loading mysqlplus--this may mean you ran a require 'mysql' before a require 'mysqplus', which must come first -- possibly also run gem uninstall mysql")
         | 
| 19 21 | 
             
              end
         | 
| 20 22 |  | 
| 21 23 | 
             
            end
         | 
    
        data/mysqlplus.gemspec
    CHANGED
    
    | @@ -1,13 +1,13 @@ | |
| 1 1 | 
             
            Gem::Specification.new do |s|
         | 
| 2 2 | 
             
              s.name     = "mysqlplus"
         | 
| 3 | 
            -
              s.version  = "0.1. | 
| 3 | 
            +
              s.version  = "0.1.2"
         | 
| 4 4 | 
             
              s.date     = "2009-03-22"
         | 
| 5 5 | 
             
              s.summary  = "Enhanced Ruby MySQL driver"
         | 
| 6 6 | 
             
              s.email    = "oldmoe@gmail.com"
         | 
| 7 7 | 
             
              s.homepage = "http://github.com/oldmoe/mysqlplus"
         | 
| 8 8 | 
             
              s.description = "Enhanced Ruby MySQL driver"
         | 
| 9 9 | 
             
              s.has_rdoc = true
         | 
| 10 | 
            -
              s.authors  = ["Muhammad A. Ali"]
         | 
| 10 | 
            +
              s.authors  = ["Muhammad A. Ali et al"]
         | 
| 11 11 | 
             
              s.platform = Gem::Platform::RUBY
         | 
| 12 12 | 
             
              s.files    = %w[
         | 
| 13 13 | 
             
                README
         | 
| @@ -18,18 +18,13 @@ Gem::Specification.new do |s| | |
| 18 18 | 
             
                ext/mysql.c
         | 
| 19 19 | 
             
                lib/mysqlplus.rb
         | 
| 20 20 | 
             
                mysqlplus.gemspec
         | 
| 21 | 
            -
             | 
| 22 | 
            -
                test/evented_test.rb
         | 
| 23 | 
            -
                test/native_threaded_test.rb
         | 
| 24 | 
            -
                test/test_all_hashes.rb
         | 
| 25 | 
            -
                test/test_failure.rb
         | 
| 26 | 
            -
                test/test_helper.rb
         | 
| 27 | 
            -
                test/test_many_requests.rb
         | 
| 28 | 
            -
                test/test_parsing_while_response_is_being_read.rb
         | 
| 29 | 
            -
                test/test_threaded_sequel.rb
         | 
| 30 | 
            -
              ]
         | 
| 21 | 
            +
              ] + Dir.glob('test/*')
         | 
| 31 22 | 
             
              s.rdoc_options = ["--main", "README"]
         | 
| 32 23 | 
             
              s.extra_rdoc_files = ["README"]
         | 
| 33 24 | 
             
              s.extensions << "ext/extconf.rb"
         | 
| 34 | 
            -
            end
         | 
| 35 25 |  | 
| 26 | 
            +
              if s.respond_to? :specification_version then
         | 
| 27 | 
            +
                current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
         | 
| 28 | 
            +
                s.specification_version = 3
         | 
| 29 | 
            +
              end
         | 
| 30 | 
            +
            end
         | 
| @@ -0,0 +1,9 @@ | |
| 1 | 
            +
            # I suppose if all the tests don't blow up, that probably means pass
         | 
| 2 | 
            +
            require 'mysqlplus'
         | 
| 3 | 
            +
            for file in Dir.glob('*_test.rb') do
         | 
| 4 | 
            +
             puts 'testing ' + file
         | 
| 5 | 
            +
             # fork so we don't run out of connections to the mysql db, as few tests ever clean up their old processes
         | 
| 6 | 
            +
             pid = Process.fork { load file }
         | 
| 7 | 
            +
             Process.wait(pid)
         | 
| 8 | 
            +
            end
         | 
| 9 | 
            +
            puts 'successful'
         | 
| @@ -1,9 +1,4 @@ | |
| 1 | 
            -
             | 
| 2 | 
            -
            # run it by substiting in a 'long' [many row] query for the query variable and toggling use_all_hashes here at the top
         | 
| 3 | 
            -
            # note that we load all the rows first, then run .all_hashes on the result [to see more easily the effect of all hashes]
         | 
| 4 | 
            -
            # on my machine and a 200_000 row table, it took 3.38s versus 3.65s
         | 
| 5 | 
            -
            require 'rubygems'
         | 
| 6 | 
            -
            require 'mysqlplus'
         | 
| 1 | 
            +
            require 'create_test_db'
         | 
| 7 2 |  | 
| 8 3 | 
             
            use_the_all_hashes_method = true 
         | 
| 9 4 |  | 
| @@ -13,16 +8,15 @@ $start = Time.now | |
| 13 8 |  | 
| 14 9 | 
             
            $connections = []
         | 
| 15 10 | 
             
            $count.times do  
         | 
| 16 | 
            -
              $connections << Mysql.real_connect('localhost','root', '', ' | 
| 11 | 
            +
              $connections << Mysql.real_connect('localhost','root', '', 'local_test_db')
         | 
| 17 12 | 
             
            end
         | 
| 18 13 |  | 
| 19 | 
            -
            puts 'connection pool ready'
         | 
| 20 14 |  | 
| 21 15 | 
             
            $threads = []
         | 
| 22 16 | 
             
            $count.times do |i|
         | 
| 23 17 | 
             
              $threads << Thread.new do
         | 
| 24 18 |  | 
| 25 | 
            -
                query = "select * from  | 
| 19 | 
            +
                query = "select * from test_table"
         | 
| 26 20 | 
             
                puts "sending query on connection #{i}"
         | 
| 27 21 | 
             
                conn = $connections[i]
         | 
| 28 22 | 
             
                result = conn.async_query(query)
         | 
| @@ -0,0 +1,22 @@ | |
| 1 | 
            +
            # If this script returns without the word pass
         | 
| 2 | 
            +
            # you may have compiled mysqlplus using ruby and
         | 
| 3 | 
            +
            # run it using a different version of ruby
         | 
| 4 | 
            +
             | 
| 5 | 
            +
            if RUBY_VERSION >= "1.9.1"
         | 
| 6 | 
            +
             require 'mysqlplus'
         | 
| 7 | 
            +
             require 'socket'
         | 
| 8 | 
            +
             require 'timeout'
         | 
| 9 | 
            +
             TCPServer.new '0.0.0.0', 8002
         | 
| 10 | 
            +
             Thread.new { 
         | 
| 11 | 
            +
              sleep 2
         | 
| 12 | 
            +
              print "pass"
         | 
| 13 | 
            +
              system("kill -9 #{Process.pid}")
         | 
| 14 | 
            +
             }
         | 
| 15 | 
            +
             Timeout::timeout(1) {
         | 
| 16 | 
            +
              # uncomment this line to do the 'real' test
         | 
| 17 | 
            +
              # which hangs otherwise (blows up if code is bad, otherwise hangs)
         | 
| 18 | 
            +
              Mysql.real_connect '127.0.0.1', 'root', 'pass', 'db', 8002
         | 
| 19 | 
            +
             }
         | 
| 20 | 
            +
             raise 'should never get here'
         | 
| 21 | 
            +
            end
         | 
| 22 | 
            +
             | 
| @@ -1,4 +1,3 @@ | |
| 1 | 
            -
            require 'rubygems'
         | 
| 2 1 | 
             
            require 'mysqlplus'
         | 
| 3 2 | 
             
            begin
         | 
| 4 3 | 
             
              Mysql.real_connect('fakehost','root', '', 'local_leadgen_dev')
         | 
| @@ -12,6 +11,7 @@ begin | |
| 12 11 | 
             
              Mysql.real_connect('localhost', 'root', 'pass', 'db', 3307)# bad port
         | 
| 13 12 | 
             
            rescue Mysql::Error
         | 
| 14 13 | 
             
            end
         | 
| 14 | 
            +
             | 
| 15 15 | 
             
            print "pass"
         | 
| 16 16 |  | 
| 17 17 |  | 
| @@ -0,0 +1,22 @@ | |
| 1 | 
            +
            # To run first execute:
         | 
| 2 | 
            +
            =begin
         | 
| 3 | 
            +
            create database local_test_db;
         | 
| 4 | 
            +
            use local_test_db;
         | 
| 5 | 
            +
            CREATE TABLE test_table (
         | 
| 6 | 
            +
                     c1 INT, 
         | 
| 7 | 
            +
                     c2 VARCHAR(20)
         | 
| 8 | 
            +
                 );
         | 
| 9 | 
            +
            =end
         | 
| 10 | 
            +
            # This script shows the effect of using .all_hashes instead of looping on each hash 
         | 
| 11 | 
            +
            # run it by substiting in a 'long' [many row] query for the query variable and toggling use_all_hashes here at the top
         | 
| 12 | 
            +
            # note that we load all the rows first, then run .all_hashes on the result [to see more easily the effect of all hashes]
         | 
| 13 | 
            +
            # on my machine and a 200_000 row table, it took 3.38s versus 3.65s for the old .each_hash way [note also that .each_hash is 
         | 
| 14 | 
            +
            # almost as fast, now, as .all_hashes--they've both been optimized]
         | 
| 15 | 
            +
            require 'mysqlplus'
         | 
| 16 | 
            +
             | 
| 17 | 
            +
            puts 'initing db'
         | 
| 18 | 
            +
            # init the DB
         | 
| 19 | 
            +
            conn = Mysql.real_connect('localhost', 'root', '', 'local_test_db')
         | 
| 20 | 
            +
            conn.query("delete from test_table")
         | 
| 21 | 
            +
            200_000.times {conn.query(" insert into test_table (c1, c2) values (3, 'ABCDEFG')")}
         | 
| 22 | 
            +
            puts 'connection pool ready'
         | 
| @@ -0,0 +1,40 @@ | |
| 1 | 
            +
            require 'mysqlplus'
         | 
| 2 | 
            +
            require 'benchmark'
         | 
| 3 | 
            +
             | 
| 4 | 
            +
            with_gc = Mysql.real_connect('localhost','root','','mysql')
         | 
| 5 | 
            +
            without_gc = Mysql.real_connect('localhost','root','','mysql')
         | 
| 6 | 
            +
            without_gc.disable_gc = true
         | 
| 7 | 
            +
             | 
| 8 | 
            +
            $gc_stats = []
         | 
| 9 | 
            +
             | 
| 10 | 
            +
            def countable_gc?
         | 
| 11 | 
            +
              GC.respond_to? :count
         | 
| 12 | 
            +
            end
         | 
| 13 | 
            +
             | 
| 14 | 
            +
            def gc_counts( label, scope )
         | 
| 15 | 
            +
              $gc_stats << "Objects #{scope} ( #{label} ) #{GC.count}"
         | 
| 16 | 
            +
            end
         | 
| 17 | 
            +
             | 
| 18 | 
            +
            def with_gc_counts( label )
         | 
| 19 | 
            +
              gc_counts( label, 'before' ) if countable_gc?
         | 
| 20 | 
            +
              yield
         | 
| 21 | 
            +
              gc_counts( label, 'after' ) if countable_gc?
         | 
| 22 | 
            +
            end
         | 
| 23 | 
            +
             | 
| 24 | 
            +
            n = 1000
         | 
| 25 | 
            +
             | 
| 26 | 
            +
            Benchmark.bmbm do |x|
         | 
| 27 | 
            +
              x.report( 'With GC' ) do
         | 
| 28 | 
            +
                with_gc_counts( 'With GC' ) do
         | 
| 29 | 
            +
                  n.times{ with_gc.c_async_query( 'SELECT * FROM user' ) }
         | 
| 30 | 
            +
                end
         | 
| 31 | 
            +
              end  
         | 
| 32 | 
            +
              GC.start  
         | 
| 33 | 
            +
              x.report( 'Without GC' ) do
         | 
| 34 | 
            +
                with_gc_counts( 'Without GC' ) do
         | 
| 35 | 
            +
                  n.times{ without_gc.c_async_query( 'SELECT * FROM user' ) }
         | 
| 36 | 
            +
                end
         | 
| 37 | 
            +
              end
         | 
| 38 | 
            +
            end
         | 
| 39 | 
            +
             | 
| 40 | 
            +
            puts $gc_stats.join( ' | ' )
         | 
| @@ -0,0 +1,34 @@ | |
| 1 | 
            +
            require File.dirname(__FILE__) + '/test_helper'
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            m = Mysql.real_connect('localhost','root')
         | 
| 4 | 
            +
            m.reconnect = true
         | 
| 5 | 
            +
            $count = 0
         | 
| 6 | 
            +
            class << m
         | 
| 7 | 
            +
              def safe_query( query )
         | 
| 8 | 
            +
                begin
         | 
| 9 | 
            +
                  send_query( query )
         | 
| 10 | 
            +
                rescue => e
         | 
| 11 | 
            +
                  $count += 1
         | 
| 12 | 
            +
                  puts e.message
         | 
| 13 | 
            +
                end
         | 
| 14 | 
            +
              end
         | 
| 15 | 
            +
              
         | 
| 16 | 
            +
            end
         | 
| 17 | 
            +
             | 
| 18 | 
            +
            m.safe_query( 'select sleep(1)' )
         | 
| 19 | 
            +
            m.safe_query( 'select sleep(1)' )#raises
         | 
| 20 | 
            +
            m.simulate_disconnect #fires mysql_library_end
         | 
| 21 | 
            +
            m.safe_query( 'select sleep(1)' )
         | 
| 22 | 
            +
            m.safe_query( 'select sleep(1)' )#raises
         | 
| 23 | 
            +
            m.close
         | 
| 24 | 
            +
            m.connect('localhost','root')
         | 
| 25 | 
            +
            m.safe_query( 'select sleep(1)' )
         | 
| 26 | 
            +
            m.safe_query( 'select sleep(1)' )#raises
         | 
| 27 | 
            +
            m.simulate_disconnect
         | 
| 28 | 
            +
            raise unless $count == 3
         | 
| 29 | 
            +
            m.safe_query( 'BEGIN' )
         | 
| 30 | 
            +
            m.safe_query( 'select sleep(1)' ) # raises
         | 
| 31 | 
            +
            m.get_result()
         | 
| 32 | 
            +
            m.safe_query( 'COMMIT' )
         | 
| 33 | 
            +
            m.get_result
         | 
| 34 | 
            +
            raise unless $count == 4
         | 
| @@ -5,8 +5,7 @@ | |
| 5 5 | 
             
            # from .82s to .62s
         | 
| 6 6 | 
             
            # you can experiment with it by changing the query here to be a long one, and toggling the do_the_use_query_optimization variable
         | 
| 7 7 | 
             
            # this also has the interesting property of 'freeing' Ruby to do thread changes mid-query.
         | 
| 8 | 
            -
            require ' | 
| 9 | 
            -
            require 'mysqlplus'
         | 
| 8 | 
            +
            require 'create_test_db'
         | 
| 10 9 |  | 
| 11 10 | 
             
            do_the_use_query_optimization = true
         | 
| 12 11 |  | 
| @@ -16,7 +15,7 @@ $start = Time.now | |
| 16 15 |  | 
| 17 16 | 
             
            $connections = []
         | 
| 18 17 | 
             
            $count.times do  
         | 
| 19 | 
            -
              $connections << Mysql.real_connect('localhost','root', '', ' | 
| 18 | 
            +
              $connections << Mysql.real_connect('localhost','root', '', 'local_test_db')
         | 
| 20 19 | 
             
            end
         | 
| 21 20 |  | 
| 22 21 | 
             
            puts 'connection pool ready'
         | 
| @@ -28,7 +27,7 @@ $count.times do |i| | |
| 28 27 | 
             
                puts "sending query on connection #{i}"
         | 
| 29 28 | 
             
                conn = $connections[i]
         | 
| 30 29 | 
             
                saved = []
         | 
| 31 | 
            -
                query = "select * from  | 
| 30 | 
            +
                query = "select * from test_table"
         | 
| 32 31 | 
             
                if do_the_use_query_optimization
         | 
| 33 32 | 
             
                  conn.query_with_result=false
         | 
| 34 33 | 
             
                  result = conn.async_query(query)
         | 
| @@ -0,0 +1,18 @@ | |
| 1 | 
            +
            require File.dirname(__FILE__) + '/test_helper'
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            $m = Mysql.real_connect('localhost','root')
         | 
| 4 | 
            +
            #$m.reconnect = true
         | 
| 5 | 
            +
             | 
| 6 | 
            +
            def assert_reconnected
         | 
| 7 | 
            +
              puts $m.reconnected?().inspect
         | 
| 8 | 
            +
              sleep 1
         | 
| 9 | 
            +
              yield
         | 
| 10 | 
            +
              puts $m.reconnected?().inspect
         | 
| 11 | 
            +
            end
         | 
| 12 | 
            +
             | 
| 13 | 
            +
            assert_reconnected do
         | 
| 14 | 
            +
              $m.simulate_disconnect
         | 
| 15 | 
            +
            end
         | 
| 16 | 
            +
            assert_reconnected do
         | 
| 17 | 
            +
              $m.close
         | 
| 18 | 
            +
            end
         | 
    
        data/test/test_helper.rb
    CHANGED
    
    
| @@ -1,7 +1,7 @@ | |
| 1 | 
            +
            require 'mysqlplus'
         | 
| 1 2 | 
             
            require 'rubygems'
         | 
| 2 3 | 
             
            require 'sequel'
         | 
| 3 4 |  | 
| 4 | 
            -
            require 'mysqlplus'
         | 
| 5 5 | 
             
            class Mysql
         | 
| 6 6 | 
             
              unless method_defined? :sync_query
         | 
| 7 7 | 
             
                alias :sync_query :query
         | 
| @@ -21,4 +21,4 @@ start = Time.now | |
| 21 21 | 
             
              end
         | 
| 22 22 | 
             
            end.map{|t| t.join }
         | 
| 23 23 |  | 
| 24 | 
            -
            p (Time.now - start)
         | 
| 24 | 
            +
            p (Time.now - start)
         | 
    
        metadata
    CHANGED
    
    | @@ -1,15 +1,20 @@ | |
| 1 1 | 
             
            --- !ruby/object:Gem::Specification 
         | 
| 2 2 | 
             
            name: mysqlplus
         | 
| 3 3 | 
             
            version: !ruby/object:Gem::Version 
         | 
| 4 | 
            -
               | 
| 4 | 
            +
              prerelease: false
         | 
| 5 | 
            +
              segments: 
         | 
| 6 | 
            +
              - 0
         | 
| 7 | 
            +
              - 1
         | 
| 8 | 
            +
              - 2
         | 
| 9 | 
            +
              version: 0.1.2
         | 
| 5 10 | 
             
            platform: ruby
         | 
| 6 11 | 
             
            authors: 
         | 
| 7 | 
            -
            - Muhammad A. Ali
         | 
| 12 | 
            +
            - Muhammad A. Ali et al
         | 
| 8 13 | 
             
            autorequire: 
         | 
| 9 14 | 
             
            bindir: bin
         | 
| 10 15 | 
             
            cert_chain: []
         | 
| 11 16 |  | 
| 12 | 
            -
            date: 2009-03-22 00:00:00 - | 
| 17 | 
            +
            date: 2009-03-22 00:00:00 -06:00
         | 
| 13 18 | 
             
            default_executable: 
         | 
| 14 19 | 
             
            dependencies: []
         | 
| 15 20 |  | 
| @@ -30,17 +35,26 @@ files: | |
| 30 35 | 
             
            - ext/mysql.c
         | 
| 31 36 | 
             
            - lib/mysqlplus.rb
         | 
| 32 37 | 
             
            - mysqlplus.gemspec
         | 
| 38 | 
            +
            - test/all_hashes_test.rb
         | 
| 39 | 
            +
            - test/async_query_with_block_test.rb
         | 
| 40 | 
            +
            - test/connect_failure2_test.rb
         | 
| 41 | 
            +
            - test/connect_failure_test.rb
         | 
| 42 | 
            +
            - test/create_test_db.rb
         | 
| 33 43 | 
             
            - test/c_threaded_test.rb
         | 
| 34 44 | 
             
            - test/evented_test.rb
         | 
| 45 | 
            +
            - test/gc_benchmark_test.rb
         | 
| 46 | 
            +
            - test/many_requests_test.rb
         | 
| 35 47 | 
             
            - test/native_threaded_test.rb
         | 
| 36 | 
            -
            - test/ | 
| 37 | 
            -
            - test/ | 
| 48 | 
            +
            - test/out_of_sync_test.rb
         | 
| 49 | 
            +
            - test/query_with_result_false_test.rb
         | 
| 50 | 
            +
            - test/reconnected_test.rb
         | 
| 51 | 
            +
            - test/RUN_ALL_TESTS.RB
         | 
| 38 52 | 
             
            - test/test_helper.rb
         | 
| 39 | 
            -
            - test/ | 
| 40 | 
            -
            - test/test_parsing_while_response_is_being_read.rb
         | 
| 41 | 
            -
            - test/test_threaded_sequel.rb
         | 
| 53 | 
            +
            - test/threaded_sequel_test.rb
         | 
| 42 54 | 
             
            has_rdoc: true
         | 
| 43 55 | 
             
            homepage: http://github.com/oldmoe/mysqlplus
         | 
| 56 | 
            +
            licenses: []
         | 
| 57 | 
            +
             | 
| 44 58 | 
             
            post_install_message: 
         | 
| 45 59 | 
             
            rdoc_options: 
         | 
| 46 60 | 
             
            - --main
         | 
| @@ -51,20 +65,22 @@ required_ruby_version: !ruby/object:Gem::Requirement | |
| 51 65 | 
             
              requirements: 
         | 
| 52 66 | 
             
              - - ">="
         | 
| 53 67 | 
             
                - !ruby/object:Gem::Version 
         | 
| 68 | 
            +
                  segments: 
         | 
| 69 | 
            +
                  - 0
         | 
| 54 70 | 
             
                  version: "0"
         | 
| 55 | 
            -
              version: 
         | 
| 56 71 | 
             
            required_rubygems_version: !ruby/object:Gem::Requirement 
         | 
| 57 72 | 
             
              requirements: 
         | 
| 58 73 | 
             
              - - ">="
         | 
| 59 74 | 
             
                - !ruby/object:Gem::Version 
         | 
| 75 | 
            +
                  segments: 
         | 
| 76 | 
            +
                  - 0
         | 
| 60 77 | 
             
                  version: "0"
         | 
| 61 | 
            -
              version: 
         | 
| 62 78 | 
             
            requirements: []
         | 
| 63 79 |  | 
| 64 80 | 
             
            rubyforge_project: 
         | 
| 65 | 
            -
            rubygems_version: 1.3. | 
| 81 | 
            +
            rubygems_version: 1.3.6
         | 
| 66 82 | 
             
            signing_key: 
         | 
| 67 | 
            -
            specification_version:  | 
| 83 | 
            +
            specification_version: 3
         | 
| 68 84 | 
             
            summary: Enhanced Ruby MySQL driver
         | 
| 69 85 | 
             
            test_files: []
         | 
| 70 86 |  |