pg 1.0.0 → 1.1.0.pre20180730144600

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 (54) 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 +52 -0
  6. data/README.rdoc +11 -0
  7. data/Rakefile +1 -1
  8. data/Rakefile.cross +1 -1
  9. data/ext/errorcodes.rb +1 -1
  10. data/ext/extconf.rb +2 -0
  11. data/ext/pg.c +3 -2
  12. data/ext/pg.h +33 -5
  13. data/ext/pg_binary_decoder.c +69 -6
  14. data/ext/pg_binary_encoder.c +1 -1
  15. data/ext/pg_coder.c +52 -3
  16. data/ext/pg_connection.c +290 -103
  17. data/ext/pg_copy_coder.c +10 -5
  18. data/ext/pg_result.c +339 -113
  19. data/ext/pg_text_decoder.c +597 -37
  20. data/ext/pg_text_encoder.c +1 -1
  21. data/ext/pg_tuple.c +540 -0
  22. data/ext/pg_type_map.c +1 -1
  23. data/ext/pg_type_map_all_strings.c +1 -1
  24. data/ext/pg_type_map_by_class.c +1 -1
  25. data/ext/pg_type_map_by_column.c +1 -1
  26. data/ext/pg_type_map_by_mri_type.c +1 -1
  27. data/ext/pg_type_map_by_oid.c +1 -1
  28. data/ext/pg_type_map_in_ruby.c +1 -1
  29. data/ext/util.c +6 -6
  30. data/ext/util.h +2 -2
  31. data/lib/pg.rb +5 -3
  32. data/lib/pg/basic_type_mapping.rb +40 -7
  33. data/lib/pg/coder.rb +1 -1
  34. data/lib/pg/connection.rb +20 -1
  35. data/lib/pg/constants.rb +1 -1
  36. data/lib/pg/exceptions.rb +1 -1
  37. data/lib/pg/result.rb +1 -1
  38. data/lib/pg/text_decoder.rb +19 -23
  39. data/lib/pg/text_encoder.rb +35 -1
  40. data/lib/pg/type_map_by_column.rb +1 -1
  41. data/spec/helpers.rb +39 -7
  42. data/spec/pg/basic_type_mapping_spec.rb +230 -27
  43. data/spec/pg/connection_spec.rb +116 -77
  44. data/spec/pg/result_spec.rb +46 -11
  45. data/spec/pg/type_map_by_class_spec.rb +1 -1
  46. data/spec/pg/type_map_by_column_spec.rb +1 -1
  47. data/spec/pg/type_map_by_mri_type_spec.rb +1 -1
  48. data/spec/pg/type_map_by_oid_spec.rb +1 -1
  49. data/spec/pg/type_map_in_ruby_spec.rb +1 -1
  50. data/spec/pg/type_map_spec.rb +1 -1
  51. data/spec/pg/type_spec.rb +177 -11
  52. data/spec/pg_spec.rb +1 -1
  53. metadata +24 -28
  54. metadata.gz.sig +0 -0
@@ -1,9 +1,25 @@
1
- #!/usr/bin/env rspec
1
+ # -*- rspec -*-
2
2
  # encoding: utf-8
3
3
 
4
4
  require_relative '../helpers'
5
5
 
6
6
  require 'pg'
7
+ require 'time'
8
+
9
+ def restore_type(types)
10
+ [0, 1].each do |format|
11
+ [types].flatten.each do |type|
12
+ PG::BasicTypeRegistry.alias_type(format, "restore_#{type}", type)
13
+ end
14
+ end
15
+ yield
16
+ ensure
17
+ [0, 1].each do |format|
18
+ [types].flatten.each do |type|
19
+ PG::BasicTypeRegistry.alias_type(format, type, "restore_#{type}")
20
+ end
21
+ end
22
+ end
7
23
 
8
24
  describe 'Basic type mapping' do
9
25
 
@@ -42,6 +58,30 @@ describe 'Basic type mapping' do
42
58
 
43
59
  expect( result_typenames(res) ).to eq( ['bigint[]', 'bigint[]', 'double precision[]', 'text[]'] )
44
60
  end
61
+
62
+ it "should do bigdecimal param encoding" do
63
+ large = ('123456790'*10) << '.' << ('012345679')
64
+ res = @conn.exec_params( "SELECT $1::numeric,$2::numeric",
65
+ [BigDecimal.new('1'), BigDecimal.new(large)], nil, basic_type_mapping )
66
+
67
+ expect( res.values ).to eq( [
68
+ [ "1.0", large ],
69
+ ] )
70
+
71
+ expect( result_typenames(res) ).to eq( ['numeric', 'numeric'] )
72
+ end
73
+
74
+ it "should do IPAddr param encoding" do
75
+ res = @conn.exec_params( "SELECT $1::inet,$2::inet,$3::cidr,$4::cidr",
76
+ ['1.2.3.4', IPAddr.new('1234::5678'), '1.2.3.4', IPAddr.new('1234:5678::/32')], nil, basic_type_mapping )
77
+
78
+ expect( res.values ).to eq( [
79
+ [ '1.2.3.4', '1234::5678', '1.2.3.4/32', '1234:5678::/32'],
80
+ ] )
81
+
82
+ expect( result_typenames(res) ).to eq( ['inet', 'inet', 'cidr', 'cidr'] )
83
+ end
84
+
45
85
  end
46
86
 
47
87
 
@@ -78,14 +118,14 @@ describe 'Basic type mapping' do
78
118
 
79
119
  it "should do boolean type conversions" do
80
120
  [1, 0].each do |format|
81
- res = @conn.exec( "SELECT true::BOOLEAN, false::BOOLEAN, NULL::BOOLEAN", [], format )
121
+ res = @conn.exec_params( "SELECT true::BOOLEAN, false::BOOLEAN, NULL::BOOLEAN", [], format )
82
122
  expect( res.values ).to eq( [[true, false, nil]] )
83
123
  end
84
124
  end
85
125
 
86
126
  it "should do binary type conversions" do
87
127
  [1, 0].each do |format|
88
- res = @conn.exec( "SELECT E'\\\\000\\\\377'::BYTEA", [], format )
128
+ res = @conn.exec_params( "SELECT E'\\\\000\\\\377'::BYTEA", [], format )
89
129
  expect( res.values ).to eq( [[["00ff"].pack("H*")]] )
90
130
  expect( res.values[0][0].encoding ).to eq( Encoding::ASCII_8BIT ) if Object.const_defined? :Encoding
91
131
  end
@@ -93,7 +133,7 @@ describe 'Basic type mapping' do
93
133
 
94
134
  it "should do integer type conversions" do
95
135
  [1, 0].each do |format|
96
- res = @conn.exec( "SELECT -8999::INT2, -899999999::INT4, -8999999999999999999::INT8", [], format )
136
+ res = @conn.exec_params( "SELECT -8999::INT2, -899999999::INT4, -8999999999999999999::INT8", [], format )
97
137
  expect( res.values ).to eq( [[-8999, -899999999, -8999999999999999999]] )
98
138
  end
99
139
  end
@@ -101,7 +141,7 @@ describe 'Basic type mapping' do
101
141
  it "should do string type conversions" do
102
142
  @conn.internal_encoding = 'utf-8' if Object.const_defined? :Encoding
103
143
  [1, 0].each do |format|
104
- res = @conn.exec( "SELECT 'abcäöü'::TEXT", [], format )
144
+ res = @conn.exec_params( "SELECT 'abcäöü'::TEXT", [], format )
105
145
  expect( res.values ).to eq( [['abcäöü']] )
106
146
  expect( res.values[0][0].encoding ).to eq( Encoding::UTF_8 ) if Object.const_defined? :Encoding
107
147
  end
@@ -109,7 +149,7 @@ describe 'Basic type mapping' do
109
149
 
110
150
  it "should do float type conversions" do
111
151
  [1, 0].each do |format|
112
- res = @conn.exec( "SELECT -8.999e3::FLOAT4,
152
+ res = @conn.exec_params( "SELECT -8.999e3::FLOAT4,
113
153
  8.999e10::FLOAT4,
114
154
  -8999999999e-99::FLOAT8,
115
155
  NULL::FLOAT4,
@@ -127,35 +167,107 @@ describe 'Basic type mapping' do
127
167
  end
128
168
  end
129
169
 
130
- it "should do datetime without time zone type conversions" do
131
- [0].each do |format|
132
- res = @conn.exec( "SELECT CAST('2013-12-31 23:58:59+02' AS TIMESTAMP WITHOUT TIME ZONE),
133
- CAST('1913-12-31 23:58:59.123-03' AS TIMESTAMP WITHOUT TIME ZONE),
134
- CAST('infinity' AS TIMESTAMP WITHOUT TIME ZONE),
135
- CAST('-infinity' AS TIMESTAMP WITHOUT TIME ZONE)", [], format )
136
- expect( res.getvalue(0,0) ).to eq( Time.new(2013, 12, 31, 23, 58, 59) )
137
- expect( res.getvalue(0,1) ).to be_within(1e-3).of(Time.new(1913, 12, 31, 23, 58, 59.123))
138
- expect( res.getvalue(0,2) ).to eq( 'infinity' )
139
- expect( res.getvalue(0,3) ).to eq( '-infinity' )
170
+ it "should do text datetime without time zone type conversions" do
171
+ # for backward compat text timestamps without time zone are treated as local times
172
+ res = @conn.exec_params( "SELECT CAST('2013-12-31 23:58:59+02' AS TIMESTAMP WITHOUT TIME ZONE),
173
+ CAST('1913-12-31 23:58:59.1231-03' AS TIMESTAMP WITHOUT TIME ZONE),
174
+ CAST('4714-11-24 23:58:59.1231-03 BC' AS TIMESTAMP WITHOUT TIME ZONE),
175
+ CAST('294276-12-31 23:58:59.1231-03' AS TIMESTAMP WITHOUT TIME ZONE),
176
+ CAST('infinity' AS TIMESTAMP WITHOUT TIME ZONE),
177
+ CAST('-infinity' AS TIMESTAMP WITHOUT TIME ZONE)", [], 0 )
178
+ expect( res.getvalue(0,0) ).to eq( Time.new(2013, 12, 31, 23, 58, 59) )
179
+ expect( res.getvalue(0,1).iso8601(3) ).to eq( Time.new(1913, 12, 31, 23, 58, 59.1231).iso8601(3) )
180
+ expect( res.getvalue(0,2).iso8601(3) ).to eq( Time.new(-4713, 11, 24, 23, 58, 59.1231).iso8601(3) )
181
+ expect( res.getvalue(0,3).iso8601(3) ).to eq( Time.new(294276, 12, 31, 23, 58, 59.1231).iso8601(3) )
182
+ expect( res.getvalue(0,4) ).to eq( 'infinity' )
183
+ expect( res.getvalue(0,5) ).to eq( '-infinity' )
184
+ end
185
+
186
+ [1, 0].each do |format|
187
+ it "should convert format #{format} timestamps per TimestampUtc" do
188
+ restore_type("timestamp") do
189
+ PG::BasicTypeRegistry.register_type 0, 'timestamp', nil, PG::TextDecoder::TimestampUtc
190
+ @conn.type_map_for_results = PG::BasicTypeMapForResults.new(@conn)
191
+ res = @conn.exec_params( "SELECT CAST('2013-07-31 23:58:59+02' AS TIMESTAMP WITHOUT TIME ZONE),
192
+ CAST('1913-12-31 23:58:59.1231-03' AS TIMESTAMP WITHOUT TIME ZONE),
193
+ CAST('4714-11-24 23:58:59.1231-03 BC' AS TIMESTAMP WITHOUT TIME ZONE),
194
+ CAST('294276-12-31 23:58:59.1231-03' AS TIMESTAMP WITHOUT TIME ZONE),
195
+ CAST('infinity' AS TIMESTAMP WITHOUT TIME ZONE),
196
+ CAST('-infinity' AS TIMESTAMP WITHOUT TIME ZONE)", [], format )
197
+ expect( res.getvalue(0,0).iso8601(3) ).to eq( Time.utc(2013, 7, 31, 23, 58, 59).iso8601(3) )
198
+ expect( res.getvalue(0,1).iso8601(3) ).to eq( Time.utc(1913, 12, 31, 23, 58, 59.1231).iso8601(3) )
199
+ expect( res.getvalue(0,2).iso8601(3) ).to eq( Time.utc(-4713, 11, 24, 23, 58, 59.1231).iso8601(3) )
200
+ expect( res.getvalue(0,3).iso8601(3) ).to eq( Time.utc(294276, 12, 31, 23, 58, 59.1231).iso8601(3) )
201
+ expect( res.getvalue(0,4) ).to eq( 'infinity' )
202
+ expect( res.getvalue(0,5) ).to eq( '-infinity' )
203
+ end
140
204
  end
141
205
  end
142
206
 
143
- it "should do datetime with time zone type conversions" do
144
- [0].each do |format|
145
- res = @conn.exec( "SELECT CAST('2013-12-31 23:58:59+02' AS TIMESTAMP WITH TIME ZONE),
146
- CAST('1913-12-31 23:58:59.123-03' AS TIMESTAMP WITH TIME ZONE),
207
+ [1, 0].each do |format|
208
+ it "should convert format #{format} timestamps per TimestampUtcToLocal" do
209
+ restore_type("timestamp") do
210
+ PG::BasicTypeRegistry.register_type 0, 'timestamp', nil, PG::TextDecoder::TimestampUtcToLocal
211
+ PG::BasicTypeRegistry.register_type 1, 'timestamp', nil, PG::BinaryDecoder::TimestampUtcToLocal
212
+ @conn.type_map_for_results = PG::BasicTypeMapForResults.new(@conn)
213
+ res = @conn.exec_params( "SELECT CAST('2013-07-31 23:58:59+02' AS TIMESTAMP WITHOUT TIME ZONE),
214
+ CAST('1913-12-31 23:58:59.1231-03' AS TIMESTAMP WITHOUT TIME ZONE),
215
+ CAST('4714-11-24 23:58:59.1231-03 BC' AS TIMESTAMP WITHOUT TIME ZONE),
216
+ CAST('294276-12-31 23:58:59.1231-03' AS TIMESTAMP WITHOUT TIME ZONE),
217
+ CAST('infinity' AS TIMESTAMP WITHOUT TIME ZONE),
218
+ CAST('-infinity' AS TIMESTAMP WITHOUT TIME ZONE)", [], format )
219
+ expect( res.getvalue(0,0).iso8601(3) ).to eq( Time.utc(2013, 7, 31, 23, 58, 59).getlocal.iso8601(3) )
220
+ expect( res.getvalue(0,1).iso8601(3) ).to eq( Time.utc(1913, 12, 31, 23, 58, 59.1231).getlocal.iso8601(3) )
221
+ expect( res.getvalue(0,2).iso8601(3) ).to eq( Time.utc(-4713, 11, 24, 23, 58, 59.1231).getlocal.iso8601(3) )
222
+ expect( res.getvalue(0,3).iso8601(3) ).to eq( Time.utc(294276, 12, 31, 23, 58, 59.1231).getlocal.iso8601(3) )
223
+ expect( res.getvalue(0,4) ).to eq( 'infinity' )
224
+ expect( res.getvalue(0,5) ).to eq( '-infinity' )
225
+ end
226
+ end
227
+ end
228
+
229
+ [1, 0].each do |format|
230
+ it "should convert format #{format} timestamps per TimestampLocal" do
231
+ restore_type("timestamp") do
232
+ PG::BasicTypeRegistry.register_type 0, 'timestamp', nil, PG::TextDecoder::TimestampLocal
233
+ PG::BasicTypeRegistry.register_type 1, 'timestamp', nil, PG::BinaryDecoder::TimestampLocal
234
+ @conn.type_map_for_results = PG::BasicTypeMapForResults.new(@conn)
235
+ res = @conn.exec_params( "SELECT CAST('2013-07-31 23:58:59' AS TIMESTAMP WITHOUT TIME ZONE),
236
+ CAST('1913-12-31 23:58:59.1231' AS TIMESTAMP WITHOUT TIME ZONE),
237
+ CAST('4714-11-24 23:58:59.1231-03 BC' AS TIMESTAMP WITHOUT TIME ZONE),
238
+ CAST('294276-12-31 23:58:59.1231+03' AS TIMESTAMP WITHOUT TIME ZONE),
239
+ CAST('infinity' AS TIMESTAMP WITHOUT TIME ZONE),
240
+ CAST('-infinity' AS TIMESTAMP WITHOUT TIME ZONE)", [], format )
241
+ expect( res.getvalue(0,0).iso8601(3) ).to eq( Time.new(2013, 7, 31, 23, 58, 59).iso8601(3) )
242
+ expect( res.getvalue(0,1).iso8601(3) ).to eq( Time.new(1913, 12, 31, 23, 58, 59.1231).iso8601(3) )
243
+ expect( res.getvalue(0,2).iso8601(3) ).to eq( Time.new(-4713, 11, 24, 23, 58, 59.1231).iso8601(3) )
244
+ expect( res.getvalue(0,3).iso8601(3) ).to eq( Time.new(294276, 12, 31, 23, 58, 59.1231).iso8601(3) )
245
+ expect( res.getvalue(0,4) ).to eq( 'infinity' )
246
+ expect( res.getvalue(0,5) ).to eq( '-infinity' )
247
+ end
248
+ end
249
+ end
250
+
251
+ [0, 1].each do |format|
252
+ it "should convert format #{format} timestamps with time zone" do
253
+ res = @conn.exec_params( "SELECT CAST('2013-12-31 23:58:59+02' AS TIMESTAMP WITH TIME ZONE),
254
+ CAST('1913-12-31 23:58:59.1231-03' AS TIMESTAMP WITH TIME ZONE),
255
+ CAST('4714-11-24 23:58:59.1231-03 BC' AS TIMESTAMP WITH TIME ZONE),
256
+ CAST('294276-12-31 23:58:59.1231+03' AS TIMESTAMP WITH TIME ZONE),
147
257
  CAST('infinity' AS TIMESTAMP WITH TIME ZONE),
148
258
  CAST('-infinity' AS TIMESTAMP WITH TIME ZONE)", [], format )
149
- expect( res.getvalue(0,0) ).to eq( Time.new(2013, 12, 31, 23, 58, 59, "+02:00") )
150
- expect( res.getvalue(0,1) ).to be_within(1e-3).of(Time.new(1913, 12, 31, 23, 58, 59.123, "-03:00"))
151
- expect( res.getvalue(0,2) ).to eq( 'infinity' )
152
- expect( res.getvalue(0,3) ).to eq( '-infinity' )
259
+ expect( res.getvalue(0,0).iso8601(3) ).to eq( Time.new(2013, 12, 31, 23, 58, 59, "+02:00").getlocal.iso8601(3) )
260
+ expect( res.getvalue(0,1).iso8601(3) ).to eq( Time.new(1913, 12, 31, 23, 58, 59.1231, "-03:00").getlocal.iso8601(3) )
261
+ expect( res.getvalue(0,2).iso8601(3) ).to eq( Time.new(-4713, 11, 24, 23, 58, 59.1231, "-03:00").getlocal.iso8601(3) )
262
+ expect( res.getvalue(0,3).iso8601(3) ).to eq( Time.new(294276, 12, 31, 23, 58, 59.1231, "+03:00").getlocal.iso8601(3) )
263
+ expect( res.getvalue(0,4) ).to eq( 'infinity' )
264
+ expect( res.getvalue(0,5) ).to eq( '-infinity' )
153
265
  end
154
266
  end
155
267
 
156
268
  it "should do date type conversions" do
157
269
  [0].each do |format|
158
- res = @conn.exec( "SELECT CAST('2113-12-31' AS DATE),
270
+ res = @conn.exec_params( "SELECT CAST('2113-12-31' AS DATE),
159
271
  CAST('1913-12-31' AS DATE),
160
272
  CAST('infinity' AS DATE),
161
273
  CAST('-infinity' AS DATE)", [], format )
@@ -166,10 +278,31 @@ describe 'Basic type mapping' do
166
278
  end
167
279
  end
168
280
 
281
+ it "should do numeric type conversions" do
282
+ [0].each do |format|
283
+ small = '123456790123.12'
284
+ large = ('123456790'*10) << '.' << ('012345679')
285
+ numerics = [
286
+ '1',
287
+ '1.0',
288
+ '1.2',
289
+ small,
290
+ large,
291
+ ]
292
+ sql_numerics = numerics.map { |v| "CAST(#{v} AS numeric)" }
293
+ res = @conn.exec_params( "SELECT #{sql_numerics.join(',')}", [], format )
294
+ expect( res.getvalue(0,0) ).to eq( BigDecimal('1') )
295
+ expect( res.getvalue(0,1) ).to eq( BigDecimal('1') )
296
+ expect( res.getvalue(0,2) ).to eq( BigDecimal('1.2') )
297
+ expect( res.getvalue(0,3) ).to eq( BigDecimal(small) )
298
+ expect( res.getvalue(0,4) ).to eq( BigDecimal(large) )
299
+ end
300
+ end
301
+
169
302
  it "should do JSON conversions", :postgresql_94 do
170
303
  [0].each do |format|
171
304
  ['JSON', 'JSONB'].each do |type|
172
- res = @conn.exec( "SELECT CAST('123' AS #{type}),
305
+ res = @conn.exec_params( "SELECT CAST('123' AS #{type}),
173
306
  CAST('12.3' AS #{type}),
174
307
  CAST('true' AS #{type}),
175
308
  CAST('false' AS #{type}),
@@ -189,7 +322,7 @@ describe 'Basic type mapping' do
189
322
 
190
323
  it "should do array type conversions" do
191
324
  [0].each do |format|
192
- res = @conn.exec( "SELECT CAST('{1,2,3}' AS INT2[]), CAST('{{1,2},{3,4}}' AS INT2[][]),
325
+ res = @conn.exec_params( "SELECT CAST('{1,2,3}' AS INT2[]), CAST('{{1,2},{3,4}}' AS INT2[][]),
193
326
  CAST('{1,2,3}' AS INT4[]),
194
327
  CAST('{1,2,3}' AS INT8[]),
195
328
  CAST('{1,2,3}' AS TEXT[]),
@@ -207,6 +340,76 @@ describe 'Basic type mapping' do
207
340
  expect( res.getvalue(0,7) ).to eq( [1.0,2.0,3.0] )
208
341
  end
209
342
  end
343
+
344
+ it "should do inet type conversions" do
345
+ [0].each do |format|
346
+ vals = [
347
+ '1.2.3.4',
348
+ '0.0.0.0/0',
349
+ '1.0.0.0/8',
350
+ '1.2.0.0/16',
351
+ '1.2.3.0/24',
352
+ '1.2.3.4/24',
353
+ '1.2.3.4/32',
354
+ '1.2.3.128/25',
355
+ '1234:3456:5678:789a:9abc:bced:edf0:f012',
356
+ '::/0',
357
+ '1234:3456::/32',
358
+ '1234:3456:5678:789a::/64',
359
+ '1234:3456:5678:789a:9abc:bced::/96',
360
+ '1234:3456:5678:789a:9abc:bced:edf0:f012/128',
361
+ '1234:3456:5678:789a:9abc:bced:edf0:f012/0',
362
+ '1234:3456:5678:789a:9abc:bced:edf0:f012/32',
363
+ '1234:3456:5678:789a:9abc:bced:edf0:f012/64',
364
+ '1234:3456:5678:789a:9abc:bced:edf0:f012/96',
365
+ ]
366
+ sql_vals = vals.map{|v| "CAST('#{v}' AS inet)"}
367
+ res = @conn.exec_params(("SELECT " + sql_vals.join(', ')), [], format )
368
+ vals.each_with_index do |v, i|
369
+ val = res.getvalue(0,i)
370
+ expect( res.getvalue(0,i) ).to eq( IPAddr.new(v) )
371
+ end
372
+ end
373
+ end
374
+
375
+ it "should do cidr type conversions" do
376
+ [0].each do |format|
377
+ vals = [
378
+ '0.0.0.0/0',
379
+ '1.0.0.0/8',
380
+ '1.2.0.0/16',
381
+ '1.2.3.0/24',
382
+ '1.2.3.4/32',
383
+ '1.2.3.128/25',
384
+ '::/0',
385
+ '1234:3456::/32',
386
+ '1234:3456:5678:789a::/64',
387
+ '1234:3456:5678:789a:9abc:bced::/96',
388
+ '1234:3456:5678:789a:9abc:bced:edf0:f012/128',
389
+ ]
390
+ sql_vals = vals.map { |v| "CAST('#{v}' AS cidr)" }
391
+ res = @conn.exec_params(("SELECT " + sql_vals.join(', ')), [], format )
392
+ vals.each_with_index do |v, i|
393
+ val = res.getvalue(0,i)
394
+ ip, prefix = v.split('/', 2)
395
+ expect( val.to_s ).to eq( ip )
396
+ if val.respond_to?(:prefix)
397
+ val_prefix = val.prefix
398
+ else
399
+ default_prefix = (val.family == Socket::AF_INET ? 32 : 128)
400
+ range = val.to_range
401
+ val_prefix = default_prefix - Math.log(((range.end.to_i - range.begin.to_i) + 1), 2).to_i
402
+ end
403
+ if v.include?('/')
404
+ expect( val_prefix ).to eq( prefix.to_i )
405
+ elsif v.include?('.')
406
+ expect( val_prefix ).to eq( 32 )
407
+ else
408
+ expect( val_prefix ).to eq( 128 )
409
+ end
410
+ end
411
+ end
412
+ end
210
413
  end
211
414
 
212
415
  context "with usage of result oids for copy decoder selection" do
@@ -1,4 +1,4 @@
1
- #!/usr/bin/env rspec
1
+ # -*- rspec -*-
2
2
  #encoding: utf-8
3
3
 
4
4
  require_relative '../helpers'
@@ -176,21 +176,8 @@ describe PG::Connection do
176
176
  it "can connect asynchronously", :socket_io 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
@@ -201,28 +188,48 @@ describe PG::Connection do
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", :socket_io 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
+ end
232
+
226
233
  it "raises proper error when sending fails" do
227
234
  conn = described_class.connect_start( '127.0.0.1', 54320, "", "", "me", "xxxx", "somedb" )
228
235
  expect{ conn.exec 'SELECT 1' }.to raise_error(PG::UnableToSend, /no connection/)
@@ -295,18 +302,15 @@ describe PG::Connection do
295
302
 
296
303
  trace_data = trace_file.read
297
304
 
298
- expected_trace_output = EXPECTED_TRACE_OUTPUT.dup
299
- # For PostgreSQL < 9.0, the output will be different:
300
- # -From backend (#4)> 13
301
- # -From backend> "SELECT 1"
302
- # +From backend (#4)> 11
303
- # +From backend> "SELECT"
304
- if @conn.server_version < 90000
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
305
+ # For async_exec the output will be different:
306
+ # From backend> Z
307
+ # From backend (#4)> 5
308
+ # +From backend> Z
309
+ # +From backend (#4)> 5
310
+ # From backend> T
311
+ trace_data.sub!( /(From backend> Z\nFrom backend \(#4\)> 5\n){3}/m, '\\1\\1' )
308
312
 
309
- expect( trace_data ).to eq( expected_trace_output )
313
+ expect( trace_data ).to eq( EXPECTED_TRACE_OUTPUT )
310
314
  end
311
315
 
312
316
  it "allows a query to be cancelled" do
@@ -401,22 +405,11 @@ describe PG::Connection do
401
405
  end
402
406
  end
403
407
 
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
408
  it "supports explicitly calling #exec_params" do
416
409
  @conn.exec( "CREATE TABLE students ( name TEXT, age INTEGER )" )
417
- @conn.exec( "INSERT INTO students VALUES( $1, $2 )", ['Wally', 8] )
418
- @conn.exec( "INSERT INTO students VALUES( $1, $2 )", ['Sally', 6] )
419
- @conn.exec( "INSERT INTO students VALUES( $1, $2 )", ['Dorothy', 4] )
410
+ @conn.exec_params( "INSERT INTO students VALUES( $1, $2 )", ['Wally', 8] )
411
+ @conn.exec_params( "INSERT INTO students VALUES( $1, $2 )", ['Sally', 6] )
412
+ @conn.exec_params( "INSERT INTO students VALUES( $1, $2 )", ['Dorothy', 4] )
420
413
 
421
414
  res = @conn.exec_params( "SELECT name FROM students WHERE age >= $1", [6] )
422
415
  expect( res.values ).to eq( [ ['Wally'], ['Sally'] ] )
@@ -874,7 +867,7 @@ describe PG::Connection do
874
867
  end
875
868
 
876
869
 
877
- it "can connect asynchronously", :socket_io do
870
+ it "handles server close while asynchronous connect", :socket_io do
878
871
  serv = TCPServer.new( '127.0.0.1', 54320 )
879
872
  conn = described_class.connect_start( '127.0.0.1', 54320, "", "", "me", "xxxx", "somedb" )
880
873
  expect( [PG::PGRES_POLLING_WRITING, PG::CONNECTION_OK] ).to include conn.connect_poll
@@ -886,11 +879,29 @@ describe PG::Connection do
886
879
  expect( conn.connect_poll ).to eq( PG::PGRES_POLLING_FAILED )
887
880
  end
888
881
 
889
- it "discards previous results (if any) before waiting on an #async_exec"
882
+ it "discards previous results at #discard_results" do
883
+ @conn.send_query( "select 1" )
884
+ @conn.discard_results
885
+ @conn.send_query( "select 41 as one" )
886
+ res = @conn.get_last_result
887
+ expect( res.to_a ).to eq( [{ 'one' => '41' }] )
888
+ end
889
+
890
+ it "discards previous results (if any) before waiting on #exec" do
891
+ @conn.send_query( "select 1" )
892
+ res = @conn.exec( "select 42 as one" )
893
+ expect( res.to_a ).to eq( [{ 'one' => '42' }] )
894
+ end
890
895
 
891
- it "calls the block if one is provided to #async_exec" do
896
+ it "discards previous errors before waiting on #exec", :without_transaction do
897
+ @conn.send_query( "ERROR" )
898
+ res = @conn.exec( "select 43 as one" )
899
+ expect( res.to_a ).to eq( [{ 'one' => '43' }] )
900
+ end
901
+
902
+ it "calls the block if one is provided to #exec" do
892
903
  result = nil
893
- @conn.async_exec( "select 47 as one" ) do |pg_res|
904
+ @conn.exec( "select 47 as one" ) do |pg_res|
894
905
  result = pg_res[0]
895
906
  end
896
907
  expect( result ).to eq( { 'one' => '47' } )
@@ -928,7 +939,7 @@ describe PG::Connection do
928
939
  end
929
940
  serv.close
930
941
  expect{ conn.block }.to raise_error(PG::ConnectionBad, /server closed the connection unexpectedly/)
931
- expect{ conn.block }.to raise_error(PG::ConnectionBad, /can't get socket descriptor/)
942
+ expect{ conn.block }.to raise_error(PG::ConnectionBad, /connection not open/)
932
943
  end
933
944
 
934
945
  it "sets the fallback_application_name on new connections" do
@@ -1176,7 +1187,7 @@ describe PG::Connection do
1176
1187
  out_string = nil
1177
1188
  @conn.transaction do |conn|
1178
1189
  conn.internal_encoding = 'iso8859-1'
1179
- res = conn.exec("VALUES ('fantasia')", [], 0)
1190
+ res = conn.exec_params("VALUES ('fantasia')", [], 0)
1180
1191
  out_string = res[0]['column1']
1181
1192
  end
1182
1193
  expect( out_string ).to eq( 'fantasia' )
@@ -1187,7 +1198,7 @@ describe PG::Connection do
1187
1198
  out_string = nil
1188
1199
  @conn.transaction do |conn|
1189
1200
  conn.internal_encoding = 'utf-8'
1190
- res = conn.exec("VALUES ('世界線航跡蔵')", [], 0)
1201
+ res = conn.exec_params("VALUES ('世界線航跡蔵')", [], 0)
1191
1202
  out_string = res[0]['column1']
1192
1203
  end
1193
1204
  expect( out_string ).to eq( '世界線航跡蔵' )
@@ -1199,7 +1210,7 @@ describe PG::Connection do
1199
1210
  @conn.transaction do |conn|
1200
1211
  conn.internal_encoding = 'EUC-JP'
1201
1212
  stmt = "VALUES ('世界線航跡蔵')".encode('EUC-JP')
1202
- res = conn.exec(stmt, [], 0)
1213
+ res = conn.exec_params(stmt, [], 0)
1203
1214
  out_string = res[0]['column1']
1204
1215
  end
1205
1216
  expect( out_string ).to eq( '世界線航跡蔵'.encode('EUC-JP') )
@@ -1212,7 +1223,7 @@ describe PG::Connection do
1212
1223
  @conn.transaction do |conn|
1213
1224
  conn.internal_encoding = 'EUC-JP'
1214
1225
  stmt = "VALUES ('世界線航跡蔵')".encode('EUC-JP')
1215
- res = conn.exec(stmt, [], 0)
1226
+ res = conn.exec_params(stmt, [], 0)
1216
1227
  conn.internal_encoding = 'utf-8'
1217
1228
  out_string = res[0]['column1']
1218
1229
  end
@@ -1291,22 +1302,11 @@ describe PG::Connection do
1291
1302
  expect( r.values ).to eq( [['grün', 'grün', 't', 'grün']] )
1292
1303
  end
1293
1304
 
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
1305
  it "should convert query string to #exec" do
1301
1306
  r = @conn.exec("SELECT 'grün'".encode("utf-16be"))
1302
1307
  expect( r.values ).to eq( [['grün']] )
1303
1308
  end
1304
1309
 
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
1310
  it "should convert strings and parameters to #prepare and #exec_prepared" do
1311
1311
  @conn.prepare("weiß1".encode("utf-16be"), "VALUES( $1, $2, $1=$2, 'grün')".encode("cp850"))
1312
1312
  r = @conn.exec_prepared("weiß1".encode("utf-32le"),
@@ -1331,8 +1331,8 @@ describe PG::Connection do
1331
1331
  expect( @conn.get_last_result.values ).to eq( [['grün']] )
1332
1332
  end
1333
1333
 
1334
- it "should convert query string and parameters to #send_query" do
1335
- @conn.send_query("VALUES( $1, $2, $1=$2, 'grün')".encode("utf-16le"),
1334
+ it "should convert query string and parameters to #send_query_params" do
1335
+ @conn.send_query_params("VALUES( $1, $2, $1=$2, 'grün')".encode("utf-16le"),
1336
1336
  ['grün'.encode('utf-32be'), 'grün'.encode('iso-8859-1')])
1337
1337
  expect( @conn.get_last_result.values ).to eq( [['grün', 'grün', 't', 'grün']] )
1338
1338
  end
@@ -1716,4 +1716,43 @@ describe PG::Connection do
1716
1716
  end
1717
1717
  end
1718
1718
  end
1719
+
1720
+ describe "deprecated forms of methods" do
1721
+ it "should forward exec to exec_params" do
1722
+ res = @conn.exec("VALUES($1::INT)", [7]).values
1723
+ expect(res).to eq( [["7"]] )
1724
+ res = @conn.exec("VALUES($1::INT)", [7], 1).values
1725
+ expect(res).to eq( [[[7].pack("N")]] )
1726
+ res = @conn.exec("VALUES(8)", [], 1).values
1727
+ expect(res).to eq( [[[8].pack("N")]] )
1728
+ end
1729
+
1730
+ it "should forward exec_params to exec" do
1731
+ res = @conn.exec_params("VALUES(3); VALUES(4)").values
1732
+ expect(res).to eq( [["4"]] )
1733
+ res = @conn.exec_params("VALUES(3); VALUES(4)", nil).values
1734
+ expect(res).to eq( [["4"]] )
1735
+ res = @conn.exec_params("VALUES(3); VALUES(4)", nil, nil).values
1736
+ expect(res).to eq( [["4"]] )
1737
+ res = @conn.exec_params("VALUES(3); VALUES(4)", nil, 1).values
1738
+ expect(res).to eq( [["4"]] )
1739
+ res = @conn.exec_params("VALUES(3); VALUES(4)", nil, nil, nil).values
1740
+ expect(res).to eq( [["4"]] )
1741
+ expect{
1742
+ @conn.exec_params("VALUES(3); VALUES(4)", nil, nil, nil, nil).values
1743
+ }.to raise_error(ArgumentError)
1744
+ end
1745
+
1746
+ it "should forward send_query to send_query_params" do
1747
+ @conn.send_query("VALUES($1)", [5])
1748
+ expect(@conn.get_last_result.values).to eq( [["5"]] )
1749
+ end
1750
+
1751
+ it "shouldn't forward send_query_params to send_query" do
1752
+ expect{ @conn.send_query_params("VALUES(4)").values }
1753
+ .to raise_error(ArgumentError)
1754
+ expect{ @conn.send_query_params("VALUES(4)", nil).values }
1755
+ .to raise_error(TypeError)
1756
+ end
1757
+ end
1719
1758
  end