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.
- checksums.yaml +4 -4
- checksums.yaml.gz.sig +0 -0
- data.tar.gz.sig +0 -0
- data/ChangeLog +0 -6595
- data/History.rdoc +110 -1
- data/Manifest.txt +3 -2
- data/README-Windows.rdoc +4 -4
- data/README.ja.rdoc +1 -2
- data/README.rdoc +44 -9
- data/Rakefile +8 -6
- data/Rakefile.cross +57 -56
- data/ext/errorcodes.def +68 -0
- data/ext/errorcodes.txt +19 -2
- data/ext/extconf.rb +6 -6
- data/ext/pg.c +138 -99
- data/ext/pg.h +34 -26
- data/ext/pg_binary_decoder.c +20 -16
- data/ext/pg_binary_encoder.c +13 -12
- data/ext/pg_coder.c +21 -9
- data/ext/pg_connection.c +413 -321
- data/ext/pg_copy_coder.c +6 -3
- data/ext/pg_record_coder.c +491 -0
- data/ext/pg_result.c +282 -128
- data/ext/pg_text_decoder.c +14 -8
- data/ext/pg_text_encoder.c +180 -48
- data/ext/pg_tuple.c +14 -6
- data/ext/pg_type_map.c +1 -1
- data/ext/pg_type_map_all_strings.c +4 -4
- data/ext/pg_type_map_by_class.c +9 -4
- data/ext/pg_type_map_by_column.c +7 -6
- data/ext/pg_type_map_by_mri_type.c +1 -1
- data/ext/pg_type_map_by_oid.c +3 -2
- data/ext/pg_type_map_in_ruby.c +1 -1
- data/ext/{util.c → pg_util.c} +5 -5
- data/ext/{util.h → pg_util.h} +0 -0
- data/lib/pg.rb +5 -5
- data/lib/pg/basic_type_mapping.rb +81 -18
- data/lib/pg/binary_decoder.rb +1 -0
- data/lib/pg/coder.rb +22 -1
- data/lib/pg/connection.rb +2 -2
- data/lib/pg/constants.rb +1 -0
- data/lib/pg/exceptions.rb +1 -0
- data/lib/pg/result.rb +13 -1
- data/lib/pg/text_decoder.rb +2 -3
- data/lib/pg/text_encoder.rb +8 -18
- data/lib/pg/type_map_by_column.rb +2 -1
- data/spec/helpers.rb +19 -19
- data/spec/pg/basic_type_mapping_spec.rb +141 -19
- data/spec/pg/connection_spec.rb +239 -93
- data/spec/pg/result_spec.rb +194 -4
- data/spec/pg/tuple_spec.rb +55 -2
- data/spec/pg/type_map_by_class_spec.rb +1 -1
- data/spec/pg/type_map_by_column_spec.rb +5 -1
- data/spec/pg/type_map_by_oid_spec.rb +2 -2
- data/spec/pg/type_spec.rb +180 -6
- metadata +41 -47
- metadata.gz.sig +0 -0
data/spec/pg/connection_spec.rb
CHANGED
@@ -173,7 +173,7 @@ describe PG::Connection do
|
|
173
173
|
end
|
174
174
|
end
|
175
175
|
|
176
|
-
it "can connect asynchronously"
|
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"
|
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"
|
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(
|
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
|
-
|
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
|
-
|
343
|
+
@conn.exec("SELECT 1 AS one")
|
299
344
|
@conn.untrace
|
300
345
|
|
301
|
-
|
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(
|
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 '
|
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("
|
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.
|
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"
|
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 "
|
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
|
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, /
|
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
|
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"
|
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
|
-
|
1188
|
-
@conn.
|
1189
|
-
|
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
|
-
|
1199
|
-
@conn.
|
1200
|
-
|
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
|
-
|
1210
|
-
|
1211
|
-
|
1212
|
-
|
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
|
-
|
1223
|
-
|
1224
|
-
|
1225
|
-
|
1226
|
-
|
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"
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
1766
|
-
|
1767
|
-
|
1768
|
-
|
1769
|
-
|
1770
|
-
|
1771
|
-
|
1772
|
-
|
1773
|
-
|
1774
|
-
|
1775
|
-
|
1776
|
-
|
1777
|
-
|
1778
|
-
|
1779
|
-
expect(
|
1780
|
-
res = @
|
1781
|
-
expect(res).to eq(
|
1782
|
-
res
|
1783
|
-
|
1784
|
-
|
1785
|
-
|
1786
|
-
|
1787
|
-
|
1788
|
-
|
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 "
|
1792
|
-
@
|
1793
|
-
expect
|
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
|