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

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.
Files changed (50) 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/2.0/pg_ext.so +0 -0
  29. data/lib/2.1/pg_ext.so +0 -0
  30. data/lib/pg.rb +11 -1
  31. data/lib/pg/basic_type_mapping.rb +377 -0
  32. data/lib/pg/coder.rb +74 -0
  33. data/lib/pg/connection.rb +43 -1
  34. data/lib/pg/result.rb +13 -3
  35. data/lib/pg/text_decoder.rb +42 -0
  36. data/lib/pg/text_encoder.rb +27 -0
  37. data/lib/pg/type_map_by_column.rb +15 -0
  38. data/lib/x64-mingw32/libpq.dll +0 -0
  39. data/spec/{lib/helpers.rb → helpers.rb} +95 -35
  40. data/spec/pg/basic_type_mapping_spec.rb +251 -0
  41. data/spec/pg/connection_spec.rb +416 -214
  42. data/spec/pg/result_spec.rb +146 -116
  43. data/spec/pg/type_map_by_column_spec.rb +135 -0
  44. data/spec/pg/type_map_by_mri_type_spec.rb +122 -0
  45. data/spec/pg/type_map_by_oid_spec.rb +133 -0
  46. data/spec/pg/type_map_spec.rb +39 -0
  47. data/spec/pg/type_spec.rb +649 -0
  48. data/spec/pg_spec.rb +10 -18
  49. metadata +129 -50
  50. metadata.gz.sig +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