pg 0.15.1 → 0.16.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|