pg 0.15.1 → 0.16.0
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.
- checksums.yaml +4 -4
- checksums.yaml.gz.sig +0 -0
- data.tar.gz.sig +1 -3
- data/ChangeLog +361 -59
- data/History.rdoc +31 -4
- data/Manifest.txt +4 -0
- data/Rakefile +30 -10
- data/ext/errorcodes.def +931 -0
- data/ext/errorcodes.rb +45 -0
- data/ext/errorcodes.txt +463 -0
- data/ext/extconf.rb +11 -5
- data/ext/gvl_wrappers.c +6 -0
- data/ext/gvl_wrappers.h +47 -21
- data/ext/pg.c +30 -10
- data/ext/pg.h +30 -0
- data/ext/pg_connection.c +105 -45
- data/ext/pg_errors.c +89 -0
- data/ext/pg_result.c +49 -68
- data/lib/pg.rb +2 -2
- data/spec/lib/helpers.rb +11 -2
- data/spec/pg/connection_spec.rb +113 -8
- data/spec/pg/result_spec.rb +69 -2
- data/spec/pg_spec.rb +13 -0
- metadata +11 -5
- metadata.gz.sig +0 -0
    
        data/ext/pg_errors.c
    ADDED
    
    | @@ -0,0 +1,89 @@ | |
| 1 | 
            +
            /*
         | 
| 2 | 
            +
             * pg_errors.c - Definition and lookup of error classes.
         | 
| 3 | 
            +
             *
         | 
| 4 | 
            +
             */
         | 
| 5 | 
            +
             | 
| 6 | 
            +
            #include "pg.h"
         | 
| 7 | 
            +
             | 
| 8 | 
            +
            VALUE rb_hErrors;
         | 
| 9 | 
            +
            VALUE rb_ePGerror;
         | 
| 10 | 
            +
            VALUE rb_eServerError;
         | 
| 11 | 
            +
            VALUE rb_eUnableToSend;
         | 
| 12 | 
            +
            VALUE rb_eConnectionBad;
         | 
| 13 | 
            +
             | 
| 14 | 
            +
            static VALUE
         | 
| 15 | 
            +
            define_error_class(const char *name, const char *baseclass_code)
         | 
| 16 | 
            +
            {
         | 
| 17 | 
            +
            	VALUE baseclass = rb_eServerError;
         | 
| 18 | 
            +
            	if(baseclass_code)
         | 
| 19 | 
            +
            	{
         | 
| 20 | 
            +
            		baseclass = rb_hash_aref( rb_hErrors, rb_str_new2(baseclass_code) );
         | 
| 21 | 
            +
            	}
         | 
| 22 | 
            +
            	return rb_define_class_under( rb_mPG, name, baseclass );
         | 
| 23 | 
            +
            }
         | 
| 24 | 
            +
             | 
| 25 | 
            +
            static void
         | 
| 26 | 
            +
            register_error_class(const char *code, VALUE klass)
         | 
| 27 | 
            +
            {
         | 
| 28 | 
            +
            	rb_hash_aset( rb_hErrors, rb_str_new2(code), klass );
         | 
| 29 | 
            +
            }
         | 
| 30 | 
            +
             | 
| 31 | 
            +
            /* Find a proper error class for the given SQLSTATE string
         | 
| 32 | 
            +
             */
         | 
| 33 | 
            +
            VALUE
         | 
| 34 | 
            +
            lookup_error_class(const char *sqlstate)
         | 
| 35 | 
            +
            {
         | 
| 36 | 
            +
            	VALUE klass;
         | 
| 37 | 
            +
             | 
| 38 | 
            +
            	if(sqlstate)
         | 
| 39 | 
            +
            	{
         | 
| 40 | 
            +
            		/* Find the proper error class by the 5-characters SQLSTATE. */
         | 
| 41 | 
            +
            		klass = rb_hash_aref( rb_hErrors, rb_str_new2(sqlstate) );
         | 
| 42 | 
            +
            		if(NIL_P(klass))
         | 
| 43 | 
            +
            		{
         | 
| 44 | 
            +
            			/* The given SQLSTATE couldn't be found. This might happen, if
         | 
| 45 | 
            +
            			 * the server side uses a newer version than the client.
         | 
| 46 | 
            +
            			 * Try to find a error class by using the 2-characters SQLSTATE.
         | 
| 47 | 
            +
            			 */
         | 
| 48 | 
            +
            			klass = rb_hash_aref( rb_hErrors, rb_str_new(sqlstate, 2) );
         | 
| 49 | 
            +
            			if(NIL_P(klass))
         | 
| 50 | 
            +
            			{
         | 
| 51 | 
            +
            				/* Also the 2-characters SQLSTATE is unknown.
         | 
| 52 | 
            +
            				 * Use the generic server error instead.
         | 
| 53 | 
            +
            				 */
         | 
| 54 | 
            +
            				klass = rb_eServerError;
         | 
| 55 | 
            +
            			}
         | 
| 56 | 
            +
            		}
         | 
| 57 | 
            +
            	}
         | 
| 58 | 
            +
            	else
         | 
| 59 | 
            +
            	{
         | 
| 60 | 
            +
            		/* Unable to retrieve the PG_DIAG_SQLSTATE.
         | 
| 61 | 
            +
            		 * Use the generic error instead.
         | 
| 62 | 
            +
            		 */
         | 
| 63 | 
            +
            		klass = rb_eUnableToSend;
         | 
| 64 | 
            +
            	}
         | 
| 65 | 
            +
             | 
| 66 | 
            +
            	return klass;
         | 
| 67 | 
            +
            }
         | 
| 68 | 
            +
             | 
| 69 | 
            +
            void
         | 
| 70 | 
            +
            init_pg_errors()
         | 
| 71 | 
            +
            {
         | 
| 72 | 
            +
            	rb_hErrors = rb_hash_new();
         | 
| 73 | 
            +
            	rb_define_const( rb_mPG, "ERROR_CLASSES", rb_hErrors );
         | 
| 74 | 
            +
             | 
| 75 | 
            +
            	rb_ePGerror = rb_define_class_under( rb_mPG, "Error", rb_eStandardError );
         | 
| 76 | 
            +
             | 
| 77 | 
            +
            	/*************************
         | 
| 78 | 
            +
            	 *  PG::Error
         | 
| 79 | 
            +
            	 *************************/
         | 
| 80 | 
            +
            	rb_define_alias( rb_ePGerror, "error", "message" );
         | 
| 81 | 
            +
            	rb_define_attr( rb_ePGerror, "connection", 1, 0 );
         | 
| 82 | 
            +
            	rb_define_attr( rb_ePGerror, "result", 1, 0 );
         | 
| 83 | 
            +
             | 
| 84 | 
            +
            	rb_eServerError = rb_define_class_under( rb_mPG, "ServerError", rb_ePGerror );
         | 
| 85 | 
            +
            	rb_eUnableToSend = rb_define_class_under( rb_mPG, "UnableToSend", rb_ePGerror );
         | 
| 86 | 
            +
            	rb_eConnectionBad = rb_define_class_under( rb_mPG, "ConnectionBad", rb_ePGerror );
         | 
| 87 | 
            +
             | 
| 88 | 
            +
            	#include "errorcodes.def"
         | 
| 89 | 
            +
            }
         | 
    
        data/ext/pg_result.c
    CHANGED
    
    | @@ -1,6 +1,6 @@ | |
| 1 1 | 
             
            /*
         | 
| 2 2 | 
             
             * pg_result.c - PG::Result class extension
         | 
| 3 | 
            -
             * $Id: pg_result.c,v  | 
| 3 | 
            +
             * $Id: pg_result.c,v de6bee6a208c 2013/07/18 13:47:31 kanis $
         | 
| 4 4 | 
             
             *
         | 
| 5 5 | 
             
             */
         | 
| 6 6 |  | 
| @@ -44,13 +44,14 @@ pg_new_result(PGresult *result, VALUE rb_pgconn) | |
| 44 44 | 
             
            VALUE
         | 
| 45 45 | 
             
            pg_result_check( VALUE self )
         | 
| 46 46 | 
             
            {
         | 
| 47 | 
            -
            	VALUE error, exception;
         | 
| 47 | 
            +
            	VALUE error, exception, klass;
         | 
| 48 48 | 
             
            	VALUE rb_pgconn = rb_iv_get( self, "@connection" );
         | 
| 49 49 | 
             
            	PGconn *conn = pg_get_pgconn(rb_pgconn);
         | 
| 50 50 | 
             
            	PGresult *result;
         | 
| 51 51 | 
             
            #ifdef M17N_SUPPORTED
         | 
| 52 52 | 
             
            	rb_encoding *enc = pg_conn_enc_get( conn );
         | 
| 53 53 | 
             
            #endif
         | 
| 54 | 
            +
            	char * sqlstate;
         | 
| 54 55 |  | 
| 55 56 | 
             
            	Data_Get_Struct(self, PGresult, result);
         | 
| 56 57 |  | 
| @@ -87,9 +88,12 @@ pg_result_check( VALUE self ) | |
| 87 88 | 
             
            #ifdef M17N_SUPPORTED
         | 
| 88 89 | 
             
            	rb_enc_set_index( error, rb_enc_to_index(enc) );
         | 
| 89 90 | 
             
            #endif
         | 
| 90 | 
            -
             | 
| 91 | 
            +
             | 
| 92 | 
            +
            	sqlstate = PQresultErrorField( result, PG_DIAG_SQLSTATE );
         | 
| 93 | 
            +
            	klass = lookup_error_class( sqlstate );
         | 
| 94 | 
            +
            	exception = rb_exc_new3( klass, error );
         | 
| 91 95 | 
             
            	rb_iv_set( exception, "@connection", rb_pgconn );
         | 
| 92 | 
            -
            	rb_iv_set( exception, "@result", self );
         | 
| 96 | 
            +
            	rb_iv_set( exception, "@result", result ? self : Qnil );
         | 
| 93 97 | 
             
            	rb_exc_raise( exception );
         | 
| 94 98 |  | 
| 95 99 | 
             
            	/* Not reached */
         | 
| @@ -245,18 +249,18 @@ pgresult_error_message(VALUE self) | |
| 245 249 | 
             
             *       conn.exec( "SELECT * FROM nonexistant_table" )
         | 
| 246 250 | 
             
             *   rescue PG::Error => err
         | 
| 247 251 | 
             
             *       p [
         | 
| 248 | 
            -
             *           result.error_field( PG::Result::PG_DIAG_SEVERITY ),
         | 
| 249 | 
            -
             *           result.error_field( PG::Result::PG_DIAG_SQLSTATE ),
         | 
| 250 | 
            -
             *           result.error_field( PG::Result::PG_DIAG_MESSAGE_PRIMARY ),
         | 
| 251 | 
            -
             *           result.error_field( PG::Result::PG_DIAG_MESSAGE_DETAIL ),
         | 
| 252 | 
            -
             *           result.error_field( PG::Result::PG_DIAG_MESSAGE_HINT ),
         | 
| 253 | 
            -
             *           result.error_field( PG::Result::PG_DIAG_STATEMENT_POSITION ),
         | 
| 254 | 
            -
             *           result.error_field( PG::Result::PG_DIAG_INTERNAL_POSITION ),
         | 
| 255 | 
            -
             *           result.error_field( PG::Result::PG_DIAG_INTERNAL_QUERY ),
         | 
| 256 | 
            -
             *           result.error_field( PG::Result::PG_DIAG_CONTEXT ),
         | 
| 257 | 
            -
             *           result.error_field( PG::Result::PG_DIAG_SOURCE_FILE ),
         | 
| 258 | 
            -
             *           result.error_field( PG::Result::PG_DIAG_SOURCE_LINE ),
         | 
| 259 | 
            -
             *           result.error_field( PG::Result::PG_DIAG_SOURCE_FUNCTION ),
         | 
| 252 | 
            +
             *           err.result.error_field( PG::Result::PG_DIAG_SEVERITY ),
         | 
| 253 | 
            +
             *           err.result.error_field( PG::Result::PG_DIAG_SQLSTATE ),
         | 
| 254 | 
            +
             *           err.result.error_field( PG::Result::PG_DIAG_MESSAGE_PRIMARY ),
         | 
| 255 | 
            +
             *           err.result.error_field( PG::Result::PG_DIAG_MESSAGE_DETAIL ),
         | 
| 256 | 
            +
             *           err.result.error_field( PG::Result::PG_DIAG_MESSAGE_HINT ),
         | 
| 257 | 
            +
             *           err.result.error_field( PG::Result::PG_DIAG_STATEMENT_POSITION ),
         | 
| 258 | 
            +
             *           err.result.error_field( PG::Result::PG_DIAG_INTERNAL_POSITION ),
         | 
| 259 | 
            +
             *           err.result.error_field( PG::Result::PG_DIAG_INTERNAL_QUERY ),
         | 
| 260 | 
            +
             *           err.result.error_field( PG::Result::PG_DIAG_CONTEXT ),
         | 
| 261 | 
            +
             *           err.result.error_field( PG::Result::PG_DIAG_SOURCE_FILE ),
         | 
| 262 | 
            +
             *           err.result.error_field( PG::Result::PG_DIAG_SOURCE_LINE ),
         | 
| 263 | 
            +
             *           err.result.error_field( PG::Result::PG_DIAG_SOURCE_FUNCTION ),
         | 
| 260 264 | 
             
             *       ]
         | 
| 261 265 | 
             
             *   end
         | 
| 262 266 | 
             
             *
         | 
| @@ -510,6 +514,31 @@ pgresult_fsize(VALUE self, VALUE index) | |
| 510 514 | 
             
            	return INT2NUM(PQfsize(result, i));
         | 
| 511 515 | 
             
            }
         | 
| 512 516 |  | 
| 517 | 
            +
             | 
| 518 | 
            +
            static VALUE
         | 
| 519 | 
            +
            pgresult_value(VALUE self, PGresult *result, int tuple_num, int field_num)
         | 
| 520 | 
            +
            {
         | 
| 521 | 
            +
                VALUE val;
         | 
| 522 | 
            +
                if ( PQgetisnull(result, tuple_num, field_num) ) {
         | 
| 523 | 
            +
                    return Qnil;
         | 
| 524 | 
            +
                }
         | 
| 525 | 
            +
                else {
         | 
| 526 | 
            +
                    val = rb_tainted_str_new( PQgetvalue(result, tuple_num, field_num ),
         | 
| 527 | 
            +
                                              PQgetlength(result, tuple_num, field_num) );
         | 
| 528 | 
            +
             | 
| 529 | 
            +
            #ifdef M17N_SUPPORTED
         | 
| 530 | 
            +
                    /* associate client encoding for text format only */
         | 
| 531 | 
            +
                    if ( 0 == PQfformat(result, field_num) ) {
         | 
| 532 | 
            +
                        ASSOCIATE_INDEX( val, self );
         | 
| 533 | 
            +
                    } else {
         | 
| 534 | 
            +
                        rb_enc_associate( val, rb_ascii8bit_encoding() );
         | 
| 535 | 
            +
                    }
         | 
| 536 | 
            +
            #endif
         | 
| 537 | 
            +
             | 
| 538 | 
            +
                    return val;
         | 
| 539 | 
            +
                }
         | 
| 540 | 
            +
            }
         | 
| 541 | 
            +
             | 
| 513 542 | 
             
            /*
         | 
| 514 543 | 
             
             * call-seq:
         | 
| 515 544 | 
             
             *    res.getvalue( tup_num, field_num )
         | 
| @@ -520,7 +549,6 @@ pgresult_fsize(VALUE self, VALUE index) | |
| 520 549 | 
             
            static VALUE
         | 
| 521 550 | 
             
            pgresult_getvalue(VALUE self, VALUE tup_num, VALUE field_num)
         | 
| 522 551 | 
             
            {
         | 
| 523 | 
            -
            	VALUE val;
         | 
| 524 552 | 
             
            	PGresult *result;
         | 
| 525 553 | 
             
            	int i = NUM2INT(tup_num);
         | 
| 526 554 | 
             
            	int j = NUM2INT(field_num);
         | 
| @@ -532,21 +560,7 @@ pgresult_getvalue(VALUE self, VALUE tup_num, VALUE field_num) | |
| 532 560 | 
             
            	if(j < 0 || j >= PQnfields(result)) {
         | 
| 533 561 | 
             
            		rb_raise(rb_eArgError,"invalid field number %d", j);
         | 
| 534 562 | 
             
            	}
         | 
| 535 | 
            -
            	 | 
| 536 | 
            -
            		return Qnil;
         | 
| 537 | 
            -
            	val = rb_tainted_str_new(PQgetvalue(result, i, j),
         | 
| 538 | 
            -
            				PQgetlength(result, i, j));
         | 
| 539 | 
            -
             | 
| 540 | 
            -
            #ifdef M17N_SUPPORTED
         | 
| 541 | 
            -
            	/* associate client encoding for text format only */
         | 
| 542 | 
            -
            	if ( 0 == PQfformat(result, j) ) {
         | 
| 543 | 
            -
            		ASSOCIATE_INDEX( val, self );
         | 
| 544 | 
            -
            	} else {
         | 
| 545 | 
            -
            		rb_enc_associate( val, rb_ascii8bit_encoding() );
         | 
| 546 | 
            -
            	}
         | 
| 547 | 
            -
            #endif
         | 
| 548 | 
            -
             | 
| 549 | 
            -
            	return val;
         | 
| 563 | 
            +
            	return pgresult_value(self, result, i, j);
         | 
| 550 564 | 
             
            }
         | 
| 551 565 |  | 
| 552 566 | 
             
            /*
         | 
| @@ -696,7 +710,7 @@ pgresult_aref(VALUE self, VALUE index) | |
| 696 710 | 
             
            	PGresult *result = pgresult_get(self);
         | 
| 697 711 | 
             
            	int tuple_num = NUM2INT(index);
         | 
| 698 712 | 
             
            	int field_num;
         | 
| 699 | 
            -
            	VALUE fname | 
| 713 | 
            +
            	VALUE fname;
         | 
| 700 714 | 
             
            	VALUE tuple;
         | 
| 701 715 |  | 
| 702 716 | 
             
            	if ( tuple_num < 0 || tuple_num >= PQntuples(result) )
         | 
| @@ -706,24 +720,7 @@ pgresult_aref(VALUE self, VALUE index) | |
| 706 720 | 
             
            	for ( field_num = 0; field_num < PQnfields(result); field_num++ ) {
         | 
| 707 721 | 
             
            		fname = rb_tainted_str_new2( PQfname(result,field_num) );
         | 
| 708 722 | 
             
            		ASSOCIATE_INDEX(fname, self);
         | 
| 709 | 
            -
            		 | 
| 710 | 
            -
            			rb_hash_aset( tuple, fname, Qnil );
         | 
| 711 | 
            -
            		}
         | 
| 712 | 
            -
            		else {
         | 
| 713 | 
            -
            			val = rb_tainted_str_new( PQgetvalue(result, tuple_num, field_num ),
         | 
| 714 | 
            -
            			                          PQgetlength(result, tuple_num, field_num) );
         | 
| 715 | 
            -
             | 
| 716 | 
            -
            #ifdef M17N_SUPPORTED
         | 
| 717 | 
            -
            			/* associate client encoding for text format only */
         | 
| 718 | 
            -
            			if ( 0 == PQfformat(result, field_num) ) {
         | 
| 719 | 
            -
            				ASSOCIATE_INDEX( val, self );
         | 
| 720 | 
            -
            			} else {
         | 
| 721 | 
            -
            				rb_enc_associate( val, rb_ascii8bit_encoding() );
         | 
| 722 | 
            -
            			}
         | 
| 723 | 
            -
            #endif
         | 
| 724 | 
            -
             | 
| 725 | 
            -
            			rb_hash_aset( tuple, fname, val );
         | 
| 726 | 
            -
            		}
         | 
| 723 | 
            +
            		rb_hash_aset( tuple, fname, pgresult_value(self, result, tuple_num, field_num) );
         | 
| 727 724 | 
             
            	}
         | 
| 728 725 | 
             
            	return tuple;
         | 
| 729 726 | 
             
            }
         | 
| @@ -748,23 +745,7 @@ pgresult_each_row(VALUE self) | |
| 748 745 |  | 
| 749 746 | 
             
            		/* populate the row */
         | 
| 750 747 | 
             
            		for ( field = 0; field < num_fields; field++ ) {
         | 
| 751 | 
            -
             | 
| 752 | 
            -
            				rb_ary_store( new_row, field, Qnil );
         | 
| 753 | 
            -
            			}
         | 
| 754 | 
            -
            			else {
         | 
| 755 | 
            -
            				VALUE val = rb_tainted_str_new( PQgetvalue(result, row, field),
         | 
| 756 | 
            -
            				                                PQgetlength(result, row, field) );
         | 
| 757 | 
            -
             | 
| 758 | 
            -
            #ifdef M17N_SUPPORTED
         | 
| 759 | 
            -
            				/* associate client encoding for text format only */
         | 
| 760 | 
            -
            				if ( 0 == PQfformat(result, field) ) {
         | 
| 761 | 
            -
            					ASSOCIATE_INDEX( val, self );
         | 
| 762 | 
            -
            				} else {
         | 
| 763 | 
            -
            					rb_enc_associate( val, rb_ascii8bit_encoding() );
         | 
| 764 | 
            -
            				}
         | 
| 765 | 
            -
            #endif
         | 
| 766 | 
            -
            				rb_ary_store( new_row, field, val );
         | 
| 767 | 
            -
            			}
         | 
| 748 | 
            +
            		    rb_ary_store( new_row, field, pgresult_value(self, result, row, field) );
         | 
| 768 749 | 
             
            		}
         | 
| 769 750 | 
             
            		rb_yield( new_row );
         | 
| 770 751 | 
             
            	}
         | 
    
        data/lib/pg.rb
    CHANGED
    
    | @@ -19,10 +19,10 @@ end | |
| 19 19 | 
             
            module PG
         | 
| 20 20 |  | 
| 21 21 | 
             
            	# Library version
         | 
| 22 | 
            -
            	VERSION = '0. | 
| 22 | 
            +
            	VERSION = '0.16.0'
         | 
| 23 23 |  | 
| 24 24 | 
             
            	# VCS revision
         | 
| 25 | 
            -
            	REVISION = %q$Revision:  | 
| 25 | 
            +
            	REVISION = %q$Revision: 4e0606f5f5aa $
         | 
| 26 26 |  | 
| 27 27 |  | 
| 28 28 | 
             
            	### Get the PG library version. If +include_buildnum+ is +true+, include the build ID.
         | 
    
        data/spec/lib/helpers.rb
    CHANGED
    
    | @@ -247,6 +247,13 @@ module PG::TestingHelpers | |
| 247 247 | 
             
            			end
         | 
| 248 248 | 
             
            		end
         | 
| 249 249 | 
             
            	end
         | 
| 250 | 
            +
             | 
| 251 | 
            +
            	def connection_string_should_contain_application_name(conn_args, app_name)
         | 
| 252 | 
            +
            		conn_name = conn_args.match(/application_name='(.*)'/)[1]
         | 
| 253 | 
            +
            		conn_name.should include(app_name[0..10])
         | 
| 254 | 
            +
            		conn_name.should include(app_name[-10..-1])
         | 
| 255 | 
            +
            		conn_name.length.should <= 64
         | 
| 256 | 
            +
            	end
         | 
| 250 257 | 
             
            end
         | 
| 251 258 |  | 
| 252 259 |  | 
| @@ -270,9 +277,11 @@ RSpec.configure do |config| | |
| 270 277 | 
             
            		PG::Connection.instance_methods.map( &:to_sym ).include?( :escape_literal )
         | 
| 271 278 |  | 
| 272 279 | 
             
            	if !PG.respond_to?( :library_version )
         | 
| 273 | 
            -
            		config.filter_run_excluding( :postgresql_91, :postgresql_92 )
         | 
| 280 | 
            +
            		config.filter_run_excluding( :postgresql_91, :postgresql_92, :postgresql_93 )
         | 
| 274 281 | 
             
            	elsif PG.library_version < 90200
         | 
| 275 | 
            -
            		config.filter_run_excluding( :postgresql_92 )
         | 
| 282 | 
            +
            		config.filter_run_excluding( :postgresql_92, :postgresql_93 )
         | 
| 283 | 
            +
            	elsif PG.library_version < 90300
         | 
| 284 | 
            +
            		config.filter_run_excluding( :postgresql_93 )
         | 
| 276 285 | 
             
            	end
         | 
| 277 286 | 
             
            end
         | 
| 278 287 |  | 
    
        data/spec/pg/connection_spec.rb
    CHANGED
    
    | @@ -177,6 +177,11 @@ describe PG::Connection do | |
| 177 177 | 
             
            		conn.should be_finished()
         | 
| 178 178 | 
             
            	end
         | 
| 179 179 |  | 
| 180 | 
            +
            	it "raises proper error when sending fails" do
         | 
| 181 | 
            +
            		conn = described_class.connect_start( '127.0.0.1', 54320, "", "", "me", "xxxx", "somedb" )
         | 
| 182 | 
            +
            		expect{ conn.exec 'SELECT 1' }.to raise_error(PG::UnableToSend, /no connection/)
         | 
| 183 | 
            +
            	end
         | 
| 184 | 
            +
             | 
| 180 185 | 
             
            	it "doesn't leave stale server connections after finish" do
         | 
| 181 186 | 
             
            		described_class.connect(@conninfo).finish
         | 
| 182 187 | 
             
            		sleep 0.5
         | 
| @@ -257,6 +262,18 @@ describe PG::Connection do | |
| 257 262 | 
             
            		error.should == true
         | 
| 258 263 | 
             
            	end
         | 
| 259 264 |  | 
| 265 | 
            +
            	it "can stop a thread that runs a blocking query" do
         | 
| 266 | 
            +
            		start = Time.now
         | 
| 267 | 
            +
            		t = Thread.new do
         | 
| 268 | 
            +
            			@conn.async_exec( 'select pg_sleep(10)' )
         | 
| 269 | 
            +
            		end
         | 
| 270 | 
            +
            		sleep 0.1
         | 
| 271 | 
            +
             | 
| 272 | 
            +
            		t.kill
         | 
| 273 | 
            +
            		t.join
         | 
| 274 | 
            +
            		(Time.now - start).should < 10
         | 
| 275 | 
            +
            	end
         | 
| 276 | 
            +
             | 
| 260 277 | 
             
            	it "automatically rolls back a transaction started with Connection#transaction if an exception " +
         | 
| 261 278 | 
             
            	   "is raised" do
         | 
| 262 279 | 
             
            		# abort the per-example transaction so we can test our own
         | 
| @@ -276,6 +293,16 @@ describe PG::Connection do | |
| 276 293 | 
             
            		res.ntuples.should == 0
         | 
| 277 294 | 
             
            	end
         | 
| 278 295 |  | 
| 296 | 
            +
            	it "returns the block result from Connection#transaction" do
         | 
| 297 | 
            +
            		# abort the per-example transaction so we can test our own
         | 
| 298 | 
            +
            		@conn.exec( 'ROLLBACK' )
         | 
| 299 | 
            +
             | 
| 300 | 
            +
            		res = @conn.transaction do
         | 
| 301 | 
            +
            			"transaction result"
         | 
| 302 | 
            +
            		end
         | 
| 303 | 
            +
            		res.should == "transaction result"
         | 
| 304 | 
            +
            	end
         | 
| 305 | 
            +
             | 
| 279 306 | 
             
            	it "not read past the end of a large object" do
         | 
| 280 307 | 
             
            		@conn.transaction do
         | 
| 281 308 | 
             
            			oid = @conn.lo_create( 0 )
         | 
| @@ -400,6 +427,21 @@ describe PG::Connection do | |
| 400 427 | 
             
            		@conn.exec( 'UNLISTEN woo' )
         | 
| 401 428 | 
             
            	end
         | 
| 402 429 |  | 
| 430 | 
            +
            	it "can receive notices while waiting for NOTIFY without exceeding the timeout", :postgresql_90 do
         | 
| 431 | 
            +
            		notices = []
         | 
| 432 | 
            +
            		@conn.set_notice_processor do |msg|
         | 
| 433 | 
            +
            			notices << [msg, Time.now]
         | 
| 434 | 
            +
            		end
         | 
| 435 | 
            +
            		st = Time.now
         | 
| 436 | 
            +
            		@conn.send_query "SELECT pg_sleep(0.5); do $$ BEGIN RAISE NOTICE 'woohoo'; END; $$ LANGUAGE plpgsql;"
         | 
| 437 | 
            +
            		@conn.wait_for_notify( 1 ).should be_nil
         | 
| 438 | 
            +
            		notices.first.should_not be_nil
         | 
| 439 | 
            +
            		et = Time.now
         | 
| 440 | 
            +
            		(et - notices.first[1]).should >= 0.4
         | 
| 441 | 
            +
            		(et - st).should >= 0.9
         | 
| 442 | 
            +
            		(et - st).should < 1.4
         | 
| 443 | 
            +
            	end
         | 
| 444 | 
            +
             | 
| 403 445 | 
             
            	it "yields the result if block is given to exec" do
         | 
| 404 446 | 
             
            		rval = @conn.exec( "select 1234::int as a union select 5678::int as a" ) do |result|
         | 
| 405 447 | 
             
            			values = []
         | 
| @@ -543,7 +585,7 @@ describe PG::Connection do | |
| 543 585 | 
             
            		conn = PG.connect( @conninfo )
         | 
| 544 586 |  | 
| 545 587 | 
             
            		conn.finish
         | 
| 546 | 
            -
            		expect { conn.finish }.to raise_error( PG:: | 
| 588 | 
            +
            		expect { conn.finish }.to raise_error( PG::ConnectionBad, /connection is closed/i )
         | 
| 547 589 | 
             
            	end
         | 
| 548 590 |  | 
| 549 591 | 
             
            	it "closes the IO fetched from #socket_io when the connection is closed", :without_transaction, :socket_io do
         | 
| @@ -551,7 +593,7 @@ describe PG::Connection do | |
| 551 593 | 
             
            		io = conn.socket_io
         | 
| 552 594 | 
             
            		conn.finish
         | 
| 553 595 | 
             
            		io.should be_closed()
         | 
| 554 | 
            -
            		expect { conn.socket_io }.to raise_error( PG:: | 
| 596 | 
            +
            		expect { conn.socket_io }.to raise_error( PG::ConnectionBad, /connection is closed/i )
         | 
| 555 597 | 
             
            	end
         | 
| 556 598 |  | 
| 557 599 | 
             
            	it "closes the IO fetched from #socket_io when the connection is reset", :without_transaction, :socket_io do
         | 
| @@ -563,6 +605,16 @@ describe PG::Connection do | |
| 563 605 | 
             
            		conn.finish
         | 
| 564 606 | 
             
            	end
         | 
| 565 607 |  | 
| 608 | 
            +
            	it "block should raise ConnectionBad for a closed connection" do
         | 
| 609 | 
            +
            		serv = TCPServer.new( '127.0.0.1', 54320 )
         | 
| 610 | 
            +
            		conn = described_class.connect_start( '127.0.0.1', 54320, "", "", "me", "xxxx", "somedb" )
         | 
| 611 | 
            +
            		while [PG::CONNECTION_STARTED, PG::CONNECTION_MADE].include?(conn.connect_poll)
         | 
| 612 | 
            +
            			sleep 0.1
         | 
| 613 | 
            +
            		end
         | 
| 614 | 
            +
            		serv.close
         | 
| 615 | 
            +
            		expect{ conn.block }.to raise_error(PG::ConnectionBad, /server closed the connection unexpectedly/)
         | 
| 616 | 
            +
            		expect{ conn.block }.to raise_error(PG::ConnectionBad, /can't get socket descriptor/)
         | 
| 617 | 
            +
            	end
         | 
| 566 618 |  | 
| 567 619 | 
             
            	context "under PostgreSQL 9", :postgresql_90 do
         | 
| 568 620 |  | 
| @@ -571,14 +623,16 @@ describe PG::Connection do | |
| 571 623 | 
             
            		end
         | 
| 572 624 |  | 
| 573 625 | 
             
            		it "sets the fallback_application_name on new connections" do
         | 
| 574 | 
            -
            			PG::Connection.parse_connect_args( 'dbname=test' ) | 
| 626 | 
            +
            			conn_string = PG::Connection.parse_connect_args( 'dbname=test' )
         | 
| 627 | 
            +
            			connection_string_should_contain_application_name(conn_string, $0)
         | 
| 575 628 | 
             
            		end
         | 
| 576 629 |  | 
| 577 630 | 
             
            		it "sets a shortened fallback_application_name on new connections" do
         | 
| 578 631 | 
             
            			old_0 = $0
         | 
| 579 632 | 
             
            			begin
         | 
| 580 633 | 
             
            				$0 = "/this/is/a/very/long/path/with/many/directories/to/our/beloved/ruby"
         | 
| 581 | 
            -
            				PG::Connection.parse_connect_args( 'dbname=test' ) | 
| 634 | 
            +
            				conn_string = PG::Connection.parse_connect_args( 'dbname=test' )
         | 
| 635 | 
            +
            				connection_string_should_contain_application_name(conn_string, $0)
         | 
| 582 636 | 
             
            			ensure
         | 
| 583 637 | 
             
            				$0 = old_0
         | 
| 584 638 | 
             
            			end
         | 
| @@ -874,17 +928,53 @@ describe PG::Connection do | |
| 874 928 | 
             
            			end
         | 
| 875 929 |  | 
| 876 930 | 
             
            			it "uses the client encoding for escaped string" do
         | 
| 877 | 
            -
            				original = "string to escape".force_encoding( " | 
| 931 | 
            +
            				original = "string to\0 escape".force_encoding( "iso8859-1" )
         | 
| 878 932 | 
             
            				@conn.set_client_encoding( "euc_jp" )
         | 
| 879 933 | 
             
            				escaped  = @conn.escape( original )
         | 
| 880 934 | 
             
            				escaped.encoding.should == Encoding::EUC_JP
         | 
| 935 | 
            +
            				escaped.should == "string to"
         | 
| 881 936 | 
             
            			end
         | 
| 882 937 |  | 
| 883 | 
            -
            			it " | 
| 884 | 
            -
            				original = "string to\0 escape"
         | 
| 938 | 
            +
            			it "uses the client encoding for escaped literal", :postgresql_90 do
         | 
| 939 | 
            +
            				original = "string to\0 escape".force_encoding( "iso8859-1" )
         | 
| 940 | 
            +
            				@conn.set_client_encoding( "euc_jp" )
         | 
| 885 941 | 
             
            				escaped  = @conn.escape_literal( original )
         | 
| 942 | 
            +
            				escaped.encoding.should == Encoding::EUC_JP
         | 
| 886 943 | 
             
            				escaped.should == "'string to'"
         | 
| 887 944 | 
             
            			end
         | 
| 945 | 
            +
             | 
| 946 | 
            +
            			it "uses the client encoding for escaped identifier", :postgresql_90 do
         | 
| 947 | 
            +
            				original = "string to\0 escape".force_encoding( "iso8859-1" )
         | 
| 948 | 
            +
            				@conn.set_client_encoding( "euc_jp" )
         | 
| 949 | 
            +
            				escaped  = @conn.escape_identifier( original )
         | 
| 950 | 
            +
            				escaped.encoding.should == Encoding::EUC_JP
         | 
| 951 | 
            +
            				escaped.should == "\"string to\""
         | 
| 952 | 
            +
            			end
         | 
| 953 | 
            +
             | 
| 954 | 
            +
            			it "uses the client encoding for quote_ident" do
         | 
| 955 | 
            +
            				original = "string to\0 escape".force_encoding( "iso8859-1" )
         | 
| 956 | 
            +
            				@conn.set_client_encoding( "euc_jp" )
         | 
| 957 | 
            +
            				escaped  = @conn.quote_ident( original )
         | 
| 958 | 
            +
            				escaped.encoding.should == Encoding::EUC_JP
         | 
| 959 | 
            +
            				escaped.should == "\"string to\""
         | 
| 960 | 
            +
            			end
         | 
| 961 | 
            +
             | 
| 962 | 
            +
            			it "uses the previous string encoding for escaped string" do
         | 
| 963 | 
            +
            				original = "string to\0 escape".force_encoding( "iso8859-1" )
         | 
| 964 | 
            +
            				@conn.set_client_encoding( "euc_jp" )
         | 
| 965 | 
            +
            				escaped  = described_class.escape( original )
         | 
| 966 | 
            +
            				escaped.encoding.should == Encoding::ISO8859_1
         | 
| 967 | 
            +
            				escaped.should == "string to"
         | 
| 968 | 
            +
            			end
         | 
| 969 | 
            +
             | 
| 970 | 
            +
            			it "uses the previous string encoding for quote_ident" do
         | 
| 971 | 
            +
            				original = "string to\0 escape".force_encoding( "iso8859-1" )
         | 
| 972 | 
            +
            				@conn.set_client_encoding( "euc_jp" )
         | 
| 973 | 
            +
            				escaped  = described_class.quote_ident( original )
         | 
| 974 | 
            +
            				escaped.encoding.should == Encoding::ISO8859_1
         | 
| 975 | 
            +
            				escaped.should == "\"string to\""
         | 
| 976 | 
            +
            			end
         | 
| 977 | 
            +
             | 
| 888 978 | 
             
            		end
         | 
| 889 979 |  | 
| 890 980 |  | 
| @@ -1010,7 +1100,7 @@ describe PG::Connection do | |
| 1010 1100 | 
             
            	end
         | 
| 1011 1101 |  | 
| 1012 1102 | 
             
            	context "OS thread support", :ruby_19 do
         | 
| 1013 | 
            -
            		it " | 
| 1103 | 
            +
            		it "Connection#exec shouldn't block a second thread" do
         | 
| 1014 1104 | 
             
            			t = Thread.new do
         | 
| 1015 1105 | 
             
            				@conn.exec( "select pg_sleep(1)" )
         | 
| 1016 1106 | 
             
            			end
         | 
| @@ -1019,5 +1109,20 @@ describe PG::Connection do | |
| 1019 1109 | 
             
            			t.should be_alive()
         | 
| 1020 1110 | 
             
            			t.join
         | 
| 1021 1111 | 
             
            		end
         | 
| 1112 | 
            +
             | 
| 1113 | 
            +
            		it "Connection.new shouldn't block a second thread" do
         | 
| 1114 | 
            +
            			serv = nil
         | 
| 1115 | 
            +
            			t = Thread.new do
         | 
| 1116 | 
            +
            				serv = TCPServer.new( '127.0.0.1', 54320 )
         | 
| 1117 | 
            +
            				expect {
         | 
| 1118 | 
            +
            					described_class.new( '127.0.0.1', 54320, "", "", "me", "xxxx", "somedb" )
         | 
| 1119 | 
            +
            				}.to raise_error(PG::ConnectionBad, /server closed the connection unexpectedly/)
         | 
| 1120 | 
            +
            			end
         | 
| 1121 | 
            +
             | 
| 1122 | 
            +
            			sleep 0.5
         | 
| 1123 | 
            +
            			t.should be_alive()
         | 
| 1124 | 
            +
            			serv.close
         | 
| 1125 | 
            +
            			t.join
         | 
| 1126 | 
            +
            		end
         | 
| 1022 1127 | 
             
            	end
         | 
| 1023 1128 | 
             
            end
         |