pg 1.1.0 → 1.2.3

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 (57) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data.tar.gz.sig +0 -0
  4. data/ChangeLog +0 -6595
  5. data/History.rdoc +110 -1
  6. data/Manifest.txt +3 -2
  7. data/README-Windows.rdoc +4 -4
  8. data/README.ja.rdoc +1 -2
  9. data/README.rdoc +44 -9
  10. data/Rakefile +8 -6
  11. data/Rakefile.cross +57 -56
  12. data/ext/errorcodes.def +68 -0
  13. data/ext/errorcodes.txt +19 -2
  14. data/ext/extconf.rb +6 -6
  15. data/ext/pg.c +138 -99
  16. data/ext/pg.h +34 -26
  17. data/ext/pg_binary_decoder.c +20 -16
  18. data/ext/pg_binary_encoder.c +13 -12
  19. data/ext/pg_coder.c +21 -9
  20. data/ext/pg_connection.c +413 -321
  21. data/ext/pg_copy_coder.c +6 -3
  22. data/ext/pg_record_coder.c +491 -0
  23. data/ext/pg_result.c +282 -128
  24. data/ext/pg_text_decoder.c +14 -8
  25. data/ext/pg_text_encoder.c +180 -48
  26. data/ext/pg_tuple.c +14 -6
  27. data/ext/pg_type_map.c +1 -1
  28. data/ext/pg_type_map_all_strings.c +4 -4
  29. data/ext/pg_type_map_by_class.c +9 -4
  30. data/ext/pg_type_map_by_column.c +7 -6
  31. data/ext/pg_type_map_by_mri_type.c +1 -1
  32. data/ext/pg_type_map_by_oid.c +3 -2
  33. data/ext/pg_type_map_in_ruby.c +1 -1
  34. data/ext/{util.c → pg_util.c} +5 -5
  35. data/ext/{util.h → pg_util.h} +0 -0
  36. data/lib/pg.rb +5 -5
  37. data/lib/pg/basic_type_mapping.rb +81 -18
  38. data/lib/pg/binary_decoder.rb +1 -0
  39. data/lib/pg/coder.rb +22 -1
  40. data/lib/pg/connection.rb +2 -2
  41. data/lib/pg/constants.rb +1 -0
  42. data/lib/pg/exceptions.rb +1 -0
  43. data/lib/pg/result.rb +13 -1
  44. data/lib/pg/text_decoder.rb +2 -3
  45. data/lib/pg/text_encoder.rb +8 -18
  46. data/lib/pg/type_map_by_column.rb +2 -1
  47. data/spec/helpers.rb +19 -19
  48. data/spec/pg/basic_type_mapping_spec.rb +141 -19
  49. data/spec/pg/connection_spec.rb +239 -93
  50. data/spec/pg/result_spec.rb +194 -4
  51. data/spec/pg/tuple_spec.rb +55 -2
  52. data/spec/pg/type_map_by_class_spec.rb +1 -1
  53. data/spec/pg/type_map_by_column_spec.rb +5 -1
  54. data/spec/pg/type_map_by_oid_spec.rb +2 -2
  55. data/spec/pg/type_spec.rb +180 -6
  56. metadata +41 -47
  57. metadata.gz.sig +0 -0
@@ -173,7 +173,7 @@ describe PG::Connection do
173
173
  end
174
174
  end
175
175
 
176
- it "can connect asynchronously", :socket_io do
176
+ it "can connect asynchronously" do
177
177
  tmpconn = described_class.connect_start( @conninfo )
178
178
  expect( tmpconn ).to be_a( described_class )
179
179
 
@@ -182,7 +182,7 @@ describe PG::Connection do
182
182
  tmpconn.finish
183
183
  end
184
184
 
185
- it "can connect asynchronously for the duration of a block", :socket_io do
185
+ it "can connect asynchronously for the duration of a block" do
186
186
  conn = nil
187
187
 
188
188
  described_class.connect_start(@conninfo) do |tmpconn|
@@ -196,7 +196,7 @@ describe PG::Connection do
196
196
  expect( conn ).to be_finished()
197
197
  end
198
198
 
199
- context "with async established connection", :socket_io do
199
+ context "with async established connection" do
200
200
  before :each do
201
201
  @conn2 = described_class.connect_start( @conninfo )
202
202
  wait_for_polling_ok(@conn2)
@@ -228,6 +228,37 @@ describe PG::Connection do
228
228
 
229
229
  res = @conn2.query("SELECT 4")
230
230
  end
231
+
232
+ it "can use conn.reset_start to restart the connection" do
233
+ ios = IO.pipe
234
+ conn = described_class.connect_start( @conninfo )
235
+ wait_for_polling_ok(conn)
236
+
237
+ # Close the two pipe file descriptors, so that the file descriptor of
238
+ # newly established connection is probably distinct from the previous one.
239
+ ios.each(&:close)
240
+ conn.reset_start
241
+ wait_for_polling_ok(conn, :reset_poll)
242
+
243
+ # The new connection should work even when the file descriptor has changed.
244
+ conn.send_query("SELECT 1")
245
+ res = wait_for_query_result(conn)
246
+ expect( res.values ).to eq([["1"]])
247
+
248
+ conn.close
249
+ end
250
+
251
+ it "should properly close a socket IO when GC'ed" do
252
+ # This results in
253
+ # Errno::ENOTSOCK: An operation was attempted on something that is not a socket.
254
+ # on Windows when rb_w32_unwrap_io_handle() isn't called in pgconn_gc_free().
255
+ 5.times do
256
+ conn = described_class.connect( @conninfo )
257
+ conn.socket_io.close
258
+ end
259
+ GC.start
260
+ IO.pipe.each(&:close)
261
+ end
231
262
  end
232
263
 
233
264
  it "raises proper error when sending fails" do
@@ -248,7 +279,7 @@ describe PG::Connection do
248
279
  expect( @conn.db ).to eq( "test" )
249
280
  expect( @conn.user ).to be_a_kind_of( String )
250
281
  expect( @conn.pass ).to eq( "" )
251
- expect( @conn.port ).to eq( 54321 )
282
+ expect( @conn.port ).to eq( @port )
252
283
  expect( @conn.tty ).to eq( "" )
253
284
  expect( @conn.options ).to eq( "" )
254
285
  end
@@ -257,7 +288,20 @@ describe PG::Connection do
257
288
  expect( @conn.host ).to eq( "localhost" )
258
289
  end
259
290
 
260
- EXPECTED_TRACE_OUTPUT = %{
291
+ it "can set error verbosity" do
292
+ old = @conn.set_error_verbosity( PG::PQERRORS_TERSE )
293
+ new = @conn.set_error_verbosity( old )
294
+ expect( new ).to eq( PG::PQERRORS_TERSE )
295
+ end
296
+
297
+ it "can set error context visibility", :postgresql_96 do
298
+ old = @conn.set_error_context_visibility( PG::PQSHOW_CONTEXT_NEVER )
299
+ new = @conn.set_error_context_visibility( old )
300
+ expect( new ).to eq( PG::PQSHOW_CONTEXT_NEVER )
301
+ end
302
+
303
+ let(:expected_trace_output) do
304
+ %{
261
305
  To backend> Msg Q
262
306
  To backend> "SELECT 1 AS one"
263
307
  To backend> Msg complete, length 21
@@ -285,6 +329,7 @@ describe PG::Connection do
285
329
  From backend (#4)> 5
286
330
  From backend> T
287
331
  }.gsub( /^\t{2}/, '' ).lstrip
332
+ end
288
333
 
289
334
  it "trace and untrace client-server communication", :unix do
290
335
  # be careful to explicitly close files so that the
@@ -295,10 +340,10 @@ describe PG::Connection do
295
340
  @conn.trace( trace_io )
296
341
  trace_io.close
297
342
 
298
- res = @conn.exec("SELECT 1 AS one")
343
+ @conn.exec("SELECT 1 AS one")
299
344
  @conn.untrace
300
345
 
301
- res = @conn.exec("SELECT 2 AS two")
346
+ @conn.exec("SELECT 2 AS two")
302
347
 
303
348
  trace_data = trace_file.read
304
349
 
@@ -310,7 +355,7 @@ describe PG::Connection do
310
355
  # From backend> T
311
356
  trace_data.sub!( /(From backend> Z\nFrom backend \(#4\)> 5\n){3}/m, '\\1\\1' )
312
357
 
313
- expect( trace_data ).to eq( EXPECTED_TRACE_OUTPUT )
358
+ expect( trace_data ).to eq( expected_trace_output )
314
359
  end
315
360
 
316
361
  it "allows a query to be cancelled" do
@@ -325,8 +370,6 @@ describe PG::Connection do
325
370
  end
326
371
 
327
372
  it "can stop a thread that runs a blocking query with async_exec" do
328
- pending "this does not work on Rubinius" if RUBY_ENGINE=='rbx'
329
-
330
373
  start = Time.now
331
374
  t = Thread.new do
332
375
  @conn.async_exec( 'select pg_sleep(10)' )
@@ -340,24 +383,16 @@ describe PG::Connection do
340
383
 
341
384
  it "should work together with signal handlers", :unix do
342
385
  signal_received = false
343
- trap 'USR1' do
386
+ trap 'USR2' do
344
387
  signal_received = true
345
388
  end
346
389
 
347
390
  Thread.new do
348
391
  sleep 0.1
349
- Process.kill("USR1", Process.pid)
392
+ Process.kill("USR2", Process.pid)
350
393
  end
351
394
  @conn.exec("select pg_sleep(0.3)")
352
395
  expect( signal_received ).to be_truthy
353
-
354
- signal_received = false
355
- Thread.new do
356
- sleep 0.1
357
- Process.kill("USR1", Process.pid)
358
- end
359
- @conn.async_exec("select pg_sleep(0.3)")
360
- expect( signal_received ).to be_truthy
361
396
  end
362
397
 
363
398
 
@@ -540,7 +575,7 @@ describe PG::Connection do
540
575
  expect( @conn.wait_for_notify( 1 ) ).to be_nil
541
576
  expect( notices.first ).to_not be_nil
542
577
  et = Time.now
543
- expect( (et - notices.first[1]) ).to be >= 0.4
578
+ expect( (et - notices.first[1]) ).to be >= 0.3
544
579
  expect( (et - st) ).to be >= 0.9
545
580
  expect( (et - st) ).to be < 1.4
546
581
  end
@@ -644,7 +679,7 @@ describe PG::Connection do
644
679
  @conn.copy_data( "COPY copytable FROM STDOUT" ) do |res|
645
680
  @conn.put_copy_data "xyz\n"
646
681
  end
647
- }.to raise_error(PG::Error, /invalid input syntax for integer/)
682
+ }.to raise_error(PG::Error, /invalid input syntax for .*integer/)
648
683
  end
649
684
  expect( @conn ).to still_be_usable
650
685
  end
@@ -734,7 +769,7 @@ describe PG::Connection do
734
769
  it "can return the default connection options as a Hash" do
735
770
  expect( described_class.conndefaults_hash ).to be_a( Hash )
736
771
  expect( described_class.conndefaults_hash ).to include( :user, :password, :dbname, :host, :port )
737
- expect( ['5432', '54321'] ).to include( described_class.conndefaults_hash[:port] )
772
+ expect( ['5432', '54321', @port.to_s] ).to include( described_class.conndefaults_hash[:port] )
738
773
  expect( @conn.conndefaults_hash ).to eq( described_class.conndefaults_hash )
739
774
  end
740
775
 
@@ -867,7 +902,7 @@ describe PG::Connection do
867
902
  end
868
903
 
869
904
 
870
- it "handles server close while asynchronous connect", :socket_io do
905
+ it "handles server close while asynchronous connect" do
871
906
  serv = TCPServer.new( '127.0.0.1', 54320 )
872
907
  conn = described_class.connect_start( '127.0.0.1', 54320, "", "", "me", "xxxx", "somedb" )
873
908
  expect( [PG::PGRES_POLLING_WRITING, PG::CONNECTION_OK] ).to include conn.connect_poll
@@ -914,7 +949,21 @@ describe PG::Connection do
914
949
  expect { conn.finish }.to raise_error( PG::ConnectionBad, /connection is closed/i )
915
950
  end
916
951
 
917
- it "closes the IO fetched from #socket_io when the connection is closed", :without_transaction, :socket_io do
952
+ it "can use conn.reset to restart the connection" do
953
+ ios = IO.pipe
954
+ conn = PG.connect( @conninfo )
955
+
956
+ # Close the two pipe file descriptors, so that the file descriptor of
957
+ # newly established connection is probably distinct from the previous one.
958
+ ios.each(&:close)
959
+ conn.reset
960
+
961
+ # The new connection should work even when the file descriptor has changed.
962
+ expect( conn.exec("SELECT 1").values ).to eq([["1"]])
963
+ conn.close
964
+ end
965
+
966
+ it "closes the IO fetched from #socket_io when the connection is closed", :without_transaction do
918
967
  conn = PG.connect( @conninfo )
919
968
  io = conn.socket_io
920
969
  conn.finish
@@ -922,7 +971,7 @@ describe PG::Connection do
922
971
  expect { conn.socket_io }.to raise_error( PG::ConnectionBad, /connection is closed/i )
923
972
  end
924
973
 
925
- it "closes the IO fetched from #socket_io when the connection is reset", :without_transaction, :socket_io do
974
+ it "closes the IO fetched from #socket_io when the connection is reset", :without_transaction do
926
975
  conn = PG.connect( @conninfo )
927
976
  io = conn.socket_io
928
977
  conn.reset
@@ -939,7 +988,7 @@ describe PG::Connection do
939
988
  end
940
989
  serv.close
941
990
  expect{ conn.block }.to raise_error(PG::ConnectionBad, /server closed the connection unexpectedly/)
942
- expect{ conn.block }.to raise_error(PG::ConnectionBad, /connection not open/)
991
+ expect{ conn.block }.to raise_error(PG::ConnectionBad, /can't get socket descriptor/)
943
992
  end
944
993
 
945
994
  it "sets the fallback_application_name on new connections" do
@@ -1110,8 +1159,16 @@ describe PG::Connection do
1110
1159
  expect( ping ).to eq( PG::PQPING_NO_RESPONSE )
1111
1160
  end
1112
1161
 
1113
- it "returns correct response when ping connection arguments are wrong" do
1162
+ it "returns error when ping connection arguments are wrong" do
1114
1163
  ping = described_class.ping('localhost', 'localhost', nil, nil, :test, nil, nil)
1164
+ expect( ping ).to_not eq( PG::PQPING_OK )
1165
+ end
1166
+
1167
+ it "returns correct response when ping connection arguments are wrong" do
1168
+ ping = described_class.ping(
1169
+ :host => 'localhost',
1170
+ :invalid_option => 9999,
1171
+ :dbname => :test)
1115
1172
  expect( ping ).to eq( PG::PQPING_NO_ATTEMPT )
1116
1173
  end
1117
1174
 
@@ -1180,53 +1237,41 @@ describe PG::Connection do
1180
1237
 
1181
1238
  end
1182
1239
 
1183
- context "multinationalization support", :ruby_19 do
1240
+ context "multinationalization support" do
1184
1241
 
1185
1242
  describe "rubyforge #22925: m17n support" do
1186
1243
  it "should return results in the same encoding as the client (iso-8859-1)" do
1187
- out_string = nil
1188
- @conn.transaction do |conn|
1189
- conn.internal_encoding = 'iso8859-1'
1190
- res = conn.exec_params("VALUES ('fantasia')", [], 0)
1191
- out_string = res[0]['column1']
1192
- end
1244
+ @conn.internal_encoding = 'iso8859-1'
1245
+ res = @conn.exec_params("VALUES ('fantasia')", [], 0)
1246
+ out_string = res[0]['column1']
1193
1247
  expect( out_string ).to eq( 'fantasia' )
1194
1248
  expect( out_string.encoding ).to eq( Encoding::ISO8859_1 )
1195
1249
  end
1196
1250
 
1197
1251
  it "should return results in the same encoding as the client (utf-8)" do
1198
- out_string = nil
1199
- @conn.transaction do |conn|
1200
- conn.internal_encoding = 'utf-8'
1201
- res = conn.exec_params("VALUES ('世界線航跡蔵')", [], 0)
1202
- out_string = res[0]['column1']
1203
- end
1252
+ @conn.internal_encoding = 'utf-8'
1253
+ res = @conn.exec_params("VALUES ('世界線航跡蔵')", [], 0)
1254
+ out_string = res[0]['column1']
1204
1255
  expect( out_string ).to eq( '世界線航跡蔵' )
1205
1256
  expect( out_string.encoding ).to eq( Encoding::UTF_8 )
1206
1257
  end
1207
1258
 
1208
1259
  it "should return results in the same encoding as the client (EUC-JP)" do
1209
- out_string = nil
1210
- @conn.transaction do |conn|
1211
- conn.internal_encoding = 'EUC-JP'
1212
- stmt = "VALUES ('世界線航跡蔵')".encode('EUC-JP')
1213
- res = conn.exec_params(stmt, [], 0)
1214
- out_string = res[0]['column1']
1215
- end
1260
+ @conn.internal_encoding = 'EUC-JP'
1261
+ stmt = "VALUES ('世界線航跡蔵')".encode('EUC-JP')
1262
+ res = @conn.exec_params(stmt, [], 0)
1263
+ out_string = res[0]['column1']
1216
1264
  expect( out_string ).to eq( '世界線航跡蔵'.encode('EUC-JP') )
1217
1265
  expect( out_string.encoding ).to eq( Encoding::EUC_JP )
1218
1266
  end
1219
1267
 
1220
1268
  it "returns the results in the correct encoding even if the client_encoding has " +
1221
1269
  "changed since the results were fetched" do
1222
- out_string = nil
1223
- @conn.transaction do |conn|
1224
- conn.internal_encoding = 'EUC-JP'
1225
- stmt = "VALUES ('世界線航跡蔵')".encode('EUC-JP')
1226
- res = conn.exec_params(stmt, [], 0)
1227
- conn.internal_encoding = 'utf-8'
1228
- out_string = res[0]['column1']
1229
- end
1270
+ @conn.internal_encoding = 'EUC-JP'
1271
+ stmt = "VALUES ('世界線航跡蔵')".encode('EUC-JP')
1272
+ res = @conn.exec_params(stmt, [], 0)
1273
+ @conn.internal_encoding = 'utf-8'
1274
+ out_string = res[0]['column1']
1230
1275
  expect( out_string ).to eq( '世界線航跡蔵'.encode('EUC-JP') )
1231
1276
  expect( out_string.encoding ).to eq( Encoding::EUC_JP )
1232
1277
  end
@@ -1236,6 +1281,22 @@ describe PG::Connection do
1236
1281
  expect( @conn.internal_encoding ).to eq( Encoding::ASCII_8BIT )
1237
1282
  end
1238
1283
 
1284
+ it "the connection should use JOHAB dummy encoding when it's set to JOHAB" do
1285
+ @conn.set_client_encoding "JOHAB"
1286
+ val = @conn.exec("SELECT chr(x'3391'::int)").values[0][0]
1287
+ expect( val.encoding.name ).to eq( "JOHAB" )
1288
+ expect( val.unpack("H*")[0] ).to eq( "dc65" )
1289
+ end
1290
+
1291
+ it "can retrieve server encoding as text" do
1292
+ enc = @conn.parameter_status "server_encoding"
1293
+ expect( enc ).to eq( "UTF8" )
1294
+ end
1295
+
1296
+ it "can retrieve server encoding as ruby encoding" do
1297
+ expect( @conn.external_encoding ).to eq( Encoding::UTF_8 )
1298
+ end
1299
+
1239
1300
  it "uses the client encoding for escaped string" do
1240
1301
  original = "Möhre to 'scape".encode( "utf-16be" )
1241
1302
  @conn.set_client_encoding( "euc_jp" )
@@ -1289,6 +1350,21 @@ describe PG::Connection do
1289
1350
  expect { @conn.set_client_encoding( :invalid ) }.to raise_error(TypeError)
1290
1351
  expect { @conn.set_client_encoding( nil ) }.to raise_error(TypeError)
1291
1352
  end
1353
+
1354
+ it "can use an encoding with high index for client encoding" do
1355
+ # Allocate a lot of encoding indices, so that MRI's ENCODING_INLINE_MAX is exceeded
1356
+ unless Encoding.name_list.include?("pgtest-0")
1357
+ 256.times do |eidx|
1358
+ Encoding::UTF_8.replicate("pgtest-#{eidx}")
1359
+ end
1360
+ end
1361
+
1362
+ # Now allocate the JOHAB encoding with an unusual high index
1363
+ @conn.set_client_encoding "JOHAB"
1364
+ val = @conn.exec("SELECT chr(x'3391'::int)").values[0][0]
1365
+ expect( val.encoding.name ).to eq( "JOHAB" )
1366
+ end
1367
+
1292
1368
  end
1293
1369
 
1294
1370
  describe "respect and convert character encoding of input strings" do
@@ -1432,7 +1508,7 @@ describe PG::Connection do
1432
1508
 
1433
1509
  describe "Ruby 1.9.x default_internal encoding" do
1434
1510
 
1435
- it "honors the Encoding.default_internal if it's set and the synchronous interface is used" do
1511
+ it "honors the Encoding.default_internal if it's set and the synchronous interface is used", :without_transaction do
1436
1512
  @conn.transaction do |txn_conn|
1437
1513
  txn_conn.internal_encoding = Encoding::ISO8859_1
1438
1514
  txn_conn.exec( "CREATE TABLE defaultinternaltest ( foo text )" )
@@ -1534,9 +1610,8 @@ describe PG::Connection do
1534
1610
  end
1535
1611
  end
1536
1612
 
1537
- it "receives properly encoded text from wait_for_notify" do
1613
+ it "receives properly encoded text from wait_for_notify", :without_transaction do
1538
1614
  @conn.internal_encoding = 'utf-8'
1539
- @conn.exec( 'ROLLBACK' )
1540
1615
  @conn.exec( 'LISTEN "Möhre"' )
1541
1616
  @conn.exec( %Q{NOTIFY "Möhre", '世界線航跡蔵'} )
1542
1617
  event, pid, msg = nil
@@ -1547,13 +1622,13 @@ describe PG::Connection do
1547
1622
 
1548
1623
  expect( event ).to eq( "Möhre" )
1549
1624
  expect( event.encoding ).to eq( Encoding::UTF_8 )
1625
+ expect( pid ).to be_a_kind_of(Integer)
1550
1626
  expect( msg ).to eq( '世界線航跡蔵' )
1551
1627
  expect( msg.encoding ).to eq( Encoding::UTF_8 )
1552
1628
  end
1553
1629
 
1554
- it "returns properly encoded text from notifies" do
1630
+ it "returns properly encoded text from notifies", :without_transaction do
1555
1631
  @conn.internal_encoding = 'utf-8'
1556
- @conn.exec( 'ROLLBACK' )
1557
1632
  @conn.exec( 'LISTEN "Möhre"' )
1558
1633
  @conn.exec( %Q{NOTIFY "Möhre", '世界線航跡蔵'} )
1559
1634
  @conn.exec( 'UNLISTEN "Möhre"' )
@@ -1567,7 +1642,7 @@ describe PG::Connection do
1567
1642
  end
1568
1643
  end
1569
1644
 
1570
- context "OS thread support", :ruby_19 do
1645
+ context "OS thread support" do
1571
1646
  it "Connection#exec shouldn't block a second thread" do
1572
1647
  t = Thread.new do
1573
1648
  @conn.exec( "select pg_sleep(1)" )
@@ -1628,12 +1703,12 @@ describe PG::Connection do
1628
1703
  row_encoder = PG::TextEncoder::CopyRow.new type_map: tm
1629
1704
 
1630
1705
  @conn.exec( "CREATE TEMP TABLE copytable (col1 TEXT)" )
1631
- res2 = @conn.copy_data( "COPY copytable FROM STDOUT" ) do |res|
1706
+ @conn.copy_data( "COPY copytable FROM STDOUT" ) do |res|
1632
1707
  @conn.put_copy_data [1], row_encoder
1633
1708
  @conn.put_copy_data ["2"], row_encoder
1634
1709
  end
1635
1710
 
1636
- res2 = @conn.copy_data( "COPY copytable FROM STDOUT", row_encoder ) do |res|
1711
+ @conn.copy_data( "COPY copytable FROM STDOUT", row_encoder ) do |res|
1637
1712
  @conn.put_copy_data [3]
1638
1713
  @conn.put_copy_data ["4"]
1639
1714
  end
@@ -1683,7 +1758,7 @@ describe PG::Connection do
1683
1758
 
1684
1759
  it "can process #copy_data input queries with row encoder and respects character encoding" do
1685
1760
  @conn2.exec( "CREATE TEMP TABLE copytable (col1 TEXT)" )
1686
- res2 = @conn2.copy_data( "COPY copytable FROM STDOUT" ) do |res|
1761
+ @conn2.copy_data( "COPY copytable FROM STDOUT" ) do |res|
1687
1762
  @conn2.put_copy_data [1]
1688
1763
  @conn2.put_copy_data ["Möhre".encode("utf-16le")]
1689
1764
  end
@@ -1734,7 +1809,7 @@ describe PG::Connection do
1734
1809
  it "can process #copy_data output with row decoder and respects character encoding" do
1735
1810
  @conn2.internal_encoding = Encoding::ISO8859_1
1736
1811
  rows = []
1737
- res2 = @conn2.copy_data( "COPY (VALUES('1'), ('Möhre')) TO STDOUT".encode("utf-16le") ) do |res|
1812
+ @conn2.copy_data( "COPY (VALUES('1'), ('Möhre')) TO STDOUT".encode("utf-16le") ) do |res|
1738
1813
  while row=@conn2.get_copy_data
1739
1814
  rows << row
1740
1815
  end
@@ -1762,35 +1837,106 @@ describe PG::Connection do
1762
1837
  end
1763
1838
  end
1764
1839
 
1765
- describe "deprecated forms of methods" do
1766
- it "should forward exec to exec_params" do
1767
- res = @conn.exec("VALUES($1::INT)", [7]).values
1768
- expect(res).to eq( [["7"]] )
1769
- res = @conn.exec("VALUES($1::INT)", [7], 1).values
1770
- expect(res).to eq( [[[7].pack("N")]] )
1771
- res = @conn.exec("VALUES(8)", [], 1).values
1772
- expect(res).to eq( [[[8].pack("N")]] )
1773
- end
1774
-
1775
- it "should forward exec_params to exec" do
1776
- res = @conn.exec_params("VALUES(3); VALUES(4)").values
1777
- expect(res).to eq( [["4"]] )
1778
- res = @conn.exec_params("VALUES(3); VALUES(4)", nil).values
1779
- expect(res).to eq( [["4"]] )
1780
- res = @conn.exec_params("VALUES(3); VALUES(4)", nil, nil).values
1781
- expect(res).to eq( [["4"]] )
1782
- res = @conn.exec_params("VALUES(3); VALUES(4)", nil, 1).values
1783
- expect(res).to eq( [["4"]] )
1784
- res = @conn.exec_params("VALUES(3); VALUES(4)", nil, nil, nil).values
1785
- expect(res).to eq( [["4"]] )
1786
- expect{
1787
- @conn.exec_params("VALUES(3); VALUES(4)", nil, nil, nil, nil).values
1788
- }.to raise_error(ArgumentError)
1840
+ describe :field_name_type do
1841
+ before :each do
1842
+ @conn2 = PG.connect(@conninfo)
1843
+ end
1844
+ after :each do
1845
+ @conn2.close
1846
+ end
1847
+
1848
+ it "uses string field names per default" do
1849
+ expect(@conn2.field_name_type).to eq(:string)
1850
+ end
1851
+
1852
+ it "can set string field names" do
1853
+ @conn2.field_name_type = :string
1854
+ expect(@conn2.field_name_type).to eq(:string)
1855
+ res = @conn2.exec("SELECT 1 as az")
1856
+ expect(res.field_name_type).to eq(:string)
1857
+ expect(res.fields).to eq(["az"])
1858
+ end
1859
+
1860
+ it "can set symbol field names" do
1861
+ @conn2.field_name_type = :symbol
1862
+ expect(@conn2.field_name_type).to eq(:symbol)
1863
+ res = @conn2.exec("SELECT 1 as az")
1864
+ expect(res.field_name_type).to eq(:symbol)
1865
+ expect(res.fields).to eq([:az])
1789
1866
  end
1790
1867
 
1791
- it "should forward send_query to send_query_params" do
1792
- @conn.send_query("VALUES($1)", [5])
1793
- expect(@conn.get_last_result.values).to eq( [["5"]] )
1868
+ it "can't set invalid values" do
1869
+ expect{ @conn2.field_name_type = :sym }.to raise_error(ArgumentError, /invalid argument :sym/)
1870
+ expect{ @conn2.field_name_type = "symbol" }.to raise_error(ArgumentError, /invalid argument "symbol"/)
1871
+ end
1872
+ end
1873
+
1874
+ describe "deprecated forms of methods" do
1875
+ if PG::VERSION < "2"
1876
+ it "should forward exec to exec_params" do
1877
+ res = @conn.exec("VALUES($1::INT)", [7]).values
1878
+ expect(res).to eq( [["7"]] )
1879
+ res = @conn.exec("VALUES($1::INT)", [7], 1).values
1880
+ expect(res).to eq( [[[7].pack("N")]] )
1881
+ res = @conn.exec("VALUES(8)", [], 1).values
1882
+ expect(res).to eq( [[[8].pack("N")]] )
1883
+ end
1884
+
1885
+ it "should forward exec_params to exec" do
1886
+ res = @conn.exec_params("VALUES(3); VALUES(4)").values
1887
+ expect(res).to eq( [["4"]] )
1888
+ res = @conn.exec_params("VALUES(3); VALUES(4)", nil).values
1889
+ expect(res).to eq( [["4"]] )
1890
+ res = @conn.exec_params("VALUES(3); VALUES(4)", nil, nil).values
1891
+ expect(res).to eq( [["4"]] )
1892
+ res = @conn.exec_params("VALUES(3); VALUES(4)", nil, 1).values
1893
+ expect(res).to eq( [["4"]] )
1894
+ res = @conn.exec_params("VALUES(3); VALUES(4)", nil, nil, nil).values
1895
+ expect(res).to eq( [["4"]] )
1896
+ expect{
1897
+ @conn.exec_params("VALUES(3); VALUES(4)", nil, nil, nil, nil).values
1898
+ }.to raise_error(ArgumentError)
1899
+ end
1900
+
1901
+ it "should forward send_query to send_query_params" do
1902
+ @conn.send_query("VALUES($1)", [5])
1903
+ expect(@conn.get_last_result.values).to eq( [["5"]] )
1904
+ end
1905
+
1906
+ it "should respond_to socket", :unix do
1907
+ expect( @conn.socket ).to eq( @conn.socket_io.fileno )
1908
+ end
1909
+ else
1910
+ # Method forwarding removed by PG::VERSION >= "2"
1911
+ it "shouldn't forward exec to exec_params" do
1912
+ expect do
1913
+ @conn.exec("VALUES($1::INT)", [7])
1914
+ end.to raise_error(ArgumentError)
1915
+ end
1916
+
1917
+ it "shouldn't forward exec_params to exec" do
1918
+ expect do
1919
+ @conn.exec_params("VALUES(3); VALUES(4)")
1920
+ end.to raise_error(ArgumentError)
1921
+ end
1922
+
1923
+ it "shouldn't forward send_query to send_query_params" do
1924
+ expect do
1925
+ @conn.send_query("VALUES($1)", [5])
1926
+ end.to raise_error(ArgumentError)
1927
+ end
1928
+
1929
+ it "shouldn't forward async_exec_params to async_exec" do
1930
+ expect do
1931
+ @conn.async_exec_params("VALUES(1)")
1932
+ end.to raise_error(ArgumentError)
1933
+ end
1934
+
1935
+ it "shouldn't respond_to socket" do
1936
+ expect do
1937
+ @conn.socket
1938
+ end.to raise_error(ArgumentError)
1939
+ end
1794
1940
  end
1795
1941
 
1796
1942
  it "shouldn't forward send_query_params to send_query" do