pg 1.1.0.pre20180730171000 → 1.1.4
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- checksums.yaml.gz.sig +0 -0
- data.tar.gz.sig +0 -0
- data/ChangeLog +6595 -0
- data/History.rdoc +24 -6
- data/Manifest.txt +70 -2
- data/Rakefile +2 -3
- data/Rakefile.cross +3 -3
- data/ext/errorcodes.def +4 -0
- data/ext/errorcodes.txt +2 -1
- data/ext/pg.c +9 -4
- data/ext/pg.h +18 -6
- data/ext/pg_binary_decoder.c +10 -6
- data/ext/pg_binary_encoder.c +1 -1
- data/ext/pg_connection.c +31 -29
- data/ext/pg_result.c +2 -0
- data/ext/pg_text_decoder.c +1 -1
- data/ext/pg_text_encoder.c +6 -7
- data/ext/pg_tuple.c +4 -3
- data/ext/pg_type_map.c +1 -1
- data/ext/pg_type_map_all_strings.c +1 -1
- data/ext/pg_type_map_by_class.c +1 -1
- data/ext/pg_type_map_by_column.c +1 -1
- data/ext/pg_type_map_by_mri_type.c +1 -1
- data/ext/pg_type_map_by_oid.c +1 -1
- data/ext/pg_type_map_in_ruby.c +1 -1
- data/ext/util.c +1 -1
- data/lib/pg.rb +2 -2
- data/spec/helpers.rb +8 -8
- data/spec/pg/basic_type_mapping_spec.rb +5 -5
- data/spec/pg/connection_spec.rb +131 -17
- data/spec/pg/tuple_spec.rb +16 -2
- data/spec/pg/type_spec.rb +6 -0
- metadata +38 -79
- metadata.gz.sig +0 -0
- data/.gems +0 -6
- data/.hgignore +0 -21
- data/.hgsigs +0 -29
- data/.hgtags +0 -36
- data/.hoerc +0 -2
- data/.irbrc +0 -23
- data/.pryrc +0 -23
- data/.tm_properties +0 -21
- data/.travis.yml +0 -41
- data/Gemfile +0 -2
- data/appveyor.yml +0 -50
- data/certs/ged.pem +0 -26
- data/misc/openssl-pg-segfault.rb +0 -31
- data/misc/postgres/History.txt +0 -9
- data/misc/postgres/Manifest.txt +0 -5
- data/misc/postgres/README.txt +0 -21
- data/misc/postgres/Rakefile +0 -21
- data/misc/postgres/lib/postgres.rb +0 -16
- data/misc/ruby-pg/History.txt +0 -9
- data/misc/ruby-pg/Manifest.txt +0 -5
- data/misc/ruby-pg/README.txt +0 -21
- data/misc/ruby-pg/Rakefile +0 -21
- data/misc/ruby-pg/lib/ruby/pg.rb +0 -16
- data/pg.gemspec +0 -61
- data/sample/array_insert.rb +0 -20
- data/sample/async_api.rb +0 -106
- data/sample/async_copyto.rb +0 -39
- data/sample/async_mixed.rb +0 -56
- data/sample/check_conn.rb +0 -21
- data/sample/copydata.rb +0 -71
- data/sample/copyfrom.rb +0 -81
- data/sample/copyto.rb +0 -19
- data/sample/cursor.rb +0 -21
- data/sample/disk_usage_report.rb +0 -177
- data/sample/issue-119.rb +0 -94
- data/sample/losample.rb +0 -69
- data/sample/minimal-testcase.rb +0 -17
- data/sample/notify_wait.rb +0 -72
- data/sample/pg_statistics.rb +0 -285
- data/sample/replication_monitor.rb +0 -222
- data/sample/test_binary_values.rb +0 -33
- data/sample/wal_shipper.rb +0 -434
- data/sample/warehouse_partitions.rb +0 -311
data/ext/pg_result.c
CHANGED
@@ -419,6 +419,8 @@ static void pgresult_init_fnames(VALUE self)
|
|
419
419
|
*
|
420
420
|
* The class to represent the query result tuples (rows).
|
421
421
|
* An instance of this class is created as the result of every query.
|
422
|
+
* All result rows and columns are stored in a memory block attached to the PG::Result object.
|
423
|
+
* Whenever a value is accessed it is casted to a Ruby object by the assigned #type_map .
|
422
424
|
*
|
423
425
|
* Since pg-1.1 the amount of memory in use by a PG::Result object is estimated and passed to ruby's garbage collector.
|
424
426
|
* You can invoke the #clear method to force deallocation of memory of the instance when finished with the result for better memory performance.
|
data/ext/pg_text_decoder.c
CHANGED
data/ext/pg_text_encoder.c
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
/*
|
2
2
|
* pg_text_encoder.c - PG::TextEncoder module
|
3
|
-
* $Id$
|
3
|
+
* $Id: pg_text_encoder.c,v e57f6b452eb3 2018/08/18 10:58:52 lars $
|
4
4
|
*
|
5
5
|
*/
|
6
6
|
|
@@ -468,20 +468,19 @@ pg_text_enc_array(t_pg_coder *conv, VALUE value, char *out, VALUE *intermediate,
|
|
468
468
|
static char *
|
469
469
|
quote_identifier( VALUE value, VALUE out_string, char *current_out ){
|
470
470
|
char *p_in = RSTRING_PTR(value);
|
471
|
-
char *ptr1;
|
472
471
|
size_t strlen = RSTRING_LEN(value);
|
472
|
+
char *p_inend = p_in + strlen;
|
473
473
|
char *end_capa = current_out;
|
474
474
|
|
475
475
|
PG_RB_STR_ENSURE_CAPA( out_string, strlen + 2, current_out, end_capa );
|
476
476
|
*current_out++ = '"';
|
477
|
-
for(
|
478
|
-
char c = *
|
477
|
+
for(; p_in != p_inend; p_in++) {
|
478
|
+
char c = *p_in;
|
479
479
|
if (c == '"'){
|
480
|
-
|
481
|
-
PG_RB_STR_ENSURE_CAPA( out_string, p_in - ptr1 + strlen + 1, current_out, end_capa );
|
480
|
+
PG_RB_STR_ENSURE_CAPA( out_string, p_inend - p_in + 2, current_out, end_capa );
|
482
481
|
*current_out++ = '"';
|
483
482
|
} else if (c == 0){
|
484
|
-
|
483
|
+
rb_raise(rb_eArgError, "string contains null byte");
|
485
484
|
}
|
486
485
|
*current_out++ = c;
|
487
486
|
}
|
data/ext/pg_tuple.c
CHANGED
@@ -311,9 +311,9 @@ pg_tuple_yield_key_value(VALUE key, VALUE index, VALUE _this)
|
|
311
311
|
|
312
312
|
/*
|
313
313
|
* call-seq:
|
314
|
-
* tup.each{ |value| ... }
|
314
|
+
* tup.each{ |key, value| ... }
|
315
315
|
*
|
316
|
-
* Invokes block for each field value in the tuple.
|
316
|
+
* Invokes block for each field name and value in the tuple.
|
317
317
|
*/
|
318
318
|
static VALUE
|
319
319
|
pg_tuple_each(VALUE self)
|
@@ -354,7 +354,8 @@ pg_tuple_each_value(VALUE self)
|
|
354
354
|
RETURN_SIZED_ENUMERATOR(self, 0, NULL, pg_tuple_num_fields_for_enum);
|
355
355
|
|
356
356
|
for(field_num = 0; field_num < this->num_fields; field_num++) {
|
357
|
-
|
357
|
+
VALUE value = pg_tuple_materialize_field(this, field_num);
|
358
|
+
rb_yield(value);
|
358
359
|
}
|
359
360
|
|
360
361
|
pg_tuple_detach(this);
|
data/ext/pg_type_map.c
CHANGED
data/ext/pg_type_map_by_class.c
CHANGED
data/ext/pg_type_map_by_column.c
CHANGED
data/ext/pg_type_map_by_oid.c
CHANGED
data/ext/pg_type_map_in_ruby.c
CHANGED
data/ext/util.c
CHANGED
data/lib/pg.rb
CHANGED
data/spec/helpers.rb
CHANGED
@@ -22,6 +22,7 @@ module PG::TestingHelpers
|
|
22
22
|
|
23
23
|
mod.around( :each ) do |example|
|
24
24
|
begin
|
25
|
+
@conn.set_default_encoding
|
25
26
|
@conn.exec( 'BEGIN' ) unless example.metadata[:without_transaction]
|
26
27
|
desc = example.source_location.join(':')
|
27
28
|
@conn.exec %Q{SET application_name TO '%s'} %
|
@@ -197,8 +198,8 @@ module PG::TestingHelpers
|
|
197
198
|
@test_pgdata = TEST_DIRECTORY + 'data'
|
198
199
|
@test_pgdata.mkpath
|
199
200
|
|
200
|
-
|
201
|
-
ENV['PGPORT']
|
201
|
+
ENV['PGPORT'] ||= "54321"
|
202
|
+
@port = ENV['PGPORT'].to_i
|
202
203
|
ENV['PGHOST'] = 'localhost'
|
203
204
|
@conninfo = "host=localhost port=#{@port} dbname=test"
|
204
205
|
|
@@ -318,20 +319,19 @@ module PG::TestingHelpers
|
|
318
319
|
return ConnStillUsableMatcher.new
|
319
320
|
end
|
320
321
|
|
321
|
-
def wait_for_polling_ok(conn)
|
322
|
-
|
323
|
-
status = conn.connect_poll
|
322
|
+
def wait_for_polling_ok(conn, meth = :connect_poll)
|
323
|
+
status = conn.send(meth)
|
324
324
|
|
325
325
|
while status != PG::PGRES_POLLING_OK
|
326
326
|
if status == PG::PGRES_POLLING_READING
|
327
|
-
select( [
|
327
|
+
select( [conn.socket_io], [], [], 5.0 ) or
|
328
328
|
raise "Asynchronous connection timed out!"
|
329
329
|
|
330
330
|
elsif status == PG::PGRES_POLLING_WRITING
|
331
|
-
select( [], [
|
331
|
+
select( [], [conn.socket_io], [], 5.0 ) or
|
332
332
|
raise "Asynchronous connection timed out!"
|
333
333
|
end
|
334
|
-
status = conn.
|
334
|
+
status = conn.send(meth)
|
335
335
|
end
|
336
336
|
end
|
337
337
|
|
@@ -62,7 +62,7 @@ describe 'Basic type mapping' do
|
|
62
62
|
it "should do bigdecimal param encoding" do
|
63
63
|
large = ('123456790'*10) << '.' << ('012345679')
|
64
64
|
res = @conn.exec_params( "SELECT $1::numeric,$2::numeric",
|
65
|
-
[BigDecimal
|
65
|
+
[BigDecimal('1'), BigDecimal(large)], nil, basic_type_mapping )
|
66
66
|
|
67
67
|
expect( res.values ).to eq( [
|
68
68
|
[ "1.0", large ],
|
@@ -256,10 +256,10 @@ describe 'Basic type mapping' do
|
|
256
256
|
CAST('294276-12-31 23:58:59.1231+03' AS TIMESTAMP WITH TIME ZONE),
|
257
257
|
CAST('infinity' AS TIMESTAMP WITH TIME ZONE),
|
258
258
|
CAST('-infinity' AS TIMESTAMP WITH TIME ZONE)", [], format )
|
259
|
-
expect( res.getvalue(0,0)
|
260
|
-
expect( res.getvalue(0,1)
|
261
|
-
expect( res.getvalue(0,2)
|
262
|
-
expect( res.getvalue(0,3)
|
259
|
+
expect( res.getvalue(0,0) ).to be_within(1e-3).of( Time.new(2013, 12, 31, 23, 58, 59, "+02:00").getlocal )
|
260
|
+
expect( res.getvalue(0,1) ).to be_within(1e-3).of( Time.new(1913, 12, 31, 23, 58, 59.1231, "-03:00").getlocal )
|
261
|
+
expect( res.getvalue(0,2) ).to be_within(1e-3).of( Time.new(-4713, 11, 24, 23, 58, 59.1231, "-03:00").getlocal )
|
262
|
+
expect( res.getvalue(0,3) ).to be_within(1e-3).of( Time.new(294276, 12, 31, 23, 58, 59.1231, "+03:00").getlocal )
|
263
263
|
expect( res.getvalue(0,4) ).to eq( 'infinity' )
|
264
264
|
expect( res.getvalue(0,5) ).to eq( '-infinity' )
|
265
265
|
end
|
data/spec/pg/connection_spec.rb
CHANGED
@@ -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
|
@@ -734,7 +765,7 @@ describe PG::Connection do
|
|
734
765
|
it "can return the default connection options as a Hash" do
|
735
766
|
expect( described_class.conndefaults_hash ).to be_a( Hash )
|
736
767
|
expect( described_class.conndefaults_hash ).to include( :user, :password, :dbname, :host, :port )
|
737
|
-
expect( ['5432', '54321'] ).to include( described_class.conndefaults_hash[:port] )
|
768
|
+
expect( ['5432', '54321', @port.to_s] ).to include( described_class.conndefaults_hash[:port] )
|
738
769
|
expect( @conn.conndefaults_hash ).to eq( described_class.conndefaults_hash )
|
739
770
|
end
|
740
771
|
|
@@ -914,6 +945,20 @@ describe PG::Connection do
|
|
914
945
|
expect { conn.finish }.to raise_error( PG::ConnectionBad, /connection is closed/i )
|
915
946
|
end
|
916
947
|
|
948
|
+
it "can use conn.reset to restart the connection" do
|
949
|
+
ios = IO.pipe
|
950
|
+
conn = PG.connect( @conninfo )
|
951
|
+
|
952
|
+
# Close the two pipe file descriptors, so that the file descriptor of
|
953
|
+
# newly established connection is probably distinct from the previous one.
|
954
|
+
ios.each(&:close)
|
955
|
+
conn.reset
|
956
|
+
|
957
|
+
# The new connection should work even when the file descriptor has changed.
|
958
|
+
expect( conn.exec("SELECT 1").values ).to eq([["1"]])
|
959
|
+
conn.close
|
960
|
+
end
|
961
|
+
|
917
962
|
it "closes the IO fetched from #socket_io when the connection is closed", :without_transaction, :socket_io do
|
918
963
|
conn = PG.connect( @conninfo )
|
919
964
|
io = conn.socket_io
|
@@ -939,7 +984,7 @@ describe PG::Connection do
|
|
939
984
|
end
|
940
985
|
serv.close
|
941
986
|
expect{ conn.block }.to raise_error(PG::ConnectionBad, /server closed the connection unexpectedly/)
|
942
|
-
expect{ conn.block }.to raise_error(PG::ConnectionBad, /
|
987
|
+
expect{ conn.block }.to raise_error(PG::ConnectionBad, /can't get socket descriptor/)
|
943
988
|
end
|
944
989
|
|
945
990
|
it "sets the fallback_application_name on new connections" do
|
@@ -1110,8 +1155,16 @@ describe PG::Connection do
|
|
1110
1155
|
expect( ping ).to eq( PG::PQPING_NO_RESPONSE )
|
1111
1156
|
end
|
1112
1157
|
|
1113
|
-
it "returns
|
1158
|
+
it "returns error when ping connection arguments are wrong" do
|
1114
1159
|
ping = described_class.ping('localhost', 'localhost', nil, nil, :test, nil, nil)
|
1160
|
+
expect( ping ).to_not eq( PG::PQPING_OK )
|
1161
|
+
end
|
1162
|
+
|
1163
|
+
it "returns correct response when ping connection arguments are wrong" do
|
1164
|
+
ping = described_class.ping(
|
1165
|
+
:host => 'localhost',
|
1166
|
+
:invalid_option => 9999,
|
1167
|
+
:dbname => :test)
|
1115
1168
|
expect( ping ).to eq( PG::PQPING_NO_ATTEMPT )
|
1116
1169
|
end
|
1117
1170
|
|
@@ -1236,52 +1289,68 @@ describe PG::Connection do
|
|
1236
1289
|
expect( @conn.internal_encoding ).to eq( Encoding::ASCII_8BIT )
|
1237
1290
|
end
|
1238
1291
|
|
1292
|
+
it "the connection should use JOHAB dummy encoding when it's set to JOHAB" do
|
1293
|
+
@conn.set_client_encoding "JOHAB"
|
1294
|
+
val = @conn.exec("SELECT chr(x'3391'::int)").values[0][0]
|
1295
|
+
expect( val.encoding.name ).to eq( "JOHAB" )
|
1296
|
+
expect( val.unpack("H*")[0] ).to eq( "dc65" )
|
1297
|
+
end
|
1298
|
+
|
1299
|
+
it "can retrieve server encoding as text" do
|
1300
|
+
enc = @conn.parameter_status "server_encoding"
|
1301
|
+
expect( enc ).to eq( "UTF8" )
|
1302
|
+
end
|
1303
|
+
|
1304
|
+
it "can retrieve server encoding as ruby encoding" do
|
1305
|
+
expect( @conn.external_encoding ).to eq( Encoding::UTF_8 )
|
1306
|
+
end
|
1307
|
+
|
1239
1308
|
it "uses the client encoding for escaped string" do
|
1240
|
-
original = "Möhre to
|
1309
|
+
original = "Möhre to 'scape".encode( "utf-16be" )
|
1241
1310
|
@conn.set_client_encoding( "euc_jp" )
|
1242
1311
|
escaped = @conn.escape( original )
|
1243
1312
|
expect( escaped.encoding ).to eq( Encoding::EUC_JP )
|
1244
|
-
expect( escaped ).to eq( "Möhre to".encode(Encoding::EUC_JP) )
|
1313
|
+
expect( escaped ).to eq( "Möhre to ''scape".encode(Encoding::EUC_JP) )
|
1245
1314
|
end
|
1246
1315
|
|
1247
1316
|
it "uses the client encoding for escaped literal" do
|
1248
|
-
original = "Möhre to
|
1317
|
+
original = "Möhre to 'scape".encode( "utf-16be" )
|
1249
1318
|
@conn.set_client_encoding( "euc_jp" )
|
1250
1319
|
escaped = @conn.escape_literal( original )
|
1251
1320
|
expect( escaped.encoding ).to eq( Encoding::EUC_JP )
|
1252
|
-
expect( escaped ).to eq( "'Möhre to'".encode(Encoding::EUC_JP) )
|
1321
|
+
expect( escaped ).to eq( "'Möhre to ''scape'".encode(Encoding::EUC_JP) )
|
1253
1322
|
end
|
1254
1323
|
|
1255
1324
|
it "uses the client encoding for escaped identifier" do
|
1256
|
-
original = "Möhre to
|
1325
|
+
original = "Möhre to 'scape".encode( "utf-16le" )
|
1257
1326
|
@conn.set_client_encoding( "euc_jp" )
|
1258
1327
|
escaped = @conn.escape_identifier( original )
|
1259
1328
|
expect( escaped.encoding ).to eq( Encoding::EUC_JP )
|
1260
|
-
expect( escaped ).to eq( "\"Möhre to\"".encode(Encoding::EUC_JP) )
|
1329
|
+
expect( escaped ).to eq( "\"Möhre to 'scape\"".encode(Encoding::EUC_JP) )
|
1261
1330
|
end
|
1262
1331
|
|
1263
1332
|
it "uses the client encoding for quote_ident" do
|
1264
|
-
original = "Möhre to
|
1333
|
+
original = "Möhre to 'scape".encode( "utf-16le" )
|
1265
1334
|
@conn.set_client_encoding( "euc_jp" )
|
1266
1335
|
escaped = @conn.quote_ident( original )
|
1267
1336
|
expect( escaped.encoding ).to eq( Encoding::EUC_JP )
|
1268
|
-
expect( escaped ).to eq( "\"Möhre to\"".encode(Encoding::EUC_JP) )
|
1337
|
+
expect( escaped ).to eq( "\"Möhre to 'scape\"".encode(Encoding::EUC_JP) )
|
1269
1338
|
end
|
1270
1339
|
|
1271
1340
|
it "uses the previous string encoding for escaped string" do
|
1272
|
-
original = "Möhre to
|
1341
|
+
original = "Möhre to 'scape".encode( "iso-8859-1" )
|
1273
1342
|
@conn.set_client_encoding( "euc_jp" )
|
1274
1343
|
escaped = described_class.escape( original )
|
1275
1344
|
expect( escaped.encoding ).to eq( Encoding::ISO8859_1 )
|
1276
|
-
expect( escaped ).to eq( "Möhre to".encode(Encoding::ISO8859_1) )
|
1345
|
+
expect( escaped ).to eq( "Möhre to ''scape".encode(Encoding::ISO8859_1) )
|
1277
1346
|
end
|
1278
1347
|
|
1279
1348
|
it "uses the previous string encoding for quote_ident" do
|
1280
|
-
original = "Möhre to
|
1349
|
+
original = "Möhre to 'scape".encode( "iso-8859-1" )
|
1281
1350
|
@conn.set_client_encoding( "euc_jp" )
|
1282
1351
|
escaped = described_class.quote_ident( original )
|
1283
1352
|
expect( escaped.encoding ).to eq( Encoding::ISO8859_1 )
|
1284
|
-
expect( escaped.encode ).to eq( "\"Möhre to\"".encode(Encoding::ISO8859_1) )
|
1353
|
+
expect( escaped.encode ).to eq( "\"Möhre to 'scape\"".encode(Encoding::ISO8859_1) )
|
1285
1354
|
end
|
1286
1355
|
|
1287
1356
|
it "raises appropriate error if set_client_encoding is called with invalid arguments" do
|
@@ -1366,9 +1435,54 @@ describe PG::Connection do
|
|
1366
1435
|
end
|
1367
1436
|
end
|
1368
1437
|
|
1438
|
+
it "rejects command strings with zero bytes" do
|
1439
|
+
expect{ @conn.exec( "SELECT 1;\x00" ) }.to raise_error(ArgumentError, /null byte/)
|
1440
|
+
expect{ @conn.exec_params( "SELECT 1;\x00", [] ) }.to raise_error(ArgumentError, /null byte/)
|
1441
|
+
expect{ @conn.prepare( "abc\x00", "SELECT 1;" ) }.to raise_error(ArgumentError, /null byte/)
|
1442
|
+
expect{ @conn.prepare( "abc", "SELECT 1;\x00" ) }.to raise_error(ArgumentError, /null byte/)
|
1443
|
+
expect{ @conn.exec_prepared( "abc\x00", [] ) }.to raise_error(ArgumentError, /null byte/)
|
1444
|
+
expect{ @conn.describe_prepared( "abc\x00" ) }.to raise_error(ArgumentError, /null byte/)
|
1445
|
+
expect{ @conn.describe_portal( "abc\x00" ) }.to raise_error(ArgumentError, /null byte/)
|
1446
|
+
expect{ @conn.send_query( "SELECT 1;\x00" ) }.to raise_error(ArgumentError, /null byte/)
|
1447
|
+
expect{ @conn.send_query_params( "SELECT 1;\x00", [] ) }.to raise_error(ArgumentError, /null byte/)
|
1448
|
+
expect{ @conn.send_prepare( "abc\x00", "SELECT 1;" ) }.to raise_error(ArgumentError, /null byte/)
|
1449
|
+
expect{ @conn.send_prepare( "abc", "SELECT 1;\x00" ) }.to raise_error(ArgumentError, /null byte/)
|
1450
|
+
expect{ @conn.send_query_prepared( "abc\x00", [] ) }.to raise_error(ArgumentError, /null byte/)
|
1451
|
+
expect{ @conn.send_describe_prepared( "abc\x00" ) }.to raise_error(ArgumentError, /null byte/)
|
1452
|
+
expect{ @conn.send_describe_portal( "abc\x00" ) }.to raise_error(ArgumentError, /null byte/)
|
1453
|
+
end
|
1454
|
+
|
1455
|
+
it "rejects query params with zero bytes" do
|
1456
|
+
expect{ @conn.exec_params( "SELECT 1;\x00", ["ab\x00"] ) }.to raise_error(ArgumentError, /null byte/)
|
1457
|
+
expect{ @conn.exec_prepared( "abc\x00", ["ab\x00"] ) }.to raise_error(ArgumentError, /null byte/)
|
1458
|
+
expect{ @conn.send_query_params( "SELECT 1;\x00", ["ab\x00"] ) }.to raise_error(ArgumentError, /null byte/)
|
1459
|
+
expect{ @conn.send_query_prepared( "abc\x00", ["ab\x00"] ) }.to raise_error(ArgumentError, /null byte/)
|
1460
|
+
end
|
1461
|
+
|
1462
|
+
it "rejects string with zero bytes in escape" do
|
1463
|
+
expect{ @conn.escape( "ab\x00cd" ) }.to raise_error(ArgumentError, /null byte/)
|
1464
|
+
end
|
1465
|
+
|
1466
|
+
it "rejects string with zero bytes in escape_literal" do
|
1467
|
+
expect{ @conn.escape_literal( "ab\x00cd" ) }.to raise_error(ArgumentError, /null byte/)
|
1468
|
+
end
|
1469
|
+
|
1470
|
+
it "rejects string with zero bytes in escape_identifier" do
|
1471
|
+
expect{ @conn.escape_identifier( "ab\x00cd" ) }.to raise_error(ArgumentError, /null byte/)
|
1472
|
+
end
|
1473
|
+
|
1474
|
+
it "rejects string with zero bytes in quote_ident" do
|
1475
|
+
expect{ described_class.quote_ident( "ab\x00cd" ) }.to raise_error(ArgumentError, /null byte/)
|
1476
|
+
end
|
1477
|
+
|
1478
|
+
it "rejects Array with string with zero bytes" do
|
1479
|
+
original = ["xyz", "2\x00"]
|
1480
|
+
expect{ described_class.quote_ident( original ) }.to raise_error(ArgumentError, /null byte/)
|
1481
|
+
end
|
1482
|
+
|
1369
1483
|
it "can quote bigger strings with quote_ident" do
|
1370
1484
|
original = "'01234567\"" * 100
|
1371
|
-
escaped = described_class.quote_ident( original
|
1485
|
+
escaped = described_class.quote_ident( original )
|
1372
1486
|
expect( escaped ).to eq( "\"" + original.gsub("\"", "\"\"") + "\"" )
|
1373
1487
|
end
|
1374
1488
|
|