pg 0.18.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 +5 -5
- checksums.yaml.gz.sig +0 -0
- data.tar.gz.sig +0 -0
- data/BSDL +2 -2
- data/ChangeLog +0 -5911
- data/History.rdoc +240 -0
- data/Manifest.txt +8 -20
- data/README-Windows.rdoc +4 -4
- data/README.ja.rdoc +1 -2
- data/README.rdoc +64 -15
- data/Rakefile +20 -21
- data/Rakefile.cross +67 -69
- data/ext/errorcodes.def +101 -0
- data/ext/errorcodes.rb +1 -1
- data/ext/errorcodes.txt +33 -2
- data/ext/extconf.rb +26 -36
- data/ext/gvl_wrappers.c +4 -0
- data/ext/gvl_wrappers.h +27 -39
- data/ext/pg.c +156 -145
- data/ext/pg.h +74 -98
- data/ext/pg_binary_decoder.c +82 -15
- data/ext/pg_binary_encoder.c +20 -19
- data/ext/pg_coder.c +103 -21
- data/ext/pg_connection.c +917 -523
- data/ext/pg_copy_coder.c +50 -12
- data/ext/pg_record_coder.c +491 -0
- data/ext/pg_result.c +590 -208
- data/ext/pg_text_decoder.c +606 -40
- data/ext/pg_text_encoder.c +245 -94
- data/ext/pg_tuple.c +549 -0
- data/ext/pg_type_map.c +14 -7
- data/ext/pg_type_map_all_strings.c +4 -4
- data/ext/pg_type_map_by_class.c +9 -4
- data/ext/pg_type_map_by_column.c +7 -6
- data/ext/pg_type_map_by_mri_type.c +1 -1
- data/ext/pg_type_map_by_oid.c +3 -2
- data/ext/pg_type_map_in_ruby.c +1 -1
- data/ext/{util.c → pg_util.c} +10 -10
- data/ext/{util.h → pg_util.h} +2 -2
- data/lib/pg.rb +23 -13
- data/lib/pg/basic_type_mapping.rb +155 -32
- data/lib/pg/binary_decoder.rb +23 -0
- data/lib/pg/coder.rb +23 -2
- data/lib/pg/connection.rb +73 -13
- data/lib/pg/constants.rb +2 -1
- data/lib/pg/exceptions.rb +2 -1
- data/lib/pg/result.rb +24 -7
- data/lib/pg/text_decoder.rb +24 -22
- data/lib/pg/text_encoder.rb +40 -8
- data/lib/pg/tuple.rb +30 -0
- data/lib/pg/type_map_by_column.rb +3 -2
- data/spec/helpers.rb +61 -36
- data/spec/pg/basic_type_mapping_spec.rb +415 -36
- data/spec/pg/connection_spec.rb +732 -327
- data/spec/pg/connection_sync_spec.rb +41 -0
- data/spec/pg/result_spec.rb +253 -21
- data/spec/pg/tuple_spec.rb +333 -0
- data/spec/pg/type_map_by_class_spec.rb +4 -4
- data/spec/pg/type_map_by_column_spec.rb +6 -2
- data/spec/pg/type_map_by_mri_type_spec.rb +2 -2
- data/spec/pg/type_map_by_oid_spec.rb +3 -3
- data/spec/pg/type_map_in_ruby_spec.rb +1 -1
- data/spec/pg/type_map_spec.rb +1 -1
- data/spec/pg/type_spec.rb +446 -20
- data/spec/pg_spec.rb +2 -2
- metadata +63 -72
- metadata.gz.sig +0 -0
- data/sample/array_insert.rb +0 -20
- data/sample/async_api.rb +0 -106
- data/sample/async_copyto.rb +0 -39
- data/sample/async_mixed.rb +0 -56
- data/sample/check_conn.rb +0 -21
- data/sample/copyfrom.rb +0 -81
- data/sample/copyto.rb +0 -19
- data/sample/cursor.rb +0 -21
- data/sample/disk_usage_report.rb +0 -186
- data/sample/issue-119.rb +0 -94
- data/sample/losample.rb +0 -69
- data/sample/minimal-testcase.rb +0 -17
- data/sample/notify_wait.rb +0 -72
- data/sample/pg_statistics.rb +0 -294
- data/sample/replication_monitor.rb +0 -231
- data/sample/test_binary_values.rb +0 -33
- data/sample/wal_shipper.rb +0 -434
- data/sample/warehouse_partitions.rb +0 -320
data/spec/helpers.rb
CHANGED
@@ -1,11 +1,13 @@
|
|
1
|
-
|
1
|
+
# -*- ruby -*-
|
2
2
|
|
3
3
|
require 'pathname'
|
4
4
|
require 'rspec'
|
5
5
|
require 'shellwords'
|
6
6
|
require 'pg'
|
7
7
|
|
8
|
-
|
8
|
+
DEFAULT_TEST_DIR_STR = File.join(Dir.pwd, "tmp_test_specs")
|
9
|
+
TEST_DIR_STR = ENV['RUBY_PG_TEST_DIR'] || DEFAULT_TEST_DIR_STR
|
10
|
+
TEST_DIRECTORY = Pathname.new(TEST_DIR_STR)
|
9
11
|
|
10
12
|
module PG::TestingHelpers
|
11
13
|
|
@@ -20,12 +22,11 @@ module PG::TestingHelpers
|
|
20
22
|
|
21
23
|
mod.around( :each ) do |example|
|
22
24
|
begin
|
25
|
+
@conn.set_default_encoding
|
23
26
|
@conn.exec( 'BEGIN' ) unless example.metadata[:without_transaction]
|
24
|
-
|
25
|
-
|
26
|
-
@conn.
|
27
|
-
[@conn.escape_string(desc.slice(-60))]
|
28
|
-
end
|
27
|
+
desc = example.source_location.join(':')
|
28
|
+
@conn.exec %Q{SET application_name TO '%s'} %
|
29
|
+
[@conn.escape_string(desc.slice(-60))]
|
29
30
|
example.run
|
30
31
|
ensure
|
31
32
|
@conn.exec( 'ROLLBACK' ) unless example.metadata[:without_transaction]
|
@@ -171,18 +172,18 @@ module PG::TestingHelpers
|
|
171
172
|
datadir = testdir + 'data'
|
172
173
|
pidfile = datadir + 'postmaster.pid'
|
173
174
|
if pidfile.exist? && pid = pidfile.read.chomp.to_i
|
174
|
-
|
175
|
+
trace "pidfile (%p) exists: %d" % [ pidfile, pid ]
|
175
176
|
begin
|
176
177
|
Process.kill( 0, pid )
|
177
178
|
rescue Errno::ESRCH
|
178
|
-
|
179
|
+
trace "No postmaster running for %s" % [ datadir ]
|
179
180
|
# Process isn't alive, so don't try to stop it
|
180
181
|
else
|
181
|
-
|
182
|
+
trace "Stopping lingering database at PID %d" % [ pid ]
|
182
183
|
run 'pg_ctl', '-D', datadir.to_s, '-m', 'fast', 'stop'
|
183
184
|
end
|
184
185
|
else
|
185
|
-
|
186
|
+
trace "No pidfile (%p)" % [ pidfile ]
|
186
187
|
end
|
187
188
|
end
|
188
189
|
end
|
@@ -193,12 +194,12 @@ module PG::TestingHelpers
|
|
193
194
|
require 'pg'
|
194
195
|
stop_existing_postmasters()
|
195
196
|
|
196
|
-
|
197
|
+
trace "Setting up test database for #{description}"
|
197
198
|
@test_pgdata = TEST_DIRECTORY + 'data'
|
198
199
|
@test_pgdata.mkpath
|
199
200
|
|
200
|
-
|
201
|
-
ENV['PGPORT']
|
201
|
+
ENV['PGPORT'] ||= "54321"
|
202
|
+
@port = ENV['PGPORT'].to_i
|
202
203
|
ENV['PGHOST'] = 'localhost'
|
203
204
|
@conninfo = "host=localhost port=#{@port} dbname=test"
|
204
205
|
|
@@ -208,7 +209,7 @@ module PG::TestingHelpers
|
|
208
209
|
begin
|
209
210
|
unless (@test_pgdata+"postgresql.conf").exist?
|
210
211
|
FileUtils.rm_rf( @test_pgdata, :verbose => $DEBUG )
|
211
|
-
|
212
|
+
trace "Running initdb"
|
212
213
|
log_and_run @logfile, 'initdb', '-E', 'UTF8', '--no-locale', '-D', @test_pgdata.to_s
|
213
214
|
end
|
214
215
|
|
@@ -217,14 +218,14 @@ module PG::TestingHelpers
|
|
217
218
|
'-D', @test_pgdata.to_s, 'start'
|
218
219
|
sleep 2
|
219
220
|
|
220
|
-
|
221
|
+
trace "Creating the test DB"
|
221
222
|
log_and_run @logfile, 'psql', '-e', '-c', 'DROP DATABASE IF EXISTS test', 'postgres'
|
222
223
|
log_and_run @logfile, 'createdb', '-e', 'test'
|
223
224
|
|
224
225
|
rescue => err
|
225
226
|
$stderr.puts "%p during test setup: %s" % [ err.class, err.message ]
|
226
227
|
$stderr.puts "See #{@logfile} for details."
|
227
|
-
$stderr.puts
|
228
|
+
$stderr.puts err.backtrace if $DEBUG
|
228
229
|
fail
|
229
230
|
end
|
230
231
|
|
@@ -238,7 +239,7 @@ module PG::TestingHelpers
|
|
238
239
|
|
239
240
|
|
240
241
|
def teardown_testing_db( conn )
|
241
|
-
|
242
|
+
trace "Tearing down test database"
|
242
243
|
|
243
244
|
if conn
|
244
245
|
check_for_lingering_connections( conn )
|
@@ -251,7 +252,7 @@ module PG::TestingHelpers
|
|
251
252
|
|
252
253
|
def check_for_lingering_connections( conn )
|
253
254
|
conn.exec( "SELECT * FROM pg_stat_activity" ) do |res|
|
254
|
-
conns = res.find_all {|row| row['pid'].to_i != conn.backend_pid }
|
255
|
+
conns = res.find_all {|row| row['pid'].to_i != conn.backend_pid && ["client backend", nil].include?(row["backend_type"]) }
|
255
256
|
unless conns.empty?
|
256
257
|
puts "Lingering connections remain:"
|
257
258
|
conns.each do |row|
|
@@ -264,7 +265,7 @@ module PG::TestingHelpers
|
|
264
265
|
|
265
266
|
# Retrieve the names of the column types of a given result set.
|
266
267
|
def result_typenames(res)
|
267
|
-
@conn.
|
268
|
+
@conn.exec_params( "SELECT " + res.nfields.times.map{|i| "format_type($#{i*2+1},$#{i*2+2})"}.join(","),
|
268
269
|
res.nfields.times.map{|i| [res.ftype(i), res.fmod(i)] }.flatten ).
|
269
270
|
values[0]
|
270
271
|
end
|
@@ -318,6 +319,39 @@ module PG::TestingHelpers
|
|
318
319
|
return ConnStillUsableMatcher.new
|
319
320
|
end
|
320
321
|
|
322
|
+
def wait_for_polling_ok(conn, meth = :connect_poll)
|
323
|
+
status = conn.send(meth)
|
324
|
+
|
325
|
+
while status != PG::PGRES_POLLING_OK
|
326
|
+
if status == PG::PGRES_POLLING_READING
|
327
|
+
select( [conn.socket_io], [], [], 5.0 ) or
|
328
|
+
raise "Asynchronous connection timed out!"
|
329
|
+
|
330
|
+
elsif status == PG::PGRES_POLLING_WRITING
|
331
|
+
select( [], [conn.socket_io], [], 5.0 ) or
|
332
|
+
raise "Asynchronous connection timed out!"
|
333
|
+
end
|
334
|
+
status = conn.send(meth)
|
335
|
+
end
|
336
|
+
end
|
337
|
+
|
338
|
+
def wait_for_query_result(conn)
|
339
|
+
result = nil
|
340
|
+
loop do
|
341
|
+
# Buffer any incoming data on the socket until a full result is ready.
|
342
|
+
conn.consume_input
|
343
|
+
while conn.is_busy
|
344
|
+
select( [conn.socket_io], nil, nil, 5.0 ) or
|
345
|
+
raise "Timeout waiting for query response."
|
346
|
+
conn.consume_input
|
347
|
+
end
|
348
|
+
|
349
|
+
# Fetch the next result. If there isn't one, the query is finished
|
350
|
+
result = conn.get_result || break
|
351
|
+
end
|
352
|
+
result
|
353
|
+
end
|
354
|
+
|
321
355
|
end
|
322
356
|
|
323
357
|
|
@@ -336,20 +370,11 @@ RSpec.configure do |config|
|
|
336
370
|
else
|
337
371
|
config.filter_run_excluding :windows
|
338
372
|
end
|
339
|
-
config.filter_run_excluding :socket_io unless
|
340
|
-
PG::Connection.instance_methods.map( &:to_sym ).include?( :socket_io )
|
341
|
-
|
342
|
-
config.filter_run_excluding :postgresql_90 unless
|
343
|
-
PG::Connection.instance_methods.map( &:to_sym ).include?( :escape_literal )
|
344
|
-
|
345
|
-
if !PG.respond_to?( :library_version )
|
346
|
-
config.filter_run_excluding( :postgresql_91, :postgresql_92, :postgresql_93, :postgresql_94 )
|
347
|
-
elsif PG.library_version < 90200
|
348
|
-
config.filter_run_excluding( :postgresql_92, :postgresql_93, :postgresql_94 )
|
349
|
-
elsif PG.library_version < 90300
|
350
|
-
config.filter_run_excluding( :postgresql_93, :postgresql_94 )
|
351
|
-
elsif PG.library_version < 90400
|
352
|
-
config.filter_run_excluding( :postgresql_94 )
|
353
|
-
end
|
354
|
-
end
|
355
373
|
|
374
|
+
config.filter_run_excluding( :postgresql_93 ) if PG.library_version < 90300
|
375
|
+
config.filter_run_excluding( :postgresql_94 ) if PG.library_version < 90400
|
376
|
+
config.filter_run_excluding( :postgresql_95 ) if PG.library_version < 90500
|
377
|
+
config.filter_run_excluding( :postgresql_96 ) if PG.library_version < 90600
|
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
|
+
end
|
@@ -1,9 +1,25 @@
|
|
1
|
-
|
1
|
+
# -*- rspec -*-
|
2
2
|
# encoding: utf-8
|
3
3
|
|
4
4
|
require_relative '../helpers'
|
5
5
|
|
6
6
|
require 'pg'
|
7
|
+
require 'time'
|
8
|
+
|
9
|
+
def restore_type(types)
|
10
|
+
[0, 1].each do |format|
|
11
|
+
[types].flatten.each do |type|
|
12
|
+
PG::BasicTypeRegistry.alias_type(format, "restore_#{type}", type)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
yield
|
16
|
+
ensure
|
17
|
+
[0, 1].each do |format|
|
18
|
+
[types].flatten.each do |type|
|
19
|
+
PG::BasicTypeRegistry.alias_type(format, type, "restore_#{type}")
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
7
23
|
|
8
24
|
describe 'Basic type mapping' do
|
9
25
|
|
@@ -16,8 +32,8 @@ describe 'Basic type mapping' do
|
|
16
32
|
# Encoding Examples
|
17
33
|
#
|
18
34
|
|
19
|
-
it "should do basic param encoding"
|
20
|
-
res = @conn.exec_params( "SELECT $1::int8
|
35
|
+
it "should do basic param encoding" do
|
36
|
+
res = @conn.exec_params( "SELECT $1::int8, $2::float, $3, $4::TEXT",
|
21
37
|
[1, 2.1, true, "b"], nil, basic_type_mapping )
|
22
38
|
|
23
39
|
expect( res.values ).to eq( [
|
@@ -27,21 +43,168 @@ describe 'Basic type mapping' do
|
|
27
43
|
expect( result_typenames(res) ).to eq( ['bigint', 'double precision', 'boolean', 'text'] )
|
28
44
|
end
|
29
45
|
|
30
|
-
it "should do
|
31
|
-
res = @conn.exec_params( "SELECT $1
|
32
|
-
|
33
|
-
|
34
|
-
|
46
|
+
it "should do basic Time encoding" do
|
47
|
+
res = @conn.exec_params( "SELECT $1 AT TIME ZONE '-02'",
|
48
|
+
[Time.new(2019, 12, 8, 20, 38, 12.123, "-01:00")], nil, basic_type_mapping )
|
49
|
+
|
50
|
+
expect( res.values ).to eq( [[ "2019-12-08 23:38:12.123" ]] )
|
51
|
+
end
|
52
|
+
|
53
|
+
it "should do basic param encoding of various float values" do
|
54
|
+
res = @conn.exec_params( "SELECT $1::float, $2::float, $3::float, $4::float, $5::float, $6::float, $7::float, $8::float, $9::float, $10::float, $11::float, $12::float",
|
55
|
+
[0, 7, 9, 0.1, 0.9, -0.11, 10.11,
|
56
|
+
9876543210987654321e-400,
|
57
|
+
9876543210987654321e400,
|
58
|
+
-1.234567890123456789e-280,
|
59
|
+
-1.234567890123456789e280,
|
60
|
+
9876543210987654321e280
|
61
|
+
], nil, basic_type_mapping )
|
62
|
+
|
63
|
+
expect( res.values[0][0, 9] ).to eq(
|
64
|
+
[ "0", "7", "9", "0.1", "0.9", "-0.11", "10.11", "0", "Infinity" ]
|
65
|
+
)
|
66
|
+
|
67
|
+
expect( res.values[0][9] ).to match( /^-1\.2345678901234\d*e\-280$/ )
|
68
|
+
expect( res.values[0][10] ).to match( /^-1\.2345678901234\d*e\+280$/ )
|
69
|
+
expect( res.values[0][11] ).to match( /^9\.8765432109876\d*e\+298$/ )
|
70
|
+
|
71
|
+
expect( result_typenames(res) ).to eq( ['double precision'] * 12 )
|
72
|
+
end
|
73
|
+
|
74
|
+
it "should do default array-as-array param encoding" do
|
75
|
+
expect( basic_type_mapping.encode_array_as).to eq(:array)
|
76
|
+
res = @conn.exec_params( "SELECT $1,$2,$3,$4,$5,$6", [
|
77
|
+
[1, 2, 3], # Integer -> bigint[]
|
78
|
+
[[1, 2], [3, nil]], # Integer two dimensions -> bigint[]
|
79
|
+
[1.11, 2.21], # Float -> double precision[]
|
80
|
+
['/,"'.gsub("/", "\\"), nil, 'abcäöü'], # String -> text[]
|
81
|
+
[BigDecimal("123.45")], # BigDecimal -> numeric[]
|
82
|
+
[IPAddr.new('1234::5678')], # IPAddr -> inet[]
|
35
83
|
], nil, basic_type_mapping )
|
36
84
|
|
37
85
|
expect( res.values ).to eq( [[
|
38
|
-
'{1,2,3}',
|
86
|
+
'{1,2,3}',
|
87
|
+
'{{1,2},{3,NULL}}',
|
39
88
|
'{1.11,2.21}',
|
40
89
|
'{"//,/"",NULL,abcäöü}'.gsub("/", "\\"),
|
90
|
+
'{123.45}',
|
91
|
+
'{1234::5678}',
|
92
|
+
]] )
|
93
|
+
|
94
|
+
expect( result_typenames(res) ).to eq( ['bigint[]', 'bigint[]', 'double precision[]', 'text[]', 'numeric[]', 'inet[]'] )
|
95
|
+
end
|
96
|
+
|
97
|
+
it "should do default array-as-array param encoding with Time objects" do
|
98
|
+
res = @conn.exec_params( "SELECT $1", [
|
99
|
+
[Time.new(2019, 12, 8, 20, 38, 12.123, "-01:00")], # Time -> timestamptz[]
|
100
|
+
], nil, basic_type_mapping )
|
101
|
+
|
102
|
+
expect( res.values[0][0] ).to match( /\{\"2019-12-08 \d\d:38:12.123[+-]\d\d\"\}/ )
|
103
|
+
expect( result_typenames(res) ).to eq( ['timestamp with time zone[]'] )
|
104
|
+
end
|
105
|
+
|
106
|
+
it "should do array-as-json encoding" do
|
107
|
+
basic_type_mapping.encode_array_as = :json
|
108
|
+
expect( basic_type_mapping.encode_array_as).to eq(:json)
|
109
|
+
|
110
|
+
res = @conn.exec_params( "SELECT $1::JSON, $2::JSON", [
|
111
|
+
[1, {a: 5}, true, ["a", 2], [3.4, nil]],
|
112
|
+
['/,"'.gsub("/", "\\"), nil, 'abcäöü'],
|
113
|
+
], nil, basic_type_mapping )
|
114
|
+
|
115
|
+
expect( res.values ).to eq( [[
|
116
|
+
'[1,{"a":5},true,["a",2],[3.4,null]]',
|
117
|
+
'["//,/"",null,"abcäöü"]'.gsub("/", "\\"),
|
118
|
+
]] )
|
119
|
+
|
120
|
+
expect( result_typenames(res) ).to eq( ['json', 'json'] )
|
121
|
+
end
|
122
|
+
|
123
|
+
it "should do hash-as-json encoding" do
|
124
|
+
res = @conn.exec_params( "SELECT $1::JSON, $2::JSON", [
|
125
|
+
{a: 5, b: ["a", 2], c: nil},
|
126
|
+
{qu: '/,"'.gsub("/", "\\"), ni: nil, uml: 'abcäöü'},
|
127
|
+
], nil, basic_type_mapping )
|
128
|
+
|
129
|
+
expect( res.values ).to eq( [[
|
130
|
+
'{"a":5,"b":["a",2],"c":null}',
|
131
|
+
'{"qu":"//,/"","ni":null,"uml":"abcäöü"}'.gsub("/", "\\"),
|
132
|
+
]] )
|
133
|
+
|
134
|
+
expect( result_typenames(res) ).to eq( ['json', 'json'] )
|
135
|
+
end
|
136
|
+
|
137
|
+
describe "Record encoding" do
|
138
|
+
before :all do
|
139
|
+
@conn.exec("CREATE TYPE test_record1 AS (i int, d float, t text)")
|
140
|
+
@conn.exec("CREATE TYPE test_record2 AS (i int, r test_record1)")
|
141
|
+
end
|
142
|
+
|
143
|
+
after :all do
|
144
|
+
@conn.exec("DROP TYPE IF EXISTS test_record2 CASCADE")
|
145
|
+
@conn.exec("DROP TYPE IF EXISTS test_record1 CASCADE")
|
146
|
+
end
|
147
|
+
|
148
|
+
it "should do array-as-record encoding" do
|
149
|
+
basic_type_mapping.encode_array_as = :record
|
150
|
+
expect( basic_type_mapping.encode_array_as).to eq(:record)
|
151
|
+
|
152
|
+
res = @conn.exec_params( "SELECT $1::test_record1, $2::test_record2, $3::text", [
|
153
|
+
[5, 3.4, "txt"],
|
154
|
+
[1, [2, 4.5, "bcd"]],
|
155
|
+
[4, 5, 6],
|
156
|
+
], nil, basic_type_mapping )
|
157
|
+
|
158
|
+
expect( res.values ).to eq( [[
|
159
|
+
'(5,3.4,txt)',
|
160
|
+
'(1,"(2,4.5,bcd)")',
|
161
|
+
'("4","5","6")',
|
162
|
+
]] )
|
163
|
+
|
164
|
+
expect( result_typenames(res) ).to eq( ['test_record1', 'test_record2', 'text'] )
|
165
|
+
end
|
166
|
+
end
|
167
|
+
|
168
|
+
it "should do bigdecimal param encoding" do
|
169
|
+
large = ('123456790'*10) << '.' << ('012345679')
|
170
|
+
res = @conn.exec_params( "SELECT $1::numeric,$2::numeric",
|
171
|
+
[BigDecimal('1'), BigDecimal(large)], nil, basic_type_mapping )
|
172
|
+
|
173
|
+
expect( res.values ).to eq( [
|
174
|
+
[ "1.0", large ],
|
175
|
+
] )
|
176
|
+
|
177
|
+
expect( result_typenames(res) ).to eq( ['numeric', 'numeric'] )
|
178
|
+
end
|
179
|
+
|
180
|
+
it "should do IPAddr param encoding" do
|
181
|
+
res = @conn.exec_params( "SELECT $1::inet,$2::inet,$3::cidr,$4::cidr",
|
182
|
+
['1.2.3.4', IPAddr.new('1234::5678'), '1.2.3.4', IPAddr.new('1234:5678::/32')], nil, basic_type_mapping )
|
183
|
+
|
184
|
+
expect( res.values ).to eq( [
|
185
|
+
[ '1.2.3.4', '1234::5678', '1.2.3.4/32', '1234:5678::/32'],
|
186
|
+
] )
|
187
|
+
|
188
|
+
expect( result_typenames(res) ).to eq( ['inet', 'inet', 'cidr', 'cidr'] )
|
189
|
+
end
|
190
|
+
|
191
|
+
it "should do array of string encoding on unknown classes" do
|
192
|
+
iv = Class.new do
|
193
|
+
def to_s
|
194
|
+
"abc"
|
195
|
+
end
|
196
|
+
end.new
|
197
|
+
res = @conn.exec_params( "SELECT $1", [
|
198
|
+
[iv, iv], # Unknown -> text[]
|
199
|
+
], nil, basic_type_mapping )
|
200
|
+
|
201
|
+
expect( res.values ).to eq( [[
|
202
|
+
'{abc,abc}',
|
41
203
|
]] )
|
42
204
|
|
43
|
-
expect( result_typenames(res) ).to eq( ['
|
205
|
+
expect( result_typenames(res) ).to eq( ['text[]'] )
|
44
206
|
end
|
207
|
+
|
45
208
|
end
|
46
209
|
|
47
210
|
|
@@ -55,7 +218,7 @@ describe 'Basic type mapping' do
|
|
55
218
|
# Decoding Examples
|
56
219
|
#
|
57
220
|
|
58
|
-
it "should do OID based type conversions"
|
221
|
+
it "should do OID based type conversions" do
|
59
222
|
res = @conn.exec( "SELECT 1, 'a', 2.0::FLOAT, TRUE, '2013-06-30'::DATE, generate_series(4,5)" )
|
60
223
|
expect( res.map_types!(basic_type_mapping).values ).to eq( [
|
61
224
|
[ 1, 'a', 2.0, true, Date.new(2013,6,30), 4 ],
|
@@ -78,14 +241,14 @@ describe 'Basic type mapping' do
|
|
78
241
|
|
79
242
|
it "should do boolean type conversions" do
|
80
243
|
[1, 0].each do |format|
|
81
|
-
res = @conn.
|
244
|
+
res = @conn.exec_params( "SELECT true::BOOLEAN, false::BOOLEAN, NULL::BOOLEAN", [], format )
|
82
245
|
expect( res.values ).to eq( [[true, false, nil]] )
|
83
246
|
end
|
84
247
|
end
|
85
248
|
|
86
249
|
it "should do binary type conversions" do
|
87
250
|
[1, 0].each do |format|
|
88
|
-
res = @conn.
|
251
|
+
res = @conn.exec_params( "SELECT E'\\\\000\\\\377'::BYTEA", [], format )
|
89
252
|
expect( res.values ).to eq( [[["00ff"].pack("H*")]] )
|
90
253
|
expect( res.values[0][0].encoding ).to eq( Encoding::ASCII_8BIT ) if Object.const_defined? :Encoding
|
91
254
|
end
|
@@ -93,7 +256,7 @@ describe 'Basic type mapping' do
|
|
93
256
|
|
94
257
|
it "should do integer type conversions" do
|
95
258
|
[1, 0].each do |format|
|
96
|
-
res = @conn.
|
259
|
+
res = @conn.exec_params( "SELECT -8999::INT2, -899999999::INT4, -8999999999999999999::INT8", [], format )
|
97
260
|
expect( res.values ).to eq( [[-8999, -899999999, -8999999999999999999]] )
|
98
261
|
end
|
99
262
|
end
|
@@ -101,7 +264,7 @@ describe 'Basic type mapping' do
|
|
101
264
|
it "should do string type conversions" do
|
102
265
|
@conn.internal_encoding = 'utf-8' if Object.const_defined? :Encoding
|
103
266
|
[1, 0].each do |format|
|
104
|
-
res = @conn.
|
267
|
+
res = @conn.exec_params( "SELECT 'abcäöü'::TEXT", [], format )
|
105
268
|
expect( res.values ).to eq( [['abcäöü']] )
|
106
269
|
expect( res.values[0][0].encoding ).to eq( Encoding::UTF_8 ) if Object.const_defined? :Encoding
|
107
270
|
end
|
@@ -109,7 +272,7 @@ describe 'Basic type mapping' do
|
|
109
272
|
|
110
273
|
it "should do float type conversions" do
|
111
274
|
[1, 0].each do |format|
|
112
|
-
res = @conn.
|
275
|
+
res = @conn.exec_params( "SELECT -8.999e3::FLOAT4,
|
113
276
|
8.999e10::FLOAT4,
|
114
277
|
-8999999999e-99::FLOAT8,
|
115
278
|
NULL::FLOAT4,
|
@@ -127,35 +290,107 @@ describe 'Basic type mapping' do
|
|
127
290
|
end
|
128
291
|
end
|
129
292
|
|
130
|
-
it "should do datetime without time zone type conversions" do
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
293
|
+
it "should do text datetime without time zone type conversions" do
|
294
|
+
# for backward compat text timestamps without time zone are treated as local times
|
295
|
+
res = @conn.exec_params( "SELECT CAST('2013-12-31 23:58:59+02' AS TIMESTAMP WITHOUT TIME ZONE),
|
296
|
+
CAST('1913-12-31 23:58:59.1231-03' AS TIMESTAMP WITHOUT TIME ZONE),
|
297
|
+
CAST('4714-11-24 23:58:59.1231-03 BC' AS TIMESTAMP WITHOUT TIME ZONE),
|
298
|
+
CAST('294276-12-31 23:58:59.1231-03' AS TIMESTAMP WITHOUT TIME ZONE),
|
299
|
+
CAST('infinity' AS TIMESTAMP WITHOUT TIME ZONE),
|
300
|
+
CAST('-infinity' AS TIMESTAMP WITHOUT TIME ZONE)", [], 0 )
|
301
|
+
expect( res.getvalue(0,0) ).to eq( Time.new(2013, 12, 31, 23, 58, 59) )
|
302
|
+
expect( res.getvalue(0,1).iso8601(3) ).to eq( Time.new(1913, 12, 31, 23, 58, 59.1231).iso8601(3) )
|
303
|
+
expect( res.getvalue(0,2).iso8601(3) ).to eq( Time.new(-4713, 11, 24, 23, 58, 59.1231).iso8601(3) )
|
304
|
+
expect( res.getvalue(0,3).iso8601(3) ).to eq( Time.new(294276, 12, 31, 23, 58, 59.1231).iso8601(3) )
|
305
|
+
expect( res.getvalue(0,4) ).to eq( 'infinity' )
|
306
|
+
expect( res.getvalue(0,5) ).to eq( '-infinity' )
|
307
|
+
end
|
308
|
+
|
309
|
+
[1, 0].each do |format|
|
310
|
+
it "should convert format #{format} timestamps per TimestampUtc" do
|
311
|
+
restore_type("timestamp") do
|
312
|
+
PG::BasicTypeRegistry.register_type 0, 'timestamp', nil, PG::TextDecoder::TimestampUtc
|
313
|
+
@conn.type_map_for_results = PG::BasicTypeMapForResults.new(@conn)
|
314
|
+
res = @conn.exec_params( "SELECT CAST('2013-07-31 23:58:59+02' AS TIMESTAMP WITHOUT TIME ZONE),
|
315
|
+
CAST('1913-12-31 23:58:59.1231-03' AS TIMESTAMP WITHOUT TIME ZONE),
|
316
|
+
CAST('4714-11-24 23:58:59.1231-03 BC' AS TIMESTAMP WITHOUT TIME ZONE),
|
317
|
+
CAST('294276-12-31 23:58:59.1231-03' AS TIMESTAMP WITHOUT TIME ZONE),
|
318
|
+
CAST('infinity' AS TIMESTAMP WITHOUT TIME ZONE),
|
319
|
+
CAST('-infinity' AS TIMESTAMP WITHOUT TIME ZONE)", [], format )
|
320
|
+
expect( res.getvalue(0,0).iso8601(3) ).to eq( Time.utc(2013, 7, 31, 23, 58, 59).iso8601(3) )
|
321
|
+
expect( res.getvalue(0,1).iso8601(3) ).to eq( Time.utc(1913, 12, 31, 23, 58, 59.1231).iso8601(3) )
|
322
|
+
expect( res.getvalue(0,2).iso8601(3) ).to eq( Time.utc(-4713, 11, 24, 23, 58, 59.1231).iso8601(3) )
|
323
|
+
expect( res.getvalue(0,3).iso8601(3) ).to eq( Time.utc(294276, 12, 31, 23, 58, 59.1231).iso8601(3) )
|
324
|
+
expect( res.getvalue(0,4) ).to eq( 'infinity' )
|
325
|
+
expect( res.getvalue(0,5) ).to eq( '-infinity' )
|
326
|
+
end
|
140
327
|
end
|
141
328
|
end
|
142
329
|
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
330
|
+
[1, 0].each do |format|
|
331
|
+
it "should convert format #{format} timestamps per TimestampUtcToLocal" do
|
332
|
+
restore_type("timestamp") do
|
333
|
+
PG::BasicTypeRegistry.register_type 0, 'timestamp', nil, PG::TextDecoder::TimestampUtcToLocal
|
334
|
+
PG::BasicTypeRegistry.register_type 1, 'timestamp', nil, PG::BinaryDecoder::TimestampUtcToLocal
|
335
|
+
@conn.type_map_for_results = PG::BasicTypeMapForResults.new(@conn)
|
336
|
+
res = @conn.exec_params( "SELECT CAST('2013-07-31 23:58:59+02' AS TIMESTAMP WITHOUT TIME ZONE),
|
337
|
+
CAST('1913-12-31 23:58:59.1231-03' AS TIMESTAMP WITHOUT TIME ZONE),
|
338
|
+
CAST('4714-11-24 23:58:59.1231-03 BC' AS TIMESTAMP WITHOUT TIME ZONE),
|
339
|
+
CAST('294276-12-31 23:58:59.1231-03' AS TIMESTAMP WITHOUT TIME ZONE),
|
340
|
+
CAST('infinity' AS TIMESTAMP WITHOUT TIME ZONE),
|
341
|
+
CAST('-infinity' AS TIMESTAMP WITHOUT TIME ZONE)", [], format )
|
342
|
+
expect( res.getvalue(0,0).iso8601(3) ).to eq( Time.utc(2013, 7, 31, 23, 58, 59).getlocal.iso8601(3) )
|
343
|
+
expect( res.getvalue(0,1).iso8601(3) ).to eq( Time.utc(1913, 12, 31, 23, 58, 59.1231).getlocal.iso8601(3) )
|
344
|
+
expect( res.getvalue(0,2).iso8601(3) ).to eq( Time.utc(-4713, 11, 24, 23, 58, 59.1231).getlocal.iso8601(3) )
|
345
|
+
expect( res.getvalue(0,3).iso8601(3) ).to eq( Time.utc(294276, 12, 31, 23, 58, 59.1231).getlocal.iso8601(3) )
|
346
|
+
expect( res.getvalue(0,4) ).to eq( 'infinity' )
|
347
|
+
expect( res.getvalue(0,5) ).to eq( '-infinity' )
|
348
|
+
end
|
349
|
+
end
|
350
|
+
end
|
351
|
+
|
352
|
+
[1, 0].each do |format|
|
353
|
+
it "should convert format #{format} timestamps per TimestampLocal" do
|
354
|
+
restore_type("timestamp") do
|
355
|
+
PG::BasicTypeRegistry.register_type 0, 'timestamp', nil, PG::TextDecoder::TimestampLocal
|
356
|
+
PG::BasicTypeRegistry.register_type 1, 'timestamp', nil, PG::BinaryDecoder::TimestampLocal
|
357
|
+
@conn.type_map_for_results = PG::BasicTypeMapForResults.new(@conn)
|
358
|
+
res = @conn.exec_params( "SELECT CAST('2013-07-31 23:58:59' AS TIMESTAMP WITHOUT TIME ZONE),
|
359
|
+
CAST('1913-12-31 23:58:59.1231' AS TIMESTAMP WITHOUT TIME ZONE),
|
360
|
+
CAST('4714-11-24 23:58:59.1231-03 BC' AS TIMESTAMP WITHOUT TIME ZONE),
|
361
|
+
CAST('294276-12-31 23:58:59.1231+03' AS TIMESTAMP WITHOUT TIME ZONE),
|
362
|
+
CAST('infinity' AS TIMESTAMP WITHOUT TIME ZONE),
|
363
|
+
CAST('-infinity' AS TIMESTAMP WITHOUT TIME ZONE)", [], format )
|
364
|
+
expect( res.getvalue(0,0).iso8601(3) ).to eq( Time.new(2013, 7, 31, 23, 58, 59).iso8601(3) )
|
365
|
+
expect( res.getvalue(0,1).iso8601(3) ).to eq( Time.new(1913, 12, 31, 23, 58, 59.1231).iso8601(3) )
|
366
|
+
expect( res.getvalue(0,2).iso8601(3) ).to eq( Time.new(-4713, 11, 24, 23, 58, 59.1231).iso8601(3) )
|
367
|
+
expect( res.getvalue(0,3).iso8601(3) ).to eq( Time.new(294276, 12, 31, 23, 58, 59.1231).iso8601(3) )
|
368
|
+
expect( res.getvalue(0,4) ).to eq( 'infinity' )
|
369
|
+
expect( res.getvalue(0,5) ).to eq( '-infinity' )
|
370
|
+
end
|
371
|
+
end
|
372
|
+
end
|
373
|
+
|
374
|
+
[0, 1].each do |format|
|
375
|
+
it "should convert format #{format} timestamps with time zone" do
|
376
|
+
res = @conn.exec_params( "SELECT CAST('2013-12-31 23:58:59+02' AS TIMESTAMP WITH TIME ZONE),
|
377
|
+
CAST('1913-12-31 23:58:59.1231-03' AS TIMESTAMP WITH TIME ZONE),
|
378
|
+
CAST('4714-11-24 23:58:59.1231-03 BC' AS TIMESTAMP WITH TIME ZONE),
|
379
|
+
CAST('294276-12-31 23:58:59.1231+03' AS TIMESTAMP WITH TIME ZONE),
|
147
380
|
CAST('infinity' AS TIMESTAMP WITH TIME ZONE),
|
148
381
|
CAST('-infinity' AS TIMESTAMP WITH TIME ZONE)", [], format )
|
149
|
-
expect( res.getvalue(0,0) ).to
|
150
|
-
expect( res.getvalue(0,1) ).to be_within(1e-3).of(Time.new(1913, 12, 31, 23, 58, 59.
|
151
|
-
expect( res.getvalue(0,2) ).to
|
152
|
-
expect( res.getvalue(0,3) ).to
|
382
|
+
expect( res.getvalue(0,0) ).to be_within(1e-3).of( Time.new(2013, 12, 31, 23, 58, 59, "+02:00").getlocal )
|
383
|
+
expect( res.getvalue(0,1) ).to be_within(1e-3).of( Time.new(1913, 12, 31, 23, 58, 59.1231, "-03:00").getlocal )
|
384
|
+
expect( res.getvalue(0,2) ).to be_within(1e-3).of( Time.new(-4713, 11, 24, 23, 58, 59.1231, "-03:00").getlocal )
|
385
|
+
expect( res.getvalue(0,3) ).to be_within(1e-3).of( Time.new(294276, 12, 31, 23, 58, 59.1231, "+03:00").getlocal )
|
386
|
+
expect( res.getvalue(0,4) ).to eq( 'infinity' )
|
387
|
+
expect( res.getvalue(0,5) ).to eq( '-infinity' )
|
153
388
|
end
|
154
389
|
end
|
155
390
|
|
156
391
|
it "should do date type conversions" do
|
157
392
|
[0].each do |format|
|
158
|
-
res = @conn.
|
393
|
+
res = @conn.exec_params( "SELECT CAST('2113-12-31' AS DATE),
|
159
394
|
CAST('1913-12-31' AS DATE),
|
160
395
|
CAST('infinity' AS DATE),
|
161
396
|
CAST('-infinity' AS DATE)", [], format )
|
@@ -166,9 +401,51 @@ describe 'Basic type mapping' do
|
|
166
401
|
end
|
167
402
|
end
|
168
403
|
|
404
|
+
it "should do numeric type conversions" do
|
405
|
+
[0].each do |format|
|
406
|
+
small = '123456790123.12'
|
407
|
+
large = ('123456790'*10) << '.' << ('012345679')
|
408
|
+
numerics = [
|
409
|
+
'1',
|
410
|
+
'1.0',
|
411
|
+
'1.2',
|
412
|
+
small,
|
413
|
+
large,
|
414
|
+
]
|
415
|
+
sql_numerics = numerics.map { |v| "CAST(#{v} AS numeric)" }
|
416
|
+
res = @conn.exec_params( "SELECT #{sql_numerics.join(',')}", [], format )
|
417
|
+
expect( res.getvalue(0,0) ).to eq( BigDecimal('1') )
|
418
|
+
expect( res.getvalue(0,1) ).to eq( BigDecimal('1') )
|
419
|
+
expect( res.getvalue(0,2) ).to eq( BigDecimal('1.2') )
|
420
|
+
expect( res.getvalue(0,3) ).to eq( BigDecimal(small) )
|
421
|
+
expect( res.getvalue(0,4) ).to eq( BigDecimal(large) )
|
422
|
+
end
|
423
|
+
end
|
424
|
+
|
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
|
+
|
169
446
|
it "should do array type conversions" do
|
170
447
|
[0].each do |format|
|
171
|
-
res = @conn.
|
448
|
+
res = @conn.exec_params( "SELECT CAST('{1,2,3}' AS INT2[]), CAST('{{1,2},{3,4}}' AS INT2[][]),
|
172
449
|
CAST('{1,2,3}' AS INT4[]),
|
173
450
|
CAST('{1,2,3}' AS INT8[]),
|
174
451
|
CAST('{1,2,3}' AS TEXT[]),
|
@@ -186,6 +463,75 @@ describe 'Basic type mapping' do
|
|
186
463
|
expect( res.getvalue(0,7) ).to eq( [1.0,2.0,3.0] )
|
187
464
|
end
|
188
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
|
189
535
|
end
|
190
536
|
|
191
537
|
context "with usage of result oids for copy decoder selection" do
|
@@ -228,6 +574,39 @@ describe 'Basic type mapping' do
|
|
228
574
|
res = @conn.exec( "SELECT * FROM copytable" )
|
229
575
|
expect( res.values ).to eq( [['a', '123', '{5,4,3}'], ['b', '234', '{2,3}']] )
|
230
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
|
231
610
|
end
|
232
611
|
|
233
612
|
context "with usage of result oids for copy encoder selection" do
|