pg 1.2.3-x86-mingw32 → 1.3.0.rc4-x86-mingw32

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 (112) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data/.appveyor.yml +36 -0
  4. data/.gems +6 -0
  5. data/.github/workflows/binary-gems.yml +86 -0
  6. data/.github/workflows/source-gem.yml +130 -0
  7. data/.gitignore +13 -0
  8. data/.hgsigs +34 -0
  9. data/.hgtags +41 -0
  10. data/.irbrc +23 -0
  11. data/.pryrc +23 -0
  12. data/.tm_properties +21 -0
  13. data/.travis.yml +49 -0
  14. data/Gemfile +14 -0
  15. data/History.rdoc +77 -7
  16. data/Manifest.txt +0 -1
  17. data/README.rdoc +7 -6
  18. data/Rakefile +27 -138
  19. data/Rakefile.cross +6 -5
  20. data/certs/ged.pem +24 -0
  21. data/ext/errorcodes.def +8 -0
  22. data/ext/errorcodes.txt +3 -1
  23. data/ext/extconf.rb +91 -19
  24. data/ext/gvl_wrappers.c +4 -0
  25. data/ext/gvl_wrappers.h +23 -0
  26. data/ext/pg.c +59 -4
  27. data/ext/pg.h +18 -1
  28. data/ext/pg_coder.c +82 -28
  29. data/ext/pg_connection.c +676 -492
  30. data/ext/pg_copy_coder.c +45 -16
  31. data/ext/pg_record_coder.c +39 -11
  32. data/ext/pg_result.c +61 -31
  33. data/ext/pg_text_decoder.c +1 -1
  34. data/ext/pg_text_encoder.c +6 -6
  35. data/ext/pg_tuple.c +47 -21
  36. data/ext/pg_type_map.c +41 -8
  37. data/ext/pg_type_map_all_strings.c +14 -1
  38. data/ext/pg_type_map_by_class.c +49 -24
  39. data/ext/pg_type_map_by_column.c +64 -28
  40. data/ext/pg_type_map_by_mri_type.c +47 -18
  41. data/ext/pg_type_map_by_oid.c +52 -23
  42. data/ext/pg_type_map_in_ruby.c +50 -19
  43. data/ext/pg_util.c +2 -2
  44. data/lib/2.5/pg_ext.so +0 -0
  45. data/lib/2.6/pg_ext.so +0 -0
  46. data/lib/2.7/pg_ext.so +0 -0
  47. data/lib/3.0/pg_ext.so +0 -0
  48. data/lib/3.1/pg_ext.so +0 -0
  49. data/lib/pg/basic_type_map_based_on_result.rb +47 -0
  50. data/lib/pg/basic_type_map_for_queries.rb +193 -0
  51. data/lib/pg/basic_type_map_for_results.rb +81 -0
  52. data/lib/pg/basic_type_registry.rb +296 -0
  53. data/lib/pg/coder.rb +1 -1
  54. data/lib/pg/connection.rb +587 -58
  55. data/lib/pg/version.rb +4 -0
  56. data/lib/pg.rb +40 -27
  57. data/lib/x86-mingw32/libpq.dll +0 -0
  58. data/misc/openssl-pg-segfault.rb +31 -0
  59. data/misc/postgres/History.txt +9 -0
  60. data/misc/postgres/Manifest.txt +5 -0
  61. data/misc/postgres/README.txt +21 -0
  62. data/misc/postgres/Rakefile +21 -0
  63. data/misc/postgres/lib/postgres.rb +16 -0
  64. data/misc/ruby-pg/History.txt +9 -0
  65. data/misc/ruby-pg/Manifest.txt +5 -0
  66. data/misc/ruby-pg/README.txt +21 -0
  67. data/misc/ruby-pg/Rakefile +21 -0
  68. data/misc/ruby-pg/lib/ruby/pg.rb +16 -0
  69. data/pg.gemspec +32 -0
  70. data/sample/array_insert.rb +20 -0
  71. data/sample/async_api.rb +106 -0
  72. data/sample/async_copyto.rb +39 -0
  73. data/sample/async_mixed.rb +56 -0
  74. data/sample/check_conn.rb +21 -0
  75. data/sample/copydata.rb +71 -0
  76. data/sample/copyfrom.rb +81 -0
  77. data/sample/copyto.rb +19 -0
  78. data/sample/cursor.rb +21 -0
  79. data/sample/disk_usage_report.rb +177 -0
  80. data/sample/issue-119.rb +94 -0
  81. data/sample/losample.rb +69 -0
  82. data/sample/minimal-testcase.rb +17 -0
  83. data/sample/notify_wait.rb +72 -0
  84. data/sample/pg_statistics.rb +285 -0
  85. data/sample/replication_monitor.rb +222 -0
  86. data/sample/test_binary_values.rb +33 -0
  87. data/sample/wal_shipper.rb +434 -0
  88. data/sample/warehouse_partitions.rb +311 -0
  89. data.tar.gz.sig +0 -0
  90. metadata +93 -233
  91. metadata.gz.sig +0 -0
  92. data/ChangeLog +0 -0
  93. data/lib/2.2/pg_ext.so +0 -0
  94. data/lib/2.3/pg_ext.so +0 -0
  95. data/lib/2.4/pg_ext.so +0 -0
  96. data/lib/pg/basic_type_mapping.rb +0 -522
  97. data/spec/data/expected_trace.out +0 -26
  98. data/spec/data/random_binary_data +0 -0
  99. data/spec/helpers.rb +0 -380
  100. data/spec/pg/basic_type_mapping_spec.rb +0 -630
  101. data/spec/pg/connection_spec.rb +0 -1949
  102. data/spec/pg/connection_sync_spec.rb +0 -41
  103. data/spec/pg/result_spec.rb +0 -681
  104. data/spec/pg/tuple_spec.rb +0 -333
  105. data/spec/pg/type_map_by_class_spec.rb +0 -138
  106. data/spec/pg/type_map_by_column_spec.rb +0 -226
  107. data/spec/pg/type_map_by_mri_type_spec.rb +0 -136
  108. data/spec/pg/type_map_by_oid_spec.rb +0 -149
  109. data/spec/pg/type_map_in_ruby_spec.rb +0 -164
  110. data/spec/pg/type_map_spec.rb +0 -22
  111. data/spec/pg/type_spec.rb +0 -1123
  112. data/spec/pg_spec.rb +0 -50
@@ -1,630 +0,0 @@
1
- # -*- rspec -*-
2
- # encoding: utf-8
3
-
4
- require_relative '../helpers'
5
-
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
23
-
24
- describe 'Basic type mapping' do
25
-
26
- describe PG::BasicTypeMapForQueries do
27
- let!(:basic_type_mapping) do
28
- PG::BasicTypeMapForQueries.new @conn
29
- end
30
-
31
- #
32
- # Encoding Examples
33
- #
34
-
35
- it "should do basic param encoding" do
36
- res = @conn.exec_params( "SELECT $1::int8, $2::float, $3, $4::TEXT",
37
- [1, 2.1, true, "b"], nil, basic_type_mapping )
38
-
39
- expect( res.values ).to eq( [
40
- [ "1", "2.1", "t", "b" ],
41
- ] )
42
-
43
- expect( result_typenames(res) ).to eq( ['bigint', 'double precision', 'boolean', 'text'] )
44
- end
45
-
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[]
83
- ], nil, basic_type_mapping )
84
-
85
- expect( res.values ).to eq( [[
86
- '{1,2,3}',
87
- '{{1,2},{3,NULL}}',
88
- '{1.11,2.21}',
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}',
203
- ]] )
204
-
205
- expect( result_typenames(res) ).to eq( ['text[]'] )
206
- end
207
-
208
- end
209
-
210
-
211
-
212
- describe PG::BasicTypeMapForResults do
213
- let!(:basic_type_mapping) do
214
- PG::BasicTypeMapForResults.new @conn
215
- end
216
-
217
- #
218
- # Decoding Examples
219
- #
220
-
221
- it "should do OID based type conversions" do
222
- res = @conn.exec( "SELECT 1, 'a', 2.0::FLOAT, TRUE, '2013-06-30'::DATE, generate_series(4,5)" )
223
- expect( res.map_types!(basic_type_mapping).values ).to eq( [
224
- [ 1, 'a', 2.0, true, Date.new(2013,6,30), 4 ],
225
- [ 1, 'a', 2.0, true, Date.new(2013,6,30), 5 ],
226
- ] )
227
- end
228
-
229
- #
230
- # Decoding Examples text+binary format converters
231
- #
232
-
233
- describe "connection wide type mapping" do
234
- before :each do
235
- @conn.type_map_for_results = basic_type_mapping
236
- end
237
-
238
- after :each do
239
- @conn.type_map_for_results = PG::TypeMapAllStrings.new
240
- end
241
-
242
- it "should do boolean type conversions" do
243
- [1, 0].each do |format|
244
- res = @conn.exec_params( "SELECT true::BOOLEAN, false::BOOLEAN, NULL::BOOLEAN", [], format )
245
- expect( res.values ).to eq( [[true, false, nil]] )
246
- end
247
- end
248
-
249
- it "should do binary type conversions" do
250
- [1, 0].each do |format|
251
- res = @conn.exec_params( "SELECT E'\\\\000\\\\377'::BYTEA", [], format )
252
- expect( res.values ).to eq( [[["00ff"].pack("H*")]] )
253
- expect( res.values[0][0].encoding ).to eq( Encoding::ASCII_8BIT ) if Object.const_defined? :Encoding
254
- end
255
- end
256
-
257
- it "should do integer type conversions" do
258
- [1, 0].each do |format|
259
- res = @conn.exec_params( "SELECT -8999::INT2, -899999999::INT4, -8999999999999999999::INT8", [], format )
260
- expect( res.values ).to eq( [[-8999, -899999999, -8999999999999999999]] )
261
- end
262
- end
263
-
264
- it "should do string type conversions" do
265
- @conn.internal_encoding = 'utf-8' if Object.const_defined? :Encoding
266
- [1, 0].each do |format|
267
- res = @conn.exec_params( "SELECT 'abcäöü'::TEXT", [], format )
268
- expect( res.values ).to eq( [['abcäöü']] )
269
- expect( res.values[0][0].encoding ).to eq( Encoding::UTF_8 ) if Object.const_defined? :Encoding
270
- end
271
- end
272
-
273
- it "should do float type conversions" do
274
- [1, 0].each do |format|
275
- res = @conn.exec_params( "SELECT -8.999e3::FLOAT4,
276
- 8.999e10::FLOAT4,
277
- -8999999999e-99::FLOAT8,
278
- NULL::FLOAT4,
279
- 'NaN'::FLOAT4,
280
- 'Infinity'::FLOAT4,
281
- '-Infinity'::FLOAT4
282
- ", [], format )
283
- expect( res.getvalue(0,0) ).to be_within(1e-2).of(-8.999e3)
284
- expect( res.getvalue(0,1) ).to be_within(1e5).of(8.999e10)
285
- expect( res.getvalue(0,2) ).to be_within(1e-109).of(-8999999999e-99)
286
- expect( res.getvalue(0,3) ).to be_nil
287
- expect( res.getvalue(0,4) ).to be_nan
288
- expect( res.getvalue(0,5) ).to eq( Float::INFINITY )
289
- expect( res.getvalue(0,6) ).to eq( -Float::INFINITY )
290
- end
291
- end
292
-
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
327
- end
328
- end
329
-
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),
380
- CAST('infinity' AS TIMESTAMP WITH TIME ZONE),
381
- CAST('-infinity' AS TIMESTAMP WITH TIME ZONE)", [], format )
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' )
388
- end
389
- end
390
-
391
- it "should do date type conversions" do
392
- [0].each do |format|
393
- res = @conn.exec_params( "SELECT CAST('2113-12-31' AS DATE),
394
- CAST('1913-12-31' AS DATE),
395
- CAST('infinity' AS DATE),
396
- CAST('-infinity' AS DATE)", [], format )
397
- expect( res.getvalue(0,0) ).to eq( Date.new(2113, 12, 31) )
398
- expect( res.getvalue(0,1) ).to eq( Date.new(1913, 12, 31) )
399
- expect( res.getvalue(0,2) ).to eq( 'infinity' )
400
- expect( res.getvalue(0,3) ).to eq( '-infinity' )
401
- end
402
- end
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
-
425
- it "should do JSON conversions", :postgresql_94 do
426
- [0].each do |format|
427
- ['JSON', 'JSONB'].each do |type|
428
- res = @conn.exec_params( "SELECT CAST('123' AS #{type}),
429
- CAST('12.3' AS #{type}),
430
- CAST('true' AS #{type}),
431
- CAST('false' AS #{type}),
432
- CAST('null' AS #{type}),
433
- CAST('[1, \"a\", null]' AS #{type}),
434
- CAST('{\"b\" : [2,3]}' AS #{type})", [], format )
435
- expect( res.getvalue(0,0) ).to eq( 123 )
436
- expect( res.getvalue(0,1) ).to be_within(0.1).of( 12.3 )
437
- expect( res.getvalue(0,2) ).to eq( true )
438
- expect( res.getvalue(0,3) ).to eq( false )
439
- expect( res.getvalue(0,4) ).to eq( nil )
440
- expect( res.getvalue(0,5) ).to eq( [1, "a", nil] )
441
- expect( res.getvalue(0,6) ).to eq( {"b" => [2, 3]} )
442
- end
443
- end
444
- end
445
-
446
- it "should do array type conversions" do
447
- [0].each do |format|
448
- res = @conn.exec_params( "SELECT CAST('{1,2,3}' AS INT2[]), CAST('{{1,2},{3,4}}' AS INT2[][]),
449
- CAST('{1,2,3}' AS INT4[]),
450
- CAST('{1,2,3}' AS INT8[]),
451
- CAST('{1,2,3}' AS TEXT[]),
452
- CAST('{1,2,3}' AS VARCHAR[]),
453
- CAST('{1,2,3}' AS FLOAT4[]),
454
- CAST('{1,2,3}' AS FLOAT8[])
455
- ", [], format )
456
- expect( res.getvalue(0,0) ).to eq( [1,2,3] )
457
- expect( res.getvalue(0,1) ).to eq( [[1,2],[3,4]] )
458
- expect( res.getvalue(0,2) ).to eq( [1,2,3] )
459
- expect( res.getvalue(0,3) ).to eq( [1,2,3] )
460
- expect( res.getvalue(0,4) ).to eq( ['1','2','3'] )
461
- expect( res.getvalue(0,5) ).to eq( ['1','2','3'] )
462
- expect( res.getvalue(0,6) ).to eq( [1.0,2.0,3.0] )
463
- expect( res.getvalue(0,7) ).to eq( [1.0,2.0,3.0] )
464
- end
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
535
- end
536
-
537
- context "with usage of result oids for copy decoder selection" do
538
- it "can type cast #copy_data output with explicit decoder" do
539
- @conn.exec( "CREATE TEMP TABLE copytable (t TEXT, i INT, ai INT[])" )
540
- @conn.exec( "INSERT INTO copytable VALUES ('a', 123, '{5,4,3}'), ('b', 234, '{2,3}')" )
541
-
542
- # Retrieve table OIDs per empty result.
543
- res = @conn.exec( "SELECT * FROM copytable LIMIT 0" )
544
- tm = basic_type_mapping.build_column_map( res )
545
- row_decoder = PG::TextDecoder::CopyRow.new type_map: tm
546
-
547
- rows = []
548
- @conn.copy_data( "COPY copytable TO STDOUT", row_decoder ) do |res|
549
- while row=@conn.get_copy_data
550
- rows << row
551
- end
552
- end
553
- expect( rows ).to eq( [['a', 123, [5,4,3]], ['b', 234, [2,3]]] )
554
- end
555
- end
556
- end
557
-
558
-
559
- describe PG::BasicTypeMapBasedOnResult do
560
- let!(:basic_type_mapping) do
561
- PG::BasicTypeMapBasedOnResult.new @conn
562
- end
563
-
564
- context "with usage of result oids for bind params encoder selection" do
565
- it "can type cast query params" do
566
- @conn.exec( "CREATE TEMP TABLE copytable (t TEXT, i INT, ai INT[])" )
567
-
568
- # Retrieve table OIDs per empty result.
569
- res = @conn.exec( "SELECT * FROM copytable LIMIT 0" )
570
- tm = basic_type_mapping.build_column_map( res )
571
-
572
- @conn.exec_params( "INSERT INTO copytable VALUES ($1, $2, $3)", ['a', 123, [5,4,3]], 0, tm )
573
- @conn.exec_params( "INSERT INTO copytable VALUES ($1, $2, $3)", ['b', 234, [2,3]], 0, tm )
574
- res = @conn.exec( "SELECT * FROM copytable" )
575
- expect( res.values ).to eq( [['a', '123', '{5,4,3}'], ['b', '234', '{2,3}']] )
576
- end
577
-
578
- it "can do JSON conversions", :postgresql_94 do
579
- ['JSON', 'JSONB'].each do |type|
580
- sql = "SELECT CAST('123' AS #{type}),
581
- CAST('12.3' AS #{type}),
582
- CAST('true' AS #{type}),
583
- CAST('false' AS #{type}),
584
- CAST('null' AS #{type}),
585
- CAST('[1, \"a\", null]' AS #{type}),
586
- CAST('{\"b\" : [2,3]}' AS #{type})"
587
-
588
- tm = basic_type_mapping.build_column_map( @conn.exec( sql ) )
589
- expect( tm.coders.map(&:name) ).to eq( [type.downcase] * 7 )
590
-
591
- res = @conn.exec_params( "SELECT $1, $2, $3, $4, $5, $6, $7",
592
- [ 123,
593
- 12.3,
594
- true,
595
- false,
596
- nil,
597
- [1, "a", nil],
598
- {"b" => [2, 3]},
599
- ], 0, tm )
600
-
601
- expect( res.getvalue(0,0) ).to eq( "123" )
602
- expect( res.getvalue(0,1) ).to eq( "12.3" )
603
- expect( res.getvalue(0,2) ).to eq( "true" )
604
- expect( res.getvalue(0,3) ).to eq( "false" )
605
- expect( res.getvalue(0,4) ).to eq( nil )
606
- expect( res.getvalue(0,5).gsub(" ","") ).to eq( "[1,\"a\",null]" )
607
- expect( res.getvalue(0,6).gsub(" ","") ).to eq( "{\"b\":[2,3]}" )
608
- end
609
- end
610
- end
611
-
612
- context "with usage of result oids for copy encoder selection" do
613
- it "can type cast #copy_data input with explicit encoder" do
614
- @conn.exec( "CREATE TEMP TABLE copytable (t TEXT, i INT, ai INT[])" )
615
-
616
- # Retrieve table OIDs per empty result set.
617
- res = @conn.exec( "SELECT * FROM copytable LIMIT 0" )
618
- tm = basic_type_mapping.build_column_map( res )
619
- row_encoder = PG::TextEncoder::CopyRow.new type_map: tm
620
-
621
- @conn.copy_data( "COPY copytable FROM STDIN", row_encoder ) do |res|
622
- @conn.put_copy_data ['a', 123, [5,4,3]]
623
- @conn.put_copy_data ['b', 234, [2,3]]
624
- end
625
- res = @conn.exec( "SELECT * FROM copytable" )
626
- expect( res.values ).to eq( [['a', '123', '{5,4,3}'], ['b', '234', '{2,3}']] )
627
- end
628
- end
629
- end
630
- end