pg 1.0.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 +156 -0
- data/Manifest.txt +8 -2
- data/README-Windows.rdoc +4 -4
- data/README.ja.rdoc +1 -2
- data/README.rdoc +55 -9
- data/Rakefile +9 -7
- data/Rakefile.cross +58 -57
- data/ext/errorcodes.def +68 -0
- data/ext/errorcodes.rb +1 -1
- data/ext/errorcodes.txt +19 -2
- data/ext/extconf.rb +7 -5
- data/ext/pg.c +141 -98
- data/ext/pg.h +64 -21
- data/ext/pg_binary_decoder.c +82 -15
- data/ext/pg_binary_encoder.c +13 -12
- data/ext/pg_coder.c +73 -12
- data/ext/pg_connection.c +625 -346
- data/ext/pg_copy_coder.c +16 -8
- data/ext/pg_record_coder.c +491 -0
- data/ext/pg_result.c +571 -191
- data/ext/pg_text_decoder.c +606 -40
- data/ext/pg_text_encoder.c +185 -54
- data/ext/pg_tuple.c +549 -0
- 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} +10 -10
- data/ext/{util.h → pg_util.h} +2 -2
- data/lib/pg.rb +8 -6
- data/lib/pg/basic_type_mapping.rb +121 -25
- data/lib/pg/binary_decoder.rb +23 -0
- data/lib/pg/coder.rb +23 -2
- data/lib/pg/connection.rb +22 -3
- data/lib/pg/constants.rb +2 -1
- data/lib/pg/exceptions.rb +2 -1
- data/lib/pg/result.rb +14 -2
- data/lib/pg/text_decoder.rb +21 -26
- data/lib/pg/text_encoder.rb +32 -8
- data/lib/pg/tuple.rb +30 -0
- data/lib/pg/type_map_by_column.rb +3 -2
- data/spec/helpers.rb +52 -20
- data/spec/pg/basic_type_mapping_spec.rb +362 -37
- data/spec/pg/connection_spec.rb +376 -146
- data/spec/pg/connection_sync_spec.rb +41 -0
- data/spec/pg/result_spec.rb +240 -15
- data/spec/pg/tuple_spec.rb +333 -0
- data/spec/pg/type_map_by_class_spec.rb +2 -2
- data/spec/pg/type_map_by_column_spec.rb +6 -2
- data/spec/pg/type_map_by_mri_type_spec.rb +1 -1
- data/spec/pg/type_map_by_oid_spec.rb +3 -3
- data/spec/pg/type_map_in_ruby_spec.rb +1 -1
- data/spec/pg/type_map_spec.rb +1 -1
- data/spec/pg/type_spec.rb +363 -17
- data/spec/pg_spec.rb +1 -1
- metadata +47 -47
- metadata.gz.sig +0 -0
data/spec/pg/connection_spec.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
|
1
|
+
# -*- rspec -*-
|
2
2
|
#encoding: utf-8
|
3
3
|
|
4
4
|
require_relative '../helpers'
|
@@ -173,56 +173,94 @@ 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
|
-
socket = tmpconn.socket_io
|
180
|
-
status = tmpconn.connect_poll
|
181
|
-
|
182
|
-
while status != PG::PGRES_POLLING_OK
|
183
|
-
if status == PG::PGRES_POLLING_READING
|
184
|
-
select( [socket], [], [], 5.0 ) or
|
185
|
-
raise "Asynchronous connection timed out!"
|
186
|
-
|
187
|
-
elsif status == PG::PGRES_POLLING_WRITING
|
188
|
-
select( [], [socket], [], 5.0 ) or
|
189
|
-
raise "Asynchronous connection timed out!"
|
190
|
-
end
|
191
|
-
status = tmpconn.connect_poll
|
192
|
-
end
|
193
179
|
|
180
|
+
wait_for_polling_ok(tmpconn)
|
194
181
|
expect( tmpconn.status ).to eq( PG::CONNECTION_OK )
|
195
182
|
tmpconn.finish
|
196
183
|
end
|
197
184
|
|
198
|
-
it "can connect asynchronously for the duration of a block"
|
185
|
+
it "can connect asynchronously for the duration of a block" do
|
199
186
|
conn = nil
|
200
187
|
|
201
188
|
described_class.connect_start(@conninfo) do |tmpconn|
|
202
189
|
expect( tmpconn ).to be_a( described_class )
|
203
190
|
conn = tmpconn
|
204
|
-
socket = tmpconn.socket_io
|
205
|
-
status = tmpconn.connect_poll
|
206
|
-
|
207
|
-
while status != PG::PGRES_POLLING_OK
|
208
|
-
if status == PG::PGRES_POLLING_READING
|
209
|
-
if(not select([socket],[],[],5.0))
|
210
|
-
raise "Asynchronous connection timed out!"
|
211
|
-
end
|
212
|
-
elsif(status == PG::PGRES_POLLING_WRITING)
|
213
|
-
if(not select([],[socket],[],5.0))
|
214
|
-
raise "Asynchronous connection timed out!"
|
215
|
-
end
|
216
|
-
end
|
217
|
-
status = tmpconn.connect_poll
|
218
|
-
end
|
219
191
|
|
192
|
+
wait_for_polling_ok(tmpconn)
|
220
193
|
expect( tmpconn.status ).to eq( PG::CONNECTION_OK )
|
221
194
|
end
|
222
195
|
|
223
196
|
expect( conn ).to be_finished()
|
224
197
|
end
|
225
198
|
|
199
|
+
context "with async established connection" do
|
200
|
+
before :each do
|
201
|
+
@conn2 = described_class.connect_start( @conninfo )
|
202
|
+
wait_for_polling_ok(@conn2)
|
203
|
+
expect( @conn2 ).to still_be_usable
|
204
|
+
end
|
205
|
+
|
206
|
+
after :each do
|
207
|
+
expect( @conn2 ).to still_be_usable
|
208
|
+
@conn2.close
|
209
|
+
end
|
210
|
+
|
211
|
+
it "conn.send_query and IO.select work" do
|
212
|
+
@conn2.send_query("SELECT 1")
|
213
|
+
res = wait_for_query_result(@conn2)
|
214
|
+
expect( res.values ).to eq([["1"]])
|
215
|
+
end
|
216
|
+
|
217
|
+
it "conn.send_query and conn.block work" do
|
218
|
+
@conn2.send_query("SELECT 2")
|
219
|
+
@conn2.block
|
220
|
+
res = @conn2.get_last_result
|
221
|
+
expect( res.values ).to eq([["2"]])
|
222
|
+
end
|
223
|
+
|
224
|
+
it "conn.async_query works" do
|
225
|
+
res = @conn2.async_query("SELECT 3")
|
226
|
+
expect( res.values ).to eq([["3"]])
|
227
|
+
expect( @conn2 ).to still_be_usable
|
228
|
+
|
229
|
+
res = @conn2.query("SELECT 4")
|
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
|
262
|
+
end
|
263
|
+
|
226
264
|
it "raises proper error when sending fails" do
|
227
265
|
conn = described_class.connect_start( '127.0.0.1', 54320, "", "", "me", "xxxx", "somedb" )
|
228
266
|
expect{ conn.exec 'SELECT 1' }.to raise_error(PG::UnableToSend, /no connection/)
|
@@ -241,7 +279,7 @@ describe PG::Connection do
|
|
241
279
|
expect( @conn.db ).to eq( "test" )
|
242
280
|
expect( @conn.user ).to be_a_kind_of( String )
|
243
281
|
expect( @conn.pass ).to eq( "" )
|
244
|
-
expect( @conn.port ).to eq(
|
282
|
+
expect( @conn.port ).to eq( @port )
|
245
283
|
expect( @conn.tty ).to eq( "" )
|
246
284
|
expect( @conn.options ).to eq( "" )
|
247
285
|
end
|
@@ -250,7 +288,20 @@ describe PG::Connection do
|
|
250
288
|
expect( @conn.host ).to eq( "localhost" )
|
251
289
|
end
|
252
290
|
|
253
|
-
|
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
|
+
%{
|
254
305
|
To backend> Msg Q
|
255
306
|
To backend> "SELECT 1 AS one"
|
256
307
|
To backend> Msg complete, length 21
|
@@ -278,6 +329,7 @@ describe PG::Connection do
|
|
278
329
|
From backend (#4)> 5
|
279
330
|
From backend> T
|
280
331
|
}.gsub( /^\t{2}/, '' ).lstrip
|
332
|
+
end
|
281
333
|
|
282
334
|
it "trace and untrace client-server communication", :unix do
|
283
335
|
# be careful to explicitly close files so that the
|
@@ -288,23 +340,20 @@ describe PG::Connection do
|
|
288
340
|
@conn.trace( trace_io )
|
289
341
|
trace_io.close
|
290
342
|
|
291
|
-
|
343
|
+
@conn.exec("SELECT 1 AS one")
|
292
344
|
@conn.untrace
|
293
345
|
|
294
|
-
|
346
|
+
@conn.exec("SELECT 2 AS two")
|
295
347
|
|
296
348
|
trace_data = trace_file.read
|
297
349
|
|
298
|
-
|
299
|
-
#
|
300
|
-
#
|
301
|
-
#
|
302
|
-
# +From backend (#4)>
|
303
|
-
#
|
304
|
-
|
305
|
-
expected_trace_output.sub!( /From backend \(#4\)> 13/, 'From backend (#4)> 11' )
|
306
|
-
expected_trace_output.sub!( /From backend> "SELECT 1"/, 'From backend> "SELECT"' )
|
307
|
-
end
|
350
|
+
# For async_exec the output will be different:
|
351
|
+
# From backend> Z
|
352
|
+
# From backend (#4)> 5
|
353
|
+
# +From backend> Z
|
354
|
+
# +From backend (#4)> 5
|
355
|
+
# From backend> T
|
356
|
+
trace_data.sub!( /(From backend> Z\nFrom backend \(#4\)> 5\n){3}/m, '\\1\\1' )
|
308
357
|
|
309
358
|
expect( trace_data ).to eq( expected_trace_output )
|
310
359
|
end
|
@@ -321,8 +370,6 @@ describe PG::Connection do
|
|
321
370
|
end
|
322
371
|
|
323
372
|
it "can stop a thread that runs a blocking query with async_exec" do
|
324
|
-
pending "this does not work on Rubinius" if RUBY_ENGINE=='rbx'
|
325
|
-
|
326
373
|
start = Time.now
|
327
374
|
t = Thread.new do
|
328
375
|
@conn.async_exec( 'select pg_sleep(10)' )
|
@@ -336,24 +383,16 @@ describe PG::Connection do
|
|
336
383
|
|
337
384
|
it "should work together with signal handlers", :unix do
|
338
385
|
signal_received = false
|
339
|
-
trap '
|
386
|
+
trap 'USR2' do
|
340
387
|
signal_received = true
|
341
388
|
end
|
342
389
|
|
343
390
|
Thread.new do
|
344
391
|
sleep 0.1
|
345
|
-
Process.kill("
|
392
|
+
Process.kill("USR2", Process.pid)
|
346
393
|
end
|
347
394
|
@conn.exec("select pg_sleep(0.3)")
|
348
395
|
expect( signal_received ).to be_truthy
|
349
|
-
|
350
|
-
signal_received = false
|
351
|
-
Thread.new do
|
352
|
-
sleep 0.1
|
353
|
-
Process.kill("USR1", Process.pid)
|
354
|
-
end
|
355
|
-
@conn.async_exec("select pg_sleep(0.3)")
|
356
|
-
expect( signal_received ).to be_truthy
|
357
396
|
end
|
358
397
|
|
359
398
|
|
@@ -401,22 +440,11 @@ describe PG::Connection do
|
|
401
440
|
end
|
402
441
|
end
|
403
442
|
|
404
|
-
|
405
|
-
it "supports parameters passed to #exec (backward compatibility)" do
|
406
|
-
@conn.exec( "CREATE TABLE students ( name TEXT, age INTEGER )" )
|
407
|
-
@conn.exec( "INSERT INTO students VALUES( $1, $2 )", ['Wally', 8] )
|
408
|
-
@conn.exec( "INSERT INTO students VALUES( $1, $2 )", ['Sally', 6] )
|
409
|
-
@conn.exec( "INSERT INTO students VALUES( $1, $2 )", ['Dorothy', 4] )
|
410
|
-
|
411
|
-
res = @conn.exec( "SELECT name FROM students WHERE age >= $1", [6] )
|
412
|
-
expect( res.values ).to eq( [ ['Wally'], ['Sally'] ] )
|
413
|
-
end
|
414
|
-
|
415
443
|
it "supports explicitly calling #exec_params" do
|
416
444
|
@conn.exec( "CREATE TABLE students ( name TEXT, age INTEGER )" )
|
417
|
-
@conn.
|
418
|
-
@conn.
|
419
|
-
@conn.
|
445
|
+
@conn.exec_params( "INSERT INTO students VALUES( $1, $2 )", ['Wally', 8] )
|
446
|
+
@conn.exec_params( "INSERT INTO students VALUES( $1, $2 )", ['Sally', 6] )
|
447
|
+
@conn.exec_params( "INSERT INTO students VALUES( $1, $2 )", ['Dorothy', 4] )
|
420
448
|
|
421
449
|
res = @conn.exec_params( "SELECT name FROM students WHERE age >= $1", [6] )
|
422
450
|
expect( res.values ).to eq( [ ['Wally'], ['Sally'] ] )
|
@@ -547,7 +575,7 @@ describe PG::Connection do
|
|
547
575
|
expect( @conn.wait_for_notify( 1 ) ).to be_nil
|
548
576
|
expect( notices.first ).to_not be_nil
|
549
577
|
et = Time.now
|
550
|
-
expect( (et - notices.first[1]) ).to be >= 0.
|
578
|
+
expect( (et - notices.first[1]) ).to be >= 0.3
|
551
579
|
expect( (et - st) ).to be >= 0.9
|
552
580
|
expect( (et - st) ).to be < 1.4
|
553
581
|
end
|
@@ -651,7 +679,7 @@ describe PG::Connection do
|
|
651
679
|
@conn.copy_data( "COPY copytable FROM STDOUT" ) do |res|
|
652
680
|
@conn.put_copy_data "xyz\n"
|
653
681
|
end
|
654
|
-
}.to raise_error(PG::Error, /invalid input syntax for integer/)
|
682
|
+
}.to raise_error(PG::Error, /invalid input syntax for .*integer/)
|
655
683
|
end
|
656
684
|
expect( @conn ).to still_be_usable
|
657
685
|
end
|
@@ -741,7 +769,7 @@ describe PG::Connection do
|
|
741
769
|
it "can return the default connection options as a Hash" do
|
742
770
|
expect( described_class.conndefaults_hash ).to be_a( Hash )
|
743
771
|
expect( described_class.conndefaults_hash ).to include( :user, :password, :dbname, :host, :port )
|
744
|
-
expect( ['5432', '54321'] ).to include( described_class.conndefaults_hash[:port] )
|
772
|
+
expect( ['5432', '54321', @port.to_s] ).to include( described_class.conndefaults_hash[:port] )
|
745
773
|
expect( @conn.conndefaults_hash ).to eq( described_class.conndefaults_hash )
|
746
774
|
end
|
747
775
|
|
@@ -874,7 +902,7 @@ describe PG::Connection do
|
|
874
902
|
end
|
875
903
|
|
876
904
|
|
877
|
-
it "
|
905
|
+
it "handles server close while asynchronous connect" do
|
878
906
|
serv = TCPServer.new( '127.0.0.1', 54320 )
|
879
907
|
conn = described_class.connect_start( '127.0.0.1', 54320, "", "", "me", "xxxx", "somedb" )
|
880
908
|
expect( [PG::PGRES_POLLING_WRITING, PG::CONNECTION_OK] ).to include conn.connect_poll
|
@@ -886,11 +914,29 @@ describe PG::Connection do
|
|
886
914
|
expect( conn.connect_poll ).to eq( PG::PGRES_POLLING_FAILED )
|
887
915
|
end
|
888
916
|
|
889
|
-
it "discards previous results
|
917
|
+
it "discards previous results at #discard_results" do
|
918
|
+
@conn.send_query( "select 1" )
|
919
|
+
@conn.discard_results
|
920
|
+
@conn.send_query( "select 41 as one" )
|
921
|
+
res = @conn.get_last_result
|
922
|
+
expect( res.to_a ).to eq( [{ 'one' => '41' }] )
|
923
|
+
end
|
924
|
+
|
925
|
+
it "discards previous results (if any) before waiting on #exec" do
|
926
|
+
@conn.send_query( "select 1" )
|
927
|
+
res = @conn.exec( "select 42 as one" )
|
928
|
+
expect( res.to_a ).to eq( [{ 'one' => '42' }] )
|
929
|
+
end
|
890
930
|
|
891
|
-
it "
|
931
|
+
it "discards previous errors before waiting on #exec", :without_transaction do
|
932
|
+
@conn.send_query( "ERROR" )
|
933
|
+
res = @conn.exec( "select 43 as one" )
|
934
|
+
expect( res.to_a ).to eq( [{ 'one' => '43' }] )
|
935
|
+
end
|
936
|
+
|
937
|
+
it "calls the block if one is provided to #exec" do
|
892
938
|
result = nil
|
893
|
-
@conn.
|
939
|
+
@conn.exec( "select 47 as one" ) do |pg_res|
|
894
940
|
result = pg_res[0]
|
895
941
|
end
|
896
942
|
expect( result ).to eq( { 'one' => '47' } )
|
@@ -903,7 +949,21 @@ describe PG::Connection do
|
|
903
949
|
expect { conn.finish }.to raise_error( PG::ConnectionBad, /connection is closed/i )
|
904
950
|
end
|
905
951
|
|
906
|
-
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
|
907
967
|
conn = PG.connect( @conninfo )
|
908
968
|
io = conn.socket_io
|
909
969
|
conn.finish
|
@@ -911,7 +971,7 @@ describe PG::Connection do
|
|
911
971
|
expect { conn.socket_io }.to raise_error( PG::ConnectionBad, /connection is closed/i )
|
912
972
|
end
|
913
973
|
|
914
|
-
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
|
915
975
|
conn = PG.connect( @conninfo )
|
916
976
|
io = conn.socket_io
|
917
977
|
conn.reset
|
@@ -1099,8 +1159,16 @@ describe PG::Connection do
|
|
1099
1159
|
expect( ping ).to eq( PG::PQPING_NO_RESPONSE )
|
1100
1160
|
end
|
1101
1161
|
|
1102
|
-
it "returns
|
1162
|
+
it "returns error when ping connection arguments are wrong" do
|
1103
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)
|
1104
1172
|
expect( ping ).to eq( PG::PQPING_NO_ATTEMPT )
|
1105
1173
|
end
|
1106
1174
|
|
@@ -1169,53 +1237,41 @@ describe PG::Connection do
|
|
1169
1237
|
|
1170
1238
|
end
|
1171
1239
|
|
1172
|
-
context "multinationalization support"
|
1240
|
+
context "multinationalization support" do
|
1173
1241
|
|
1174
1242
|
describe "rubyforge #22925: m17n support" do
|
1175
1243
|
it "should return results in the same encoding as the client (iso-8859-1)" do
|
1176
|
-
|
1177
|
-
@conn.
|
1178
|
-
|
1179
|
-
res = conn.exec("VALUES ('fantasia')", [], 0)
|
1180
|
-
out_string = res[0]['column1']
|
1181
|
-
end
|
1244
|
+
@conn.internal_encoding = 'iso8859-1'
|
1245
|
+
res = @conn.exec_params("VALUES ('fantasia')", [], 0)
|
1246
|
+
out_string = res[0]['column1']
|
1182
1247
|
expect( out_string ).to eq( 'fantasia' )
|
1183
1248
|
expect( out_string.encoding ).to eq( Encoding::ISO8859_1 )
|
1184
1249
|
end
|
1185
1250
|
|
1186
1251
|
it "should return results in the same encoding as the client (utf-8)" do
|
1187
|
-
|
1188
|
-
@conn.
|
1189
|
-
|
1190
|
-
res = conn.exec("VALUES ('世界線航跡蔵')", [], 0)
|
1191
|
-
out_string = res[0]['column1']
|
1192
|
-
end
|
1252
|
+
@conn.internal_encoding = 'utf-8'
|
1253
|
+
res = @conn.exec_params("VALUES ('世界線航跡蔵')", [], 0)
|
1254
|
+
out_string = res[0]['column1']
|
1193
1255
|
expect( out_string ).to eq( '世界線航跡蔵' )
|
1194
1256
|
expect( out_string.encoding ).to eq( Encoding::UTF_8 )
|
1195
1257
|
end
|
1196
1258
|
|
1197
1259
|
it "should return results in the same encoding as the client (EUC-JP)" do
|
1198
|
-
|
1199
|
-
|
1200
|
-
|
1201
|
-
|
1202
|
-
res = conn.exec(stmt, [], 0)
|
1203
|
-
out_string = res[0]['column1']
|
1204
|
-
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']
|
1205
1264
|
expect( out_string ).to eq( '世界線航跡蔵'.encode('EUC-JP') )
|
1206
1265
|
expect( out_string.encoding ).to eq( Encoding::EUC_JP )
|
1207
1266
|
end
|
1208
1267
|
|
1209
1268
|
it "returns the results in the correct encoding even if the client_encoding has " +
|
1210
1269
|
"changed since the results were fetched" do
|
1211
|
-
|
1212
|
-
|
1213
|
-
|
1214
|
-
|
1215
|
-
|
1216
|
-
conn.internal_encoding = 'utf-8'
|
1217
|
-
out_string = res[0]['column1']
|
1218
|
-
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']
|
1219
1275
|
expect( out_string ).to eq( '世界線航跡蔵'.encode('EUC-JP') )
|
1220
1276
|
expect( out_string.encoding ).to eq( Encoding::EUC_JP )
|
1221
1277
|
end
|
@@ -1225,52 +1281,68 @@ describe PG::Connection do
|
|
1225
1281
|
expect( @conn.internal_encoding ).to eq( Encoding::ASCII_8BIT )
|
1226
1282
|
end
|
1227
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
|
+
|
1228
1300
|
it "uses the client encoding for escaped string" do
|
1229
|
-
original = "Möhre to
|
1301
|
+
original = "Möhre to 'scape".encode( "utf-16be" )
|
1230
1302
|
@conn.set_client_encoding( "euc_jp" )
|
1231
1303
|
escaped = @conn.escape( original )
|
1232
1304
|
expect( escaped.encoding ).to eq( Encoding::EUC_JP )
|
1233
|
-
expect( escaped ).to eq( "Möhre to".encode(Encoding::EUC_JP) )
|
1305
|
+
expect( escaped ).to eq( "Möhre to ''scape".encode(Encoding::EUC_JP) )
|
1234
1306
|
end
|
1235
1307
|
|
1236
1308
|
it "uses the client encoding for escaped literal" do
|
1237
|
-
original = "Möhre to
|
1309
|
+
original = "Möhre to 'scape".encode( "utf-16be" )
|
1238
1310
|
@conn.set_client_encoding( "euc_jp" )
|
1239
1311
|
escaped = @conn.escape_literal( original )
|
1240
1312
|
expect( escaped.encoding ).to eq( Encoding::EUC_JP )
|
1241
|
-
expect( escaped ).to eq( "'Möhre to'".encode(Encoding::EUC_JP) )
|
1313
|
+
expect( escaped ).to eq( "'Möhre to ''scape'".encode(Encoding::EUC_JP) )
|
1242
1314
|
end
|
1243
1315
|
|
1244
1316
|
it "uses the client encoding for escaped identifier" do
|
1245
|
-
original = "Möhre to
|
1317
|
+
original = "Möhre to 'scape".encode( "utf-16le" )
|
1246
1318
|
@conn.set_client_encoding( "euc_jp" )
|
1247
1319
|
escaped = @conn.escape_identifier( original )
|
1248
1320
|
expect( escaped.encoding ).to eq( Encoding::EUC_JP )
|
1249
|
-
expect( escaped ).to eq( "\"Möhre to\"".encode(Encoding::EUC_JP) )
|
1321
|
+
expect( escaped ).to eq( "\"Möhre to 'scape\"".encode(Encoding::EUC_JP) )
|
1250
1322
|
end
|
1251
1323
|
|
1252
1324
|
it "uses the client encoding for quote_ident" do
|
1253
|
-
original = "Möhre to
|
1325
|
+
original = "Möhre to 'scape".encode( "utf-16le" )
|
1254
1326
|
@conn.set_client_encoding( "euc_jp" )
|
1255
1327
|
escaped = @conn.quote_ident( original )
|
1256
1328
|
expect( escaped.encoding ).to eq( Encoding::EUC_JP )
|
1257
|
-
expect( escaped ).to eq( "\"Möhre to\"".encode(Encoding::EUC_JP) )
|
1329
|
+
expect( escaped ).to eq( "\"Möhre to 'scape\"".encode(Encoding::EUC_JP) )
|
1258
1330
|
end
|
1259
1331
|
|
1260
1332
|
it "uses the previous string encoding for escaped string" do
|
1261
|
-
original = "Möhre to
|
1333
|
+
original = "Möhre to 'scape".encode( "iso-8859-1" )
|
1262
1334
|
@conn.set_client_encoding( "euc_jp" )
|
1263
1335
|
escaped = described_class.escape( original )
|
1264
1336
|
expect( escaped.encoding ).to eq( Encoding::ISO8859_1 )
|
1265
|
-
expect( escaped ).to eq( "Möhre to".encode(Encoding::ISO8859_1) )
|
1337
|
+
expect( escaped ).to eq( "Möhre to ''scape".encode(Encoding::ISO8859_1) )
|
1266
1338
|
end
|
1267
1339
|
|
1268
1340
|
it "uses the previous string encoding for quote_ident" do
|
1269
|
-
original = "Möhre to
|
1341
|
+
original = "Möhre to 'scape".encode( "iso-8859-1" )
|
1270
1342
|
@conn.set_client_encoding( "euc_jp" )
|
1271
1343
|
escaped = described_class.quote_ident( original )
|
1272
1344
|
expect( escaped.encoding ).to eq( Encoding::ISO8859_1 )
|
1273
|
-
expect( escaped.encode ).to eq( "\"Möhre to\"".encode(Encoding::ISO8859_1) )
|
1345
|
+
expect( escaped.encode ).to eq( "\"Möhre to 'scape\"".encode(Encoding::ISO8859_1) )
|
1274
1346
|
end
|
1275
1347
|
|
1276
1348
|
it "raises appropriate error if set_client_encoding is called with invalid arguments" do
|
@@ -1278,6 +1350,21 @@ describe PG::Connection do
|
|
1278
1350
|
expect { @conn.set_client_encoding( :invalid ) }.to raise_error(TypeError)
|
1279
1351
|
expect { @conn.set_client_encoding( nil ) }.to raise_error(TypeError)
|
1280
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
|
+
|
1281
1368
|
end
|
1282
1369
|
|
1283
1370
|
describe "respect and convert character encoding of input strings" do
|
@@ -1291,22 +1378,11 @@ describe PG::Connection do
|
|
1291
1378
|
expect( r.values ).to eq( [['grün', 'grün', 't', 'grün']] )
|
1292
1379
|
end
|
1293
1380
|
|
1294
|
-
it "should convert query string and parameters to #async_exec" do
|
1295
|
-
r = @conn.async_exec("VALUES( $1, $2, $1=$2, 'grün')".encode("cp936"),
|
1296
|
-
['grün'.encode('cp850'), 'grün'.encode('utf-16le')])
|
1297
|
-
expect( r.values ).to eq( [['grün', 'grün', 't', 'grün']] )
|
1298
|
-
end
|
1299
|
-
|
1300
1381
|
it "should convert query string to #exec" do
|
1301
1382
|
r = @conn.exec("SELECT 'grün'".encode("utf-16be"))
|
1302
1383
|
expect( r.values ).to eq( [['grün']] )
|
1303
1384
|
end
|
1304
1385
|
|
1305
|
-
it "should convert query string to #async_exec" do
|
1306
|
-
r = @conn.async_exec("SELECT 'grün'".encode("utf-16le"))
|
1307
|
-
expect( r.values ).to eq( [['grün']] )
|
1308
|
-
end
|
1309
|
-
|
1310
1386
|
it "should convert strings and parameters to #prepare and #exec_prepared" do
|
1311
1387
|
@conn.prepare("weiß1".encode("utf-16be"), "VALUES( $1, $2, $1=$2, 'grün')".encode("cp850"))
|
1312
1388
|
r = @conn.exec_prepared("weiß1".encode("utf-32le"),
|
@@ -1331,8 +1407,8 @@ describe PG::Connection do
|
|
1331
1407
|
expect( @conn.get_last_result.values ).to eq( [['grün']] )
|
1332
1408
|
end
|
1333
1409
|
|
1334
|
-
it "should convert query string and parameters to #
|
1335
|
-
@conn.
|
1410
|
+
it "should convert query string and parameters to #send_query_params" do
|
1411
|
+
@conn.send_query_params("VALUES( $1, $2, $1=$2, 'grün')".encode("utf-16le"),
|
1336
1412
|
['grün'.encode('utf-32be'), 'grün'.encode('iso-8859-1')])
|
1337
1413
|
expect( @conn.get_last_result.values ).to eq( [['grün', 'grün', 't', 'grün']] )
|
1338
1414
|
end
|
@@ -1366,9 +1442,54 @@ describe PG::Connection do
|
|
1366
1442
|
end
|
1367
1443
|
end
|
1368
1444
|
|
1445
|
+
it "rejects command strings with zero bytes" do
|
1446
|
+
expect{ @conn.exec( "SELECT 1;\x00" ) }.to raise_error(ArgumentError, /null byte/)
|
1447
|
+
expect{ @conn.exec_params( "SELECT 1;\x00", [] ) }.to raise_error(ArgumentError, /null byte/)
|
1448
|
+
expect{ @conn.prepare( "abc\x00", "SELECT 1;" ) }.to raise_error(ArgumentError, /null byte/)
|
1449
|
+
expect{ @conn.prepare( "abc", "SELECT 1;\x00" ) }.to raise_error(ArgumentError, /null byte/)
|
1450
|
+
expect{ @conn.exec_prepared( "abc\x00", [] ) }.to raise_error(ArgumentError, /null byte/)
|
1451
|
+
expect{ @conn.describe_prepared( "abc\x00" ) }.to raise_error(ArgumentError, /null byte/)
|
1452
|
+
expect{ @conn.describe_portal( "abc\x00" ) }.to raise_error(ArgumentError, /null byte/)
|
1453
|
+
expect{ @conn.send_query( "SELECT 1;\x00" ) }.to raise_error(ArgumentError, /null byte/)
|
1454
|
+
expect{ @conn.send_query_params( "SELECT 1;\x00", [] ) }.to raise_error(ArgumentError, /null byte/)
|
1455
|
+
expect{ @conn.send_prepare( "abc\x00", "SELECT 1;" ) }.to raise_error(ArgumentError, /null byte/)
|
1456
|
+
expect{ @conn.send_prepare( "abc", "SELECT 1;\x00" ) }.to raise_error(ArgumentError, /null byte/)
|
1457
|
+
expect{ @conn.send_query_prepared( "abc\x00", [] ) }.to raise_error(ArgumentError, /null byte/)
|
1458
|
+
expect{ @conn.send_describe_prepared( "abc\x00" ) }.to raise_error(ArgumentError, /null byte/)
|
1459
|
+
expect{ @conn.send_describe_portal( "abc\x00" ) }.to raise_error(ArgumentError, /null byte/)
|
1460
|
+
end
|
1461
|
+
|
1462
|
+
it "rejects query params with zero bytes" do
|
1463
|
+
expect{ @conn.exec_params( "SELECT 1;\x00", ["ab\x00"] ) }.to raise_error(ArgumentError, /null byte/)
|
1464
|
+
expect{ @conn.exec_prepared( "abc\x00", ["ab\x00"] ) }.to raise_error(ArgumentError, /null byte/)
|
1465
|
+
expect{ @conn.send_query_params( "SELECT 1;\x00", ["ab\x00"] ) }.to raise_error(ArgumentError, /null byte/)
|
1466
|
+
expect{ @conn.send_query_prepared( "abc\x00", ["ab\x00"] ) }.to raise_error(ArgumentError, /null byte/)
|
1467
|
+
end
|
1468
|
+
|
1469
|
+
it "rejects string with zero bytes in escape" do
|
1470
|
+
expect{ @conn.escape( "ab\x00cd" ) }.to raise_error(ArgumentError, /null byte/)
|
1471
|
+
end
|
1472
|
+
|
1473
|
+
it "rejects string with zero bytes in escape_literal" do
|
1474
|
+
expect{ @conn.escape_literal( "ab\x00cd" ) }.to raise_error(ArgumentError, /null byte/)
|
1475
|
+
end
|
1476
|
+
|
1477
|
+
it "rejects string with zero bytes in escape_identifier" do
|
1478
|
+
expect{ @conn.escape_identifier( "ab\x00cd" ) }.to raise_error(ArgumentError, /null byte/)
|
1479
|
+
end
|
1480
|
+
|
1481
|
+
it "rejects string with zero bytes in quote_ident" do
|
1482
|
+
expect{ described_class.quote_ident( "ab\x00cd" ) }.to raise_error(ArgumentError, /null byte/)
|
1483
|
+
end
|
1484
|
+
|
1485
|
+
it "rejects Array with string with zero bytes" do
|
1486
|
+
original = ["xyz", "2\x00"]
|
1487
|
+
expect{ described_class.quote_ident( original ) }.to raise_error(ArgumentError, /null byte/)
|
1488
|
+
end
|
1489
|
+
|
1369
1490
|
it "can quote bigger strings with quote_ident" do
|
1370
1491
|
original = "'01234567\"" * 100
|
1371
|
-
escaped = described_class.quote_ident( original
|
1492
|
+
escaped = described_class.quote_ident( original )
|
1372
1493
|
expect( escaped ).to eq( "\"" + original.gsub("\"", "\"\"") + "\"" )
|
1373
1494
|
end
|
1374
1495
|
|
@@ -1387,7 +1508,7 @@ describe PG::Connection do
|
|
1387
1508
|
|
1388
1509
|
describe "Ruby 1.9.x default_internal encoding" do
|
1389
1510
|
|
1390
|
-
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
|
1391
1512
|
@conn.transaction do |txn_conn|
|
1392
1513
|
txn_conn.internal_encoding = Encoding::ISO8859_1
|
1393
1514
|
txn_conn.exec( "CREATE TABLE defaultinternaltest ( foo text )" )
|
@@ -1489,9 +1610,8 @@ describe PG::Connection do
|
|
1489
1610
|
end
|
1490
1611
|
end
|
1491
1612
|
|
1492
|
-
it "receives properly encoded text from wait_for_notify" do
|
1613
|
+
it "receives properly encoded text from wait_for_notify", :without_transaction do
|
1493
1614
|
@conn.internal_encoding = 'utf-8'
|
1494
|
-
@conn.exec( 'ROLLBACK' )
|
1495
1615
|
@conn.exec( 'LISTEN "Möhre"' )
|
1496
1616
|
@conn.exec( %Q{NOTIFY "Möhre", '世界線航跡蔵'} )
|
1497
1617
|
event, pid, msg = nil
|
@@ -1502,13 +1622,13 @@ describe PG::Connection do
|
|
1502
1622
|
|
1503
1623
|
expect( event ).to eq( "Möhre" )
|
1504
1624
|
expect( event.encoding ).to eq( Encoding::UTF_8 )
|
1625
|
+
expect( pid ).to be_a_kind_of(Integer)
|
1505
1626
|
expect( msg ).to eq( '世界線航跡蔵' )
|
1506
1627
|
expect( msg.encoding ).to eq( Encoding::UTF_8 )
|
1507
1628
|
end
|
1508
1629
|
|
1509
|
-
it "returns properly encoded text from notifies" do
|
1630
|
+
it "returns properly encoded text from notifies", :without_transaction do
|
1510
1631
|
@conn.internal_encoding = 'utf-8'
|
1511
|
-
@conn.exec( 'ROLLBACK' )
|
1512
1632
|
@conn.exec( 'LISTEN "Möhre"' )
|
1513
1633
|
@conn.exec( %Q{NOTIFY "Möhre", '世界線航跡蔵'} )
|
1514
1634
|
@conn.exec( 'UNLISTEN "Möhre"' )
|
@@ -1522,7 +1642,7 @@ describe PG::Connection do
|
|
1522
1642
|
end
|
1523
1643
|
end
|
1524
1644
|
|
1525
|
-
context "OS thread support"
|
1645
|
+
context "OS thread support" do
|
1526
1646
|
it "Connection#exec shouldn't block a second thread" do
|
1527
1647
|
t = Thread.new do
|
1528
1648
|
@conn.exec( "select pg_sleep(1)" )
|
@@ -1583,12 +1703,12 @@ describe PG::Connection do
|
|
1583
1703
|
row_encoder = PG::TextEncoder::CopyRow.new type_map: tm
|
1584
1704
|
|
1585
1705
|
@conn.exec( "CREATE TEMP TABLE copytable (col1 TEXT)" )
|
1586
|
-
|
1706
|
+
@conn.copy_data( "COPY copytable FROM STDOUT" ) do |res|
|
1587
1707
|
@conn.put_copy_data [1], row_encoder
|
1588
1708
|
@conn.put_copy_data ["2"], row_encoder
|
1589
1709
|
end
|
1590
1710
|
|
1591
|
-
|
1711
|
+
@conn.copy_data( "COPY copytable FROM STDOUT", row_encoder ) do |res|
|
1592
1712
|
@conn.put_copy_data [3]
|
1593
1713
|
@conn.put_copy_data ["4"]
|
1594
1714
|
end
|
@@ -1638,7 +1758,7 @@ describe PG::Connection do
|
|
1638
1758
|
|
1639
1759
|
it "can process #copy_data input queries with row encoder and respects character encoding" do
|
1640
1760
|
@conn2.exec( "CREATE TEMP TABLE copytable (col1 TEXT)" )
|
1641
|
-
|
1761
|
+
@conn2.copy_data( "COPY copytable FROM STDOUT" ) do |res|
|
1642
1762
|
@conn2.put_copy_data [1]
|
1643
1763
|
@conn2.put_copy_data ["Möhre".encode("utf-16le")]
|
1644
1764
|
end
|
@@ -1689,7 +1809,7 @@ describe PG::Connection do
|
|
1689
1809
|
it "can process #copy_data output with row decoder and respects character encoding" do
|
1690
1810
|
@conn2.internal_encoding = Encoding::ISO8859_1
|
1691
1811
|
rows = []
|
1692
|
-
|
1812
|
+
@conn2.copy_data( "COPY (VALUES('1'), ('Möhre')) TO STDOUT".encode("utf-16le") ) do |res|
|
1693
1813
|
while row=@conn2.get_copy_data
|
1694
1814
|
rows << row
|
1695
1815
|
end
|
@@ -1716,4 +1836,114 @@ describe PG::Connection do
|
|
1716
1836
|
end
|
1717
1837
|
end
|
1718
1838
|
end
|
1839
|
+
|
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])
|
1866
|
+
end
|
1867
|
+
|
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
|
1940
|
+
end
|
1941
|
+
|
1942
|
+
it "shouldn't forward send_query_params to send_query" do
|
1943
|
+
expect{ @conn.send_query_params("VALUES(4)").values }
|
1944
|
+
.to raise_error(ArgumentError)
|
1945
|
+
expect{ @conn.send_query_params("VALUES(4)", nil).values }
|
1946
|
+
.to raise_error(TypeError)
|
1947
|
+
end
|
1948
|
+
end
|
1719
1949
|
end
|