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.
- checksums.yaml +4 -4
- checksums.yaml.gz.sig +0 -0
- data.tar.gz.sig +0 -0
- data/ChangeLog +0 -6595
- data/History.rdoc +52 -0
- data/README.rdoc +11 -0
- data/Rakefile +1 -1
- data/Rakefile.cross +1 -1
- data/ext/errorcodes.rb +1 -1
- data/ext/extconf.rb +2 -0
- data/ext/pg.c +3 -2
- data/ext/pg.h +33 -5
- data/ext/pg_binary_decoder.c +69 -6
- data/ext/pg_binary_encoder.c +1 -1
- data/ext/pg_coder.c +52 -3
- data/ext/pg_connection.c +290 -103
- data/ext/pg_copy_coder.c +10 -5
- data/ext/pg_result.c +339 -113
- data/ext/pg_text_decoder.c +597 -37
- data/ext/pg_text_encoder.c +1 -1
- data/ext/pg_tuple.c +540 -0
- 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 +6 -6
- data/ext/util.h +2 -2
- data/lib/pg.rb +5 -3
- data/lib/pg/basic_type_mapping.rb +40 -7
- data/lib/pg/coder.rb +1 -1
- data/lib/pg/connection.rb +20 -1
- data/lib/pg/constants.rb +1 -1
- data/lib/pg/exceptions.rb +1 -1
- data/lib/pg/result.rb +1 -1
- data/lib/pg/text_decoder.rb +19 -23
- data/lib/pg/text_encoder.rb +35 -1
- data/lib/pg/type_map_by_column.rb +1 -1
- data/spec/helpers.rb +39 -7
- data/spec/pg/basic_type_mapping_spec.rb +230 -27
- data/spec/pg/connection_spec.rb +116 -77
- data/spec/pg/result_spec.rb +46 -11
- data/spec/pg/type_map_by_class_spec.rb +1 -1
- data/spec/pg/type_map_by_column_spec.rb +1 -1
- data/spec/pg/type_map_by_mri_type_spec.rb +1 -1
- data/spec/pg/type_map_by_oid_spec.rb +1 -1
- 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 +177 -11
- data/spec/pg_spec.rb +1 -1
- metadata +24 -28
- metadata.gz.sig +0 -0
@@ -1,9 +1,25 @@
|
|
1
|
-
|
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.
|
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.
|
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.
|
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.
|
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.
|
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
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
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
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
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
|
151
|
-
expect( res.getvalue(0,2) ).to eq(
|
152
|
-
expect( res.getvalue(0,3) ).to eq(
|
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.
|
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.
|
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.
|
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
|
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'
|
@@ -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
|
-
|
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
|
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(
|
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.
|
418
|
-
@conn.
|
419
|
-
@conn.
|
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 "
|
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
|
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 "
|
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.
|
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, /
|
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.
|
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.
|
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.
|
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.
|
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 #
|
1335
|
-
@conn.
|
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
|