pg 1.1.3 → 1.5.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (140) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data/.appveyor.yml +42 -0
  4. data/.gems +6 -0
  5. data/.github/workflows/binary-gems.yml +117 -0
  6. data/.github/workflows/source-gem.yml +141 -0
  7. data/.gitignore +22 -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.md +884 -0
  16. data/Manifest.txt +3 -3
  17. data/README-Windows.rdoc +4 -4
  18. data/README.ja.md +300 -0
  19. data/README.md +286 -0
  20. data/Rakefile +37 -137
  21. data/Rakefile.cross +62 -62
  22. data/certs/ged.pem +24 -0
  23. data/certs/larskanis-2022.pem +26 -0
  24. data/certs/larskanis-2023.pem +24 -0
  25. data/ext/errorcodes.def +80 -0
  26. data/ext/errorcodes.rb +0 -0
  27. data/ext/errorcodes.txt +22 -2
  28. data/ext/extconf.rb +105 -26
  29. data/ext/gvl_wrappers.c +4 -0
  30. data/ext/gvl_wrappers.h +23 -0
  31. data/ext/pg.c +204 -152
  32. data/ext/pg.h +52 -21
  33. data/ext/pg_binary_decoder.c +100 -17
  34. data/ext/pg_binary_encoder.c +238 -13
  35. data/ext/pg_coder.c +109 -34
  36. data/ext/pg_connection.c +1383 -983
  37. data/ext/pg_copy_coder.c +356 -35
  38. data/ext/pg_errors.c +1 -1
  39. data/ext/pg_record_coder.c +522 -0
  40. data/ext/pg_result.c +439 -172
  41. data/ext/pg_text_decoder.c +42 -18
  42. data/ext/pg_text_encoder.c +201 -56
  43. data/ext/pg_tuple.c +97 -66
  44. data/ext/pg_type_map.c +45 -11
  45. data/ext/pg_type_map_all_strings.c +21 -7
  46. data/ext/pg_type_map_by_class.c +59 -27
  47. data/ext/pg_type_map_by_column.c +80 -37
  48. data/ext/pg_type_map_by_mri_type.c +49 -20
  49. data/ext/pg_type_map_by_oid.c +62 -29
  50. data/ext/pg_type_map_in_ruby.c +56 -22
  51. data/ext/{util.c → pg_util.c} +7 -7
  52. data/lib/pg/basic_type_map_based_on_result.rb +67 -0
  53. data/lib/pg/basic_type_map_for_queries.rb +198 -0
  54. data/lib/pg/basic_type_map_for_results.rb +104 -0
  55. data/lib/pg/basic_type_registry.rb +299 -0
  56. data/lib/pg/binary_decoder/date.rb +9 -0
  57. data/lib/pg/binary_decoder/timestamp.rb +26 -0
  58. data/lib/pg/binary_encoder/timestamp.rb +20 -0
  59. data/lib/pg/coder.rb +35 -12
  60. data/lib/pg/connection.rb +744 -84
  61. data/lib/pg/exceptions.rb +15 -1
  62. data/lib/pg/result.rb +13 -1
  63. data/lib/pg/text_decoder/date.rb +18 -0
  64. data/lib/pg/text_decoder/inet.rb +9 -0
  65. data/lib/pg/text_decoder/json.rb +14 -0
  66. data/lib/pg/text_decoder/numeric.rb +9 -0
  67. data/lib/pg/text_decoder/timestamp.rb +30 -0
  68. data/lib/pg/text_encoder/date.rb +12 -0
  69. data/lib/pg/text_encoder/inet.rb +28 -0
  70. data/lib/pg/text_encoder/json.rb +14 -0
  71. data/lib/pg/text_encoder/numeric.rb +9 -0
  72. data/lib/pg/text_encoder/timestamp.rb +24 -0
  73. data/lib/pg/type_map_by_column.rb +2 -1
  74. data/lib/pg/version.rb +4 -0
  75. data/lib/pg.rb +94 -39
  76. data/misc/openssl-pg-segfault.rb +31 -0
  77. data/misc/postgres/History.txt +9 -0
  78. data/misc/postgres/Manifest.txt +5 -0
  79. data/misc/postgres/README.txt +21 -0
  80. data/misc/postgres/Rakefile +21 -0
  81. data/misc/postgres/lib/postgres.rb +16 -0
  82. data/misc/ruby-pg/History.txt +9 -0
  83. data/misc/ruby-pg/Manifest.txt +5 -0
  84. data/misc/ruby-pg/README.txt +21 -0
  85. data/misc/ruby-pg/Rakefile +21 -0
  86. data/misc/ruby-pg/lib/ruby/pg.rb +16 -0
  87. data/pg.gemspec +34 -0
  88. data/rakelib/task_extension.rb +46 -0
  89. data/sample/array_insert.rb +20 -0
  90. data/sample/async_api.rb +102 -0
  91. data/sample/async_copyto.rb +39 -0
  92. data/sample/async_mixed.rb +56 -0
  93. data/sample/check_conn.rb +21 -0
  94. data/sample/copydata.rb +71 -0
  95. data/sample/copyfrom.rb +81 -0
  96. data/sample/copyto.rb +19 -0
  97. data/sample/cursor.rb +21 -0
  98. data/sample/disk_usage_report.rb +177 -0
  99. data/sample/issue-119.rb +94 -0
  100. data/sample/losample.rb +69 -0
  101. data/sample/minimal-testcase.rb +17 -0
  102. data/sample/notify_wait.rb +72 -0
  103. data/sample/pg_statistics.rb +285 -0
  104. data/sample/replication_monitor.rb +222 -0
  105. data/sample/test_binary_values.rb +33 -0
  106. data/sample/wal_shipper.rb +434 -0
  107. data/sample/warehouse_partitions.rb +311 -0
  108. data/translation/.po4a-version +7 -0
  109. data/translation/po/all.pot +936 -0
  110. data/translation/po/ja.po +1036 -0
  111. data/translation/po4a.cfg +12 -0
  112. data.tar.gz.sig +0 -0
  113. metadata +144 -222
  114. metadata.gz.sig +0 -0
  115. data/ChangeLog +0 -6595
  116. data/History.rdoc +0 -485
  117. data/README.ja.rdoc +0 -14
  118. data/README.rdoc +0 -178
  119. data/lib/pg/basic_type_mapping.rb +0 -459
  120. data/lib/pg/binary_decoder.rb +0 -22
  121. data/lib/pg/constants.rb +0 -11
  122. data/lib/pg/text_decoder.rb +0 -47
  123. data/lib/pg/text_encoder.rb +0 -69
  124. data/spec/data/expected_trace.out +0 -26
  125. data/spec/data/random_binary_data +0 -0
  126. data/spec/helpers.rb +0 -381
  127. data/spec/pg/basic_type_mapping_spec.rb +0 -508
  128. data/spec/pg/connection_spec.rb +0 -1849
  129. data/spec/pg/connection_sync_spec.rb +0 -41
  130. data/spec/pg/result_spec.rb +0 -491
  131. data/spec/pg/tuple_spec.rb +0 -280
  132. data/spec/pg/type_map_by_class_spec.rb +0 -138
  133. data/spec/pg/type_map_by_column_spec.rb +0 -222
  134. data/spec/pg/type_map_by_mri_type_spec.rb +0 -136
  135. data/spec/pg/type_map_by_oid_spec.rb +0 -149
  136. data/spec/pg/type_map_in_ruby_spec.rb +0 -164
  137. data/spec/pg/type_map_spec.rb +0 -22
  138. data/spec/pg/type_spec.rb +0 -949
  139. data/spec/pg_spec.rb +0 -50
  140. /data/ext/{util.h → pg_util.h} +0 -0
@@ -1,508 +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", :ruby_19 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 array param encoding" do
47
- res = @conn.exec_params( "SELECT $1,$2,$3,$4", [
48
- [1, 2, 3], [[1, 2], [3, nil]],
49
- [1.11, 2.21],
50
- ['/,"'.gsub("/", "\\"), nil, 'abcäöü'],
51
- ], nil, basic_type_mapping )
52
-
53
- expect( res.values ).to eq( [[
54
- '{1,2,3}', '{{1,2},{3,NULL}}',
55
- '{1.11,2.21}',
56
- '{"//,/"",NULL,abcäöü}'.gsub("/", "\\"),
57
- ]] )
58
-
59
- expect( result_typenames(res) ).to eq( ['bigint[]', 'bigint[]', 'double precision[]', 'text[]'] )
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
-
85
- end
86
-
87
-
88
-
89
- describe PG::BasicTypeMapForResults do
90
- let!(:basic_type_mapping) do
91
- PG::BasicTypeMapForResults.new @conn
92
- end
93
-
94
- #
95
- # Decoding Examples
96
- #
97
-
98
- it "should do OID based type conversions", :ruby_19 do
99
- res = @conn.exec( "SELECT 1, 'a', 2.0::FLOAT, TRUE, '2013-06-30'::DATE, generate_series(4,5)" )
100
- expect( res.map_types!(basic_type_mapping).values ).to eq( [
101
- [ 1, 'a', 2.0, true, Date.new(2013,6,30), 4 ],
102
- [ 1, 'a', 2.0, true, Date.new(2013,6,30), 5 ],
103
- ] )
104
- end
105
-
106
- #
107
- # Decoding Examples text+binary format converters
108
- #
109
-
110
- describe "connection wide type mapping" do
111
- before :each do
112
- @conn.type_map_for_results = basic_type_mapping
113
- end
114
-
115
- after :each do
116
- @conn.type_map_for_results = PG::TypeMapAllStrings.new
117
- end
118
-
119
- it "should do boolean type conversions" do
120
- [1, 0].each do |format|
121
- res = @conn.exec_params( "SELECT true::BOOLEAN, false::BOOLEAN, NULL::BOOLEAN", [], format )
122
- expect( res.values ).to eq( [[true, false, nil]] )
123
- end
124
- end
125
-
126
- it "should do binary type conversions" do
127
- [1, 0].each do |format|
128
- res = @conn.exec_params( "SELECT E'\\\\000\\\\377'::BYTEA", [], format )
129
- expect( res.values ).to eq( [[["00ff"].pack("H*")]] )
130
- expect( res.values[0][0].encoding ).to eq( Encoding::ASCII_8BIT ) if Object.const_defined? :Encoding
131
- end
132
- end
133
-
134
- it "should do integer type conversions" do
135
- [1, 0].each do |format|
136
- res = @conn.exec_params( "SELECT -8999::INT2, -899999999::INT4, -8999999999999999999::INT8", [], format )
137
- expect( res.values ).to eq( [[-8999, -899999999, -8999999999999999999]] )
138
- end
139
- end
140
-
141
- it "should do string type conversions" do
142
- @conn.internal_encoding = 'utf-8' if Object.const_defined? :Encoding
143
- [1, 0].each do |format|
144
- res = @conn.exec_params( "SELECT 'abcäöü'::TEXT", [], format )
145
- expect( res.values ).to eq( [['abcäöü']] )
146
- expect( res.values[0][0].encoding ).to eq( Encoding::UTF_8 ) if Object.const_defined? :Encoding
147
- end
148
- end
149
-
150
- it "should do float type conversions" do
151
- [1, 0].each do |format|
152
- res = @conn.exec_params( "SELECT -8.999e3::FLOAT4,
153
- 8.999e10::FLOAT4,
154
- -8999999999e-99::FLOAT8,
155
- NULL::FLOAT4,
156
- 'NaN'::FLOAT4,
157
- 'Infinity'::FLOAT4,
158
- '-Infinity'::FLOAT4
159
- ", [], format )
160
- expect( res.getvalue(0,0) ).to be_within(1e-2).of(-8.999e3)
161
- expect( res.getvalue(0,1) ).to be_within(1e5).of(8.999e10)
162
- expect( res.getvalue(0,2) ).to be_within(1e-109).of(-8999999999e-99)
163
- expect( res.getvalue(0,3) ).to be_nil
164
- expect( res.getvalue(0,4) ).to be_nan
165
- expect( res.getvalue(0,5) ).to eq( Float::INFINITY )
166
- expect( res.getvalue(0,6) ).to eq( -Float::INFINITY )
167
- end
168
- end
169
-
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
204
- end
205
- end
206
-
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),
257
- CAST('infinity' AS TIMESTAMP WITH TIME ZONE),
258
- CAST('-infinity' AS TIMESTAMP WITH TIME ZONE)", [], format )
259
- expect( res.getvalue(0,0) ).to be_within(1e-3).of( Time.new(2013, 12, 31, 23, 58, 59, "+02:00").getlocal )
260
- expect( res.getvalue(0,1) ).to be_within(1e-3).of( Time.new(1913, 12, 31, 23, 58, 59.1231, "-03:00").getlocal )
261
- expect( res.getvalue(0,2) ).to be_within(1e-3).of( Time.new(-4713, 11, 24, 23, 58, 59.1231, "-03:00").getlocal )
262
- expect( res.getvalue(0,3) ).to be_within(1e-3).of( Time.new(294276, 12, 31, 23, 58, 59.1231, "+03:00").getlocal )
263
- expect( res.getvalue(0,4) ).to eq( 'infinity' )
264
- expect( res.getvalue(0,5) ).to eq( '-infinity' )
265
- end
266
- end
267
-
268
- it "should do date type conversions" do
269
- [0].each do |format|
270
- res = @conn.exec_params( "SELECT CAST('2113-12-31' AS DATE),
271
- CAST('1913-12-31' AS DATE),
272
- CAST('infinity' AS DATE),
273
- CAST('-infinity' AS DATE)", [], format )
274
- expect( res.getvalue(0,0) ).to eq( Date.new(2113, 12, 31) )
275
- expect( res.getvalue(0,1) ).to eq( Date.new(1913, 12, 31) )
276
- expect( res.getvalue(0,2) ).to eq( 'infinity' )
277
- expect( res.getvalue(0,3) ).to eq( '-infinity' )
278
- end
279
- end
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
-
302
- it "should do JSON conversions", :postgresql_94 do
303
- [0].each do |format|
304
- ['JSON', 'JSONB'].each do |type|
305
- res = @conn.exec_params( "SELECT CAST('123' AS #{type}),
306
- CAST('12.3' AS #{type}),
307
- CAST('true' AS #{type}),
308
- CAST('false' AS #{type}),
309
- CAST('null' AS #{type}),
310
- CAST('[1, \"a\", null]' AS #{type}),
311
- CAST('{\"b\" : [2,3]}' AS #{type})", [], format )
312
- expect( res.getvalue(0,0) ).to eq( 123 )
313
- expect( res.getvalue(0,1) ).to be_within(0.1).of( 12.3 )
314
- expect( res.getvalue(0,2) ).to eq( true )
315
- expect( res.getvalue(0,3) ).to eq( false )
316
- expect( res.getvalue(0,4) ).to eq( nil )
317
- expect( res.getvalue(0,5) ).to eq( [1, "a", nil] )
318
- expect( res.getvalue(0,6) ).to eq( {"b" => [2, 3]} )
319
- end
320
- end
321
- end
322
-
323
- it "should do array type conversions" do
324
- [0].each do |format|
325
- res = @conn.exec_params( "SELECT CAST('{1,2,3}' AS INT2[]), CAST('{{1,2},{3,4}}' AS INT2[][]),
326
- CAST('{1,2,3}' AS INT4[]),
327
- CAST('{1,2,3}' AS INT8[]),
328
- CAST('{1,2,3}' AS TEXT[]),
329
- CAST('{1,2,3}' AS VARCHAR[]),
330
- CAST('{1,2,3}' AS FLOAT4[]),
331
- CAST('{1,2,3}' AS FLOAT8[])
332
- ", [], format )
333
- expect( res.getvalue(0,0) ).to eq( [1,2,3] )
334
- expect( res.getvalue(0,1) ).to eq( [[1,2],[3,4]] )
335
- expect( res.getvalue(0,2) ).to eq( [1,2,3] )
336
- expect( res.getvalue(0,3) ).to eq( [1,2,3] )
337
- expect( res.getvalue(0,4) ).to eq( ['1','2','3'] )
338
- expect( res.getvalue(0,5) ).to eq( ['1','2','3'] )
339
- expect( res.getvalue(0,6) ).to eq( [1.0,2.0,3.0] )
340
- expect( res.getvalue(0,7) ).to eq( [1.0,2.0,3.0] )
341
- end
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
413
- end
414
-
415
- context "with usage of result oids for copy decoder selection" do
416
- it "can type cast #copy_data output with explicit decoder" do
417
- @conn.exec( "CREATE TEMP TABLE copytable (t TEXT, i INT, ai INT[])" )
418
- @conn.exec( "INSERT INTO copytable VALUES ('a', 123, '{5,4,3}'), ('b', 234, '{2,3}')" )
419
-
420
- # Retrieve table OIDs per empty result.
421
- res = @conn.exec( "SELECT * FROM copytable LIMIT 0" )
422
- tm = basic_type_mapping.build_column_map( res )
423
- row_decoder = PG::TextDecoder::CopyRow.new type_map: tm
424
-
425
- rows = []
426
- @conn.copy_data( "COPY copytable TO STDOUT", row_decoder ) do |res|
427
- while row=@conn.get_copy_data
428
- rows << row
429
- end
430
- end
431
- expect( rows ).to eq( [['a', 123, [5,4,3]], ['b', 234, [2,3]]] )
432
- end
433
- end
434
- end
435
-
436
-
437
- describe PG::BasicTypeMapBasedOnResult do
438
- let!(:basic_type_mapping) do
439
- PG::BasicTypeMapBasedOnResult.new @conn
440
- end
441
-
442
- context "with usage of result oids for bind params encoder selection" do
443
- it "can type cast query params" do
444
- @conn.exec( "CREATE TEMP TABLE copytable (t TEXT, i INT, ai INT[])" )
445
-
446
- # Retrieve table OIDs per empty result.
447
- res = @conn.exec( "SELECT * FROM copytable LIMIT 0" )
448
- tm = basic_type_mapping.build_column_map( res )
449
-
450
- @conn.exec_params( "INSERT INTO copytable VALUES ($1, $2, $3)", ['a', 123, [5,4,3]], 0, tm )
451
- @conn.exec_params( "INSERT INTO copytable VALUES ($1, $2, $3)", ['b', 234, [2,3]], 0, tm )
452
- res = @conn.exec( "SELECT * FROM copytable" )
453
- expect( res.values ).to eq( [['a', '123', '{5,4,3}'], ['b', '234', '{2,3}']] )
454
- end
455
-
456
- it "can do JSON conversions", :postgresql_94 do
457
- ['JSON', 'JSONB'].each do |type|
458
- sql = "SELECT CAST('123' AS #{type}),
459
- CAST('12.3' AS #{type}),
460
- CAST('true' AS #{type}),
461
- CAST('false' AS #{type}),
462
- CAST('null' AS #{type}),
463
- CAST('[1, \"a\", null]' AS #{type}),
464
- CAST('{\"b\" : [2,3]}' AS #{type})"
465
-
466
- tm = basic_type_mapping.build_column_map( @conn.exec( sql ) )
467
- expect( tm.coders.map(&:name) ).to eq( [type.downcase] * 7 )
468
-
469
- res = @conn.exec_params( "SELECT $1, $2, $3, $4, $5, $6, $7",
470
- [ 123,
471
- 12.3,
472
- true,
473
- false,
474
- nil,
475
- [1, "a", nil],
476
- {"b" => [2, 3]},
477
- ], 0, tm )
478
-
479
- expect( res.getvalue(0,0) ).to eq( "123" )
480
- expect( res.getvalue(0,1) ).to eq( "12.3" )
481
- expect( res.getvalue(0,2) ).to eq( "true" )
482
- expect( res.getvalue(0,3) ).to eq( "false" )
483
- expect( res.getvalue(0,4) ).to eq( nil )
484
- expect( res.getvalue(0,5).gsub(" ","") ).to eq( "[1,\"a\",null]" )
485
- expect( res.getvalue(0,6).gsub(" ","") ).to eq( "{\"b\":[2,3]}" )
486
- end
487
- end
488
- end
489
-
490
- context "with usage of result oids for copy encoder selection" do
491
- it "can type cast #copy_data input with explicit encoder" do
492
- @conn.exec( "CREATE TEMP TABLE copytable (t TEXT, i INT, ai INT[])" )
493
-
494
- # Retrieve table OIDs per empty result set.
495
- res = @conn.exec( "SELECT * FROM copytable LIMIT 0" )
496
- tm = basic_type_mapping.build_column_map( res )
497
- row_encoder = PG::TextEncoder::CopyRow.new type_map: tm
498
-
499
- @conn.copy_data( "COPY copytable FROM STDIN", row_encoder ) do |res|
500
- @conn.put_copy_data ['a', 123, [5,4,3]]
501
- @conn.put_copy_data ['b', 234, [2,3]]
502
- end
503
- res = @conn.exec( "SELECT * FROM copytable" )
504
- expect( res.values ).to eq( [['a', '123', '{5,4,3}'], ['b', '234', '{2,3}']] )
505
- end
506
- end
507
- end
508
- end