pg 1.2.2-x64-mingw32 → 1.3.0.rc3-x64-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 (111) 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 +85 -0
  6. data/.github/workflows/source-gem.yml +129 -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 +86 -7
  16. data/Manifest.txt +0 -1
  17. data/README.rdoc +8 -7
  18. data/Rakefile +28 -139
  19. data/Rakefile.cross +17 -17
  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 +90 -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 -0
  28. data/ext/pg_coder.c +90 -24
  29. data/ext/pg_connection.c +615 -533
  30. data/ext/pg_copy_coder.c +45 -15
  31. data/ext/pg_record_coder.c +38 -9
  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 +50 -21
  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/pg/basic_type_map_based_on_result.rb +47 -0
  49. data/lib/pg/basic_type_map_for_queries.rb +193 -0
  50. data/lib/pg/basic_type_map_for_results.rb +81 -0
  51. data/lib/pg/basic_type_registry.rb +296 -0
  52. data/lib/pg/coder.rb +1 -1
  53. data/lib/pg/connection.rb +586 -57
  54. data/lib/pg/version.rb +4 -0
  55. data/lib/pg.rb +40 -27
  56. data/lib/x64-mingw32/libpq.dll +0 -0
  57. data/misc/openssl-pg-segfault.rb +31 -0
  58. data/misc/postgres/History.txt +9 -0
  59. data/misc/postgres/Manifest.txt +5 -0
  60. data/misc/postgres/README.txt +21 -0
  61. data/misc/postgres/Rakefile +21 -0
  62. data/misc/postgres/lib/postgres.rb +16 -0
  63. data/misc/ruby-pg/History.txt +9 -0
  64. data/misc/ruby-pg/Manifest.txt +5 -0
  65. data/misc/ruby-pg/README.txt +21 -0
  66. data/misc/ruby-pg/Rakefile +21 -0
  67. data/misc/ruby-pg/lib/ruby/pg.rb +16 -0
  68. data/pg.gemspec +32 -0
  69. data/sample/array_insert.rb +20 -0
  70. data/sample/async_api.rb +106 -0
  71. data/sample/async_copyto.rb +39 -0
  72. data/sample/async_mixed.rb +56 -0
  73. data/sample/check_conn.rb +21 -0
  74. data/sample/copydata.rb +71 -0
  75. data/sample/copyfrom.rb +81 -0
  76. data/sample/copyto.rb +19 -0
  77. data/sample/cursor.rb +21 -0
  78. data/sample/disk_usage_report.rb +177 -0
  79. data/sample/issue-119.rb +94 -0
  80. data/sample/losample.rb +69 -0
  81. data/sample/minimal-testcase.rb +17 -0
  82. data/sample/notify_wait.rb +72 -0
  83. data/sample/pg_statistics.rb +285 -0
  84. data/sample/replication_monitor.rb +222 -0
  85. data/sample/test_binary_values.rb +33 -0
  86. data/sample/wal_shipper.rb +434 -0
  87. data/sample/warehouse_partitions.rb +311 -0
  88. data.tar.gz.sig +0 -0
  89. metadata +92 -233
  90. metadata.gz.sig +0 -0
  91. data/ChangeLog +0 -0
  92. data/lib/2.2/pg_ext.so +0 -0
  93. data/lib/2.3/pg_ext.so +0 -0
  94. data/lib/2.4/pg_ext.so +0 -0
  95. data/lib/pg/basic_type_mapping.rb +0 -522
  96. data/spec/data/expected_trace.out +0 -26
  97. data/spec/data/random_binary_data +0 -0
  98. data/spec/helpers.rb +0 -382
  99. data/spec/pg/basic_type_mapping_spec.rb +0 -645
  100. data/spec/pg/connection_spec.rb +0 -1911
  101. data/spec/pg/connection_sync_spec.rb +0 -41
  102. data/spec/pg/result_spec.rb +0 -681
  103. data/spec/pg/tuple_spec.rb +0 -333
  104. data/spec/pg/type_map_by_class_spec.rb +0 -138
  105. data/spec/pg/type_map_by_column_spec.rb +0 -226
  106. data/spec/pg/type_map_by_mri_type_spec.rb +0 -136
  107. data/spec/pg/type_map_by_oid_spec.rb +0 -149
  108. data/spec/pg/type_map_in_ruby_spec.rb +0 -164
  109. data/spec/pg/type_map_spec.rb +0 -22
  110. data/spec/pg/type_spec.rb +0 -1123
  111. data/spec/pg_spec.rb +0 -50
@@ -1,645 +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
- def expect_to_typecase_result_value_warning
25
- warning = 'Warning: no type cast defined for type "name" with oid 19. '\
26
- "Please cast this type explicitly to TEXT to be safe for future changes.\n"\
27
- 'Warning: no type cast defined for type "regproc" with oid 24. '\
28
- "Please cast this type explicitly to TEXT to be safe for future changes.\n"
29
- expect { yield }.to output(warning).to_stderr
30
- end
31
-
32
- describe 'Basic type mapping' do
33
-
34
- describe PG::BasicTypeMapForQueries do
35
- let!(:basic_type_mapping) do
36
- PG::BasicTypeMapForQueries.new @conn
37
- end
38
-
39
- #
40
- # Encoding Examples
41
- #
42
-
43
- it "should do basic param encoding" do
44
- res = @conn.exec_params( "SELECT $1::int8, $2::float, $3, $4::TEXT",
45
- [1, 2.1, true, "b"], nil, basic_type_mapping )
46
-
47
- expect( res.values ).to eq( [
48
- [ "1", "2.1", "t", "b" ],
49
- ] )
50
-
51
- expect( result_typenames(res) ).to eq( ['bigint', 'double precision', 'boolean', 'text'] )
52
- end
53
-
54
- it "should do basic Time encoding" do
55
- res = @conn.exec_params( "SELECT $1 AT TIME ZONE '-02'",
56
- [Time.new(2019, 12, 8, 20, 38, 12.123, "-01:00")], nil, basic_type_mapping )
57
-
58
- expect( res.values ).to eq( [[ "2019-12-08 23:38:12.123" ]] )
59
- end
60
-
61
- it "should do basic param encoding of various float values" do
62
- 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",
63
- [0, 7, 9, 0.1, 0.9, -0.11, 10.11,
64
- 9876543210987654321e-400,
65
- 9876543210987654321e400,
66
- -1.234567890123456789e-280,
67
- -1.234567890123456789e280,
68
- 9876543210987654321e280
69
- ], nil, basic_type_mapping )
70
-
71
- expect( res.values[0][0, 9] ).to eq(
72
- [ "0", "7", "9", "0.1", "0.9", "-0.11", "10.11", "0", "Infinity" ]
73
- )
74
-
75
- expect( res.values[0][9] ).to match( /^-1\.2345678901234\d*e\-280$/ )
76
- expect( res.values[0][10] ).to match( /^-1\.2345678901234\d*e\+280$/ )
77
- expect( res.values[0][11] ).to match( /^9\.8765432109876\d*e\+298$/ )
78
-
79
- expect( result_typenames(res) ).to eq( ['double precision'] * 12 )
80
- end
81
-
82
- it "should do default array-as-array param encoding" do
83
- expect( basic_type_mapping.encode_array_as).to eq(:array)
84
- res = @conn.exec_params( "SELECT $1,$2,$3,$4,$5,$6", [
85
- [1, 2, 3], # Integer -> bigint[]
86
- [[1, 2], [3, nil]], # Integer two dimensions -> bigint[]
87
- [1.11, 2.21], # Float -> double precision[]
88
- ['/,"'.gsub("/", "\\"), nil, 'abcäöü'], # String -> text[]
89
- [BigDecimal("123.45")], # BigDecimal -> numeric[]
90
- [IPAddr.new('1234::5678')], # IPAddr -> inet[]
91
- ], nil, basic_type_mapping )
92
-
93
- expect( res.values ).to eq( [[
94
- '{1,2,3}',
95
- '{{1,2},{3,NULL}}',
96
- '{1.11,2.21}',
97
- '{"//,/"",NULL,abcäöü}'.gsub("/", "\\"),
98
- '{123.45}',
99
- '{1234::5678}',
100
- ]] )
101
-
102
- expect( result_typenames(res) ).to eq( ['bigint[]', 'bigint[]', 'double precision[]', 'text[]', 'numeric[]', 'inet[]'] )
103
- end
104
-
105
- it "should do default array-as-array param encoding with Time objects" do
106
- res = @conn.exec_params( "SELECT $1", [
107
- [Time.new(2019, 12, 8, 20, 38, 12.123, "-01:00")], # Time -> timestamptz[]
108
- ], nil, basic_type_mapping )
109
-
110
- expect( res.values[0][0] ).to match( /\{\"2019-12-08 \d\d:38:12.123[+-]\d\d\"\}/ )
111
- expect( result_typenames(res) ).to eq( ['timestamp with time zone[]'] )
112
- end
113
-
114
- it "should do array-as-json encoding" do
115
- basic_type_mapping.encode_array_as = :json
116
- expect( basic_type_mapping.encode_array_as).to eq(:json)
117
-
118
- res = @conn.exec_params( "SELECT $1::JSON, $2::JSON", [
119
- [1, {a: 5}, true, ["a", 2], [3.4, nil]],
120
- ['/,"'.gsub("/", "\\"), nil, 'abcäöü'],
121
- ], nil, basic_type_mapping )
122
-
123
- expect( res.values ).to eq( [[
124
- '[1,{"a":5},true,["a",2],[3.4,null]]',
125
- '["//,/"",null,"abcäöü"]'.gsub("/", "\\"),
126
- ]] )
127
-
128
- expect( result_typenames(res) ).to eq( ['json', 'json'] )
129
- end
130
-
131
- it "should do hash-as-json encoding" do
132
- res = @conn.exec_params( "SELECT $1::JSON, $2::JSON", [
133
- {a: 5, b: ["a", 2], c: nil},
134
- {qu: '/,"'.gsub("/", "\\"), ni: nil, uml: 'abcäöü'},
135
- ], nil, basic_type_mapping )
136
-
137
- expect( res.values ).to eq( [[
138
- '{"a":5,"b":["a",2],"c":null}',
139
- '{"qu":"//,/"","ni":null,"uml":"abcäöü"}'.gsub("/", "\\"),
140
- ]] )
141
-
142
- expect( result_typenames(res) ).to eq( ['json', 'json'] )
143
- end
144
-
145
- describe "Record encoding" do
146
- before :all do
147
- @conn.exec("CREATE TYPE test_record1 AS (i int, d float, t text)")
148
- @conn.exec("CREATE TYPE test_record2 AS (i int, r test_record1)")
149
- end
150
-
151
- after :all do
152
- @conn.exec("DROP TYPE IF EXISTS test_record2 CASCADE")
153
- @conn.exec("DROP TYPE IF EXISTS test_record1 CASCADE")
154
- end
155
-
156
- it "should do array-as-record encoding" do
157
- basic_type_mapping.encode_array_as = :record
158
- expect( basic_type_mapping.encode_array_as).to eq(:record)
159
-
160
- res = @conn.exec_params( "SELECT $1::test_record1, $2::test_record2, $3::text", [
161
- [5, 3.4, "txt"],
162
- [1, [2, 4.5, "bcd"]],
163
- [4, 5, 6],
164
- ], nil, basic_type_mapping )
165
-
166
- expect( res.values ).to eq( [[
167
- '(5,3.4,txt)',
168
- '(1,"(2,4.5,bcd)")',
169
- '("4","5","6")',
170
- ]] )
171
-
172
- expect( result_typenames(res) ).to eq( ['test_record1', 'test_record2', 'text'] )
173
- end
174
- end
175
-
176
- it "should do bigdecimal param encoding" do
177
- large = ('123456790'*10) << '.' << ('012345679')
178
- res = @conn.exec_params( "SELECT $1::numeric,$2::numeric",
179
- [BigDecimal('1'), BigDecimal(large)], nil, basic_type_mapping )
180
-
181
- expect( res.values ).to eq( [
182
- [ "1.0", large ],
183
- ] )
184
-
185
- expect( result_typenames(res) ).to eq( ['numeric', 'numeric'] )
186
- end
187
-
188
- it "should do IPAddr param encoding" do
189
- res = @conn.exec_params( "SELECT $1::inet,$2::inet,$3::cidr,$4::cidr",
190
- ['1.2.3.4', IPAddr.new('1234::5678'), '1.2.3.4', IPAddr.new('1234:5678::/32')], nil, basic_type_mapping )
191
-
192
- expect( res.values ).to eq( [
193
- [ '1.2.3.4', '1234::5678', '1.2.3.4/32', '1234:5678::/32'],
194
- ] )
195
-
196
- expect( result_typenames(res) ).to eq( ['inet', 'inet', 'cidr', 'cidr'] )
197
- end
198
-
199
- it "should do array of string encoding on unknown classes" do
200
- iv = Class.new do
201
- def to_s
202
- "abc"
203
- end
204
- end.new
205
- res = @conn.exec_params( "SELECT $1", [
206
- [iv, iv], # Unknown -> text[]
207
- ], nil, basic_type_mapping )
208
-
209
- expect( res.values ).to eq( [[
210
- '{abc,abc}',
211
- ]] )
212
-
213
- expect( result_typenames(res) ).to eq( ['text[]'] )
214
- end
215
-
216
- end
217
-
218
-
219
-
220
- describe PG::BasicTypeMapForResults do
221
- let!(:basic_type_mapping) do
222
- PG::BasicTypeMapForResults.new @conn
223
- end
224
-
225
- #
226
- # Decoding Examples
227
- #
228
-
229
- it "should do OID based type conversions" do
230
- res = @conn.exec( "SELECT 1, 'a', 2.0::FLOAT, TRUE, '2013-06-30'::DATE, generate_series(4,5)" )
231
- expect( res.map_types!(basic_type_mapping).values ).to eq( [
232
- [ 1, 'a', 2.0, true, Date.new(2013,6,30), 4 ],
233
- [ 1, 'a', 2.0, true, Date.new(2013,6,30), 5 ],
234
- ] )
235
- end
236
-
237
- #
238
- # Decoding Examples text+binary format converters
239
- #
240
-
241
- describe "connection wide type mapping" do
242
- before :each do
243
- @conn.type_map_for_results = basic_type_mapping
244
- end
245
-
246
- after :each do
247
- @conn.type_map_for_results = PG::TypeMapAllStrings.new
248
- end
249
-
250
- it "should do boolean type conversions" do
251
- [1, 0].each do |format|
252
- res = @conn.exec_params( "SELECT true::BOOLEAN, false::BOOLEAN, NULL::BOOLEAN", [], format )
253
- expect( res.values ).to eq( [[true, false, nil]] )
254
- end
255
- end
256
-
257
- it "should do binary type conversions" do
258
- [1, 0].each do |format|
259
- res = @conn.exec_params( "SELECT E'\\\\000\\\\377'::BYTEA", [], format )
260
- expect( res.values ).to eq( [[["00ff"].pack("H*")]] )
261
- expect( res.values[0][0].encoding ).to eq( Encoding::ASCII_8BIT ) if Object.const_defined? :Encoding
262
- end
263
- end
264
-
265
- it "should do integer type conversions" do
266
- [1, 0].each do |format|
267
- res = @conn.exec_params( "SELECT -8999::INT2, -899999999::INT4, -8999999999999999999::INT8", [], format )
268
- expect( res.values ).to eq( [[-8999, -899999999, -8999999999999999999]] )
269
- end
270
- end
271
-
272
- it "should do string type conversions" do
273
- @conn.internal_encoding = 'utf-8' if Object.const_defined? :Encoding
274
- [1, 0].each do |format|
275
- res = @conn.exec_params( "SELECT 'abcäöü'::TEXT", [], format )
276
- expect( res.values ).to eq( [['abcäöü']] )
277
- expect( res.values[0][0].encoding ).to eq( Encoding::UTF_8 ) if Object.const_defined? :Encoding
278
- end
279
- end
280
-
281
- it "should do float type conversions" do
282
- [1, 0].each do |format|
283
- res = @conn.exec_params( "SELECT -8.999e3::FLOAT4,
284
- 8.999e10::FLOAT4,
285
- -8999999999e-99::FLOAT8,
286
- NULL::FLOAT4,
287
- 'NaN'::FLOAT4,
288
- 'Infinity'::FLOAT4,
289
- '-Infinity'::FLOAT4
290
- ", [], format )
291
- expect( res.getvalue(0,0) ).to be_within(1e-2).of(-8.999e3)
292
- expect( res.getvalue(0,1) ).to be_within(1e5).of(8.999e10)
293
- expect( res.getvalue(0,2) ).to be_within(1e-109).of(-8999999999e-99)
294
- expect( res.getvalue(0,3) ).to be_nil
295
- expect( res.getvalue(0,4) ).to be_nan
296
- expect( res.getvalue(0,5) ).to eq( Float::INFINITY )
297
- expect( res.getvalue(0,6) ).to eq( -Float::INFINITY )
298
- end
299
- end
300
-
301
- it "should do text datetime without time zone type conversions" do
302
- # for backward compat text timestamps without time zone are treated as local times
303
- res = @conn.exec_params( "SELECT CAST('2013-12-31 23:58:59+02' AS TIMESTAMP WITHOUT TIME ZONE),
304
- CAST('1913-12-31 23:58:59.1231-03' AS TIMESTAMP WITHOUT TIME ZONE),
305
- CAST('4714-11-24 23:58:59.1231-03 BC' AS TIMESTAMP WITHOUT TIME ZONE),
306
- CAST('294276-12-31 23:58:59.1231-03' AS TIMESTAMP WITHOUT TIME ZONE),
307
- CAST('infinity' AS TIMESTAMP WITHOUT TIME ZONE),
308
- CAST('-infinity' AS TIMESTAMP WITHOUT TIME ZONE)", [], 0 )
309
- expect( res.getvalue(0,0) ).to eq( Time.new(2013, 12, 31, 23, 58, 59) )
310
- expect( res.getvalue(0,1).iso8601(3) ).to eq( Time.new(1913, 12, 31, 23, 58, 59.1231).iso8601(3) )
311
- expect( res.getvalue(0,2).iso8601(3) ).to eq( Time.new(-4713, 11, 24, 23, 58, 59.1231).iso8601(3) )
312
- expect( res.getvalue(0,3).iso8601(3) ).to eq( Time.new(294276, 12, 31, 23, 58, 59.1231).iso8601(3) )
313
- expect( res.getvalue(0,4) ).to eq( 'infinity' )
314
- expect( res.getvalue(0,5) ).to eq( '-infinity' )
315
- end
316
-
317
- [1, 0].each do |format|
318
- it "should convert format #{format} timestamps per TimestampUtc" do
319
- restore_type("timestamp") do
320
- PG::BasicTypeRegistry.register_type 0, 'timestamp', nil, PG::TextDecoder::TimestampUtc
321
- expect_to_typecase_result_value_warning do
322
- @conn.type_map_for_results = PG::BasicTypeMapForResults.new(@conn)
323
- end
324
- res = @conn.exec_params( "SELECT CAST('2013-07-31 23:58:59+02' AS TIMESTAMP WITHOUT TIME ZONE),
325
- CAST('1913-12-31 23:58:59.1231-03' AS TIMESTAMP WITHOUT TIME ZONE),
326
- CAST('4714-11-24 23:58:59.1231-03 BC' AS TIMESTAMP WITHOUT TIME ZONE),
327
- CAST('294276-12-31 23:58:59.1231-03' AS TIMESTAMP WITHOUT TIME ZONE),
328
- CAST('infinity' AS TIMESTAMP WITHOUT TIME ZONE),
329
- CAST('-infinity' AS TIMESTAMP WITHOUT TIME ZONE)", [], format )
330
- expect( res.getvalue(0,0).iso8601(3) ).to eq( Time.utc(2013, 7, 31, 23, 58, 59).iso8601(3) )
331
- expect( res.getvalue(0,1).iso8601(3) ).to eq( Time.utc(1913, 12, 31, 23, 58, 59.1231).iso8601(3) )
332
- expect( res.getvalue(0,2).iso8601(3) ).to eq( Time.utc(-4713, 11, 24, 23, 58, 59.1231).iso8601(3) )
333
- expect( res.getvalue(0,3).iso8601(3) ).to eq( Time.utc(294276, 12, 31, 23, 58, 59.1231).iso8601(3) )
334
- expect( res.getvalue(0,4) ).to eq( 'infinity' )
335
- expect( res.getvalue(0,5) ).to eq( '-infinity' )
336
- end
337
- end
338
- end
339
-
340
- [1, 0].each do |format|
341
- it "should convert format #{format} timestamps per TimestampUtcToLocal" do
342
- restore_type("timestamp") do
343
- PG::BasicTypeRegistry.register_type 0, 'timestamp', nil, PG::TextDecoder::TimestampUtcToLocal
344
- PG::BasicTypeRegistry.register_type 1, 'timestamp', nil, PG::BinaryDecoder::TimestampUtcToLocal
345
- expect_to_typecase_result_value_warning do
346
- @conn.type_map_for_results = PG::BasicTypeMapForResults.new(@conn)
347
- end
348
- res = @conn.exec_params( "SELECT CAST('2013-07-31 23:58:59+02' AS TIMESTAMP WITHOUT TIME ZONE),
349
- CAST('1913-12-31 23:58:59.1231-03' AS TIMESTAMP WITHOUT TIME ZONE),
350
- CAST('4714-11-24 23:58:59.1231-03 BC' AS TIMESTAMP WITHOUT TIME ZONE),
351
- CAST('294276-12-31 23:58:59.1231-03' AS TIMESTAMP WITHOUT TIME ZONE),
352
- CAST('infinity' AS TIMESTAMP WITHOUT TIME ZONE),
353
- CAST('-infinity' AS TIMESTAMP WITHOUT TIME ZONE)", [], format )
354
- expect( res.getvalue(0,0).iso8601(3) ).to eq( Time.utc(2013, 7, 31, 23, 58, 59).getlocal.iso8601(3) )
355
- expect( res.getvalue(0,1).iso8601(3) ).to eq( Time.utc(1913, 12, 31, 23, 58, 59.1231).getlocal.iso8601(3) )
356
- expect( res.getvalue(0,2).iso8601(3) ).to eq( Time.utc(-4713, 11, 24, 23, 58, 59.1231).getlocal.iso8601(3) )
357
- expect( res.getvalue(0,3).iso8601(3) ).to eq( Time.utc(294276, 12, 31, 23, 58, 59.1231).getlocal.iso8601(3) )
358
- expect( res.getvalue(0,4) ).to eq( 'infinity' )
359
- expect( res.getvalue(0,5) ).to eq( '-infinity' )
360
- end
361
- end
362
- end
363
-
364
- [1, 0].each do |format|
365
- it "should convert format #{format} timestamps per TimestampLocal" do
366
- restore_type("timestamp") do
367
- PG::BasicTypeRegistry.register_type 0, 'timestamp', nil, PG::TextDecoder::TimestampLocal
368
- PG::BasicTypeRegistry.register_type 1, 'timestamp', nil, PG::BinaryDecoder::TimestampLocal
369
- expect_to_typecase_result_value_warning do
370
- @conn.type_map_for_results = PG::BasicTypeMapForResults.new(@conn)
371
- end
372
- res = @conn.exec_params( "SELECT CAST('2013-07-31 23:58:59' AS TIMESTAMP WITHOUT TIME ZONE),
373
- CAST('1913-12-31 23:58:59.1231' AS TIMESTAMP WITHOUT TIME ZONE),
374
- CAST('4714-11-24 23:58:59.1231-03 BC' AS TIMESTAMP WITHOUT TIME ZONE),
375
- CAST('294276-12-31 23:58:59.1231+03' AS TIMESTAMP WITHOUT TIME ZONE),
376
- CAST('infinity' AS TIMESTAMP WITHOUT TIME ZONE),
377
- CAST('-infinity' AS TIMESTAMP WITHOUT TIME ZONE)", [], format )
378
- expect( res.getvalue(0,0).iso8601(3) ).to eq( Time.new(2013, 7, 31, 23, 58, 59).iso8601(3) )
379
- expect( res.getvalue(0,1).iso8601(3) ).to eq( Time.new(1913, 12, 31, 23, 58, 59.1231).iso8601(3) )
380
- expect( res.getvalue(0,2).iso8601(3) ).to eq( Time.new(-4713, 11, 24, 23, 58, 59.1231).iso8601(3) )
381
- expect( res.getvalue(0,3).iso8601(3) ).to eq( Time.new(294276, 12, 31, 23, 58, 59.1231).iso8601(3) )
382
- expect( res.getvalue(0,4) ).to eq( 'infinity' )
383
- expect( res.getvalue(0,5) ).to eq( '-infinity' )
384
- end
385
- end
386
- end
387
-
388
- [0, 1].each do |format|
389
- it "should convert format #{format} timestamps with time zone" do
390
- res = @conn.exec_params( "SELECT CAST('2013-12-31 23:58:59+02' AS TIMESTAMP WITH TIME ZONE),
391
- CAST('1913-12-31 23:58:59.1231-03' AS TIMESTAMP WITH TIME ZONE),
392
- CAST('4714-11-24 23:58:59.1231-03 BC' AS TIMESTAMP WITH TIME ZONE),
393
- CAST('294276-12-31 23:58:59.1231+03' AS TIMESTAMP WITH TIME ZONE),
394
- CAST('infinity' AS TIMESTAMP WITH TIME ZONE),
395
- CAST('-infinity' AS TIMESTAMP WITH TIME ZONE)", [], format )
396
- expect( res.getvalue(0,0) ).to be_within(1e-3).of( Time.new(2013, 12, 31, 23, 58, 59, "+02:00").getlocal )
397
- expect( res.getvalue(0,1) ).to be_within(1e-3).of( Time.new(1913, 12, 31, 23, 58, 59.1231, "-03:00").getlocal )
398
- expect( res.getvalue(0,2) ).to be_within(1e-3).of( Time.new(-4713, 11, 24, 23, 58, 59.1231, "-03:00").getlocal )
399
- expect( res.getvalue(0,3) ).to be_within(1e-3).of( Time.new(294276, 12, 31, 23, 58, 59.1231, "+03:00").getlocal )
400
- expect( res.getvalue(0,4) ).to eq( 'infinity' )
401
- expect( res.getvalue(0,5) ).to eq( '-infinity' )
402
- end
403
- end
404
-
405
- it "should do date type conversions" do
406
- [0].each do |format|
407
- res = @conn.exec_params( "SELECT CAST('2113-12-31' AS DATE),
408
- CAST('1913-12-31' AS DATE),
409
- CAST('infinity' AS DATE),
410
- CAST('-infinity' AS DATE)", [], format )
411
- expect( res.getvalue(0,0) ).to eq( Date.new(2113, 12, 31) )
412
- expect( res.getvalue(0,1) ).to eq( Date.new(1913, 12, 31) )
413
- expect( res.getvalue(0,2) ).to eq( 'infinity' )
414
- expect( res.getvalue(0,3) ).to eq( '-infinity' )
415
- end
416
- end
417
-
418
- it "should do numeric type conversions" do
419
- [0].each do |format|
420
- small = '123456790123.12'
421
- large = ('123456790'*10) << '.' << ('012345679')
422
- numerics = [
423
- '1',
424
- '1.0',
425
- '1.2',
426
- small,
427
- large,
428
- ]
429
- sql_numerics = numerics.map { |v| "CAST(#{v} AS numeric)" }
430
- res = @conn.exec_params( "SELECT #{sql_numerics.join(',')}", [], format )
431
- expect( res.getvalue(0,0) ).to eq( BigDecimal('1') )
432
- expect( res.getvalue(0,1) ).to eq( BigDecimal('1') )
433
- expect( res.getvalue(0,2) ).to eq( BigDecimal('1.2') )
434
- expect( res.getvalue(0,3) ).to eq( BigDecimal(small) )
435
- expect( res.getvalue(0,4) ).to eq( BigDecimal(large) )
436
- end
437
- end
438
-
439
- it "should do JSON conversions", :postgresql_94 do
440
- [0].each do |format|
441
- ['JSON', 'JSONB'].each do |type|
442
- res = @conn.exec_params( "SELECT CAST('123' AS #{type}),
443
- CAST('12.3' AS #{type}),
444
- CAST('true' AS #{type}),
445
- CAST('false' AS #{type}),
446
- CAST('null' AS #{type}),
447
- CAST('[1, \"a\", null]' AS #{type}),
448
- CAST('{\"b\" : [2,3]}' AS #{type})", [], format )
449
- expect( res.getvalue(0,0) ).to eq( 123 )
450
- expect( res.getvalue(0,1) ).to be_within(0.1).of( 12.3 )
451
- expect( res.getvalue(0,2) ).to eq( true )
452
- expect( res.getvalue(0,3) ).to eq( false )
453
- expect( res.getvalue(0,4) ).to eq( nil )
454
- expect( res.getvalue(0,5) ).to eq( [1, "a", nil] )
455
- expect( res.getvalue(0,6) ).to eq( {"b" => [2, 3]} )
456
- end
457
- end
458
- end
459
-
460
- it "should do array type conversions" do
461
- [0].each do |format|
462
- res = @conn.exec_params( "SELECT CAST('{1,2,3}' AS INT2[]), CAST('{{1,2},{3,4}}' AS INT2[][]),
463
- CAST('{1,2,3}' AS INT4[]),
464
- CAST('{1,2,3}' AS INT8[]),
465
- CAST('{1,2,3}' AS TEXT[]),
466
- CAST('{1,2,3}' AS VARCHAR[]),
467
- CAST('{1,2,3}' AS FLOAT4[]),
468
- CAST('{1,2,3}' AS FLOAT8[])
469
- ", [], format )
470
- expect( res.getvalue(0,0) ).to eq( [1,2,3] )
471
- expect( res.getvalue(0,1) ).to eq( [[1,2],[3,4]] )
472
- expect( res.getvalue(0,2) ).to eq( [1,2,3] )
473
- expect( res.getvalue(0,3) ).to eq( [1,2,3] )
474
- expect( res.getvalue(0,4) ).to eq( ['1','2','3'] )
475
- expect( res.getvalue(0,5) ).to eq( ['1','2','3'] )
476
- expect( res.getvalue(0,6) ).to eq( [1.0,2.0,3.0] )
477
- expect( res.getvalue(0,7) ).to eq( [1.0,2.0,3.0] )
478
- end
479
- end
480
-
481
- it "should do inet type conversions" do
482
- [0].each do |format|
483
- vals = [
484
- '1.2.3.4',
485
- '0.0.0.0/0',
486
- '1.0.0.0/8',
487
- '1.2.0.0/16',
488
- '1.2.3.0/24',
489
- '1.2.3.4/24',
490
- '1.2.3.4/32',
491
- '1.2.3.128/25',
492
- '1234:3456:5678:789a:9abc:bced:edf0:f012',
493
- '::/0',
494
- '1234:3456::/32',
495
- '1234:3456:5678:789a::/64',
496
- '1234:3456:5678:789a:9abc:bced::/96',
497
- '1234:3456:5678:789a:9abc:bced:edf0:f012/128',
498
- '1234:3456:5678:789a:9abc:bced:edf0:f012/0',
499
- '1234:3456:5678:789a:9abc:bced:edf0:f012/32',
500
- '1234:3456:5678:789a:9abc:bced:edf0:f012/64',
501
- '1234:3456:5678:789a:9abc:bced:edf0:f012/96',
502
- ]
503
- sql_vals = vals.map{|v| "CAST('#{v}' AS inet)"}
504
- res = @conn.exec_params(("SELECT " + sql_vals.join(', ')), [], format )
505
- vals.each_with_index do |v, i|
506
- val = res.getvalue(0,i)
507
- expect( res.getvalue(0,i) ).to eq( IPAddr.new(v) )
508
- end
509
- end
510
- end
511
-
512
- it "should do cidr type conversions" do
513
- [0].each do |format|
514
- vals = [
515
- '0.0.0.0/0',
516
- '1.0.0.0/8',
517
- '1.2.0.0/16',
518
- '1.2.3.0/24',
519
- '1.2.3.4/32',
520
- '1.2.3.128/25',
521
- '::/0',
522
- '1234:3456::/32',
523
- '1234:3456:5678:789a::/64',
524
- '1234:3456:5678:789a:9abc:bced::/96',
525
- '1234:3456:5678:789a:9abc:bced:edf0:f012/128',
526
- ]
527
- sql_vals = vals.map { |v| "CAST('#{v}' AS cidr)" }
528
- res = @conn.exec_params(("SELECT " + sql_vals.join(', ')), [], format )
529
- vals.each_with_index do |v, i|
530
- val = res.getvalue(0,i)
531
- ip, prefix = v.split('/', 2)
532
- expect( val.to_s ).to eq( ip )
533
- if val.respond_to?(:prefix)
534
- val_prefix = val.prefix
535
- else
536
- default_prefix = (val.family == Socket::AF_INET ? 32 : 128)
537
- range = val.to_range
538
- val_prefix = default_prefix - Math.log(((range.end.to_i - range.begin.to_i) + 1), 2).to_i
539
- end
540
- if v.include?('/')
541
- expect( val_prefix ).to eq( prefix.to_i )
542
- elsif v.include?('.')
543
- expect( val_prefix ).to eq( 32 )
544
- else
545
- expect( val_prefix ).to eq( 128 )
546
- end
547
- end
548
- end
549
- end
550
- end
551
-
552
- context "with usage of result oids for copy decoder selection" do
553
- it "can type cast #copy_data output with explicit decoder" do
554
- @conn.exec( "CREATE TEMP TABLE copytable (t TEXT, i INT, ai INT[])" )
555
- @conn.exec( "INSERT INTO copytable VALUES ('a', 123, '{5,4,3}'), ('b', 234, '{2,3}')" )
556
-
557
- # Retrieve table OIDs per empty result.
558
- res = @conn.exec( "SELECT * FROM copytable LIMIT 0" )
559
- tm = basic_type_mapping.build_column_map( res )
560
- row_decoder = PG::TextDecoder::CopyRow.new type_map: tm
561
-
562
- rows = []
563
- @conn.copy_data( "COPY copytable TO STDOUT", row_decoder ) do |res|
564
- while row=@conn.get_copy_data
565
- rows << row
566
- end
567
- end
568
- expect( rows ).to eq( [['a', 123, [5,4,3]], ['b', 234, [2,3]]] )
569
- end
570
- end
571
- end
572
-
573
-
574
- describe PG::BasicTypeMapBasedOnResult do
575
- let!(:basic_type_mapping) do
576
- PG::BasicTypeMapBasedOnResult.new @conn
577
- end
578
-
579
- context "with usage of result oids for bind params encoder selection" do
580
- it "can type cast query params" do
581
- @conn.exec( "CREATE TEMP TABLE copytable (t TEXT, i INT, ai INT[])" )
582
-
583
- # Retrieve table OIDs per empty result.
584
- res = @conn.exec( "SELECT * FROM copytable LIMIT 0" )
585
- tm = basic_type_mapping.build_column_map( res )
586
-
587
- @conn.exec_params( "INSERT INTO copytable VALUES ($1, $2, $3)", ['a', 123, [5,4,3]], 0, tm )
588
- @conn.exec_params( "INSERT INTO copytable VALUES ($1, $2, $3)", ['b', 234, [2,3]], 0, tm )
589
- res = @conn.exec( "SELECT * FROM copytable" )
590
- expect( res.values ).to eq( [['a', '123', '{5,4,3}'], ['b', '234', '{2,3}']] )
591
- end
592
-
593
- it "can do JSON conversions", :postgresql_94 do
594
- ['JSON', 'JSONB'].each do |type|
595
- sql = "SELECT CAST('123' AS #{type}),
596
- CAST('12.3' AS #{type}),
597
- CAST('true' AS #{type}),
598
- CAST('false' AS #{type}),
599
- CAST('null' AS #{type}),
600
- CAST('[1, \"a\", null]' AS #{type}),
601
- CAST('{\"b\" : [2,3]}' AS #{type})"
602
-
603
- tm = basic_type_mapping.build_column_map( @conn.exec( sql ) )
604
- expect( tm.coders.map(&:name) ).to eq( [type.downcase] * 7 )
605
-
606
- res = @conn.exec_params( "SELECT $1, $2, $3, $4, $5, $6, $7",
607
- [ 123,
608
- 12.3,
609
- true,
610
- false,
611
- nil,
612
- [1, "a", nil],
613
- {"b" => [2, 3]},
614
- ], 0, tm )
615
-
616
- expect( res.getvalue(0,0) ).to eq( "123" )
617
- expect( res.getvalue(0,1) ).to eq( "12.3" )
618
- expect( res.getvalue(0,2) ).to eq( "true" )
619
- expect( res.getvalue(0,3) ).to eq( "false" )
620
- expect( res.getvalue(0,4) ).to eq( nil )
621
- expect( res.getvalue(0,5).gsub(" ","") ).to eq( "[1,\"a\",null]" )
622
- expect( res.getvalue(0,6).gsub(" ","") ).to eq( "{\"b\":[2,3]}" )
623
- end
624
- end
625
- end
626
-
627
- context "with usage of result oids for copy encoder selection" do
628
- it "can type cast #copy_data input with explicit encoder" do
629
- @conn.exec( "CREATE TEMP TABLE copytable (t TEXT, i INT, ai INT[])" )
630
-
631
- # Retrieve table OIDs per empty result set.
632
- res = @conn.exec( "SELECT * FROM copytable LIMIT 0" )
633
- tm = basic_type_mapping.build_column_map( res )
634
- row_encoder = PG::TextEncoder::CopyRow.new type_map: tm
635
-
636
- @conn.copy_data( "COPY copytable FROM STDIN", row_encoder ) do |res|
637
- @conn.put_copy_data ['a', 123, [5,4,3]]
638
- @conn.put_copy_data ['b', 234, [2,3]]
639
- end
640
- res = @conn.exec( "SELECT * FROM copytable" )
641
- expect( res.values ).to eq( [['a', '123', '{5,4,3}'], ['b', '234', '{2,3}']] )
642
- end
643
- end
644
- end
645
- end