pg 1.1.4 → 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 +86 -0
- data/Manifest.txt +3 -2
- data/README-Windows.rdoc +4 -4
- data/README.ja.rdoc +1 -2
- data/README.rdoc +44 -9
- data/Rakefile +8 -6
- data/Rakefile.cross +57 -56
- data/ext/errorcodes.def +64 -0
- data/ext/errorcodes.txt +18 -2
- data/ext/extconf.rb +6 -6
- data/ext/pg.c +132 -95
- data/ext/pg.h +21 -18
- data/ext/pg_binary_decoder.c +9 -9
- data/ext/pg_binary_encoder.c +13 -12
- data/ext/pg_coder.c +21 -9
- data/ext/pg_connection.c +388 -298
- data/ext/pg_copy_coder.c +6 -3
- data/ext/pg_record_coder.c +491 -0
- data/ext/pg_result.c +279 -127
- data/ext/pg_text_decoder.c +14 -8
- data/ext/pg_text_encoder.c +180 -48
- data/ext/pg_tuple.c +14 -6
- 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} +5 -5
- data/ext/{util.h → pg_util.h} +0 -0
- data/lib/pg.rb +4 -4
- data/lib/pg/basic_type_mapping.rb +81 -18
- data/lib/pg/binary_decoder.rb +1 -0
- data/lib/pg/coder.rb +22 -1
- data/lib/pg/connection.rb +2 -2
- data/lib/pg/constants.rb +1 -0
- data/lib/pg/exceptions.rb +1 -0
- data/lib/pg/result.rb +13 -1
- data/lib/pg/text_decoder.rb +2 -3
- data/lib/pg/text_encoder.rb +8 -18
- data/lib/pg/type_map_by_column.rb +2 -1
- data/spec/helpers.rb +11 -11
- data/spec/pg/basic_type_mapping_spec.rb +140 -18
- data/spec/pg/connection_spec.rb +166 -89
- data/spec/pg/result_spec.rb +194 -4
- data/spec/pg/tuple_spec.rb +55 -2
- data/spec/pg/type_map_by_class_spec.rb +1 -1
- data/spec/pg/type_map_by_column_spec.rb +5 -1
- data/spec/pg/type_map_by_oid_spec.rb +2 -2
- data/spec/pg/type_spec.rb +180 -6
- metadata +31 -30
- metadata.gz.sig +0 -0
data/lib/pg/connection.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
# -*- ruby -*-
|
2
|
+
# frozen_string_literal: true
|
2
3
|
|
3
4
|
require 'pg' unless defined?( PG )
|
4
5
|
require 'uri'
|
@@ -47,7 +48,7 @@ class PG::Connection
|
|
47
48
|
|
48
49
|
if args.length == 1
|
49
50
|
case args.first
|
50
|
-
when URI, /\A#{URI
|
51
|
+
when URI, /\A#{URI::ABS_URI_REF}\z/
|
51
52
|
uri = URI(args.first)
|
52
53
|
options.merge!( Hash[URI.decode_www_form( uri.query )] ) if uri.query
|
53
54
|
when /=/
|
@@ -288,4 +289,3 @@ class PG::Connection
|
|
288
289
|
# pg-1.1.0+ defaults to libpq's async API for query related blocking methods
|
289
290
|
self.async_api = true
|
290
291
|
end # class PG::Connection
|
291
|
-
|
data/lib/pg/constants.rb
CHANGED
data/lib/pg/exceptions.rb
CHANGED
data/lib/pg/result.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
# -*- ruby -*-
|
2
|
+
# frozen_string_literal: true
|
2
3
|
|
3
4
|
require 'pg' unless defined?( PG )
|
4
5
|
|
@@ -9,12 +10,23 @@ class PG::Result
|
|
9
10
|
#
|
10
11
|
# +type_map+: a PG::TypeMap instance.
|
11
12
|
#
|
12
|
-
#
|
13
|
+
# This method is equal to #type_map= , but returns self, so that calls can be chained.
|
14
|
+
#
|
15
|
+
# See also PG::BasicTypeMapForResults
|
13
16
|
def map_types!(type_map)
|
14
17
|
self.type_map = type_map
|
15
18
|
return self
|
16
19
|
end
|
17
20
|
|
21
|
+
# Set the data type for all field name returning methods.
|
22
|
+
#
|
23
|
+
# +type+: a Symbol defining the field name type.
|
24
|
+
#
|
25
|
+
# This method is equal to #field_name_type= , but returns self, so that calls can be chained.
|
26
|
+
def field_names_as(type)
|
27
|
+
self.field_name_type = type
|
28
|
+
return self
|
29
|
+
end
|
18
30
|
|
19
31
|
### Return a String representation of the object suitable for debugging.
|
20
32
|
def inspect
|
data/lib/pg/text_decoder.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
# -*- ruby -*-
|
2
|
+
# frozen_string_literal: true
|
2
3
|
|
3
4
|
require 'date'
|
4
5
|
require 'json'
|
@@ -6,10 +7,8 @@ require 'json'
|
|
6
7
|
module PG
|
7
8
|
module TextDecoder
|
8
9
|
class Date < SimpleDecoder
|
9
|
-
ISO_DATE = /\A(\d{4})-(\d\d)-(\d\d)\z/
|
10
|
-
|
11
10
|
def decode(string, tuple=nil, field=nil)
|
12
|
-
if string =~
|
11
|
+
if string =~ /\A(\d{4})-(\d\d)-(\d\d)\z/
|
13
12
|
::Date.new $1.to_i, $2.to_i, $3.to_i
|
14
13
|
else
|
15
14
|
string
|
data/lib/pg/text_encoder.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
# -*- ruby -*-
|
2
|
+
# frozen_string_literal: true
|
2
3
|
|
3
4
|
require 'json'
|
4
5
|
require 'ipaddr'
|
@@ -6,36 +7,26 @@ require 'ipaddr'
|
|
6
7
|
module PG
|
7
8
|
module TextEncoder
|
8
9
|
class Date < SimpleEncoder
|
9
|
-
STRFTIME_ISO_DATE = "%Y-%m-%d".freeze
|
10
10
|
def encode(value)
|
11
|
-
value.respond_to?(:strftime) ? value.strftime(
|
11
|
+
value.respond_to?(:strftime) ? value.strftime("%Y-%m-%d") : value
|
12
12
|
end
|
13
13
|
end
|
14
14
|
|
15
15
|
class TimestampWithoutTimeZone < SimpleEncoder
|
16
|
-
STRFTIME_ISO_DATETIME_WITHOUT_TIMEZONE = "%Y-%m-%d %H:%M:%S.%N".freeze
|
17
16
|
def encode(value)
|
18
|
-
value.respond_to?(:strftime) ? value.strftime(
|
17
|
+
value.respond_to?(:strftime) ? value.strftime("%Y-%m-%d %H:%M:%S.%N") : value
|
19
18
|
end
|
20
19
|
end
|
21
20
|
|
22
21
|
class TimestampUtc < SimpleEncoder
|
23
|
-
STRFTIME_ISO_DATETIME_WITHOUT_TIMEZONE_UTC = "%Y-%m-%d %H:%M:%S.%N".freeze
|
24
22
|
def encode(value)
|
25
|
-
value.respond_to?(:utc) ? value.utc.strftime(
|
23
|
+
value.respond_to?(:utc) ? value.utc.strftime("%Y-%m-%d %H:%M:%S.%N") : value
|
26
24
|
end
|
27
25
|
end
|
28
26
|
|
29
27
|
class TimestampWithTimeZone < SimpleEncoder
|
30
|
-
STRFTIME_ISO_DATETIME_WITH_TIMEZONE = "%Y-%m-%d %H:%M:%S.%N %:z".freeze
|
31
28
|
def encode(value)
|
32
|
-
value.respond_to?(:strftime) ? value.strftime(
|
33
|
-
end
|
34
|
-
end
|
35
|
-
|
36
|
-
class Numeric < SimpleEncoder
|
37
|
-
def encode(value)
|
38
|
-
value.is_a?(BigDecimal) ? value.to_s('F') : value
|
29
|
+
value.respond_to?(:strftime) ? value.strftime("%Y-%m-%d %H:%M:%S.%N %:z") : value
|
39
30
|
end
|
40
31
|
end
|
41
32
|
|
@@ -51,12 +42,12 @@ module PG
|
|
51
42
|
when IPAddr
|
52
43
|
default_prefix = (value.family == Socket::AF_INET ? 32 : 128)
|
53
44
|
s = value.to_s
|
54
|
-
|
45
|
+
if value.respond_to?(:prefix)
|
55
46
|
prefix = value.prefix
|
56
|
-
|
47
|
+
else
|
57
48
|
range = value.to_range
|
58
49
|
prefix = default_prefix - Math.log(((range.end.to_i - range.begin.to_i) + 1), 2).to_i
|
59
|
-
|
50
|
+
end
|
60
51
|
s << "/" << prefix.to_s if prefix != default_prefix
|
61
52
|
s
|
62
53
|
else
|
@@ -66,4 +57,3 @@ module PG
|
|
66
57
|
end
|
67
58
|
end
|
68
59
|
end # module PG
|
69
|
-
|
@@ -1,4 +1,5 @@
|
|
1
1
|
# -*- ruby -*-
|
2
|
+
# frozen_string_literal: true
|
2
3
|
|
3
4
|
require 'pg' unless defined?( PG )
|
4
5
|
|
@@ -9,7 +10,7 @@ class PG::TypeMapByColumn
|
|
9
10
|
end
|
10
11
|
|
11
12
|
def inspect
|
12
|
-
type_strings = coders.map{|c| c ?
|
13
|
+
type_strings = coders.map{|c| c ? c.inspect_short : 'nil' }
|
13
14
|
"#<#{self.class} #{type_strings.join(' ')}>"
|
14
15
|
end
|
15
16
|
end
|
data/spec/helpers.rb
CHANGED
@@ -172,18 +172,18 @@ module PG::TestingHelpers
|
|
172
172
|
datadir = testdir + 'data'
|
173
173
|
pidfile = datadir + 'postmaster.pid'
|
174
174
|
if pidfile.exist? && pid = pidfile.read.chomp.to_i
|
175
|
-
|
175
|
+
trace "pidfile (%p) exists: %d" % [ pidfile, pid ]
|
176
176
|
begin
|
177
177
|
Process.kill( 0, pid )
|
178
178
|
rescue Errno::ESRCH
|
179
|
-
|
179
|
+
trace "No postmaster running for %s" % [ datadir ]
|
180
180
|
# Process isn't alive, so don't try to stop it
|
181
181
|
else
|
182
|
-
|
182
|
+
trace "Stopping lingering database at PID %d" % [ pid ]
|
183
183
|
run 'pg_ctl', '-D', datadir.to_s, '-m', 'fast', 'stop'
|
184
184
|
end
|
185
185
|
else
|
186
|
-
|
186
|
+
trace "No pidfile (%p)" % [ pidfile ]
|
187
187
|
end
|
188
188
|
end
|
189
189
|
end
|
@@ -194,7 +194,7 @@ module PG::TestingHelpers
|
|
194
194
|
require 'pg'
|
195
195
|
stop_existing_postmasters()
|
196
196
|
|
197
|
-
|
197
|
+
trace "Setting up test database for #{description}"
|
198
198
|
@test_pgdata = TEST_DIRECTORY + 'data'
|
199
199
|
@test_pgdata.mkpath
|
200
200
|
|
@@ -209,7 +209,7 @@ module PG::TestingHelpers
|
|
209
209
|
begin
|
210
210
|
unless (@test_pgdata+"postgresql.conf").exist?
|
211
211
|
FileUtils.rm_rf( @test_pgdata, :verbose => $DEBUG )
|
212
|
-
|
212
|
+
trace "Running initdb"
|
213
213
|
log_and_run @logfile, 'initdb', '-E', 'UTF8', '--no-locale', '-D', @test_pgdata.to_s
|
214
214
|
end
|
215
215
|
|
@@ -218,14 +218,14 @@ module PG::TestingHelpers
|
|
218
218
|
'-D', @test_pgdata.to_s, 'start'
|
219
219
|
sleep 2
|
220
220
|
|
221
|
-
|
221
|
+
trace "Creating the test DB"
|
222
222
|
log_and_run @logfile, 'psql', '-e', '-c', 'DROP DATABASE IF EXISTS test', 'postgres'
|
223
223
|
log_and_run @logfile, 'createdb', '-e', 'test'
|
224
224
|
|
225
225
|
rescue => err
|
226
226
|
$stderr.puts "%p during test setup: %s" % [ err.class, err.message ]
|
227
227
|
$stderr.puts "See #{@logfile} for details."
|
228
|
-
$stderr.puts
|
228
|
+
$stderr.puts err.backtrace if $DEBUG
|
229
229
|
fail
|
230
230
|
end
|
231
231
|
|
@@ -239,7 +239,7 @@ module PG::TestingHelpers
|
|
239
239
|
|
240
240
|
|
241
241
|
def teardown_testing_db( conn )
|
242
|
-
|
242
|
+
trace "Tearing down test database"
|
243
243
|
|
244
244
|
if conn
|
245
245
|
check_for_lingering_connections( conn )
|
@@ -370,11 +370,11 @@ RSpec.configure do |config|
|
|
370
370
|
else
|
371
371
|
config.filter_run_excluding :windows
|
372
372
|
end
|
373
|
-
config.filter_run_excluding :socket_io unless
|
374
|
-
PG::Connection.instance_methods.map( &:to_sym ).include?( :socket_io )
|
375
373
|
|
376
374
|
config.filter_run_excluding( :postgresql_93 ) if PG.library_version < 90300
|
377
375
|
config.filter_run_excluding( :postgresql_94 ) if PG.library_version < 90400
|
378
376
|
config.filter_run_excluding( :postgresql_95 ) if PG.library_version < 90500
|
377
|
+
config.filter_run_excluding( :postgresql_96 ) if PG.library_version < 90600
|
379
378
|
config.filter_run_excluding( :postgresql_10 ) if PG.library_version < 100000
|
379
|
+
config.filter_run_excluding( :postgresql_12 ) if PG.library_version < 120000
|
380
380
|
end
|
@@ -32,8 +32,8 @@ describe 'Basic type mapping' do
|
|
32
32
|
# Encoding Examples
|
33
33
|
#
|
34
34
|
|
35
|
-
it "should do basic param encoding"
|
36
|
-
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",
|
37
37
|
[1, 2.1, true, "b"], nil, basic_type_mapping )
|
38
38
|
|
39
39
|
expect( res.values ).to eq( [
|
@@ -43,20 +43,126 @@ describe 'Basic type mapping' do
|
|
43
43
|
expect( result_typenames(res) ).to eq( ['bigint', 'double precision', 'boolean', 'text'] )
|
44
44
|
end
|
45
45
|
|
46
|
-
it "should do
|
47
|
-
res = @conn.exec_params( "SELECT $1
|
48
|
-
|
49
|
-
|
50
|
-
|
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[]
|
51
83
|
], nil, basic_type_mapping )
|
52
84
|
|
53
85
|
expect( res.values ).to eq( [[
|
54
|
-
'{1,2,3}',
|
86
|
+
'{1,2,3}',
|
87
|
+
'{{1,2},{3,NULL}}',
|
55
88
|
'{1.11,2.21}',
|
56
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("/", "\\"),
|
57
118
|
]] )
|
58
119
|
|
59
|
-
expect( result_typenames(res) ).to eq( ['
|
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
|
60
166
|
end
|
61
167
|
|
62
168
|
it "should do bigdecimal param encoding" do
|
@@ -82,6 +188,23 @@ describe 'Basic type mapping' do
|
|
82
188
|
expect( result_typenames(res) ).to eq( ['inet', 'inet', 'cidr', 'cidr'] )
|
83
189
|
end
|
84
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
|
+
|
85
208
|
end
|
86
209
|
|
87
210
|
|
@@ -95,7 +218,7 @@ describe 'Basic type mapping' do
|
|
95
218
|
# Decoding Examples
|
96
219
|
#
|
97
220
|
|
98
|
-
it "should do OID based type conversions"
|
221
|
+
it "should do OID based type conversions" do
|
99
222
|
res = @conn.exec( "SELECT 1, 'a', 2.0::FLOAT, TRUE, '2013-06-30'::DATE, generate_series(4,5)" )
|
100
223
|
expect( res.map_types!(basic_type_mapping).values ).to eq( [
|
101
224
|
[ 1, 'a', 2.0, true, Date.new(2013,6,30), 4 ],
|
@@ -366,7 +489,6 @@ describe 'Basic type mapping' do
|
|
366
489
|
sql_vals = vals.map{|v| "CAST('#{v}' AS inet)"}
|
367
490
|
res = @conn.exec_params(("SELECT " + sql_vals.join(', ')), [], format )
|
368
491
|
vals.each_with_index do |v, i|
|
369
|
-
val = res.getvalue(0,i)
|
370
492
|
expect( res.getvalue(0,i) ).to eq( IPAddr.new(v) )
|
371
493
|
end
|
372
494
|
end
|
@@ -390,22 +512,22 @@ describe 'Basic type mapping' do
|
|
390
512
|
sql_vals = vals.map { |v| "CAST('#{v}' AS cidr)" }
|
391
513
|
res = @conn.exec_params(("SELECT " + sql_vals.join(', ')), [], format )
|
392
514
|
vals.each_with_index do |v, i|
|
393
|
-
|
515
|
+
val = res.getvalue(0,i)
|
394
516
|
ip, prefix = v.split('/', 2)
|
395
|
-
|
517
|
+
expect( val.to_s ).to eq( ip )
|
396
518
|
if val.respond_to?(:prefix)
|
397
519
|
val_prefix = val.prefix
|
398
520
|
else
|
399
|
-
|
521
|
+
default_prefix = (val.family == Socket::AF_INET ? 32 : 128)
|
400
522
|
range = val.to_range
|
401
523
|
val_prefix = default_prefix - Math.log(((range.end.to_i - range.begin.to_i) + 1), 2).to_i
|
402
524
|
end
|
403
525
|
if v.include?('/')
|
404
|
-
|
526
|
+
expect( val_prefix ).to eq( prefix.to_i )
|
405
527
|
elsif v.include?('.')
|
406
|
-
|
407
|
-
|
408
|
-
|
528
|
+
expect( val_prefix ).to eq( 32 )
|
529
|
+
else
|
530
|
+
expect( val_prefix ).to eq( 128 )
|
409
531
|
end
|
410
532
|
end
|
411
533
|
end
|