pg 1.0.0-x64-mingw32 → 1.1.0.pre20180730144600-x64-mingw32

Sign up to get free protection for your applications and to get access to all the features.
Files changed (61) hide show
  1. checksums.yaml +5 -5
  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 +2 -2
  8. data/Rakefile.cross +4 -4
  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/2.0/pg_ext.so +0 -0
  32. data/lib/2.1/pg_ext.so +0 -0
  33. data/lib/2.2/pg_ext.so +0 -0
  34. data/lib/2.3/pg_ext.so +0 -0
  35. data/lib/2.4/pg_ext.so +0 -0
  36. data/lib/2.5/pg_ext.so +0 -0
  37. data/lib/libpq.dll +0 -0
  38. data/lib/pg.rb +5 -3
  39. data/lib/pg/basic_type_mapping.rb +40 -7
  40. data/lib/pg/coder.rb +1 -1
  41. data/lib/pg/connection.rb +20 -1
  42. data/lib/pg/constants.rb +1 -1
  43. data/lib/pg/exceptions.rb +1 -1
  44. data/lib/pg/result.rb +1 -1
  45. data/lib/pg/text_decoder.rb +19 -23
  46. data/lib/pg/text_encoder.rb +35 -1
  47. data/lib/pg/type_map_by_column.rb +1 -1
  48. data/spec/helpers.rb +39 -7
  49. data/spec/pg/basic_type_mapping_spec.rb +230 -27
  50. data/spec/pg/connection_spec.rb +116 -77
  51. data/spec/pg/result_spec.rb +46 -11
  52. data/spec/pg/type_map_by_class_spec.rb +1 -1
  53. data/spec/pg/type_map_by_column_spec.rb +1 -1
  54. data/spec/pg/type_map_by_mri_type_spec.rb +1 -1
  55. data/spec/pg/type_map_by_oid_spec.rb +1 -1
  56. data/spec/pg/type_map_in_ruby_spec.rb +1 -1
  57. data/spec/pg/type_map_spec.rb +1 -1
  58. data/spec/pg/type_spec.rb +177 -11
  59. data/spec/pg_spec.rb +1 -1
  60. metadata +25 -29
  61. 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