pg 0.12.2 → 0.13.0.pre298

Sign up to get free protection for your applications and to get access to all the features.
Files changed (49) hide show
  1. data.tar.gz.sig +0 -0
  2. data/.hoerc +2 -0
  3. data/.tm_properties +12 -0
  4. data/ChangeLog +86 -6
  5. data/Contributors.rdoc +7 -0
  6. data/History.rdoc +29 -0
  7. data/LICENSE +12 -14
  8. data/Manifest.txt +15 -14
  9. data/{BSD → POSTGRES} +0 -0
  10. data/{README.OS_X.rdoc → README-OS_X.rdoc} +0 -0
  11. data/{README.windows.rdoc → README-Windows.rdoc} +0 -0
  12. data/README.ja.rdoc +1 -1
  13. data/README.rdoc +39 -27
  14. data/Rakefile +1 -2
  15. data/ext/extconf.rb +9 -2
  16. data/ext/pg.c +232 -4297
  17. data/ext/pg.h +87 -23
  18. data/ext/pg_connection.c +3301 -0
  19. data/ext/pg_result.c +905 -0
  20. data/lib/pg.rb +26 -43
  21. data/lib/pg/connection.rb +58 -0
  22. data/lib/pg/constants.rb +11 -0
  23. data/lib/pg/exceptions.rb +11 -0
  24. data/lib/pg/result.rb +11 -0
  25. data/misc/openssl-pg-segfault.rb +1 -1
  26. data/sample/async_api.rb +16 -21
  27. data/sample/async_copyto.rb +1 -1
  28. data/sample/async_mixed.rb +56 -0
  29. data/sample/copyfrom.rb +1 -1
  30. data/sample/copyto.rb +1 -1
  31. data/sample/cursor.rb +1 -1
  32. data/sample/losample.rb +6 -6
  33. data/sample/notify_wait.rb +51 -22
  34. data/sample/test_binary_values.rb +4 -6
  35. data/spec/lib/helpers.rb +14 -10
  36. data/spec/{pgconn_spec.rb → pg/connection_spec.rb} +227 -60
  37. data/spec/{pgresult_spec.rb → pg/result_spec.rb} +31 -35
  38. data/spec/pg_spec.rb +22 -0
  39. metadata +44 -42
  40. metadata.gz.sig +0 -0
  41. data/GPL +0 -340
  42. data/ext/compat.c +0 -541
  43. data/ext/compat.h +0 -184
  44. data/sample/psql.rb +0 -1181
  45. data/sample/psqlHelp.rb +0 -158
  46. data/sample/test1.rb +0 -60
  47. data/sample/test2.rb +0 -44
  48. data/sample/test4.rb +0 -71
  49. data/spec/m17n_spec.rb +0 -170
@@ -2,18 +2,16 @@
2
2
 
3
3
  require 'pg'
4
4
 
5
- connhash = { :dbname => 'test' }
6
-
7
- db = PGconn.connect( connhash )
5
+ db = PG.connect( :dbname => 'test' )
8
6
  db.exec "DROP TABLE IF EXISTS test"
9
7
  db.exec "CREATE TABLE test (a INTEGER, b BYTEA)"
10
8
 
11
9
  a = 42
12
10
  b = [1, 2, 3]
13
- db.exec "INSERT INTO test(a, b) VALUES($1::int, $2::bytea)", \
14
- [a, {:value => b.pack('N*'), :format => 1}]
11
+ db.exec "INSERT INTO test(a, b) VALUES($1::int, $2::bytea)",
12
+ [a, {:value => b.pack('N*'), :format => 1}]
15
13
 
16
- db.exec "SELECT a::int, b::bytea FROM test LIMIT 1", [], 1 do |res|
14
+ db.exec( "SELECT a::int, b::bytea FROM test LIMIT 1", [], 1 ) do |res|
17
15
 
18
16
  res.nfields.times do |i|
19
17
  puts "Field %d is: %s, a %s (%s) column from table %p" % [
@@ -3,17 +3,11 @@
3
3
  require 'pathname'
4
4
  require 'rspec'
5
5
  require 'shellwords'
6
+ require 'pg'
6
7
 
7
8
  TEST_DIRECTORY = Pathname.getwd + "tmp_test_specs"
8
9
 
9
- RSpec.configure do |config|
10
- ruby_version_vec = RUBY_VERSION.split('.').map {|c| c.to_i }.pack( "N*" )
11
-
12
- config.mock_with :rspec
13
- config.filter_run_excluding :ruby_19 => true if ruby_version_vec <= [1,9,1].pack( "N*" )
14
- end
15
-
16
- module PgTestingHelpers
10
+ module PG::TestingHelpers
17
11
 
18
12
 
19
13
  # Set some ANSI escape code constants (Shamelessly stolen from Perl's
@@ -202,7 +196,7 @@ module PgTestingHelpers
202
196
  unless (@test_pgdata+"postgresql.conf").exist?
203
197
  FileUtils.rm_rf( @test_pgdata, :verbose => $DEBUG )
204
198
  $stderr.puts "Running initdb"
205
- log_and_run @logfile, 'initdb', '--no-locale', '-D', @test_pgdata.to_s
199
+ log_and_run @logfile, 'initdb', '-E', 'UTF8', '--no-locale', '-D', @test_pgdata.to_s
206
200
  end
207
201
 
208
202
  trace "Starting postgres"
@@ -221,7 +215,7 @@ module PgTestingHelpers
221
215
  fail
222
216
  end
223
217
 
224
- conn = PGconn.connect( @conninfo )
218
+ conn = PG.connect( @conninfo )
225
219
  conn.set_notice_processor do |message|
226
220
  $stderr.puts( message ) if $DEBUG
227
221
  end
@@ -238,3 +232,13 @@ module PgTestingHelpers
238
232
  end
239
233
 
240
234
 
235
+ RSpec.configure do |config|
236
+ ruby_version_vec = RUBY_VERSION.split('.').map {|c| c.to_i }.pack( "N*" )
237
+
238
+ config.include( PG::TestingHelpers )
239
+ config.treat_symbols_as_metadata_keys_with_true_values = true
240
+
241
+ config.mock_with :rspec
242
+ config.filter_run_excluding :ruby_19 => true if ruby_version_vec <= [1,9,1].pack( "N*" )
243
+ end
244
+
@@ -1,38 +1,33 @@
1
1
  #!/usr/bin/env rspec
2
- # encoding: utf-8
2
+ #encoding: utf-8
3
3
 
4
4
  BEGIN {
5
5
  require 'pathname'
6
- require 'rbconfig'
7
6
 
8
- basedir = Pathname( __FILE__ ).dirname.parent
7
+ basedir = Pathname( __FILE__ ).dirname.parent.parent
9
8
  libdir = basedir + 'lib'
10
- archlib = libdir + Config::CONFIG['sitearch']
11
9
 
12
10
  $LOAD_PATH.unshift( basedir.to_s ) unless $LOAD_PATH.include?( basedir.to_s )
13
11
  $LOAD_PATH.unshift( libdir.to_s ) unless $LOAD_PATH.include?( libdir.to_s )
14
- $LOAD_PATH.unshift( archlib.to_s ) unless $LOAD_PATH.include?( archlib.to_s )
15
12
  }
16
13
 
17
14
  require 'rspec'
18
15
  require 'spec/lib/helpers'
19
- require 'pg'
20
16
  require 'timeout'
17
+ require 'pg'
21
18
 
22
- describe PGconn do
23
- include PgTestingHelpers
24
-
19
+ describe PG::Connection do
25
20
 
26
21
  before( :all ) do
27
- @conn = setup_testing_db( "PGconn" )
22
+ @conn = setup_testing_db( "PG_Connection" )
28
23
  end
29
24
 
30
25
  before( :each ) do
31
- @conn.exec( 'BEGIN' )
26
+ @conn.exec( 'BEGIN' ) unless example.metadata[:without_transaction]
32
27
  end
33
28
 
34
29
  after( :each ) do
35
- @conn.exec( 'ROLLBACK' )
30
+ @conn.exec( 'ROLLBACK' ) unless example.metadata[:without_transaction]
36
31
  end
37
32
 
38
33
  after( :all ) do
@@ -45,7 +40,7 @@ describe PGconn do
45
40
  #
46
41
 
47
42
  it "can create a connection option string from a Hash of options" do
48
- optstring = PGconn.parse_connect_args(
43
+ optstring = described_class.parse_connect_args(
49
44
  :host => 'pgsql.example.com',
50
45
  :dbname => 'db01',
51
46
  'sslmode' => 'require'
@@ -58,7 +53,7 @@ describe PGconn do
58
53
  end
59
54
 
60
55
  it "can create a connection option string from positional parameters" do
61
- optstring = PGconn.parse_connect_args( 'pgsql.example.com', nil, '-c geqo=off', nil,
56
+ optstring = described_class.parse_connect_args( 'pgsql.example.com', nil, '-c geqo=off', nil,
62
57
  'sales' )
63
58
 
64
59
  optstring.should be_a( String )
@@ -71,7 +66,7 @@ describe PGconn do
71
66
  end
72
67
 
73
68
  it "can create a connection option string from a mix of positional and hash parameters" do
74
- optstring = PGconn.parse_connect_args( 'pgsql.example.com',
69
+ optstring = described_class.parse_connect_args( 'pgsql.example.com',
75
70
  :dbname => 'licensing', :user => 'jrandom' )
76
71
 
77
72
  optstring.should be_a( String )
@@ -81,64 +76,94 @@ describe PGconn do
81
76
  end
82
77
 
83
78
  it "escapes single quotes and backslashes in connection parameters" do
84
- PGconn.parse_connect_args( "DB 'browser' \\" ).should == "host='DB \\'browser\\' \\\\'"
79
+ described_class.parse_connect_args( "DB 'browser' \\" ).should == "host='DB \\'browser\\' \\\\'"
85
80
 
86
81
  end
87
82
 
88
83
  it "connects with defaults if no connection parameters are given" do
89
- PGconn.parse_connect_args.should == ''
84
+ described_class.parse_connect_args.should == ''
90
85
  end
91
86
 
92
87
  it "connects successfully with connection string" do
93
- tmpconn = PGconn.connect(@conninfo)
94
- tmpconn.status.should== PGconn::CONNECTION_OK
88
+ tmpconn = described_class.connect(@conninfo)
89
+ tmpconn.status.should== PG::CONNECTION_OK
95
90
  tmpconn.finish
96
91
  end
97
92
 
98
93
  it "connects using 7 arguments converted to strings" do
99
- tmpconn = PGconn.connect('localhost', @port, nil, nil, :test, nil, nil)
100
- tmpconn.status.should== PGconn::CONNECTION_OK
94
+ tmpconn = described_class.connect('localhost', @port, nil, nil, :test, nil, nil)
95
+ tmpconn.status.should== PG::CONNECTION_OK
101
96
  tmpconn.finish
102
97
  end
103
98
 
104
99
  it "connects using a hash of connection parameters" do
105
- tmpconn = PGconn.connect(
100
+ tmpconn = described_class.connect(
106
101
  :host => 'localhost',
107
102
  :port => @port,
108
103
  :dbname => :test)
109
- tmpconn.status.should== PGconn::CONNECTION_OK
104
+ tmpconn.status.should== PG::CONNECTION_OK
110
105
  tmpconn.finish
111
106
  end
112
107
 
113
108
  it "raises an exception when connecting with an invalid number of arguments" do
114
109
  expect {
115
- PGconn.connect( 1, 2, 3, 4, 5, 6, 7, 'extra' )
110
+ described_class.connect( 1, 2, 3, 4, 5, 6, 7, 'extra' )
116
111
  }.to raise_error( ArgumentError, /extra positional parameter/i )
117
112
  end
118
113
 
119
114
 
120
115
  it "can connect asynchronously" do
121
- tmpconn = PGconn.connect_start(@conninfo)
122
- socket = IO.for_fd(tmpconn.socket)
116
+ tmpconn = described_class.connect_start( @conninfo )
117
+ tmpconn.should be_a( described_class )
118
+ socket = IO.for_fd( tmpconn.socket )
123
119
  status = tmpconn.connect_poll
124
- while(status != PGconn::PGRES_POLLING_OK) do
125
- if(status == PGconn::PGRES_POLLING_READING)
126
- if(not select([socket],[],[],5.0))
120
+
121
+ while status != PG::PGRES_POLLING_OK
122
+ if status == PG::PGRES_POLLING_READING
123
+ select( [socket], [], [], 5.0 ) or
127
124
  raise "Asynchronous connection timed out!"
128
- end
129
- elsif(status == PGconn::PGRES_POLLING_WRITING)
130
- if(not select([],[socket],[],5.0))
125
+
126
+ elsif status == PG::PGRES_POLLING_WRITING
127
+ select( [], [socket], [], 5.0 ) or
131
128
  raise "Asynchronous connection timed out!"
132
- end
133
129
  end
134
130
  status = tmpconn.connect_poll
135
131
  end
136
- tmpconn.status.should== PGconn::CONNECTION_OK
132
+
133
+ tmpconn.status.should == PG::CONNECTION_OK
137
134
  tmpconn.finish
138
135
  end
139
136
 
137
+ it "can connect asynchronously for the duration of a block" do
138
+ conn = nil
139
+
140
+ described_class.connect_start(@conninfo) do |tmpconn|
141
+ tmpconn.should be_a( described_class )
142
+ conn = tmpconn
143
+ socket = IO.for_fd(tmpconn.socket)
144
+ status = tmpconn.connect_poll
145
+
146
+ while status != PG::PGRES_POLLING_OK
147
+ if status == PG::PGRES_POLLING_READING
148
+ if(not select([socket],[],[],5.0))
149
+ raise "Asynchronous connection timed out!"
150
+ end
151
+ elsif(status == PG::PGRES_POLLING_WRITING)
152
+ if(not select([],[socket],[],5.0))
153
+ raise "Asynchronous connection timed out!"
154
+ end
155
+ end
156
+ status = tmpconn.connect_poll
157
+ end
158
+
159
+ tmpconn.status.should == PG::CONNECTION_OK
160
+ end
161
+
162
+ conn.should be_finished()
163
+ end
164
+
140
165
  it "doesn't leave stale server connections after finish" do
141
- PGconn.connect(@conninfo).finish
166
+ described_class.connect(@conninfo).finish
142
167
  sleep 0.5
143
168
  res = @conn.exec(%[SELECT COUNT(*) AS n FROM pg_stat_activity
144
169
  WHERE usename IS NOT NULL])
@@ -213,13 +238,13 @@ describe PGconn do
213
238
  @conn.send_query("SELECT pg_sleep(1000)")
214
239
  @conn.cancel
215
240
  tmpres = @conn.get_result
216
- if(tmpres.result_status != PGresult::PGRES_TUPLES_OK)
241
+ if(tmpres.result_status != PG::PGRES_TUPLES_OK)
217
242
  error = true
218
243
  end
219
244
  error.should == true
220
245
  end
221
246
 
222
- it "automatically rolls back a transaction started with PGconn#transaction if an exception " +
247
+ it "automatically rolls back a transaction started with described_class#transaction if an exception " +
223
248
  "is raised" do
224
249
  # abort the per-example transaction so we can test our own
225
250
  @conn.exec( 'ROLLBACK' )
@@ -241,10 +266,10 @@ describe PGconn do
241
266
  it "not read past the end of a large object" do
242
267
  @conn.transaction do
243
268
  oid = @conn.lo_create( 0 )
244
- fd = @conn.lo_open( oid, PGconn::INV_READ|PGconn::INV_WRITE )
269
+ fd = @conn.lo_open( oid, PG::INV_READ|PG::INV_WRITE )
245
270
  @conn.lo_write( fd, "foobar" )
246
271
  @conn.lo_read( fd, 10 ).should be_nil()
247
- @conn.lo_lseek( fd, 0, PGconn::SEEK_SET )
272
+ @conn.lo_lseek( fd, 0, PG::SEEK_SET )
248
273
  @conn.lo_read( fd, 10 ).should == 'foobar'
249
274
  end
250
275
  end
@@ -256,7 +281,7 @@ describe PGconn do
256
281
 
257
282
  pid = fork do
258
283
  begin
259
- conn = PGconn.connect( @conninfo )
284
+ conn = described_class.connect( @conninfo )
260
285
  sleep 1
261
286
  conn.exec( 'NOTIFY woo' )
262
287
  ensure
@@ -277,7 +302,7 @@ describe PGconn do
277
302
 
278
303
  pid = fork do
279
304
  begin
280
- conn = PGconn.connect( @conninfo )
305
+ conn = described_class.connect( @conninfo )
281
306
  sleep 1
282
307
  conn.exec( 'NOTIFY woo' )
283
308
  ensure
@@ -304,7 +329,7 @@ describe PGconn do
304
329
 
305
330
  pid = fork do
306
331
  begin
307
- conn = PGconn.connect( @conninfo )
332
+ conn = described_class.connect( @conninfo )
308
333
  conn.exec( 'NOTIFY woo' )
309
334
  conn.exec( 'NOTIFY war' )
310
335
  conn.exec( 'NOTIFY woz' )
@@ -336,7 +361,7 @@ describe PGconn do
336
361
 
337
362
  pid = fork do
338
363
  begin
339
- conn = PGconn.connect( @conninfo )
364
+ conn = described_class.connect( @conninfo )
340
365
  conn.exec( 'NOTIFY woo' )
341
366
  ensure
342
367
  conn.finish
@@ -367,7 +392,7 @@ describe PGconn do
367
392
  @conn.exec( 'LISTEN knees' )
368
393
 
369
394
  pid = fork do
370
- conn = PGconn.connect( @conninfo )
395
+ conn = described_class.connect( @conninfo )
371
396
  conn.exec( %Q{NOTIFY knees, 'skirt and boots'} )
372
397
  conn.finish
373
398
  exit!
@@ -391,7 +416,7 @@ describe PGconn do
391
416
  @conn.exec( 'LISTEN knees' )
392
417
 
393
418
  pid = fork do
394
- conn = PGconn.connect( @conninfo )
419
+ conn = described_class.connect( @conninfo )
395
420
  conn.exec( %Q{NOTIFY knees} )
396
421
  conn.finish
397
422
  exit!
@@ -414,7 +439,7 @@ describe PGconn do
414
439
  @conn.exec( 'LISTEN knees' )
415
440
 
416
441
  pid = fork do
417
- conn = PGconn.connect( @conninfo )
442
+ conn = described_class.connect( @conninfo )
418
443
  conn.exec( %Q{NOTIFY knees} )
419
444
  conn.finish
420
445
  exit!
@@ -438,7 +463,7 @@ describe PGconn do
438
463
  @conn.exec( 'LISTEN knees' )
439
464
 
440
465
  pid = fork do
441
- conn = PGconn.connect( @conninfo )
466
+ conn = described_class.connect( @conninfo )
442
467
  conn.exec( %Q{NOTIFY knees, 'skirt and boots'} )
443
468
  conn.finish
444
469
  exit!
@@ -464,7 +489,7 @@ describe PGconn do
464
489
  @conn.exec( 'LISTEN knees' )
465
490
 
466
491
  pid = fork do
467
- conn = PGconn.connect( @conninfo )
492
+ conn = described_class.connect( @conninfo )
468
493
  conn.exec( %Q{NOTIFY knees, 'skirt and boots'} )
469
494
  conn.finish
470
495
  exit!
@@ -488,7 +513,7 @@ describe PGconn do
488
513
  @conn.exec( 'LISTEN knees' )
489
514
 
490
515
  pid = fork do
491
- conn = PGconn.connect( @conninfo )
516
+ conn = described_class.connect( @conninfo )
492
517
  conn.exec( %Q{NOTIFY knees, 'skirt and boots'} )
493
518
  conn.finish
494
519
  exit!
@@ -512,7 +537,7 @@ describe PGconn do
512
537
  it "yields the result if block is given to exec" do
513
538
  rval = @conn.exec( "select 1234::int as a union select 5678::int as a" ) do |result|
514
539
  values = []
515
- result.should be_kind_of( PGresult )
540
+ result.should be_kind_of( PG::Result )
516
541
  result.ntuples.should == 2
517
542
  result.each do |tuple|
518
543
  values << tuple['a']
@@ -543,7 +568,7 @@ describe PGconn do
543
568
  end
544
569
 
545
570
 
546
- it "PGconn#block shouldn't block a second thread" do
571
+ it "described_class#block shouldn't block a second thread" do
547
572
  t = Thread.new do
548
573
  @conn.send_query( "select pg_sleep(3)" )
549
574
  @conn.block
@@ -556,7 +581,7 @@ describe PGconn do
556
581
  t.join
557
582
  end
558
583
 
559
- it "PGconn#block should allow a timeout" do
584
+ it "described_class#block should allow a timeout" do
560
585
  @conn.send_query( "select pg_sleep(3)" )
561
586
 
562
587
  start = Time.now
@@ -568,7 +593,7 @@ describe PGconn do
568
593
 
569
594
 
570
595
  it "can encrypt a string given a password and username" do
571
- PGconn.encrypt_password("postgres", "postgres").
596
+ described_class.encrypt_password("postgres", "postgres").
572
597
  should =~ /\S+/
573
598
  end
574
599
 
@@ -576,13 +601,13 @@ describe PGconn do
576
601
  it "raises an appropriate error if either of the required arguments for encrypt_password " +
577
602
  "is not valid" do
578
603
  expect {
579
- PGconn.encrypt_password( nil, nil )
604
+ described_class.encrypt_password( nil, nil )
580
605
  }.to raise_error( TypeError )
581
606
  expect {
582
- PGconn.encrypt_password( "postgres", nil )
607
+ described_class.encrypt_password( "postgres", nil )
583
608
  }.to raise_error( TypeError )
584
609
  expect {
585
- PGconn.encrypt_password( nil, "postgres" )
610
+ described_class.encrypt_password( nil, "postgres" )
586
611
  }.to raise_error( TypeError )
587
612
  end
588
613
 
@@ -627,14 +652,14 @@ describe PGconn do
627
652
 
628
653
  it "can connect asynchronously" do
629
654
  serv = TCPServer.new( '127.0.0.1', 54320 )
630
- conn = PGconn.connect_start( '127.0.0.1', 54320, "", "", "me", "xxxx", "somedb" )
631
- conn.connect_poll.should == PGconn::PGRES_POLLING_WRITING
655
+ conn = described_class.connect_start( '127.0.0.1', 54320, "", "", "me", "xxxx", "somedb" )
656
+ conn.connect_poll.should == PG::PGRES_POLLING_WRITING
632
657
  select( nil, [IO.for_fd(conn.socket)], nil, 0.2 )
633
658
  serv.close
634
- if conn.connect_poll == PGconn::PGRES_POLLING_READING
659
+ if conn.connect_poll == PG::PGRES_POLLING_READING
635
660
  select( [IO.for_fd(conn.socket)], nil, nil, 0.2 )
636
661
  end
637
- conn.connect_poll.should == PGconn::PGRES_POLLING_FAILED
662
+ conn.connect_poll.should == PG::PGRES_POLLING_FAILED
638
663
  end
639
664
 
640
665
  it "discards previous results (if any) before waiting on an #async_exec"
@@ -647,4 +672,146 @@ describe PGconn do
647
672
  result.should == { 'one' => '47' }
648
673
  end
649
674
 
675
+
676
+ describe "multinationalization support", :ruby_19 => true do
677
+
678
+ it "should return the same bytes in text format that are sent as inline text" do
679
+ binary_file = File.join(Dir.pwd, 'spec/data', 'random_binary_data')
680
+ in_bytes = File.open(binary_file, 'r:ASCII-8BIT').read
681
+ escaped_bytes = described_class.escape_bytea( in_bytes )
682
+ out_bytes = nil
683
+
684
+ @conn.transaction do |conn|
685
+ conn.exec("SET standard_conforming_strings=on")
686
+ res = conn.exec("VALUES ('#{escaped_bytes}'::bytea)", [], 0)
687
+ out_bytes = described_class.unescape_bytea( res[0]['column1'] )
688
+ end
689
+
690
+ out_bytes.should == in_bytes
691
+ end
692
+
693
+ describe "rubyforge #22925: m17n support" do
694
+ it "should return results in the same encoding as the client (iso-8859-1)" do
695
+ out_string = nil
696
+ @conn.transaction do |conn|
697
+ conn.internal_encoding = 'iso8859-1'
698
+ res = conn.exec("VALUES ('fantasia')", [], 0)
699
+ out_string = res[0]['column1']
700
+ end
701
+ out_string.should == 'fantasia'
702
+ out_string.encoding.should == Encoding::ISO8859_1
703
+ end
704
+
705
+ it "should return results in the same encoding as the client (utf-8)" do
706
+ out_string = nil
707
+ @conn.transaction do |conn|
708
+ conn.internal_encoding = 'utf-8'
709
+ res = conn.exec("VALUES ('世界線航跡蔵')", [], 0)
710
+ out_string = res[0]['column1']
711
+ end
712
+ out_string.should == '世界線航跡蔵'
713
+ out_string.encoding.should == Encoding::UTF_8
714
+ end
715
+
716
+ it "should return results in the same encoding as the client (EUC-JP)" do
717
+ out_string = nil
718
+ @conn.transaction do |conn|
719
+ conn.internal_encoding = 'EUC-JP'
720
+ stmt = "VALUES ('世界線航跡蔵')".encode('EUC-JP')
721
+ res = conn.exec(stmt, [], 0)
722
+ out_string = res[0]['column1']
723
+ end
724
+ out_string.should == '世界線航跡蔵'.encode('EUC-JP')
725
+ out_string.encoding.should == Encoding::EUC_JP
726
+ end
727
+
728
+ it "returns the results in the correct encoding even if the client_encoding has " +
729
+ "changed since the results were fetched" do
730
+ out_string = nil
731
+ @conn.transaction do |conn|
732
+ conn.internal_encoding = 'EUC-JP'
733
+ stmt = "VALUES ('世界線航跡蔵')".encode('EUC-JP')
734
+ res = conn.exec(stmt, [], 0)
735
+ conn.internal_encoding = 'utf-8'
736
+ out_string = res[0]['column1']
737
+ end
738
+ out_string.should == '世界線航跡蔵'.encode('EUC-JP')
739
+ out_string.encoding.should == Encoding::EUC_JP
740
+ end
741
+
742
+ it "the connection should return ASCII-8BIT when it's set to SQL_ASCII" do
743
+ @conn.exec "SET client_encoding TO SQL_ASCII"
744
+ @conn.client_encoding.should == Encoding::ASCII_8BIT
745
+ end
746
+
747
+ it "works around the unsupported JOHAB encoding by returning stuff in 'ASCII_8BIT'" do
748
+ pending "figuring out how to create a string in the JOHAB encoding" do
749
+ out_string = nil
750
+ @conn.transaction do |conn|
751
+ conn.exec( "set client_encoding = 'JOHAB';" )
752
+ stmt = "VALUES ('foo')".encode('JOHAB')
753
+ res = conn.exec( stmt, [], 0 )
754
+ out_string = res[0]['column1']
755
+ end
756
+ out_string.should == 'foo'.encode( Encoding::ASCII_8BIT )
757
+ out_string.encoding.should == Encoding::ASCII_8BIT
758
+ end
759
+ end
760
+
761
+ it "uses the client encoding for escaped string" do
762
+ original = "string to escape".force_encoding( "euc-jp" )
763
+ @conn.set_client_encoding( "euc_jp" )
764
+ escaped = @conn.escape( original )
765
+ escaped.encoding.should == Encoding::EUC_JP
766
+ end
767
+ end
768
+
769
+
770
+ describe "Ruby 1.9.x default_internal encoding" do
771
+
772
+ it "honors the Encoding.default_internal if it's set and the synchronous interface is used" do
773
+ @conn.transaction do |txn_conn|
774
+ txn_conn.internal_encoding = Encoding::ISO8859_1
775
+ txn_conn.exec( "CREATE TABLE defaultinternaltest ( foo text )" )
776
+ txn_conn.exec( "INSERT INTO defaultinternaltest VALUES ('Grün und Weiß')" )
777
+ end
778
+
779
+ begin
780
+ prev_encoding = Encoding.default_internal
781
+ Encoding.default_internal = Encoding::UTF_8
782
+
783
+ conn = PG.connect( @conninfo )
784
+ conn.internal_encoding.should == Encoding::UTF_8
785
+ res = conn.exec( "SELECT foo FROM defaultinternaltest" )
786
+ res[0]['foo'].encoding.should == Encoding::UTF_8
787
+ ensure
788
+ conn.finish if conn
789
+ Encoding.default_internal = prev_encoding
790
+ end
791
+ end
792
+
793
+ end
794
+
795
+
796
+ it "encodes exception messages with the connection's encoding (#96)", :without_transaction do
797
+ # Use a new connection so the client_encoding isn't set outside of this example
798
+ conn = PG.connect( @conninfo )
799
+ conn.client_encoding = 'iso-8859-15'
800
+
801
+ conn.transaction do
802
+ conn.exec "CREATE TABLE foo (bar TEXT)"
803
+
804
+ begin
805
+ query = "INSERT INTO foo VALUES ('Côte d'Ivoire')".encode( 'iso-8859-15' )
806
+ conn.exec( query )
807
+ rescue => err
808
+ err.message.encoding.should == Encoding::ISO8859_15
809
+ else
810
+ fail "No exception raised?!"
811
+ end
812
+ end
813
+
814
+ end
815
+
816
+ end
650
817
  end