pg 0.17.1-x86-mingw32 → 0.18.0.pre20141017160319-x86-mingw32

Sign up to get free protection for your applications and to get access to all the features.
Files changed (52) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data.tar.gz.sig +0 -0
  4. data/ChangeLog +1885 -169
  5. data/History.rdoc +6 -0
  6. data/Manifest.txt +25 -1
  7. data/README.rdoc +47 -0
  8. data/Rakefile +21 -12
  9. data/Rakefile.cross +39 -33
  10. data/ext/extconf.rb +27 -26
  11. data/ext/pg.c +73 -19
  12. data/ext/pg.h +194 -6
  13. data/ext/pg_binary_decoder.c +160 -0
  14. data/ext/pg_binary_encoder.c +160 -0
  15. data/ext/pg_coder.c +473 -0
  16. data/ext/pg_connection.c +872 -534
  17. data/ext/pg_copy_coder.c +557 -0
  18. data/ext/pg_result.c +266 -111
  19. data/ext/pg_text_decoder.c +424 -0
  20. data/ext/pg_text_encoder.c +631 -0
  21. data/ext/pg_type_map.c +113 -0
  22. data/ext/pg_type_map_all_strings.c +113 -0
  23. data/ext/pg_type_map_by_column.c +254 -0
  24. data/ext/pg_type_map_by_mri_type.c +266 -0
  25. data/ext/pg_type_map_by_oid.c +341 -0
  26. data/ext/util.c +149 -0
  27. data/ext/util.h +65 -0
  28. data/lib/1.9/pg_ext.so +0 -0
  29. data/lib/2.0/pg_ext.so +0 -0
  30. data/lib/2.1/pg_ext.so +0 -0
  31. data/lib/i386-mingw32/libpq.dll +0 -0
  32. data/lib/pg.rb +11 -1
  33. data/lib/pg/basic_type_mapping.rb +377 -0
  34. data/lib/pg/coder.rb +74 -0
  35. data/lib/pg/connection.rb +43 -1
  36. data/lib/pg/result.rb +13 -3
  37. data/lib/pg/text_decoder.rb +42 -0
  38. data/lib/pg/text_encoder.rb +27 -0
  39. data/lib/pg/type_map_by_column.rb +15 -0
  40. data/spec/{lib/helpers.rb → helpers.rb} +95 -35
  41. data/spec/pg/basic_type_mapping_spec.rb +251 -0
  42. data/spec/pg/connection_spec.rb +416 -214
  43. data/spec/pg/result_spec.rb +146 -116
  44. data/spec/pg/type_map_by_column_spec.rb +135 -0
  45. data/spec/pg/type_map_by_mri_type_spec.rb +122 -0
  46. data/spec/pg/type_map_by_oid_spec.rb +133 -0
  47. data/spec/pg/type_map_spec.rb +39 -0
  48. data/spec/pg/type_spec.rb +649 -0
  49. data/spec/pg_spec.rb +10 -18
  50. metadata +130 -52
  51. metadata.gz.sig +0 -0
  52. data/lib/1.8/pg_ext.so +0 -0
@@ -1,49 +1,14 @@
1
1
  #!/usr/bin/env rspec
2
2
  #encoding: utf-8
3
3
 
4
- BEGIN {
5
- require 'pathname'
4
+ require_relative '../helpers'
6
5
 
7
- basedir = Pathname( __FILE__ ).dirname.parent.parent
8
- libdir = basedir + 'lib'
9
-
10
- $LOAD_PATH.unshift( basedir.to_s ) unless $LOAD_PATH.include?( basedir.to_s )
11
- $LOAD_PATH.unshift( libdir.to_s ) unless $LOAD_PATH.include?( libdir.to_s )
12
- }
13
-
14
- require 'rspec'
15
- require 'spec/lib/helpers'
16
6
  require 'timeout'
17
7
  require 'socket'
18
8
  require 'pg'
19
9
 
20
10
  describe PG::Connection do
21
11
 
22
- before( :all ) do
23
- @conn = setup_testing_db( described_class.name )
24
- end
25
-
26
- before( :each ) do
27
- @conn.exec( 'BEGIN' ) unless example.metadata[:without_transaction]
28
- if PG.respond_to?( :library_version )
29
- @conn.exec_params %Q{SET application_name TO '%s'} %
30
- [@conn.escape_string(example.description[0,60])]
31
- end
32
- end
33
-
34
- after( :each ) do
35
- @conn.exec( 'ROLLBACK' ) unless example.metadata[:without_transaction]
36
- end
37
-
38
- after( :all ) do
39
- teardown_testing_db( @conn )
40
- end
41
-
42
-
43
- #
44
- # Examples
45
- #
46
-
47
12
  it "can create a connection option string from a Hash of options" do
48
13
  optstring = described_class.parse_connect_args(
49
14
  :host => 'pgsql.example.com',
@@ -51,54 +16,55 @@ describe PG::Connection do
51
16
  'sslmode' => 'require'
52
17
  )
53
18
 
54
- optstring.should be_a( String )
55
- optstring.should =~ /(^|\s)host='pgsql.example.com'/
56
- optstring.should =~ /(^|\s)dbname='db01'/
57
- optstring.should =~ /(^|\s)sslmode='require'/
19
+ expect( optstring ).to be_a( String )
20
+ expect( optstring ).to match( /(^|\s)host='pgsql.example.com'/ )
21
+ expect( optstring ).to match( /(^|\s)dbname='db01'/ )
22
+ expect( optstring ).to match( /(^|\s)sslmode='require'/ )
58
23
  end
59
24
 
60
25
  it "can create a connection option string from positional parameters" do
61
26
  optstring = described_class.parse_connect_args( 'pgsql.example.com', nil, '-c geqo=off', nil,
62
27
  'sales' )
63
28
 
64
- optstring.should be_a( String )
65
- optstring.should =~ /(^|\s)host='pgsql.example.com'/
66
- optstring.should =~ /(^|\s)dbname='sales'/
67
- optstring.should =~ /(^|\s)options='-c geqo=off'/
29
+ expect( optstring ).to be_a( String )
30
+ expect( optstring ).to match( /(^|\s)host='pgsql.example.com'/ )
31
+ expect( optstring ).to match( /(^|\s)dbname='sales'/ )
32
+ expect( optstring ).to match( /(^|\s)options='-c geqo=off'/ )
68
33
 
69
- optstring.should_not =~ /port=/
70
- optstring.should_not =~ /tty=/
34
+ expect( optstring ).to_not match( /port=/ )
35
+ expect( optstring ).to_not match( /tty=/ )
71
36
  end
72
37
 
73
38
  it "can create a connection option string from a mix of positional and hash parameters" do
74
39
  optstring = described_class.parse_connect_args( 'pgsql.example.com',
75
40
  :dbname => 'licensing', :user => 'jrandom' )
76
41
 
77
- optstring.should be_a( String )
78
- optstring.should =~ /(^|\s)host='pgsql.example.com'/
79
- optstring.should =~ /(^|\s)dbname='licensing'/
80
- optstring.should =~ /(^|\s)user='jrandom'/
42
+ expect( optstring ).to be_a( String )
43
+ expect( optstring ).to match( /(^|\s)host='pgsql.example.com'/ )
44
+ expect( optstring ).to match( /(^|\s)dbname='licensing'/ )
45
+ expect( optstring ).to match( /(^|\s)user='jrandom'/ )
81
46
  end
82
47
 
83
48
  it "escapes single quotes and backslashes in connection parameters" do
84
- described_class.parse_connect_args( "DB 'browser' \\" ).
85
- should =~ /host='DB \\'browser\\' \\\\'/
49
+ expect(
50
+ described_class.parse_connect_args( "DB 'browser' \\" )
51
+ ).to match( /host='DB \\'browser\\' \\\\'/ )
86
52
 
87
53
  end
88
54
 
89
55
  it "connects with defaults if no connection parameters are given" do
90
- described_class.parse_connect_args.should == ''
56
+ expect( described_class.parse_connect_args ).to eq( '' )
91
57
  end
92
58
 
93
59
  it "connects successfully with connection string" do
94
60
  tmpconn = described_class.connect(@conninfo)
95
- tmpconn.status.should == PG::CONNECTION_OK
61
+ expect( tmpconn.status ).to eq( PG::CONNECTION_OK )
96
62
  tmpconn.finish
97
63
  end
98
64
 
99
65
  it "connects using 7 arguments converted to strings" do
100
66
  tmpconn = described_class.connect('localhost', @port, nil, nil, :test, nil, nil)
101
- tmpconn.status.should == PG::CONNECTION_OK
67
+ expect( tmpconn.status ).to eq( PG::CONNECTION_OK )
102
68
  tmpconn.finish
103
69
  end
104
70
 
@@ -107,7 +73,7 @@ describe PG::Connection do
107
73
  :host => 'localhost',
108
74
  :port => @port,
109
75
  :dbname => :test)
110
- tmpconn.status.should == PG::CONNECTION_OK
76
+ expect( tmpconn.status ).to eq( PG::CONNECTION_OK )
111
77
  tmpconn.finish
112
78
  end
113
79
 
@@ -117,7 +83,7 @@ describe PG::Connection do
117
83
  :port => @port,
118
84
  :dbname => :test,
119
85
  :keepalives => 1)
120
- tmpconn.status.should == PG::CONNECTION_OK
86
+ expect( tmpconn.status ).to eq( PG::CONNECTION_OK )
121
87
  tmpconn.finish
122
88
  end
123
89
 
@@ -129,7 +95,7 @@ describe PG::Connection do
129
95
 
130
96
  it "can connect asynchronously", :socket_io do
131
97
  tmpconn = described_class.connect_start( @conninfo )
132
- tmpconn.should be_a( described_class )
98
+ expect( tmpconn ).to be_a( described_class )
133
99
  socket = tmpconn.socket_io
134
100
  status = tmpconn.connect_poll
135
101
 
@@ -145,7 +111,7 @@ describe PG::Connection do
145
111
  status = tmpconn.connect_poll
146
112
  end
147
113
 
148
- tmpconn.status.should == PG::CONNECTION_OK
114
+ expect( tmpconn.status ).to eq( PG::CONNECTION_OK )
149
115
  tmpconn.finish
150
116
  end
151
117
 
@@ -153,7 +119,7 @@ describe PG::Connection do
153
119
  conn = nil
154
120
 
155
121
  described_class.connect_start(@conninfo) do |tmpconn|
156
- tmpconn.should be_a( described_class )
122
+ expect( tmpconn ).to be_a( described_class )
157
123
  conn = tmpconn
158
124
  socket = tmpconn.socket_io
159
125
  status = tmpconn.connect_poll
@@ -171,10 +137,10 @@ describe PG::Connection do
171
137
  status = tmpconn.connect_poll
172
138
  end
173
139
 
174
- tmpconn.status.should == PG::CONNECTION_OK
140
+ expect( tmpconn.status ).to eq( PG::CONNECTION_OK )
175
141
  end
176
142
 
177
- conn.should be_finished()
143
+ expect( conn ).to be_finished()
178
144
  end
179
145
 
180
146
  it "raises proper error when sending fails" do
@@ -188,7 +154,7 @@ describe PG::Connection do
188
154
  res = @conn.exec(%[SELECT COUNT(*) AS n FROM pg_stat_activity
189
155
  WHERE usename IS NOT NULL])
190
156
  # there's still the global @conn, but should be no more
191
- res[0]['n'].should == '1'
157
+ expect( res[0]['n'] ).to eq( '1' )
192
158
  end
193
159
 
194
160
 
@@ -248,7 +214,7 @@ describe PG::Connection do
248
214
  expected_trace_output.sub!( /From backend> "SELECT 1"/, 'From backend> "SELECT"' )
249
215
  end
250
216
 
251
- trace_data.should == expected_trace_output
217
+ expect( trace_data ).to eq( expected_trace_output )
252
218
  end
253
219
 
254
220
  it "allows a query to be cancelled" do
@@ -259,10 +225,12 @@ describe PG::Connection do
259
225
  if(tmpres.result_status != PG::PGRES_TUPLES_OK)
260
226
  error = true
261
227
  end
262
- error.should == true
228
+ expect( error ).to eq( true )
263
229
  end
264
230
 
265
231
  it "can stop a thread that runs a blocking query with async_exec" do
232
+ pending "this does not work on Rubinius" if RUBY_ENGINE=='rbx'
233
+
266
234
  start = Time.now
267
235
  t = Thread.new do
268
236
  @conn.async_exec( 'select pg_sleep(10)' )
@@ -271,10 +239,10 @@ describe PG::Connection do
271
239
 
272
240
  t.kill
273
241
  t.join
274
- (Time.now - start).should < 10
242
+ expect( (Time.now - start) ).to be < 10
275
243
  end
276
244
 
277
- it "should work together with signal handlers" do
245
+ it "should work together with signal handlers", :unix do
278
246
  signal_received = false
279
247
  trap 'USR1' do
280
248
  signal_received = true
@@ -285,7 +253,7 @@ describe PG::Connection do
285
253
  Process.kill("USR1", Process.pid)
286
254
  end
287
255
  @conn.exec("select pg_sleep(0.3)")
288
- signal_received.should be_true
256
+ expect( signal_received ).to be_truthy
289
257
 
290
258
  signal_received = false
291
259
  Thread.new do
@@ -293,7 +261,7 @@ describe PG::Connection do
293
261
  Process.kill("USR1", Process.pid)
294
262
  end
295
263
  @conn.async_exec("select pg_sleep(0.3)")
296
- signal_received.should be_true
264
+ expect( signal_received ).to be_truthy
297
265
  end
298
266
 
299
267
 
@@ -305,15 +273,19 @@ describe PG::Connection do
305
273
  res = nil
306
274
  @conn.exec( "CREATE TABLE pie ( flavor TEXT )" )
307
275
 
308
- expect {
309
- res = @conn.transaction do
310
- @conn.exec( "INSERT INTO pie VALUES ('rhubarb'), ('cherry'), ('schizophrenia')" )
311
- raise "Oh noes! All pie is gone!"
312
- end
313
- }.to raise_exception( RuntimeError, /all pie is gone/i )
276
+ begin
277
+ expect {
278
+ res = @conn.transaction do
279
+ @conn.exec( "INSERT INTO pie VALUES ('rhubarb'), ('cherry'), ('schizophrenia')" )
280
+ raise "Oh noes! All pie is gone!"
281
+ end
282
+ }.to raise_exception( RuntimeError, /all pie is gone/i )
314
283
 
315
- res = @conn.exec( "SELECT * FROM pie" )
316
- res.ntuples.should == 0
284
+ res = @conn.exec( "SELECT * FROM pie" )
285
+ expect( res.ntuples ).to eq( 0 )
286
+ ensure
287
+ @conn.exec( "DROP TABLE pie" )
288
+ end
317
289
  end
318
290
 
319
291
  it "returns the block result from Connection#transaction" do
@@ -323,7 +295,7 @@ describe PG::Connection do
323
295
  res = @conn.transaction do
324
296
  "transaction result"
325
297
  end
326
- res.should == "transaction result"
298
+ expect( res ).to eq( "transaction result" )
327
299
  end
328
300
 
329
301
  it "not read past the end of a large object" do
@@ -331,9 +303,9 @@ describe PG::Connection do
331
303
  oid = @conn.lo_create( 0 )
332
304
  fd = @conn.lo_open( oid, PG::INV_READ|PG::INV_WRITE )
333
305
  @conn.lo_write( fd, "foobar" )
334
- @conn.lo_read( fd, 10 ).should be_nil()
306
+ expect( @conn.lo_read( fd, 10 ) ).to be_nil()
335
307
  @conn.lo_lseek( fd, 0, PG::SEEK_SET )
336
- @conn.lo_read( fd, 10 ).should == 'foobar'
308
+ expect( @conn.lo_read( fd, 10 ) ).to eq( 'foobar' )
337
309
  end
338
310
  end
339
311
 
@@ -345,7 +317,7 @@ describe PG::Connection do
345
317
  @conn.exec( "INSERT INTO students VALUES( $1, $2 )", ['Dorothy', 4] )
346
318
 
347
319
  res = @conn.exec( "SELECT name FROM students WHERE age >= $1", [6] )
348
- res.values.should == [ ['Wally'], ['Sally'] ]
320
+ expect( res.values ).to eq( [ ['Wally'], ['Sally'] ] )
349
321
  end
350
322
 
351
323
  it "supports explicitly calling #exec_params" do
@@ -355,9 +327,32 @@ describe PG::Connection do
355
327
  @conn.exec( "INSERT INTO students VALUES( $1, $2 )", ['Dorothy', 4] )
356
328
 
357
329
  res = @conn.exec_params( "SELECT name FROM students WHERE age >= $1", [6] )
358
- res.values.should == [ ['Wally'], ['Sally'] ]
330
+ expect( res.values ).to eq( [ ['Wally'], ['Sally'] ] )
359
331
  end
360
332
 
333
+ it "supports hash form parameters for #exec_params" do
334
+ hash_param_bin = { value: ["00ff"].pack("H*"), type: 17, format: 1 }
335
+ hash_param_nil = { value: nil, type: 17, format: 1 }
336
+ res = @conn.exec_params( "SELECT $1, $2",
337
+ [ hash_param_bin, hash_param_nil ] )
338
+ expect( res.values ).to eq( [["\\x00ff", nil]] )
339
+ expect( result_typenames(res) ).to eq( ['bytea', 'bytea'] )
340
+ end
341
+
342
+ it "should work with arbitrary number of params" do
343
+ begin
344
+ 3.step( 12, 0.2 ) do |exp|
345
+ num_params = (2 ** exp).to_i
346
+ sql = num_params.times.map{|n| "$#{n+1}::INT" }.join(",")
347
+ params = num_params.times.to_a
348
+ res = @conn.exec_params( "SELECT #{sql}", params )
349
+ expect( res.nfields ).to eq( num_params )
350
+ expect( res.values ).to eq( [num_params.times.map(&:to_s)] )
351
+ end
352
+ rescue PG::ProgramLimitExceeded
353
+ # Stop silently if the server complains about too many params
354
+ end
355
+ end
361
356
 
362
357
  it "can wait for NOTIFY events" do
363
358
  @conn.exec( 'ROLLBACK' )
@@ -373,7 +368,7 @@ describe PG::Connection do
373
368
  end
374
369
  end
375
370
 
376
- @conn.wait_for_notify( 10 ).should == 'woo'
371
+ expect( @conn.wait_for_notify( 10 ) ).to eq( 'woo' )
377
372
  @conn.exec( 'UNLISTEN woo' )
378
373
 
379
374
  t.join
@@ -395,8 +390,8 @@ describe PG::Connection do
395
390
 
396
391
  eventpid = event = nil
397
392
  @conn.wait_for_notify( 10 ) {|*args| event, eventpid = args }
398
- event.should == 'woo'
399
- eventpid.should be_an( Integer )
393
+ expect( event ).to eq( 'woo' )
394
+ expect( eventpid ).to be_an( Integer )
400
395
 
401
396
  @conn.exec( 'UNLISTEN woo' )
402
397
 
@@ -423,8 +418,8 @@ describe PG::Connection do
423
418
  channels << @conn.wait_for_notify( 2 )
424
419
  end
425
420
 
426
- channels.should have( 3 ).members
427
- channels.should include( 'woo', 'war', 'woz' )
421
+ expect( channels.size ).to eq( 3 )
422
+ expect( channels ).to include( 'woo', 'war', 'woz' )
428
423
 
429
424
  @conn.exec( 'UNLISTEN woz' )
430
425
  @conn.exec( 'UNLISTEN war' )
@@ -446,7 +441,7 @@ describe PG::Connection do
446
441
  # Cause the notification to buffer, but not be read yet
447
442
  @conn.exec( 'SELECT 1' )
448
443
 
449
- @conn.wait_for_notify( 10 ).should == 'woo'
444
+ expect( @conn.wait_for_notify( 10 ) ).to eq( 'woo' )
450
445
  @conn.exec( 'UNLISTEN woo' )
451
446
  end
452
447
 
@@ -457,41 +452,41 @@ describe PG::Connection do
457
452
  end
458
453
  st = Time.now
459
454
  @conn.send_query "SELECT pg_sleep(0.5); do $$ BEGIN RAISE NOTICE 'woohoo'; END; $$ LANGUAGE plpgsql;"
460
- @conn.wait_for_notify( 1 ).should be_nil
461
- notices.first.should_not be_nil
455
+ expect( @conn.wait_for_notify( 1 ) ).to be_nil
456
+ expect( notices.first ).to_not be_nil
462
457
  et = Time.now
463
- (et - notices.first[1]).should >= 0.4
464
- (et - st).should >= 0.9
465
- (et - st).should < 1.4
458
+ expect( (et - notices.first[1]) ).to be >= 0.4
459
+ expect( (et - st) ).to be >= 0.9
460
+ expect( (et - st) ).to be < 1.4
466
461
  end
467
462
 
468
463
  it "yields the result if block is given to exec" do
469
464
  rval = @conn.exec( "select 1234::int as a union select 5678::int as a" ) do |result|
470
465
  values = []
471
- result.should be_kind_of( PG::Result )
472
- result.ntuples.should == 2
466
+ expect( result ).to be_kind_of( PG::Result )
467
+ expect( result.ntuples ).to eq( 2 )
473
468
  result.each do |tuple|
474
469
  values << tuple['a']
475
470
  end
476
471
  values
477
472
  end
478
473
 
479
- rval.should have( 2 ).members
480
- rval.should include( '5678', '1234' )
474
+ expect( rval.size ).to eq( 2 )
475
+ expect( rval ).to include( '5678', '1234' )
481
476
  end
482
477
 
483
478
  it "can process #copy_data output queries" do
484
479
  rows = []
485
480
  res2 = @conn.copy_data( "COPY (SELECT 1 UNION ALL SELECT 2) TO STDOUT" ) do |res|
486
- res.result_status.should == PG::PGRES_COPY_OUT
487
- res.nfields.should == 1
481
+ expect( res.result_status ).to eq( PG::PGRES_COPY_OUT )
482
+ expect( res.nfields ).to eq( 1 )
488
483
  while row=@conn.get_copy_data
489
484
  rows << row
490
485
  end
491
486
  end
492
- rows.should == ["1\n", "2\n"]
493
- res2.result_status.should == PG::PGRES_COMMAND_OK
494
- verify_clean_exec_status
487
+ expect( rows ).to eq( ["1\n", "2\n"] )
488
+ expect( res2.result_status ).to eq( PG::PGRES_COMMAND_OK )
489
+ expect( @conn ).to still_be_usable
495
490
  end
496
491
 
497
492
  it "can handle incomplete #copy_data output queries" do
@@ -500,7 +495,7 @@ describe PG::Connection do
500
495
  @conn.get_copy_data
501
496
  end
502
497
  }.to raise_error(PG::NotAllCopyDataRetrieved, /Not all/)
503
- verify_clean_exec_status
498
+ expect( @conn ).to still_be_usable
504
499
  end
505
500
 
506
501
  it "can handle client errors in #copy_data for output" do
@@ -509,10 +504,10 @@ describe PG::Connection do
509
504
  raise "boom"
510
505
  end
511
506
  }.to raise_error(RuntimeError, "boom")
512
- verify_clean_exec_status
507
+ expect( @conn ).to still_be_usable
513
508
  end
514
509
 
515
- it "can handle server errors in #copy_data for output" do
510
+ it "can handle server errors in #copy_data for output", :postgresql_90 do
516
511
  @conn.exec "ROLLBACK"
517
512
  @conn.transaction do
518
513
  @conn.exec( "CREATE FUNCTION errfunc() RETURNS int AS $$ BEGIN RAISE 'test-error'; END; $$ LANGUAGE plpgsql;" )
@@ -523,23 +518,23 @@ describe PG::Connection do
523
518
  end
524
519
  }.to raise_error(PG::Error, /test-error/)
525
520
  end
526
- verify_clean_exec_status
521
+ expect( @conn ).to still_be_usable
527
522
  end
528
523
 
529
524
  it "can process #copy_data input queries" do
530
525
  @conn.exec( "CREATE TEMP TABLE copytable (col1 TEXT)" )
531
526
  res2 = @conn.copy_data( "COPY copytable FROM STDOUT" ) do |res|
532
- res.result_status.should == PG::PGRES_COPY_IN
533
- res.nfields.should == 1
527
+ expect( res.result_status ).to eq( PG::PGRES_COPY_IN )
528
+ expect( res.nfields ).to eq( 1 )
534
529
  @conn.put_copy_data "1\n"
535
530
  @conn.put_copy_data "2\n"
536
531
  end
537
- res2.result_status.should == PG::PGRES_COMMAND_OK
532
+ expect( res2.result_status ).to eq( PG::PGRES_COMMAND_OK )
538
533
 
539
- verify_clean_exec_status
534
+ expect( @conn ).to still_be_usable
540
535
 
541
536
  res = @conn.exec( "SELECT * FROM copytable ORDER BY col1" )
542
- res.values.should == [["1"], ["2"]]
537
+ expect( res.values ).to eq( [["1"], ["2"]] )
543
538
  end
544
539
 
545
540
  it "can handle client errors in #copy_data for input" do
@@ -552,7 +547,8 @@ describe PG::Connection do
552
547
  end
553
548
  }.to raise_error(RuntimeError, "boom")
554
549
  end
555
- verify_clean_exec_status
550
+
551
+ expect( @conn ).to still_be_usable
556
552
  end
557
553
 
558
554
  it "can handle server errors in #copy_data for input" do
@@ -565,7 +561,7 @@ describe PG::Connection do
565
561
  end
566
562
  }.to raise_error(PG::Error, /invalid input syntax for integer/)
567
563
  end
568
- verify_clean_exec_status
564
+ expect( @conn ).to still_be_usable
569
565
  end
570
566
 
571
567
  it "should raise an error for non copy statements in #copy_data" do
@@ -573,7 +569,7 @@ describe PG::Connection do
573
569
  @conn.copy_data( "SELECT 1" ){}
574
570
  }.to raise_error(ArgumentError, /no COPY/)
575
571
 
576
- verify_clean_exec_status
572
+ expect( @conn ).to still_be_usable
577
573
  end
578
574
 
579
575
  it "correctly finishes COPY queries passed to #async_exec" do
@@ -589,8 +585,8 @@ describe PG::Connection do
589
585
  results << data if data
590
586
  end until data.nil?
591
587
 
592
- results.should have( 2 ).members
593
- results.should include( "1\n", "2\n" )
588
+ expect( results.size ).to eq( 2 )
589
+ expect( results ).to include( "1\n", "2\n" )
594
590
  end
595
591
 
596
592
 
@@ -602,10 +598,10 @@ describe PG::Connection do
602
598
  end
603
599
 
604
600
  sleep 0.5
605
- t.should be_alive()
601
+ expect( t ).to be_alive()
606
602
  @conn.cancel
607
603
  t.join
608
- (Time.now - start).should < 3
604
+ expect( (Time.now - start) ).to be < 3
609
605
  end
610
606
 
611
607
  it "described_class#block should allow a timeout" do
@@ -615,13 +611,49 @@ describe PG::Connection do
615
611
  @conn.block( 0.1 )
616
612
  finish = Time.now
617
613
 
618
- (finish - start).should be_within( 0.05 ).of( 0.1 )
614
+ expect( (finish - start) ).to be_within( 0.05 ).of( 0.1 )
619
615
  end
620
616
 
621
617
 
622
618
  it "can encrypt a string given a password and username" do
623
- described_class.encrypt_password("postgres", "postgres").
624
- should =~ /\S+/
619
+ expect( described_class.encrypt_password("postgres", "postgres") ).to match( /\S+/ )
620
+ end
621
+
622
+ it "can return the default connection options" do
623
+ expect( described_class.conndefaults ).to be_a( Array )
624
+ expect( described_class.conndefaults ).to all( be_a(Hash) )
625
+ expect( described_class.conndefaults[0] ).to include( :keyword, :label, :dispchar, :dispsize )
626
+ expect( @conn.conndefaults ).to eq( described_class.conndefaults )
627
+ end
628
+
629
+ it "can return the default connection options as a Hash" do
630
+ expect( described_class.conndefaults_hash ).to be_a( Hash )
631
+ expect( described_class.conndefaults_hash ).to include( :user, :password, :dbname, :host, :port )
632
+ expect( described_class.conndefaults_hash[:port] ).to eq( '54321' )
633
+ expect( @conn.conndefaults_hash ).to eq( described_class.conndefaults_hash )
634
+ end
635
+
636
+ it "can return the connection's connection options", :postgresql_93 do
637
+ expect( @conn.conninfo ).to be_a( Array )
638
+ expect( @conn.conninfo ).to all( be_a(Hash) )
639
+ expect( @conn.conninfo[0] ).to include( :keyword, :label, :dispchar, :dispsize )
640
+ end
641
+
642
+
643
+ it "can return the connection's connection options as a Hash", :postgresql_93 do
644
+ expect( @conn.conninfo_hash ).to be_a( Hash )
645
+ expect( @conn.conninfo_hash ).to include( :user, :password, :connect_timeout, :dbname, :host )
646
+ expect( @conn.conninfo_hash[:dbname] ).to eq( 'test' )
647
+ end
648
+
649
+
650
+ it "honors the connect_timeout connection parameter", :postgresql_93 do
651
+ conn = PG.connect( port: @port, dbname: 'test', connect_timeout: 11 )
652
+ begin
653
+ expect( conn.conninfo_hash[:connect_timeout] ).to eq( "11" )
654
+ ensure
655
+ conn.finish
656
+ end
625
657
  end
626
658
 
627
659
 
@@ -641,15 +673,15 @@ describe PG::Connection do
641
673
 
642
674
  it "allows fetching a column of values from a result by column number" do
643
675
  res = @conn.exec( 'VALUES (1,2),(2,3),(3,4)' )
644
- res.column_values( 0 ).should == %w[1 2 3]
645
- res.column_values( 1 ).should == %w[2 3 4]
676
+ expect( res.column_values( 0 ) ).to eq( %w[1 2 3] )
677
+ expect( res.column_values( 1 ) ).to eq( %w[2 3 4] )
646
678
  end
647
679
 
648
680
 
649
681
  it "allows fetching a column of values from a result by field name" do
650
682
  res = @conn.exec( 'VALUES (1,2),(2,3),(3,4)' )
651
- res.field_values( 'column1' ).should == %w[1 2 3]
652
- res.field_values( 'column2' ).should == %w[2 3 4]
683
+ expect( res.field_values( 'column1' ) ).to eq( %w[1 2 3] )
684
+ expect( res.field_values( 'column2' ) ).to eq( %w[2 3 4] )
653
685
  end
654
686
 
655
687
 
@@ -680,13 +712,13 @@ describe PG::Connection do
680
712
  it "can connect asynchronously", :socket_io do
681
713
  serv = TCPServer.new( '127.0.0.1', 54320 )
682
714
  conn = described_class.connect_start( '127.0.0.1', 54320, "", "", "me", "xxxx", "somedb" )
683
- [PG::PGRES_POLLING_WRITING, PG::CONNECTION_OK].should include conn.connect_poll
715
+ expect( [PG::PGRES_POLLING_WRITING, PG::CONNECTION_OK] ).to include conn.connect_poll
684
716
  select( nil, [conn.socket_io], nil, 0.2 )
685
717
  serv.close
686
718
  if conn.connect_poll == PG::PGRES_POLLING_READING
687
719
  select( [conn.socket_io], nil, nil, 0.2 )
688
720
  end
689
- conn.connect_poll.should == PG::PGRES_POLLING_FAILED
721
+ expect( conn.connect_poll ).to eq( PG::PGRES_POLLING_FAILED )
690
722
  end
691
723
 
692
724
  it "discards previous results (if any) before waiting on an #async_exec"
@@ -696,7 +728,7 @@ describe PG::Connection do
696
728
  @conn.async_exec( "select 47 as one" ) do |pg_res|
697
729
  result = pg_res[0]
698
730
  end
699
- result.should == { 'one' => '47' }
731
+ expect( result ).to eq( { 'one' => '47' } )
700
732
  end
701
733
 
702
734
  it "raises a rescue-able error if #finish is called twice", :without_transaction do
@@ -710,7 +742,7 @@ describe PG::Connection do
710
742
  conn = PG.connect( @conninfo )
711
743
  io = conn.socket_io
712
744
  conn.finish
713
- io.should be_closed()
745
+ expect( io ).to be_closed()
714
746
  expect { conn.socket_io }.to raise_error( PG::ConnectionBad, /connection is closed/i )
715
747
  end
716
748
 
@@ -718,8 +750,8 @@ describe PG::Connection do
718
750
  conn = PG.connect( @conninfo )
719
751
  io = conn.socket_io
720
752
  conn.reset
721
- io.should be_closed()
722
- conn.socket_io.should_not equal( io )
753
+ expect( io ).to be_closed()
754
+ expect( conn.socket_io ).to_not equal( io )
723
755
  conn.finish
724
756
  end
725
757
 
@@ -742,7 +774,11 @@ describe PG::Connection do
742
774
 
743
775
  it "sets the fallback_application_name on new connections" do
744
776
  conn_string = PG::Connection.parse_connect_args( 'dbname=test' )
745
- connection_string_should_contain_application_name(conn_string, $0)
777
+
778
+ conn_name = conn_string[ /application_name='(.*?)'/, 1 ]
779
+ expect( conn_name ).to include( $0[0..10] )
780
+ expect( conn_name ).to include( $0[-10..-1] )
781
+ expect( conn_name.length ).to be <= 64
746
782
  end
747
783
 
748
784
  it "sets a shortened fallback_application_name on new connections" do
@@ -750,7 +786,10 @@ describe PG::Connection do
750
786
  begin
751
787
  $0 = "/this/is/a/very/long/path/with/many/directories/to/our/beloved/ruby"
752
788
  conn_string = PG::Connection.parse_connect_args( 'dbname=test' )
753
- connection_string_should_contain_application_name(conn_string, $0)
789
+ conn_name = conn_string[ /application_name='(.*?)'/, 1 ]
790
+ expect( conn_name ).to include( $0[0..10] )
791
+ expect( conn_name ).to include( $0[-10..-1] )
792
+ expect( conn_name.length ).to be <= 64
754
793
  ensure
755
794
  $0 = old_0
756
795
  end
@@ -772,9 +811,9 @@ describe PG::Connection do
772
811
  end
773
812
  @conn.exec( 'UNLISTEN knees' )
774
813
 
775
- event.should == 'knees'
776
- pid.should be_a_kind_of( Integer )
777
- msg.should == 'skirt and boots'
814
+ expect( event ).to eq( 'knees' )
815
+ expect( pid ).to be_a_kind_of( Integer )
816
+ expect( msg ).to eq( 'skirt and boots' )
778
817
  end
779
818
 
780
819
  it "accepts nil as the timeout in #wait_for_notify " do
@@ -791,8 +830,8 @@ describe PG::Connection do
791
830
  end
792
831
  @conn.exec( 'UNLISTEN knees' )
793
832
 
794
- event.should == 'knees'
795
- pid.should be_a_kind_of( Integer )
833
+ expect( event ).to eq( 'knees' )
834
+ expect( pid ).to be_a_kind_of( Integer )
796
835
  end
797
836
 
798
837
  it "sends nil as the payload if the notification wasn't given one" do
@@ -809,7 +848,7 @@ describe PG::Connection do
809
848
  end
810
849
  @conn.exec( 'UNLISTEN knees' )
811
850
 
812
- payload.should be_nil()
851
+ expect( payload ).to be_nil()
813
852
  end
814
853
 
815
854
  it "calls the block supplied to wait_for_notify with the notify payload if it accepts " +
@@ -828,9 +867,9 @@ describe PG::Connection do
828
867
  end
829
868
  @conn.exec( 'UNLISTEN knees' )
830
869
 
831
- event.should == 'knees'
832
- pid.should be_a_kind_of( Integer )
833
- msg.should be_nil()
870
+ expect( event ).to eq( 'knees' )
871
+ expect( pid ).to be_a_kind_of( Integer )
872
+ expect( msg ).to be_nil()
834
873
  end
835
874
 
836
875
  it "calls the block supplied to wait_for_notify with the notify payload if it " +
@@ -849,7 +888,7 @@ describe PG::Connection do
849
888
  end
850
889
  @conn.exec( 'UNLISTEN knees' )
851
890
 
852
- notification_received.should be_true()
891
+ expect( notification_received ).to be_truthy()
853
892
  end
854
893
 
855
894
  it "calls the block supplied to wait_for_notify with the notify payload if it accepts " +
@@ -868,9 +907,9 @@ describe PG::Connection do
868
907
  end
869
908
  @conn.exec( 'UNLISTEN knees' )
870
909
 
871
- event.should == 'knees'
872
- pid.should be_a_kind_of( Integer )
873
- msg.should == 'skirt and boots'
910
+ expect( event ).to eq( 'knees' )
911
+ expect( pid ).to be_a_kind_of( Integer )
912
+ expect( msg ).to eq( 'skirt and boots' )
874
913
  end
875
914
 
876
915
  end
@@ -879,12 +918,12 @@ describe PG::Connection do
879
918
 
880
919
  it "pings successfully with connection string" do
881
920
  ping = described_class.ping(@conninfo)
882
- ping.should == PG::PQPING_OK
921
+ expect( ping ).to eq( PG::PQPING_OK )
883
922
  end
884
923
 
885
924
  it "pings using 7 arguments converted to strings" do
886
925
  ping = described_class.ping('localhost', @port, nil, nil, :test, nil, nil)
887
- ping.should == PG::PQPING_OK
926
+ expect( ping ).to eq( PG::PQPING_OK )
888
927
  end
889
928
 
890
929
  it "pings using a hash of connection parameters" do
@@ -892,7 +931,7 @@ describe PG::Connection do
892
931
  :host => 'localhost',
893
932
  :port => @port,
894
933
  :dbname => :test)
895
- ping.should == PG::PQPING_OK
934
+ expect( ping ).to eq( PG::PQPING_OK )
896
935
  end
897
936
 
898
937
  it "returns correct response when ping connection cannot be established" do
@@ -900,12 +939,12 @@ describe PG::Connection do
900
939
  :host => 'localhost',
901
940
  :port => 9999,
902
941
  :dbname => :test)
903
- ping.should == PG::PQPING_NO_RESPONSE
942
+ expect( ping ).to eq( PG::PQPING_NO_RESPONSE )
904
943
  end
905
944
 
906
945
  it "returns correct response when ping connection arguments are wrong" do
907
946
  ping = described_class.ping('localhost', 'localhost', nil, nil, :test, nil, nil)
908
- ping.should == PG::PQPING_NO_ATTEMPT
947
+ expect( ping ).to eq( PG::PQPING_NO_ATTEMPT )
909
948
  end
910
949
 
911
950
 
@@ -930,15 +969,15 @@ describe PG::Connection do
930
969
  res = @conn.get_result or break
931
970
  results << res
932
971
  end
933
- results.length.should == 11
972
+ expect( results.length ).to eq( 11 )
934
973
  results[0..-2].each do |res|
935
- res.result_status.should == PG::PGRES_SINGLE_TUPLE
974
+ expect( res.result_status ).to eq( PG::PGRES_SINGLE_TUPLE )
936
975
  values = res.field_values('generate_series')
937
- values.length.should == 1
938
- values.first.to_i.should > 0
976
+ expect( values.length ).to eq( 1 )
977
+ expect( values.first.to_i ).to be > 0
939
978
  end
940
- results.last.result_status.should == PG::PGRES_TUPLES_OK
941
- results.last.ntuples.should == 0
979
+ expect( results.last.result_status ).to eq( PG::PGRES_TUPLES_OK )
980
+ expect( results.last.ntuples ).to eq( 0 )
942
981
  end
943
982
 
944
983
  it "should receive rows before entire query is finished" do
@@ -952,8 +991,8 @@ describe PG::Connection do
952
991
  res.check
953
992
  first_row_time = Time.now unless first_row_time
954
993
  end
955
- (Time.now - start_time).should >= 1.0
956
- (first_row_time - start_time).should < 1.0
994
+ expect( (Time.now - start_time) ).to be >= 1.0
995
+ expect( (first_row_time - start_time) ).to be < 1.0
957
996
  end
958
997
 
959
998
  it "should receive rows before entire query fails" do
@@ -969,8 +1008,8 @@ describe PG::Connection do
969
1008
  first_result ||= res
970
1009
  end
971
1010
  end.to raise_error(PG::Error)
972
- first_result.kind_of?(PG::Result).should be_true
973
- first_result.result_status.should == PG::PGRES_SINGLE_TUPLE
1011
+ expect( first_result.kind_of?(PG::Result) ).to be_truthy
1012
+ expect( first_result.result_status ).to eq( PG::PGRES_SINGLE_TUPLE )
974
1013
  end
975
1014
  end
976
1015
  end
@@ -985,8 +1024,8 @@ describe PG::Connection do
985
1024
  res = conn.exec("VALUES ('fantasia')", [], 0)
986
1025
  out_string = res[0]['column1']
987
1026
  end
988
- out_string.should == 'fantasia'
989
- out_string.encoding.should == Encoding::ISO8859_1
1027
+ expect( out_string ).to eq( 'fantasia' )
1028
+ expect( out_string.encoding ).to eq( Encoding::ISO8859_1 )
990
1029
  end
991
1030
 
992
1031
  it "should return results in the same encoding as the client (utf-8)" do
@@ -996,8 +1035,8 @@ describe PG::Connection do
996
1035
  res = conn.exec("VALUES ('世界線航跡蔵')", [], 0)
997
1036
  out_string = res[0]['column1']
998
1037
  end
999
- out_string.should == '世界線航跡蔵'
1000
- out_string.encoding.should == Encoding::UTF_8
1038
+ expect( out_string ).to eq( '世界線航跡蔵' )
1039
+ expect( out_string.encoding ).to eq( Encoding::UTF_8 )
1001
1040
  end
1002
1041
 
1003
1042
  it "should return results in the same encoding as the client (EUC-JP)" do
@@ -1008,8 +1047,8 @@ describe PG::Connection do
1008
1047
  res = conn.exec(stmt, [], 0)
1009
1048
  out_string = res[0]['column1']
1010
1049
  end
1011
- out_string.should == '世界線航跡蔵'.encode('EUC-JP')
1012
- out_string.encoding.should == Encoding::EUC_JP
1050
+ expect( out_string ).to eq( '世界線航跡蔵'.encode('EUC-JP') )
1051
+ expect( out_string.encoding ).to eq( Encoding::EUC_JP )
1013
1052
  end
1014
1053
 
1015
1054
  it "returns the results in the correct encoding even if the client_encoding has " +
@@ -1022,75 +1061,61 @@ describe PG::Connection do
1022
1061
  conn.internal_encoding = 'utf-8'
1023
1062
  out_string = res[0]['column1']
1024
1063
  end
1025
- out_string.should == '世界線航跡蔵'.encode('EUC-JP')
1026
- out_string.encoding.should == Encoding::EUC_JP
1064
+ expect( out_string ).to eq( '世界線航跡蔵'.encode('EUC-JP') )
1065
+ expect( out_string.encoding ).to eq( Encoding::EUC_JP )
1027
1066
  end
1028
1067
 
1029
1068
  it "the connection should return ASCII-8BIT when it's set to SQL_ASCII" do
1030
1069
  @conn.exec "SET client_encoding TO SQL_ASCII"
1031
- @conn.internal_encoding.should == Encoding::ASCII_8BIT
1032
- end
1033
-
1034
- it "works around the unsupported JOHAB encoding by returning stuff in 'ASCII_8BIT'" do
1035
- pending "figuring out how to create a string in the JOHAB encoding" do
1036
- out_string = nil
1037
- @conn.transaction do |conn|
1038
- conn.exec( "set client_encoding = 'JOHAB';" )
1039
- stmt = "VALUES ('foo')".encode('JOHAB')
1040
- res = conn.exec( stmt, [], 0 )
1041
- out_string = res[0]['column1']
1042
- end
1043
- out_string.should == 'foo'.encode( Encoding::ASCII_8BIT )
1044
- out_string.encoding.should == Encoding::ASCII_8BIT
1045
- end
1070
+ expect( @conn.internal_encoding ).to eq( Encoding::ASCII_8BIT )
1046
1071
  end
1047
1072
 
1048
1073
  it "uses the client encoding for escaped string" do
1049
1074
  original = "string to\0 escape".force_encoding( "iso8859-1" )
1050
1075
  @conn.set_client_encoding( "euc_jp" )
1051
1076
  escaped = @conn.escape( original )
1052
- escaped.encoding.should == Encoding::EUC_JP
1053
- escaped.should == "string to"
1077
+ expect( escaped.encoding ).to eq( Encoding::EUC_JP )
1078
+ expect( escaped ).to eq( "string to" )
1054
1079
  end
1055
1080
 
1056
1081
  it "uses the client encoding for escaped literal", :postgresql_90 do
1057
1082
  original = "string to\0 escape".force_encoding( "iso8859-1" )
1058
1083
  @conn.set_client_encoding( "euc_jp" )
1059
1084
  escaped = @conn.escape_literal( original )
1060
- escaped.encoding.should == Encoding::EUC_JP
1061
- escaped.should == "'string to'"
1085
+ expect( escaped.encoding ).to eq( Encoding::EUC_JP )
1086
+ expect( escaped ).to eq( "'string to'" )
1062
1087
  end
1063
1088
 
1064
1089
  it "uses the client encoding for escaped identifier", :postgresql_90 do
1065
1090
  original = "string to\0 escape".force_encoding( "iso8859-1" )
1066
1091
  @conn.set_client_encoding( "euc_jp" )
1067
1092
  escaped = @conn.escape_identifier( original )
1068
- escaped.encoding.should == Encoding::EUC_JP
1069
- escaped.should == "\"string to\""
1093
+ expect( escaped.encoding ).to eq( Encoding::EUC_JP )
1094
+ expect( escaped ).to eq( "\"string to\"" )
1070
1095
  end
1071
1096
 
1072
1097
  it "uses the client encoding for quote_ident" do
1073
1098
  original = "string to\0 escape".force_encoding( "iso8859-1" )
1074
1099
  @conn.set_client_encoding( "euc_jp" )
1075
1100
  escaped = @conn.quote_ident( original )
1076
- escaped.encoding.should == Encoding::EUC_JP
1077
- escaped.should == "\"string to\""
1101
+ expect( escaped.encoding ).to eq( Encoding::EUC_JP )
1102
+ expect( escaped ).to eq( "\"string to\"" )
1078
1103
  end
1079
1104
 
1080
1105
  it "uses the previous string encoding for escaped string" do
1081
1106
  original = "string to\0 escape".force_encoding( "iso8859-1" )
1082
1107
  @conn.set_client_encoding( "euc_jp" )
1083
1108
  escaped = described_class.escape( original )
1084
- escaped.encoding.should == Encoding::ISO8859_1
1085
- escaped.should == "string to"
1109
+ expect( escaped.encoding ).to eq( Encoding::ISO8859_1 )
1110
+ expect( escaped ).to eq( "string to" )
1086
1111
  end
1087
1112
 
1088
1113
  it "uses the previous string encoding for quote_ident" do
1089
1114
  original = "string to\0 escape".force_encoding( "iso8859-1" )
1090
1115
  @conn.set_client_encoding( "euc_jp" )
1091
1116
  escaped = described_class.quote_ident( original )
1092
- escaped.encoding.should == Encoding::ISO8859_1
1093
- escaped.should == "\"string to\""
1117
+ expect( escaped.encoding ).to eq( Encoding::ISO8859_1 )
1118
+ expect( escaped ).to eq( "\"string to\"" )
1094
1119
  end
1095
1120
 
1096
1121
  end
@@ -1110,10 +1135,11 @@ describe PG::Connection do
1110
1135
  Encoding.default_internal = Encoding::UTF_8
1111
1136
 
1112
1137
  conn = PG.connect( @conninfo )
1113
- conn.internal_encoding.should == Encoding::UTF_8
1138
+ expect( conn.internal_encoding ).to eq( Encoding::UTF_8 )
1114
1139
  res = conn.exec( "SELECT foo FROM defaultinternaltest" )
1115
- res[0]['foo'].encoding.should == Encoding::UTF_8
1140
+ expect( res[0]['foo'].encoding ).to eq( Encoding::UTF_8 )
1116
1141
  ensure
1142
+ conn.exec( "DROP TABLE defaultinternaltest" )
1117
1143
  conn.finish if conn
1118
1144
  Encoding.default_internal = prev_encoding
1119
1145
  end
@@ -1126,7 +1152,7 @@ describe PG::Connection do
1126
1152
 
1127
1153
  @conn.set_default_encoding
1128
1154
 
1129
- @conn.internal_encoding.should == Encoding::KOI8_R
1155
+ expect( @conn.internal_encoding ).to eq( Encoding::KOI8_R )
1130
1156
  ensure
1131
1157
  Encoding.default_internal = prev_encoding
1132
1158
  end
@@ -1147,7 +1173,7 @@ describe PG::Connection do
1147
1173
  query = "INSERT INTO foo VALUES ('Côte d'Ivoire')".encode( 'iso-8859-15' )
1148
1174
  conn.exec( query )
1149
1175
  rescue => err
1150
- err.message.encoding.should == Encoding::ISO8859_15
1176
+ expect( err.message.encoding ).to eq( Encoding::ISO8859_15 )
1151
1177
  else
1152
1178
  fail "No exception raised?!"
1153
1179
  end
@@ -1156,6 +1182,21 @@ describe PG::Connection do
1156
1182
  conn.finish if conn
1157
1183
  end
1158
1184
 
1185
+ it "handles clearing result in or after set_notice_receiver", :postgresql_90 do
1186
+ r = nil
1187
+ @conn.set_notice_receiver do |result|
1188
+ r = result
1189
+ expect( r.cleared? ).to eq(false)
1190
+ end
1191
+ @conn.exec "do $$ BEGIN RAISE NOTICE 'foo'; END; $$ LANGUAGE plpgsql;"
1192
+ sleep 0.2
1193
+ expect( r ).to be_a( PG::Result )
1194
+ expect( r.cleared? ).to eq(true)
1195
+ expect( r.autoclear? ).to eq(true)
1196
+ r.clear
1197
+ @conn.set_notice_receiver
1198
+ end
1199
+
1159
1200
  it "receives properly encoded messages in the notice callbacks", :postgresql_90 do
1160
1201
  [:receiver, :processor].each do |kind|
1161
1202
  notices = []
@@ -1174,10 +1215,10 @@ describe PG::Connection do
1174
1215
  @conn.exec "do $$ BEGIN RAISE NOTICE '世界線航跡蔵'; END; $$ LANGUAGE plpgsql;"
1175
1216
  end
1176
1217
 
1177
- notices.length.should == 3
1218
+ expect( notices.length ).to eq( 3 )
1178
1219
  notices.each do |notice|
1179
- notice.should =~ /^NOTICE:.*世界線航跡蔵/
1180
- notice.encoding.should == Encoding::UTF_8
1220
+ expect( notice ).to match( /^NOTICE:.*世界線航跡蔵/ )
1221
+ expect( notice.encoding ).to eq( Encoding::UTF_8 )
1181
1222
  end
1182
1223
  @conn.set_notice_receiver
1183
1224
  @conn.set_notice_processor
@@ -1195,10 +1236,10 @@ describe PG::Connection do
1195
1236
  end
1196
1237
  @conn.exec( 'UNLISTEN "Möhre"' )
1197
1238
 
1198
- event.should == "Möhre"
1199
- event.encoding.should == Encoding::UTF_8
1200
- msg.should == '世界線航跡蔵'
1201
- msg.encoding.should == Encoding::UTF_8
1239
+ expect( event ).to eq( "Möhre" )
1240
+ expect( event.encoding ).to eq( Encoding::UTF_8 )
1241
+ expect( msg ).to eq( '世界線航跡蔵' )
1242
+ expect( msg.encoding ).to eq( Encoding::UTF_8 )
1202
1243
  end
1203
1244
 
1204
1245
  it "returns properly encoded text from notifies", :postgresql_90 do
@@ -1209,11 +1250,11 @@ describe PG::Connection do
1209
1250
  @conn.exec( 'UNLISTEN "Möhre"' )
1210
1251
 
1211
1252
  notification = @conn.notifies
1212
- notification[:relname].should == "Möhre"
1213
- notification[:relname].encoding.should == Encoding::UTF_8
1214
- notification[:extra].should == '世界線航跡蔵'
1215
- notification[:extra].encoding.should == Encoding::UTF_8
1216
- notification[:be_pid].should > 0
1253
+ expect( notification[:relname] ).to eq( "Möhre" )
1254
+ expect( notification[:relname].encoding ).to eq( Encoding::UTF_8 )
1255
+ expect( notification[:extra] ).to eq( '世界線航跡蔵' )
1256
+ expect( notification[:extra].encoding ).to eq( Encoding::UTF_8 )
1257
+ expect( notification[:be_pid] ).to be > 0
1217
1258
  end
1218
1259
  end
1219
1260
 
@@ -1224,7 +1265,7 @@ describe PG::Connection do
1224
1265
  end
1225
1266
 
1226
1267
  sleep 0.5
1227
- t.should be_alive()
1268
+ expect( t ).to be_alive()
1228
1269
  t.join
1229
1270
  end
1230
1271
 
@@ -1238,9 +1279,170 @@ describe PG::Connection do
1238
1279
  end
1239
1280
 
1240
1281
  sleep 0.5
1241
- t.should be_alive()
1282
+ expect( t ).to be_alive()
1242
1283
  serv.close
1243
1284
  t.join
1244
1285
  end
1245
1286
  end
1287
+
1288
+ describe "type casting" do
1289
+ it "should raise an error on invalid param mapping" do
1290
+ expect{
1291
+ @conn.exec_params( "SELECT 1", [], nil, :invalid )
1292
+ }.to raise_error(TypeError)
1293
+ end
1294
+
1295
+ it "should return nil if no type mapping is set" do
1296
+ expect( @conn.type_map_for_queries ).to be_nil
1297
+ expect( @conn.type_map_for_results ).to be_nil
1298
+ end
1299
+
1300
+ it "shouldn't type map params unless requested" do
1301
+ expect{
1302
+ @conn.exec_params( "SELECT $1", [5] )
1303
+ }.to raise_error(PG::IndeterminateDatatype)
1304
+ end
1305
+
1306
+ it "should raise an error on invalid encoder to put_copy_data" do
1307
+ expect{
1308
+ @conn.put_copy_data [1], :invalid
1309
+ }.to raise_error(TypeError)
1310
+ end
1311
+
1312
+ it "can type cast parameters to put_copy_data with explicit encoder" do
1313
+ tm = PG::TypeMapByColumn.new [nil]
1314
+ row_encoder = PG::TextEncoder::CopyRow.new type_map: tm
1315
+
1316
+ @conn.exec( "CREATE TEMP TABLE copytable (col1 TEXT)" )
1317
+ res2 = @conn.copy_data( "COPY copytable FROM STDOUT" ) do |res|
1318
+ @conn.put_copy_data [1], row_encoder
1319
+ @conn.put_copy_data ["2"], row_encoder
1320
+ end
1321
+
1322
+ res2 = @conn.copy_data( "COPY copytable FROM STDOUT", row_encoder ) do |res|
1323
+ @conn.put_copy_data [3]
1324
+ @conn.put_copy_data ["4"]
1325
+ end
1326
+
1327
+ res = @conn.exec( "SELECT * FROM copytable ORDER BY col1" )
1328
+ expect( res.values ).to eq( [["1"], ["2"], ["3"], ["4"]] )
1329
+ end
1330
+
1331
+ context "with default query type map" do
1332
+ before :each do
1333
+ @conn2 = described_class.new(@conninfo)
1334
+ tm = PG::TypeMapByMriType.new
1335
+ tm['T_FIXNUM'] = PG::TextEncoder::Integer.new oid: 20
1336
+ @conn2.type_map_for_queries = tm
1337
+
1338
+ row_encoder = PG::TextEncoder::CopyRow.new type_map: tm
1339
+ @conn2.encoder_for_put_copy_data = row_encoder
1340
+ end
1341
+ after :each do
1342
+ @conn2.close
1343
+ end
1344
+
1345
+ it "should respect a type mapping for params and it's OID and format code" do
1346
+ res = @conn2.exec_params( "SELECT $1", [5] )
1347
+ expect( res.values ).to eq( [["5"]] )
1348
+ expect( res.ftype(0) ).to eq( 20 )
1349
+ end
1350
+
1351
+ it "should return the current type mapping" do
1352
+ expect( @conn2.type_map_for_queries ).to be_kind_of(PG::TypeMapByMriType)
1353
+ end
1354
+
1355
+ it "should work with arbitrary number of params in conjunction with type casting" do
1356
+ begin
1357
+ 3.step( 12, 0.2 ) do |exp|
1358
+ num_params = (2 ** exp).to_i
1359
+ sql = num_params.times.map{|n| "$#{n+1}" }.join(",")
1360
+ params = num_params.times.to_a
1361
+ res = @conn2.exec_params( "SELECT #{sql}", params )
1362
+ expect( res.nfields ).to eq( num_params )
1363
+ expect( res.values ).to eq( [num_params.times.map(&:to_s)] )
1364
+ end
1365
+ rescue PG::ProgramLimitExceeded
1366
+ # Stop silently as soon the server complains about too many params
1367
+ end
1368
+ end
1369
+
1370
+ it "can process #copy_data input queries with row encoder" do
1371
+ @conn2.exec( "CREATE TEMP TABLE copytable (col1 TEXT)" )
1372
+ res2 = @conn2.copy_data( "COPY copytable FROM STDOUT" ) do |res|
1373
+ @conn2.put_copy_data [1]
1374
+ @conn2.put_copy_data ["2"]
1375
+ end
1376
+
1377
+ res = @conn2.exec( "SELECT * FROM copytable ORDER BY col1" )
1378
+ expect( res.values ).to eq( [["1"], ["2"]] )
1379
+ end
1380
+ end
1381
+
1382
+ context "with default result type map" do
1383
+ before :each do
1384
+ @conn2 = described_class.new(@conninfo)
1385
+ tm = PG::TypeMapByOid.new
1386
+ tm.add_coder PG::TextDecoder::Integer.new oid: 23, format: 0
1387
+ @conn2.type_map_for_results = tm
1388
+
1389
+ row_decoder = PG::TextDecoder::CopyRow.new
1390
+ @conn2.decoder_for_get_copy_data = row_decoder
1391
+ end
1392
+ after :each do
1393
+ @conn2.close
1394
+ end
1395
+
1396
+ it "should respect a type mapping for result" do
1397
+ res = @conn2.exec_params( "SELECT $1::INT", ["5"] )
1398
+ expect( res.values ).to eq( [[5]] )
1399
+ end
1400
+
1401
+ it "should return the current type mapping" do
1402
+ expect( @conn2.type_map_for_results ).to be_kind_of(PG::TypeMapByOid)
1403
+ end
1404
+
1405
+ it "should work with arbitrary number of params in conjunction with type casting" do
1406
+ begin
1407
+ 3.step( 12, 0.2 ) do |exp|
1408
+ num_params = (2 ** exp).to_i
1409
+ sql = num_params.times.map{|n| "$#{n+1}::INT" }.join(",")
1410
+ params = num_params.times.to_a
1411
+ res = @conn2.exec_params( "SELECT #{sql}", params )
1412
+ expect( res.nfields ).to eq( num_params )
1413
+ expect( res.values ).to eq( [num_params.times.to_a] )
1414
+ end
1415
+ rescue PG::ProgramLimitExceeded
1416
+ # Stop silently as soon the server complains about too many params
1417
+ end
1418
+ end
1419
+
1420
+ it "can process #copy_data output with row decoder" do
1421
+ rows = []
1422
+ res2 = @conn2.copy_data( "COPY (SELECT 1 UNION ALL SELECT 2) TO STDOUT" ) do |res|
1423
+ while row=@conn2.get_copy_data
1424
+ rows << row
1425
+ end
1426
+ end
1427
+ expect( rows ).to eq( [["1"], ["2"]] )
1428
+ end
1429
+
1430
+ it "can type cast #copy_data output with explicit decoder" do
1431
+ tm = PG::TypeMapByColumn.new [PG::TextDecoder::Integer.new]
1432
+ row_decoder = PG::TextDecoder::CopyRow.new type_map: tm
1433
+ rows = []
1434
+ @conn.copy_data( "COPY (SELECT 1 UNION ALL SELECT 2) TO STDOUT", row_decoder ) do |res|
1435
+ while row=@conn.get_copy_data
1436
+ rows << row
1437
+ end
1438
+ end
1439
+ @conn.copy_data( "COPY (SELECT 3 UNION ALL SELECT 4) TO STDOUT" ) do |res|
1440
+ while row=@conn.get_copy_data( false, row_decoder )
1441
+ rows << row
1442
+ end
1443
+ end
1444
+ expect( rows ).to eq( [[1], [2], [3], [4]] )
1445
+ end
1446
+ end
1447
+ end
1246
1448
  end