pg 1.0.0 → 1.2.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- checksums.yaml.gz.sig +0 -0
- data.tar.gz.sig +0 -0
- data/ChangeLog +0 -6595
- data/History.rdoc +156 -0
- data/Manifest.txt +8 -2
- data/README-Windows.rdoc +4 -4
- data/README.ja.rdoc +1 -2
- data/README.rdoc +55 -9
- data/Rakefile +9 -7
- data/Rakefile.cross +58 -57
- data/ext/errorcodes.def +68 -0
- data/ext/errorcodes.rb +1 -1
- data/ext/errorcodes.txt +19 -2
- data/ext/extconf.rb +7 -5
- data/ext/pg.c +141 -98
- data/ext/pg.h +64 -21
- data/ext/pg_binary_decoder.c +82 -15
- data/ext/pg_binary_encoder.c +13 -12
- data/ext/pg_coder.c +73 -12
- data/ext/pg_connection.c +625 -346
- data/ext/pg_copy_coder.c +16 -8
- data/ext/pg_record_coder.c +491 -0
- data/ext/pg_result.c +571 -191
- data/ext/pg_text_decoder.c +606 -40
- data/ext/pg_text_encoder.c +185 -54
- data/ext/pg_tuple.c +549 -0
- data/ext/pg_type_map.c +1 -1
- data/ext/pg_type_map_all_strings.c +4 -4
- data/ext/pg_type_map_by_class.c +9 -4
- data/ext/pg_type_map_by_column.c +7 -6
- data/ext/pg_type_map_by_mri_type.c +1 -1
- data/ext/pg_type_map_by_oid.c +3 -2
- data/ext/pg_type_map_in_ruby.c +1 -1
- data/ext/{util.c → pg_util.c} +10 -10
- data/ext/{util.h → pg_util.h} +2 -2
- data/lib/pg.rb +8 -6
- data/lib/pg/basic_type_mapping.rb +121 -25
- data/lib/pg/binary_decoder.rb +23 -0
- data/lib/pg/coder.rb +23 -2
- data/lib/pg/connection.rb +22 -3
- data/lib/pg/constants.rb +2 -1
- data/lib/pg/exceptions.rb +2 -1
- data/lib/pg/result.rb +14 -2
- data/lib/pg/text_decoder.rb +21 -26
- data/lib/pg/text_encoder.rb +32 -8
- data/lib/pg/tuple.rb +30 -0
- data/lib/pg/type_map_by_column.rb +3 -2
- data/spec/helpers.rb +52 -20
- data/spec/pg/basic_type_mapping_spec.rb +362 -37
- data/spec/pg/connection_spec.rb +376 -146
- data/spec/pg/connection_sync_spec.rb +41 -0
- data/spec/pg/result_spec.rb +240 -15
- data/spec/pg/tuple_spec.rb +333 -0
- data/spec/pg/type_map_by_class_spec.rb +2 -2
- data/spec/pg/type_map_by_column_spec.rb +6 -2
- data/spec/pg/type_map_by_mri_type_spec.rb +1 -1
- data/spec/pg/type_map_by_oid_spec.rb +3 -3
- data/spec/pg/type_map_in_ruby_spec.rb +1 -1
- data/spec/pg/type_map_spec.rb +1 -1
- data/spec/pg/type_spec.rb +363 -17
- data/spec/pg_spec.rb +1 -1
- metadata +47 -47
- metadata.gz.sig +0 -0
@@ -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
|
|
@@ -16,8 +32,8 @@ describe 'Basic type mapping' do
|
|
16
32
|
# Encoding Examples
|
17
33
|
#
|
18
34
|
|
19
|
-
it "should do basic param encoding"
|
20
|
-
res = @conn.exec_params( "SELECT $1::int8
|
35
|
+
it "should do basic param encoding" do
|
36
|
+
res = @conn.exec_params( "SELECT $1::int8, $2::float, $3, $4::TEXT",
|
21
37
|
[1, 2.1, true, "b"], nil, basic_type_mapping )
|
22
38
|
|
23
39
|
expect( res.values ).to eq( [
|
@@ -27,21 +43,168 @@ describe 'Basic type mapping' do
|
|
27
43
|
expect( result_typenames(res) ).to eq( ['bigint', 'double precision', 'boolean', 'text'] )
|
28
44
|
end
|
29
45
|
|
30
|
-
it "should do
|
31
|
-
res = @conn.exec_params( "SELECT $1
|
32
|
-
|
33
|
-
|
34
|
-
|
46
|
+
it "should do basic Time encoding" do
|
47
|
+
res = @conn.exec_params( "SELECT $1 AT TIME ZONE '-02'",
|
48
|
+
[Time.new(2019, 12, 8, 20, 38, 12.123, "-01:00")], nil, basic_type_mapping )
|
49
|
+
|
50
|
+
expect( res.values ).to eq( [[ "2019-12-08 23:38:12.123" ]] )
|
51
|
+
end
|
52
|
+
|
53
|
+
it "should do basic param encoding of various float values" do
|
54
|
+
res = @conn.exec_params( "SELECT $1::float, $2::float, $3::float, $4::float, $5::float, $6::float, $7::float, $8::float, $9::float, $10::float, $11::float, $12::float",
|
55
|
+
[0, 7, 9, 0.1, 0.9, -0.11, 10.11,
|
56
|
+
9876543210987654321e-400,
|
57
|
+
9876543210987654321e400,
|
58
|
+
-1.234567890123456789e-280,
|
59
|
+
-1.234567890123456789e280,
|
60
|
+
9876543210987654321e280
|
61
|
+
], nil, basic_type_mapping )
|
62
|
+
|
63
|
+
expect( res.values[0][0, 9] ).to eq(
|
64
|
+
[ "0", "7", "9", "0.1", "0.9", "-0.11", "10.11", "0", "Infinity" ]
|
65
|
+
)
|
66
|
+
|
67
|
+
expect( res.values[0][9] ).to match( /^-1\.2345678901234\d*e\-280$/ )
|
68
|
+
expect( res.values[0][10] ).to match( /^-1\.2345678901234\d*e\+280$/ )
|
69
|
+
expect( res.values[0][11] ).to match( /^9\.8765432109876\d*e\+298$/ )
|
70
|
+
|
71
|
+
expect( result_typenames(res) ).to eq( ['double precision'] * 12 )
|
72
|
+
end
|
73
|
+
|
74
|
+
it "should do default array-as-array param encoding" do
|
75
|
+
expect( basic_type_mapping.encode_array_as).to eq(:array)
|
76
|
+
res = @conn.exec_params( "SELECT $1,$2,$3,$4,$5,$6", [
|
77
|
+
[1, 2, 3], # Integer -> bigint[]
|
78
|
+
[[1, 2], [3, nil]], # Integer two dimensions -> bigint[]
|
79
|
+
[1.11, 2.21], # Float -> double precision[]
|
80
|
+
['/,"'.gsub("/", "\\"), nil, 'abcäöü'], # String -> text[]
|
81
|
+
[BigDecimal("123.45")], # BigDecimal -> numeric[]
|
82
|
+
[IPAddr.new('1234::5678')], # IPAddr -> inet[]
|
35
83
|
], nil, basic_type_mapping )
|
36
84
|
|
37
85
|
expect( res.values ).to eq( [[
|
38
|
-
'{1,2,3}',
|
86
|
+
'{1,2,3}',
|
87
|
+
'{{1,2},{3,NULL}}',
|
39
88
|
'{1.11,2.21}',
|
40
89
|
'{"//,/"",NULL,abcäöü}'.gsub("/", "\\"),
|
90
|
+
'{123.45}',
|
91
|
+
'{1234::5678}',
|
92
|
+
]] )
|
93
|
+
|
94
|
+
expect( result_typenames(res) ).to eq( ['bigint[]', 'bigint[]', 'double precision[]', 'text[]', 'numeric[]', 'inet[]'] )
|
95
|
+
end
|
96
|
+
|
97
|
+
it "should do default array-as-array param encoding with Time objects" do
|
98
|
+
res = @conn.exec_params( "SELECT $1", [
|
99
|
+
[Time.new(2019, 12, 8, 20, 38, 12.123, "-01:00")], # Time -> timestamptz[]
|
100
|
+
], nil, basic_type_mapping )
|
101
|
+
|
102
|
+
expect( res.values[0][0] ).to match( /\{\"2019-12-08 \d\d:38:12.123[+-]\d\d\"\}/ )
|
103
|
+
expect( result_typenames(res) ).to eq( ['timestamp with time zone[]'] )
|
104
|
+
end
|
105
|
+
|
106
|
+
it "should do array-as-json encoding" do
|
107
|
+
basic_type_mapping.encode_array_as = :json
|
108
|
+
expect( basic_type_mapping.encode_array_as).to eq(:json)
|
109
|
+
|
110
|
+
res = @conn.exec_params( "SELECT $1::JSON, $2::JSON", [
|
111
|
+
[1, {a: 5}, true, ["a", 2], [3.4, nil]],
|
112
|
+
['/,"'.gsub("/", "\\"), nil, 'abcäöü'],
|
113
|
+
], nil, basic_type_mapping )
|
114
|
+
|
115
|
+
expect( res.values ).to eq( [[
|
116
|
+
'[1,{"a":5},true,["a",2],[3.4,null]]',
|
117
|
+
'["//,/"",null,"abcäöü"]'.gsub("/", "\\"),
|
118
|
+
]] )
|
119
|
+
|
120
|
+
expect( result_typenames(res) ).to eq( ['json', 'json'] )
|
121
|
+
end
|
122
|
+
|
123
|
+
it "should do hash-as-json encoding" do
|
124
|
+
res = @conn.exec_params( "SELECT $1::JSON, $2::JSON", [
|
125
|
+
{a: 5, b: ["a", 2], c: nil},
|
126
|
+
{qu: '/,"'.gsub("/", "\\"), ni: nil, uml: 'abcäöü'},
|
127
|
+
], nil, basic_type_mapping )
|
128
|
+
|
129
|
+
expect( res.values ).to eq( [[
|
130
|
+
'{"a":5,"b":["a",2],"c":null}',
|
131
|
+
'{"qu":"//,/"","ni":null,"uml":"abcäöü"}'.gsub("/", "\\"),
|
132
|
+
]] )
|
133
|
+
|
134
|
+
expect( result_typenames(res) ).to eq( ['json', 'json'] )
|
135
|
+
end
|
136
|
+
|
137
|
+
describe "Record encoding" do
|
138
|
+
before :all do
|
139
|
+
@conn.exec("CREATE TYPE test_record1 AS (i int, d float, t text)")
|
140
|
+
@conn.exec("CREATE TYPE test_record2 AS (i int, r test_record1)")
|
141
|
+
end
|
142
|
+
|
143
|
+
after :all do
|
144
|
+
@conn.exec("DROP TYPE IF EXISTS test_record2 CASCADE")
|
145
|
+
@conn.exec("DROP TYPE IF EXISTS test_record1 CASCADE")
|
146
|
+
end
|
147
|
+
|
148
|
+
it "should do array-as-record encoding" do
|
149
|
+
basic_type_mapping.encode_array_as = :record
|
150
|
+
expect( basic_type_mapping.encode_array_as).to eq(:record)
|
151
|
+
|
152
|
+
res = @conn.exec_params( "SELECT $1::test_record1, $2::test_record2, $3::text", [
|
153
|
+
[5, 3.4, "txt"],
|
154
|
+
[1, [2, 4.5, "bcd"]],
|
155
|
+
[4, 5, 6],
|
156
|
+
], nil, basic_type_mapping )
|
157
|
+
|
158
|
+
expect( res.values ).to eq( [[
|
159
|
+
'(5,3.4,txt)',
|
160
|
+
'(1,"(2,4.5,bcd)")',
|
161
|
+
'("4","5","6")',
|
162
|
+
]] )
|
163
|
+
|
164
|
+
expect( result_typenames(res) ).to eq( ['test_record1', 'test_record2', 'text'] )
|
165
|
+
end
|
166
|
+
end
|
167
|
+
|
168
|
+
it "should do bigdecimal param encoding" do
|
169
|
+
large = ('123456790'*10) << '.' << ('012345679')
|
170
|
+
res = @conn.exec_params( "SELECT $1::numeric,$2::numeric",
|
171
|
+
[BigDecimal('1'), BigDecimal(large)], nil, basic_type_mapping )
|
172
|
+
|
173
|
+
expect( res.values ).to eq( [
|
174
|
+
[ "1.0", large ],
|
175
|
+
] )
|
176
|
+
|
177
|
+
expect( result_typenames(res) ).to eq( ['numeric', 'numeric'] )
|
178
|
+
end
|
179
|
+
|
180
|
+
it "should do IPAddr param encoding" do
|
181
|
+
res = @conn.exec_params( "SELECT $1::inet,$2::inet,$3::cidr,$4::cidr",
|
182
|
+
['1.2.3.4', IPAddr.new('1234::5678'), '1.2.3.4', IPAddr.new('1234:5678::/32')], nil, basic_type_mapping )
|
183
|
+
|
184
|
+
expect( res.values ).to eq( [
|
185
|
+
[ '1.2.3.4', '1234::5678', '1.2.3.4/32', '1234:5678::/32'],
|
186
|
+
] )
|
187
|
+
|
188
|
+
expect( result_typenames(res) ).to eq( ['inet', 'inet', 'cidr', 'cidr'] )
|
189
|
+
end
|
190
|
+
|
191
|
+
it "should do array of string encoding on unknown classes" do
|
192
|
+
iv = Class.new do
|
193
|
+
def to_s
|
194
|
+
"abc"
|
195
|
+
end
|
196
|
+
end.new
|
197
|
+
res = @conn.exec_params( "SELECT $1", [
|
198
|
+
[iv, iv], # Unknown -> text[]
|
199
|
+
], nil, basic_type_mapping )
|
200
|
+
|
201
|
+
expect( res.values ).to eq( [[
|
202
|
+
'{abc,abc}',
|
41
203
|
]] )
|
42
204
|
|
43
|
-
expect( result_typenames(res) ).to eq( ['
|
205
|
+
expect( result_typenames(res) ).to eq( ['text[]'] )
|
44
206
|
end
|
207
|
+
|
45
208
|
end
|
46
209
|
|
47
210
|
|
@@ -55,7 +218,7 @@ describe 'Basic type mapping' do
|
|
55
218
|
# Decoding Examples
|
56
219
|
#
|
57
220
|
|
58
|
-
it "should do OID based type conversions"
|
221
|
+
it "should do OID based type conversions" do
|
59
222
|
res = @conn.exec( "SELECT 1, 'a', 2.0::FLOAT, TRUE, '2013-06-30'::DATE, generate_series(4,5)" )
|
60
223
|
expect( res.map_types!(basic_type_mapping).values ).to eq( [
|
61
224
|
[ 1, 'a', 2.0, true, Date.new(2013,6,30), 4 ],
|
@@ -78,14 +241,14 @@ describe 'Basic type mapping' do
|
|
78
241
|
|
79
242
|
it "should do boolean type conversions" do
|
80
243
|
[1, 0].each do |format|
|
81
|
-
res = @conn.
|
244
|
+
res = @conn.exec_params( "SELECT true::BOOLEAN, false::BOOLEAN, NULL::BOOLEAN", [], format )
|
82
245
|
expect( res.values ).to eq( [[true, false, nil]] )
|
83
246
|
end
|
84
247
|
end
|
85
248
|
|
86
249
|
it "should do binary type conversions" do
|
87
250
|
[1, 0].each do |format|
|
88
|
-
res = @conn.
|
251
|
+
res = @conn.exec_params( "SELECT E'\\\\000\\\\377'::BYTEA", [], format )
|
89
252
|
expect( res.values ).to eq( [[["00ff"].pack("H*")]] )
|
90
253
|
expect( res.values[0][0].encoding ).to eq( Encoding::ASCII_8BIT ) if Object.const_defined? :Encoding
|
91
254
|
end
|
@@ -93,7 +256,7 @@ describe 'Basic type mapping' do
|
|
93
256
|
|
94
257
|
it "should do integer type conversions" do
|
95
258
|
[1, 0].each do |format|
|
96
|
-
res = @conn.
|
259
|
+
res = @conn.exec_params( "SELECT -8999::INT2, -899999999::INT4, -8999999999999999999::INT8", [], format )
|
97
260
|
expect( res.values ).to eq( [[-8999, -899999999, -8999999999999999999]] )
|
98
261
|
end
|
99
262
|
end
|
@@ -101,7 +264,7 @@ describe 'Basic type mapping' do
|
|
101
264
|
it "should do string type conversions" do
|
102
265
|
@conn.internal_encoding = 'utf-8' if Object.const_defined? :Encoding
|
103
266
|
[1, 0].each do |format|
|
104
|
-
res = @conn.
|
267
|
+
res = @conn.exec_params( "SELECT 'abcäöü'::TEXT", [], format )
|
105
268
|
expect( res.values ).to eq( [['abcäöü']] )
|
106
269
|
expect( res.values[0][0].encoding ).to eq( Encoding::UTF_8 ) if Object.const_defined? :Encoding
|
107
270
|
end
|
@@ -109,7 +272,7 @@ describe 'Basic type mapping' do
|
|
109
272
|
|
110
273
|
it "should do float type conversions" do
|
111
274
|
[1, 0].each do |format|
|
112
|
-
res = @conn.
|
275
|
+
res = @conn.exec_params( "SELECT -8.999e3::FLOAT4,
|
113
276
|
8.999e10::FLOAT4,
|
114
277
|
-8999999999e-99::FLOAT8,
|
115
278
|
NULL::FLOAT4,
|
@@ -127,35 +290,107 @@ describe 'Basic type mapping' do
|
|
127
290
|
end
|
128
291
|
end
|
129
292
|
|
130
|
-
it "should do datetime without time zone type conversions" do
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
293
|
+
it "should do text datetime without time zone type conversions" do
|
294
|
+
# for backward compat text timestamps without time zone are treated as local times
|
295
|
+
res = @conn.exec_params( "SELECT CAST('2013-12-31 23:58:59+02' AS TIMESTAMP WITHOUT TIME ZONE),
|
296
|
+
CAST('1913-12-31 23:58:59.1231-03' AS TIMESTAMP WITHOUT TIME ZONE),
|
297
|
+
CAST('4714-11-24 23:58:59.1231-03 BC' AS TIMESTAMP WITHOUT TIME ZONE),
|
298
|
+
CAST('294276-12-31 23:58:59.1231-03' AS TIMESTAMP WITHOUT TIME ZONE),
|
299
|
+
CAST('infinity' AS TIMESTAMP WITHOUT TIME ZONE),
|
300
|
+
CAST('-infinity' AS TIMESTAMP WITHOUT TIME ZONE)", [], 0 )
|
301
|
+
expect( res.getvalue(0,0) ).to eq( Time.new(2013, 12, 31, 23, 58, 59) )
|
302
|
+
expect( res.getvalue(0,1).iso8601(3) ).to eq( Time.new(1913, 12, 31, 23, 58, 59.1231).iso8601(3) )
|
303
|
+
expect( res.getvalue(0,2).iso8601(3) ).to eq( Time.new(-4713, 11, 24, 23, 58, 59.1231).iso8601(3) )
|
304
|
+
expect( res.getvalue(0,3).iso8601(3) ).to eq( Time.new(294276, 12, 31, 23, 58, 59.1231).iso8601(3) )
|
305
|
+
expect( res.getvalue(0,4) ).to eq( 'infinity' )
|
306
|
+
expect( res.getvalue(0,5) ).to eq( '-infinity' )
|
307
|
+
end
|
308
|
+
|
309
|
+
[1, 0].each do |format|
|
310
|
+
it "should convert format #{format} timestamps per TimestampUtc" do
|
311
|
+
restore_type("timestamp") do
|
312
|
+
PG::BasicTypeRegistry.register_type 0, 'timestamp', nil, PG::TextDecoder::TimestampUtc
|
313
|
+
@conn.type_map_for_results = PG::BasicTypeMapForResults.new(@conn)
|
314
|
+
res = @conn.exec_params( "SELECT CAST('2013-07-31 23:58:59+02' AS TIMESTAMP WITHOUT TIME ZONE),
|
315
|
+
CAST('1913-12-31 23:58:59.1231-03' AS TIMESTAMP WITHOUT TIME ZONE),
|
316
|
+
CAST('4714-11-24 23:58:59.1231-03 BC' AS TIMESTAMP WITHOUT TIME ZONE),
|
317
|
+
CAST('294276-12-31 23:58:59.1231-03' AS TIMESTAMP WITHOUT TIME ZONE),
|
318
|
+
CAST('infinity' AS TIMESTAMP WITHOUT TIME ZONE),
|
319
|
+
CAST('-infinity' AS TIMESTAMP WITHOUT TIME ZONE)", [], format )
|
320
|
+
expect( res.getvalue(0,0).iso8601(3) ).to eq( Time.utc(2013, 7, 31, 23, 58, 59).iso8601(3) )
|
321
|
+
expect( res.getvalue(0,1).iso8601(3) ).to eq( Time.utc(1913, 12, 31, 23, 58, 59.1231).iso8601(3) )
|
322
|
+
expect( res.getvalue(0,2).iso8601(3) ).to eq( Time.utc(-4713, 11, 24, 23, 58, 59.1231).iso8601(3) )
|
323
|
+
expect( res.getvalue(0,3).iso8601(3) ).to eq( Time.utc(294276, 12, 31, 23, 58, 59.1231).iso8601(3) )
|
324
|
+
expect( res.getvalue(0,4) ).to eq( 'infinity' )
|
325
|
+
expect( res.getvalue(0,5) ).to eq( '-infinity' )
|
326
|
+
end
|
140
327
|
end
|
141
328
|
end
|
142
329
|
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
330
|
+
[1, 0].each do |format|
|
331
|
+
it "should convert format #{format} timestamps per TimestampUtcToLocal" do
|
332
|
+
restore_type("timestamp") do
|
333
|
+
PG::BasicTypeRegistry.register_type 0, 'timestamp', nil, PG::TextDecoder::TimestampUtcToLocal
|
334
|
+
PG::BasicTypeRegistry.register_type 1, 'timestamp', nil, PG::BinaryDecoder::TimestampUtcToLocal
|
335
|
+
@conn.type_map_for_results = PG::BasicTypeMapForResults.new(@conn)
|
336
|
+
res = @conn.exec_params( "SELECT CAST('2013-07-31 23:58:59+02' AS TIMESTAMP WITHOUT TIME ZONE),
|
337
|
+
CAST('1913-12-31 23:58:59.1231-03' AS TIMESTAMP WITHOUT TIME ZONE),
|
338
|
+
CAST('4714-11-24 23:58:59.1231-03 BC' AS TIMESTAMP WITHOUT TIME ZONE),
|
339
|
+
CAST('294276-12-31 23:58:59.1231-03' AS TIMESTAMP WITHOUT TIME ZONE),
|
340
|
+
CAST('infinity' AS TIMESTAMP WITHOUT TIME ZONE),
|
341
|
+
CAST('-infinity' AS TIMESTAMP WITHOUT TIME ZONE)", [], format )
|
342
|
+
expect( res.getvalue(0,0).iso8601(3) ).to eq( Time.utc(2013, 7, 31, 23, 58, 59).getlocal.iso8601(3) )
|
343
|
+
expect( res.getvalue(0,1).iso8601(3) ).to eq( Time.utc(1913, 12, 31, 23, 58, 59.1231).getlocal.iso8601(3) )
|
344
|
+
expect( res.getvalue(0,2).iso8601(3) ).to eq( Time.utc(-4713, 11, 24, 23, 58, 59.1231).getlocal.iso8601(3) )
|
345
|
+
expect( res.getvalue(0,3).iso8601(3) ).to eq( Time.utc(294276, 12, 31, 23, 58, 59.1231).getlocal.iso8601(3) )
|
346
|
+
expect( res.getvalue(0,4) ).to eq( 'infinity' )
|
347
|
+
expect( res.getvalue(0,5) ).to eq( '-infinity' )
|
348
|
+
end
|
349
|
+
end
|
350
|
+
end
|
351
|
+
|
352
|
+
[1, 0].each do |format|
|
353
|
+
it "should convert format #{format} timestamps per TimestampLocal" do
|
354
|
+
restore_type("timestamp") do
|
355
|
+
PG::BasicTypeRegistry.register_type 0, 'timestamp', nil, PG::TextDecoder::TimestampLocal
|
356
|
+
PG::BasicTypeRegistry.register_type 1, 'timestamp', nil, PG::BinaryDecoder::TimestampLocal
|
357
|
+
@conn.type_map_for_results = PG::BasicTypeMapForResults.new(@conn)
|
358
|
+
res = @conn.exec_params( "SELECT CAST('2013-07-31 23:58:59' AS TIMESTAMP WITHOUT TIME ZONE),
|
359
|
+
CAST('1913-12-31 23:58:59.1231' AS TIMESTAMP WITHOUT TIME ZONE),
|
360
|
+
CAST('4714-11-24 23:58:59.1231-03 BC' AS TIMESTAMP WITHOUT TIME ZONE),
|
361
|
+
CAST('294276-12-31 23:58:59.1231+03' AS TIMESTAMP WITHOUT TIME ZONE),
|
362
|
+
CAST('infinity' AS TIMESTAMP WITHOUT TIME ZONE),
|
363
|
+
CAST('-infinity' AS TIMESTAMP WITHOUT TIME ZONE)", [], format )
|
364
|
+
expect( res.getvalue(0,0).iso8601(3) ).to eq( Time.new(2013, 7, 31, 23, 58, 59).iso8601(3) )
|
365
|
+
expect( res.getvalue(0,1).iso8601(3) ).to eq( Time.new(1913, 12, 31, 23, 58, 59.1231).iso8601(3) )
|
366
|
+
expect( res.getvalue(0,2).iso8601(3) ).to eq( Time.new(-4713, 11, 24, 23, 58, 59.1231).iso8601(3) )
|
367
|
+
expect( res.getvalue(0,3).iso8601(3) ).to eq( Time.new(294276, 12, 31, 23, 58, 59.1231).iso8601(3) )
|
368
|
+
expect( res.getvalue(0,4) ).to eq( 'infinity' )
|
369
|
+
expect( res.getvalue(0,5) ).to eq( '-infinity' )
|
370
|
+
end
|
371
|
+
end
|
372
|
+
end
|
373
|
+
|
374
|
+
[0, 1].each do |format|
|
375
|
+
it "should convert format #{format} timestamps with time zone" do
|
376
|
+
res = @conn.exec_params( "SELECT CAST('2013-12-31 23:58:59+02' AS TIMESTAMP WITH TIME ZONE),
|
377
|
+
CAST('1913-12-31 23:58:59.1231-03' AS TIMESTAMP WITH TIME ZONE),
|
378
|
+
CAST('4714-11-24 23:58:59.1231-03 BC' AS TIMESTAMP WITH TIME ZONE),
|
379
|
+
CAST('294276-12-31 23:58:59.1231+03' AS TIMESTAMP WITH TIME ZONE),
|
147
380
|
CAST('infinity' AS TIMESTAMP WITH TIME ZONE),
|
148
381
|
CAST('-infinity' AS TIMESTAMP WITH TIME ZONE)", [], format )
|
149
|
-
expect( res.getvalue(0,0) ).to
|
150
|
-
expect( res.getvalue(0,1) ).to be_within(1e-3).of(Time.new(1913, 12, 31, 23, 58, 59.
|
151
|
-
expect( res.getvalue(0,2) ).to
|
152
|
-
expect( res.getvalue(0,3) ).to
|
382
|
+
expect( res.getvalue(0,0) ).to be_within(1e-3).of( Time.new(2013, 12, 31, 23, 58, 59, "+02:00").getlocal )
|
383
|
+
expect( res.getvalue(0,1) ).to be_within(1e-3).of( Time.new(1913, 12, 31, 23, 58, 59.1231, "-03:00").getlocal )
|
384
|
+
expect( res.getvalue(0,2) ).to be_within(1e-3).of( Time.new(-4713, 11, 24, 23, 58, 59.1231, "-03:00").getlocal )
|
385
|
+
expect( res.getvalue(0,3) ).to be_within(1e-3).of( Time.new(294276, 12, 31, 23, 58, 59.1231, "+03:00").getlocal )
|
386
|
+
expect( res.getvalue(0,4) ).to eq( 'infinity' )
|
387
|
+
expect( res.getvalue(0,5) ).to eq( '-infinity' )
|
153
388
|
end
|
154
389
|
end
|
155
390
|
|
156
391
|
it "should do date type conversions" do
|
157
392
|
[0].each do |format|
|
158
|
-
res = @conn.
|
393
|
+
res = @conn.exec_params( "SELECT CAST('2113-12-31' AS DATE),
|
159
394
|
CAST('1913-12-31' AS DATE),
|
160
395
|
CAST('infinity' AS DATE),
|
161
396
|
CAST('-infinity' AS DATE)", [], format )
|
@@ -166,10 +401,31 @@ describe 'Basic type mapping' do
|
|
166
401
|
end
|
167
402
|
end
|
168
403
|
|
404
|
+
it "should do numeric type conversions" do
|
405
|
+
[0].each do |format|
|
406
|
+
small = '123456790123.12'
|
407
|
+
large = ('123456790'*10) << '.' << ('012345679')
|
408
|
+
numerics = [
|
409
|
+
'1',
|
410
|
+
'1.0',
|
411
|
+
'1.2',
|
412
|
+
small,
|
413
|
+
large,
|
414
|
+
]
|
415
|
+
sql_numerics = numerics.map { |v| "CAST(#{v} AS numeric)" }
|
416
|
+
res = @conn.exec_params( "SELECT #{sql_numerics.join(',')}", [], format )
|
417
|
+
expect( res.getvalue(0,0) ).to eq( BigDecimal('1') )
|
418
|
+
expect( res.getvalue(0,1) ).to eq( BigDecimal('1') )
|
419
|
+
expect( res.getvalue(0,2) ).to eq( BigDecimal('1.2') )
|
420
|
+
expect( res.getvalue(0,3) ).to eq( BigDecimal(small) )
|
421
|
+
expect( res.getvalue(0,4) ).to eq( BigDecimal(large) )
|
422
|
+
end
|
423
|
+
end
|
424
|
+
|
169
425
|
it "should do JSON conversions", :postgresql_94 do
|
170
426
|
[0].each do |format|
|
171
427
|
['JSON', 'JSONB'].each do |type|
|
172
|
-
res = @conn.
|
428
|
+
res = @conn.exec_params( "SELECT CAST('123' AS #{type}),
|
173
429
|
CAST('12.3' AS #{type}),
|
174
430
|
CAST('true' AS #{type}),
|
175
431
|
CAST('false' AS #{type}),
|
@@ -189,7 +445,7 @@ describe 'Basic type mapping' do
|
|
189
445
|
|
190
446
|
it "should do array type conversions" do
|
191
447
|
[0].each do |format|
|
192
|
-
res = @conn.
|
448
|
+
res = @conn.exec_params( "SELECT CAST('{1,2,3}' AS INT2[]), CAST('{{1,2},{3,4}}' AS INT2[][]),
|
193
449
|
CAST('{1,2,3}' AS INT4[]),
|
194
450
|
CAST('{1,2,3}' AS INT8[]),
|
195
451
|
CAST('{1,2,3}' AS TEXT[]),
|
@@ -207,6 +463,75 @@ describe 'Basic type mapping' do
|
|
207
463
|
expect( res.getvalue(0,7) ).to eq( [1.0,2.0,3.0] )
|
208
464
|
end
|
209
465
|
end
|
466
|
+
|
467
|
+
it "should do inet type conversions" do
|
468
|
+
[0].each do |format|
|
469
|
+
vals = [
|
470
|
+
'1.2.3.4',
|
471
|
+
'0.0.0.0/0',
|
472
|
+
'1.0.0.0/8',
|
473
|
+
'1.2.0.0/16',
|
474
|
+
'1.2.3.0/24',
|
475
|
+
'1.2.3.4/24',
|
476
|
+
'1.2.3.4/32',
|
477
|
+
'1.2.3.128/25',
|
478
|
+
'1234:3456:5678:789a:9abc:bced:edf0:f012',
|
479
|
+
'::/0',
|
480
|
+
'1234:3456::/32',
|
481
|
+
'1234:3456:5678:789a::/64',
|
482
|
+
'1234:3456:5678:789a:9abc:bced::/96',
|
483
|
+
'1234:3456:5678:789a:9abc:bced:edf0:f012/128',
|
484
|
+
'1234:3456:5678:789a:9abc:bced:edf0:f012/0',
|
485
|
+
'1234:3456:5678:789a:9abc:bced:edf0:f012/32',
|
486
|
+
'1234:3456:5678:789a:9abc:bced:edf0:f012/64',
|
487
|
+
'1234:3456:5678:789a:9abc:bced:edf0:f012/96',
|
488
|
+
]
|
489
|
+
sql_vals = vals.map{|v| "CAST('#{v}' AS inet)"}
|
490
|
+
res = @conn.exec_params(("SELECT " + sql_vals.join(', ')), [], format )
|
491
|
+
vals.each_with_index do |v, i|
|
492
|
+
expect( res.getvalue(0,i) ).to eq( IPAddr.new(v) )
|
493
|
+
end
|
494
|
+
end
|
495
|
+
end
|
496
|
+
|
497
|
+
it "should do cidr type conversions" do
|
498
|
+
[0].each do |format|
|
499
|
+
vals = [
|
500
|
+
'0.0.0.0/0',
|
501
|
+
'1.0.0.0/8',
|
502
|
+
'1.2.0.0/16',
|
503
|
+
'1.2.3.0/24',
|
504
|
+
'1.2.3.4/32',
|
505
|
+
'1.2.3.128/25',
|
506
|
+
'::/0',
|
507
|
+
'1234:3456::/32',
|
508
|
+
'1234:3456:5678:789a::/64',
|
509
|
+
'1234:3456:5678:789a:9abc:bced::/96',
|
510
|
+
'1234:3456:5678:789a:9abc:bced:edf0:f012/128',
|
511
|
+
]
|
512
|
+
sql_vals = vals.map { |v| "CAST('#{v}' AS cidr)" }
|
513
|
+
res = @conn.exec_params(("SELECT " + sql_vals.join(', ')), [], format )
|
514
|
+
vals.each_with_index do |v, i|
|
515
|
+
val = res.getvalue(0,i)
|
516
|
+
ip, prefix = v.split('/', 2)
|
517
|
+
expect( val.to_s ).to eq( ip )
|
518
|
+
if val.respond_to?(:prefix)
|
519
|
+
val_prefix = val.prefix
|
520
|
+
else
|
521
|
+
default_prefix = (val.family == Socket::AF_INET ? 32 : 128)
|
522
|
+
range = val.to_range
|
523
|
+
val_prefix = default_prefix - Math.log(((range.end.to_i - range.begin.to_i) + 1), 2).to_i
|
524
|
+
end
|
525
|
+
if v.include?('/')
|
526
|
+
expect( val_prefix ).to eq( prefix.to_i )
|
527
|
+
elsif v.include?('.')
|
528
|
+
expect( val_prefix ).to eq( 32 )
|
529
|
+
else
|
530
|
+
expect( val_prefix ).to eq( 128 )
|
531
|
+
end
|
532
|
+
end
|
533
|
+
end
|
534
|
+
end
|
210
535
|
end
|
211
536
|
|
212
537
|
context "with usage of result oids for copy decoder selection" do
|