pg 0.18.4-x86-mingw32 → 0.19.0.pre20160817083826-x86-mingw32
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- checksums.yaml.gz.sig +0 -0
- data.tar.gz.sig +0 -0
- data/ChangeLog +686 -167
- data/History.rdoc +23 -0
- data/README.rdoc +6 -6
- data/Rakefile +10 -12
- data/Rakefile.cross +6 -6
- data/ext/errorcodes.def +16 -0
- data/ext/errorcodes.txt +5 -1
- data/ext/extconf.rb +9 -1
- data/ext/gvl_wrappers.h +4 -0
- data/ext/pg.c +1 -1
- data/ext/pg.h +6 -3
- data/ext/pg_binary_decoder.c +1 -1
- data/ext/pg_binary_encoder.c +8 -8
- data/ext/pg_coder.c +30 -9
- data/ext/pg_connection.c +203 -77
- data/ext/pg_copy_coder.c +34 -4
- data/ext/pg_result.c +2 -2
- data/ext/pg_text_decoder.c +1 -1
- data/ext/pg_text_encoder.c +62 -42
- data/ext/pg_type_map.c +1 -1
- data/ext/pg_type_map_all_strings.c +1 -1
- data/ext/pg_type_map_by_class.c +1 -1
- data/ext/pg_type_map_by_column.c +1 -1
- data/ext/pg_type_map_by_mri_type.c +1 -1
- data/ext/pg_type_map_by_oid.c +1 -1
- data/ext/pg_type_map_in_ruby.c +1 -1
- data/ext/util.c +1 -1
- data/lib/1.9/pg_ext.so +0 -0
- data/lib/2.0/pg_ext.so +0 -0
- data/lib/2.1/pg_ext.so +0 -0
- data/lib/2.2/pg_ext.so +0 -0
- data/lib/2.3/pg_ext.so +0 -0
- data/lib/libpq.dll +0 -0
- data/lib/pg.rb +3 -3
- data/lib/pg/basic_type_mapping.rb +35 -8
- data/lib/pg/connection.rb +46 -6
- data/lib/pg/result.rb +6 -2
- data/lib/pg/text_decoder.rb +7 -0
- data/lib/pg/text_encoder.rb +8 -0
- data/sample/disk_usage_report.rb +1 -1
- data/sample/pg_statistics.rb +1 -1
- data/sample/replication_monitor.rb +1 -1
- data/spec/helpers.rb +6 -9
- data/spec/pg/basic_type_mapping_spec.rb +54 -0
- data/spec/pg/connection_spec.rb +130 -23
- data/spec/pg/type_map_by_class_spec.rb +1 -1
- data/spec/pg/type_map_by_mri_type_spec.rb +1 -1
- data/spec/pg/type_spec.rb +82 -2
- metadata +33 -35
- metadata.gz.sig +0 -0
- data/lib/i386-mingw32/libpq.dll +0 -0
data/ext/pg_type_map_in_ruby.c
CHANGED
data/ext/util.c
CHANGED
data/lib/1.9/pg_ext.so
CHANGED
Binary file
|
data/lib/2.0/pg_ext.so
CHANGED
Binary file
|
data/lib/2.1/pg_ext.so
CHANGED
Binary file
|
data/lib/2.2/pg_ext.so
CHANGED
Binary file
|
data/lib/2.3/pg_ext.so
ADDED
Binary file
|
data/lib/libpq.dll
ADDED
Binary file
|
data/lib/pg.rb
CHANGED
@@ -10,7 +10,7 @@ rescue LoadError
|
|
10
10
|
|
11
11
|
# Set the PATH environment variable, so that libpq.dll can be found.
|
12
12
|
old_path = ENV['PATH']
|
13
|
-
ENV['PATH'] = "#{File.expand_path("
|
13
|
+
ENV['PATH'] = "#{File.expand_path("..", __FILE__)};#{old_path}"
|
14
14
|
require "#{major_minor}/pg_ext"
|
15
15
|
ENV['PATH'] = old_path
|
16
16
|
else
|
@@ -24,10 +24,10 @@ end
|
|
24
24
|
module PG
|
25
25
|
|
26
26
|
# Library version
|
27
|
-
VERSION = '0.
|
27
|
+
VERSION = '0.19.0.pre20160817083826'
|
28
28
|
|
29
29
|
# VCS revision
|
30
|
-
REVISION = %q$Revision
|
30
|
+
REVISION = %q$Revision$
|
31
31
|
|
32
32
|
class NotAllCopyDataRetrieved < PG::Error
|
33
33
|
end
|
@@ -188,7 +188,8 @@ module PG::BasicTypeRegistry
|
|
188
188
|
# register_type 'polygon', OID::Text.new
|
189
189
|
# register_type 'circle', OID::Text.new
|
190
190
|
# register_type 'hstore', OID::Hstore.new
|
191
|
-
|
191
|
+
register_type 0, 'json', PG::TextEncoder::JSON, PG::TextDecoder::JSON
|
192
|
+
alias_type 0, 'jsonb', 'json'
|
192
193
|
# register_type 'citext', OID::Text.new
|
193
194
|
# register_type 'ltree', OID::Text.new
|
194
195
|
#
|
@@ -226,8 +227,8 @@ end
|
|
226
227
|
#
|
227
228
|
# Example:
|
228
229
|
# conn = PG::Connection.new
|
229
|
-
# # Assign a default ruleset for type casts of
|
230
|
-
# conn.
|
230
|
+
# # Assign a default ruleset for type casts of output values.
|
231
|
+
# conn.type_map_for_results = PG::BasicTypeMapForResults.new(conn)
|
231
232
|
# # Execute a query.
|
232
233
|
# res = conn.exec_params( "SELECT $1::INT", ['5'] )
|
233
234
|
# # Retrieve and cast the result value. Value format is 0 (text) and OID is 20. Therefore typecasting
|
@@ -236,8 +237,28 @@ end
|
|
236
237
|
#
|
237
238
|
# PG::TypeMapByOid#fit_to_result(result, false) can be used to generate
|
238
239
|
# a result independent PG::TypeMapByColumn type map, which can subsequently be used
|
239
|
-
# to cast #get_copy_data fields
|
240
|
+
# to cast #get_copy_data fields:
|
241
|
+
#
|
242
|
+
# For the following table:
|
243
|
+
# conn.exec( "CREATE TABLE copytable AS VALUES('a', 123, '{5,4,3}'::INT[])" )
|
244
|
+
#
|
245
|
+
# # Retrieve table OIDs per empty result set.
|
246
|
+
# res = conn.exec( "SELECT * FROM copytable LIMIT 0" )
|
247
|
+
# # Build a type map for common database to ruby type decoders.
|
248
|
+
# btm = PG::BasicTypeMapForResults.new(conn)
|
249
|
+
# # Build a PG::TypeMapByColumn with decoders suitable for copytable.
|
250
|
+
# tm = btm.build_column_map( res )
|
251
|
+
# row_decoder = PG::TextDecoder::CopyRow.new type_map: tm
|
252
|
+
#
|
253
|
+
# conn.copy_data( "COPY copytable TO STDOUT", row_decoder ) do |res|
|
254
|
+
# while row=conn.get_copy_data
|
255
|
+
# p row
|
256
|
+
# end
|
257
|
+
# end
|
258
|
+
# This prints the rows with type casted columns:
|
259
|
+
# ["a", 123, [5, 4, 3]]
|
240
260
|
#
|
261
|
+
# See also PG::BasicTypeMapBasedOnResult for the encoder direction.
|
241
262
|
class PG::BasicTypeMapForResults < PG::TypeMapByOid
|
242
263
|
include PG::BasicTypeRegistry
|
243
264
|
|
@@ -290,12 +311,17 @@ end
|
|
290
311
|
#
|
291
312
|
# # Retrieve table OIDs per empty result set.
|
292
313
|
# res = conn.exec( "SELECT * FROM copytable LIMIT 0" )
|
293
|
-
#
|
314
|
+
# # Build a type map for common ruby to database type encoders.
|
315
|
+
# btm = PG::BasicTypeMapBasedOnResult.new(conn)
|
316
|
+
# # Build a PG::TypeMapByColumn with encoders suitable for copytable.
|
317
|
+
# tm = btm.build_column_map( res )
|
294
318
|
# row_encoder = PG::TextEncoder::CopyRow.new type_map: tm
|
295
319
|
#
|
296
320
|
# conn.copy_data( "COPY copytable FROM STDIN", row_encoder ) do |res|
|
297
321
|
# conn.put_copy_data ['a', 123, [5,4,3]]
|
298
322
|
# end
|
323
|
+
# This inserts a single row into copytable with type casts from ruby to
|
324
|
+
# database types.
|
299
325
|
class PG::BasicTypeMapBasedOnResult < PG::TypeMapByOid
|
300
326
|
include PG::BasicTypeRegistry
|
301
327
|
|
@@ -314,15 +340,16 @@ end
|
|
314
340
|
# OIDs of supported type casts are not hard-coded in the sources, but are retrieved from the
|
315
341
|
# PostgreSQL's pg_type table in PG::BasicTypeMapForQueries.new .
|
316
342
|
#
|
317
|
-
# Query params are type casted based on the
|
343
|
+
# Query params are type casted based on the class of the given value.
|
318
344
|
#
|
319
345
|
# Higher level libraries will most likely not make use of this class, but use their
|
320
|
-
# own set of rules to choose suitable
|
346
|
+
# own derivation of PG::TypeMapByClass or another set of rules to choose suitable
|
347
|
+
# encoders and decoders for the values to be sent.
|
321
348
|
#
|
322
349
|
# Example:
|
323
350
|
# conn = PG::Connection.new
|
324
351
|
# # Assign a default ruleset for type casts of input and output values.
|
325
|
-
# conn.
|
352
|
+
# conn.type_map_for_queries = PG::BasicTypeMapForQueries.new(conn)
|
326
353
|
# # Execute a query. The Integer param value is typecasted internally by PG::BinaryEncoder::Int8.
|
327
354
|
# # The format of the parameter is set to 1 (binary) and the OID of this parameter is set to 20 (int8).
|
328
355
|
# res = conn.exec_params( "SELECT $1", [5] )
|
data/lib/pg/connection.rb
CHANGED
@@ -110,12 +110,20 @@ class PG::Connection
|
|
110
110
|
# of #put_copy_data, #get_copy_data and #put_copy_end.
|
111
111
|
#
|
112
112
|
# Example with CSV input format:
|
113
|
-
# conn.exec "create table my_table (a text,b text,c text,d text
|
113
|
+
# conn.exec "create table my_table (a text,b text,c text,d text)"
|
114
114
|
# conn.copy_data "COPY my_table FROM STDIN CSV" do
|
115
|
-
# conn.put_copy_data "some,
|
116
|
-
# conn.put_copy_data "more,
|
115
|
+
# conn.put_copy_data "some,data,to,copy\n"
|
116
|
+
# conn.put_copy_data "more,data,to,copy\n"
|
117
|
+
# end
|
118
|
+
# This creates +my_table+ and inserts two CSV rows.
|
119
|
+
#
|
120
|
+
# The same with text format encoder PG::TextEncoder::CopyRow
|
121
|
+
# and Array input:
|
122
|
+
# enco = PG::TextEncoder::CopyRow.new
|
123
|
+
# conn.copy_data "COPY my_table FROM STDIN", enco do
|
124
|
+
# conn.put_copy_data ['some', 'data', 'to', 'copy']
|
125
|
+
# conn.put_copy_data ['more', 'data', 'to', 'copy']
|
117
126
|
# end
|
118
|
-
# This creates +my_table+ and inserts two rows.
|
119
127
|
#
|
120
128
|
# Example with CSV output format:
|
121
129
|
# conn.copy_data "COPY my_table TO STDOUT CSV" do
|
@@ -124,8 +132,21 @@ class PG::Connection
|
|
124
132
|
# end
|
125
133
|
# end
|
126
134
|
# This prints all rows of +my_table+ to stdout:
|
127
|
-
# "some,
|
128
|
-
# "more,
|
135
|
+
# "some,data,to,copy\n"
|
136
|
+
# "more,data,to,copy\n"
|
137
|
+
#
|
138
|
+
# The same with text format decoder PG::TextDecoder::CopyRow
|
139
|
+
# and Array output:
|
140
|
+
# deco = PG::TextDecoder::CopyRow.new
|
141
|
+
# conn.copy_data "COPY my_table TO STDOUT", deco do
|
142
|
+
# while row=conn.get_copy_data
|
143
|
+
# p row
|
144
|
+
# end
|
145
|
+
# end
|
146
|
+
# This receives all rows of +my_table+ as ruby array:
|
147
|
+
# ["some", "data", "to", "copy"]
|
148
|
+
# ["more", "data", "to", "copy"]
|
149
|
+
|
129
150
|
def copy_data( sql, coder=nil )
|
130
151
|
res = exec( sql )
|
131
152
|
|
@@ -224,8 +245,27 @@ class PG::Connection
|
|
224
245
|
end
|
225
246
|
end
|
226
247
|
|
248
|
+
# Method 'ssl_attribute' was introduced in PostgreSQL 9.5.
|
249
|
+
if self.instance_methods.find{|m| m.to_sym == :ssl_attribute }
|
250
|
+
# call-seq:
|
251
|
+
# conn.ssl_attributes -> Hash<String,String>
|
252
|
+
#
|
253
|
+
# Returns SSL-related information about the connection as key/value pairs
|
254
|
+
#
|
255
|
+
# The available attributes varies depending on the SSL library being used,
|
256
|
+
# and the type of connection.
|
257
|
+
#
|
258
|
+
# See also #ssl_attribute
|
259
|
+
def ssl_attributes
|
260
|
+
ssl_attribute_names.each.with_object({}) do |n,h|
|
261
|
+
h[n] = ssl_attribute(n)
|
262
|
+
end
|
263
|
+
end
|
264
|
+
end
|
265
|
+
|
227
266
|
end # class PG::Connection
|
228
267
|
|
268
|
+
# :stopdoc:
|
229
269
|
# Backward-compatible alias
|
230
270
|
PGconn = PG::Connection
|
231
271
|
|
data/lib/pg/result.rb
CHANGED
@@ -12,15 +12,19 @@ class PG::Result
|
|
12
12
|
# See PG::BasicTypeMapForResults
|
13
13
|
def map_types!(type_map)
|
14
14
|
self.type_map = type_map
|
15
|
-
self
|
15
|
+
return self
|
16
16
|
end
|
17
17
|
|
18
|
+
|
19
|
+
### Return a String representation of the object suitable for debugging.
|
18
20
|
def inspect
|
19
21
|
str = self.to_s
|
20
22
|
str[-1,0] = " status=#{res_status(result_status)} ntuples=#{ntuples} nfields=#{nfields} cmd_tuples=#{cmd_tuples}"
|
21
|
-
str
|
23
|
+
return str
|
22
24
|
end
|
25
|
+
|
23
26
|
end # class PG::Result
|
24
27
|
|
28
|
+
# :stopdoc:
|
25
29
|
# Backward-compatible alias
|
26
30
|
PGresult = PG::Result
|
data/lib/pg/text_decoder.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
|
3
3
|
require 'date'
|
4
|
+
require 'json'
|
4
5
|
|
5
6
|
module PG
|
6
7
|
module TextDecoder
|
@@ -39,6 +40,12 @@ module PG
|
|
39
40
|
end
|
40
41
|
end
|
41
42
|
end
|
43
|
+
|
44
|
+
class JSON < SimpleDecoder
|
45
|
+
def decode(string, tuple=nil, field=nil)
|
46
|
+
::JSON.load(string)
|
47
|
+
end
|
48
|
+
end
|
42
49
|
end
|
43
50
|
end # module PG
|
44
51
|
|
data/lib/pg/text_encoder.rb
CHANGED
@@ -1,5 +1,7 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
|
3
|
+
require 'json'
|
4
|
+
|
3
5
|
module PG
|
4
6
|
module TextEncoder
|
5
7
|
class Date < SimpleEncoder
|
@@ -22,6 +24,12 @@ module PG
|
|
22
24
|
value.respond_to?(:strftime) ? value.strftime(STRFTIME_ISO_DATETIME_WITH_TIMEZONE) : value
|
23
25
|
end
|
24
26
|
end
|
27
|
+
|
28
|
+
class JSON < SimpleEncoder
|
29
|
+
def encode(value)
|
30
|
+
::JSON.dump(value)
|
31
|
+
end
|
32
|
+
end
|
25
33
|
end
|
26
34
|
end # module PG
|
27
35
|
|
data/sample/disk_usage_report.rb
CHANGED
data/sample/pg_statistics.rb
CHANGED
@@ -36,7 +36,7 @@ end
|
|
36
36
|
###
|
37
37
|
class PGMonitor
|
38
38
|
|
39
|
-
VERSION = %q$Id
|
39
|
+
VERSION = %q$Id$
|
40
40
|
|
41
41
|
# When to consider a slave as 'behind', measured in WAL segments.
|
42
42
|
# The default WAL segment size is 16, so we'll alert after
|
data/spec/helpers.rb
CHANGED
@@ -339,17 +339,14 @@ RSpec.configure do |config|
|
|
339
339
|
config.filter_run_excluding :socket_io unless
|
340
340
|
PG::Connection.instance_methods.map( &:to_sym ).include?( :socket_io )
|
341
341
|
|
342
|
-
|
343
|
-
|
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 )
|
342
|
+
if PG.library_version < 90200
|
343
|
+
config.filter_run_excluding( :postgresql_92, :postgresql_93, :postgresql_94, :postgresql_95 )
|
349
344
|
elsif PG.library_version < 90300
|
350
|
-
config.filter_run_excluding( :postgresql_93, :postgresql_94 )
|
345
|
+
config.filter_run_excluding( :postgresql_93, :postgresql_94, :postgresql_95 )
|
351
346
|
elsif PG.library_version < 90400
|
352
|
-
config.filter_run_excluding( :postgresql_94 )
|
347
|
+
config.filter_run_excluding( :postgresql_94, :postgresql_95 )
|
348
|
+
elsif PG.library_version < 90500
|
349
|
+
config.filter_run_excluding( :postgresql_95 )
|
353
350
|
end
|
354
351
|
end
|
355
352
|
|
@@ -166,6 +166,27 @@ describe 'Basic type mapping' do
|
|
166
166
|
end
|
167
167
|
end
|
168
168
|
|
169
|
+
it "should do JSON conversions", :postgresql_94 do
|
170
|
+
[0].each do |format|
|
171
|
+
['JSON', 'JSONB'].each do |type|
|
172
|
+
res = @conn.exec( "SELECT CAST('123' AS #{type}),
|
173
|
+
CAST('12.3' AS #{type}),
|
174
|
+
CAST('true' AS #{type}),
|
175
|
+
CAST('false' AS #{type}),
|
176
|
+
CAST('null' AS #{type}),
|
177
|
+
CAST('[1, \"a\", null]' AS #{type}),
|
178
|
+
CAST('{\"b\" : [2,3]}' AS #{type})", [], format )
|
179
|
+
expect( res.getvalue(0,0) ).to eq( 123 )
|
180
|
+
expect( res.getvalue(0,1) ).to be_within(0.1).of( 12.3 )
|
181
|
+
expect( res.getvalue(0,2) ).to eq( true )
|
182
|
+
expect( res.getvalue(0,3) ).to eq( false )
|
183
|
+
expect( res.getvalue(0,4) ).to eq( nil )
|
184
|
+
expect( res.getvalue(0,5) ).to eq( [1, "a", nil] )
|
185
|
+
expect( res.getvalue(0,6) ).to eq( {"b" => [2, 3]} )
|
186
|
+
end
|
187
|
+
end
|
188
|
+
end
|
189
|
+
|
169
190
|
it "should do array type conversions" do
|
170
191
|
[0].each do |format|
|
171
192
|
res = @conn.exec( "SELECT CAST('{1,2,3}' AS INT2[]), CAST('{{1,2},{3,4}}' AS INT2[][]),
|
@@ -228,6 +249,39 @@ describe 'Basic type mapping' do
|
|
228
249
|
res = @conn.exec( "SELECT * FROM copytable" )
|
229
250
|
expect( res.values ).to eq( [['a', '123', '{5,4,3}'], ['b', '234', '{2,3}']] )
|
230
251
|
end
|
252
|
+
|
253
|
+
it "can do JSON conversions", :postgresql_94 do
|
254
|
+
['JSON', 'JSONB'].each do |type|
|
255
|
+
sql = "SELECT CAST('123' AS #{type}),
|
256
|
+
CAST('12.3' AS #{type}),
|
257
|
+
CAST('true' AS #{type}),
|
258
|
+
CAST('false' AS #{type}),
|
259
|
+
CAST('null' AS #{type}),
|
260
|
+
CAST('[1, \"a\", null]' AS #{type}),
|
261
|
+
CAST('{\"b\" : [2,3]}' AS #{type})"
|
262
|
+
|
263
|
+
tm = basic_type_mapping.build_column_map( @conn.exec( sql ) )
|
264
|
+
expect( tm.coders.map(&:name) ).to eq( [type.downcase] * 7 )
|
265
|
+
|
266
|
+
res = @conn.exec_params( "SELECT $1, $2, $3, $4, $5, $6, $7",
|
267
|
+
[ 123,
|
268
|
+
12.3,
|
269
|
+
true,
|
270
|
+
false,
|
271
|
+
nil,
|
272
|
+
[1, "a", nil],
|
273
|
+
{"b" => [2, 3]},
|
274
|
+
], 0, tm )
|
275
|
+
|
276
|
+
expect( res.getvalue(0,0) ).to eq( "123" )
|
277
|
+
expect( res.getvalue(0,1) ).to eq( "12.3" )
|
278
|
+
expect( res.getvalue(0,2) ).to eq( "true" )
|
279
|
+
expect( res.getvalue(0,3) ).to eq( "false" )
|
280
|
+
expect( res.getvalue(0,4) ).to eq( nil )
|
281
|
+
expect( res.getvalue(0,5).gsub(" ","") ).to eq( "[1,\"a\",null]" )
|
282
|
+
expect( res.getvalue(0,6).gsub(" ","") ).to eq( "{\"b\":[2,3]}" )
|
283
|
+
end
|
284
|
+
end
|
231
285
|
end
|
232
286
|
|
233
287
|
context "with usage of result oids for copy encoder selection" do
|
data/spec/pg/connection_spec.rb
CHANGED
@@ -684,13 +684,13 @@ describe PG::Connection do
|
|
684
684
|
end
|
685
685
|
|
686
686
|
it "described_class#block should allow a timeout" do
|
687
|
-
@conn.send_query( "select pg_sleep(
|
687
|
+
@conn.send_query( "select pg_sleep(1)" )
|
688
688
|
|
689
689
|
start = Time.now
|
690
|
-
@conn.block( 0.
|
690
|
+
@conn.block( 0.3 )
|
691
691
|
finish = Time.now
|
692
692
|
|
693
|
-
expect( (finish - start) ).to be_within( 0.
|
693
|
+
expect( (finish - start) ).to be_within( 0.2 ).of( 0.3 )
|
694
694
|
end
|
695
695
|
|
696
696
|
|
@@ -725,6 +725,25 @@ describe PG::Connection do
|
|
725
725
|
expect( @conn.conninfo_hash[:dbname] ).to eq( 'test' )
|
726
726
|
end
|
727
727
|
|
728
|
+
describe "connection information related to SSL" do
|
729
|
+
|
730
|
+
it "can retrieve connection's ssl state", :postgresql_95 do
|
731
|
+
expect( @conn.ssl_in_use? ).to be false
|
732
|
+
end
|
733
|
+
|
734
|
+
it "can retrieve connection's ssl attribute_names", :postgresql_95 do
|
735
|
+
expect( @conn.ssl_attribute_names ).to be_a(Array)
|
736
|
+
end
|
737
|
+
|
738
|
+
it "can retrieve a single ssl connection attribute", :postgresql_95 do
|
739
|
+
expect( @conn.ssl_attribute('dbname') ).to eq( nil )
|
740
|
+
end
|
741
|
+
|
742
|
+
it "can retrieve all connection's ssl attributes", :postgresql_95 do
|
743
|
+
expect( @conn.ssl_attributes ).to be_a_kind_of( Hash )
|
744
|
+
end
|
745
|
+
end
|
746
|
+
|
728
747
|
|
729
748
|
it "honors the connect_timeout connection parameter", :postgresql_93 do
|
730
749
|
conn = PG.connect( port: @port, dbname: 'test', connect_timeout: 11 )
|
@@ -1070,8 +1089,8 @@ describe PG::Connection do
|
|
1070
1089
|
res.check
|
1071
1090
|
first_row_time = Time.now unless first_row_time
|
1072
1091
|
end
|
1073
|
-
expect( (Time.now - start_time) ).to be >=
|
1074
|
-
expect( (first_row_time - start_time) ).to be <
|
1092
|
+
expect( (Time.now - start_time) ).to be >= 0.9
|
1093
|
+
expect( (first_row_time - start_time) ).to be < 0.9
|
1075
1094
|
end
|
1076
1095
|
|
1077
1096
|
it "should receive rows before entire query fails" do
|
@@ -1150,51 +1169,137 @@ describe PG::Connection do
|
|
1150
1169
|
end
|
1151
1170
|
|
1152
1171
|
it "uses the client encoding for escaped string" do
|
1153
|
-
original = "
|
1172
|
+
original = "Möhre to\0 escape".encode( "utf-16be" )
|
1154
1173
|
@conn.set_client_encoding( "euc_jp" )
|
1155
1174
|
escaped = @conn.escape( original )
|
1156
1175
|
expect( escaped.encoding ).to eq( Encoding::EUC_JP )
|
1157
|
-
expect( escaped ).to eq( "
|
1176
|
+
expect( escaped ).to eq( "Möhre to".encode(Encoding::EUC_JP) )
|
1158
1177
|
end
|
1159
1178
|
|
1160
1179
|
it "uses the client encoding for escaped literal", :postgresql_90 do
|
1161
|
-
original = "
|
1180
|
+
original = "Möhre to\0 escape".encode( "utf-16be" )
|
1162
1181
|
@conn.set_client_encoding( "euc_jp" )
|
1163
1182
|
escaped = @conn.escape_literal( original )
|
1164
1183
|
expect( escaped.encoding ).to eq( Encoding::EUC_JP )
|
1165
|
-
expect( escaped ).to eq( "'
|
1184
|
+
expect( escaped ).to eq( "'Möhre to'".encode(Encoding::EUC_JP) )
|
1166
1185
|
end
|
1167
1186
|
|
1168
1187
|
it "uses the client encoding for escaped identifier", :postgresql_90 do
|
1169
|
-
original = "
|
1188
|
+
original = "Möhre to\0 escape".encode( "utf-16le" )
|
1170
1189
|
@conn.set_client_encoding( "euc_jp" )
|
1171
1190
|
escaped = @conn.escape_identifier( original )
|
1172
1191
|
expect( escaped.encoding ).to eq( Encoding::EUC_JP )
|
1173
|
-
expect( escaped ).to eq( "\"
|
1192
|
+
expect( escaped ).to eq( "\"Möhre to\"".encode(Encoding::EUC_JP) )
|
1174
1193
|
end
|
1175
1194
|
|
1176
1195
|
it "uses the client encoding for quote_ident" do
|
1177
|
-
original = "
|
1196
|
+
original = "Möhre to\0 escape".encode( "utf-16le" )
|
1178
1197
|
@conn.set_client_encoding( "euc_jp" )
|
1179
1198
|
escaped = @conn.quote_ident( original )
|
1180
1199
|
expect( escaped.encoding ).to eq( Encoding::EUC_JP )
|
1181
|
-
expect( escaped ).to eq( "\"
|
1200
|
+
expect( escaped ).to eq( "\"Möhre to\"".encode(Encoding::EUC_JP) )
|
1182
1201
|
end
|
1183
1202
|
|
1184
1203
|
it "uses the previous string encoding for escaped string" do
|
1185
|
-
original = "
|
1204
|
+
original = "Möhre to\0 escape".encode( "iso-8859-1" )
|
1186
1205
|
@conn.set_client_encoding( "euc_jp" )
|
1187
1206
|
escaped = described_class.escape( original )
|
1188
1207
|
expect( escaped.encoding ).to eq( Encoding::ISO8859_1 )
|
1189
|
-
expect( escaped ).to eq( "
|
1208
|
+
expect( escaped ).to eq( "Möhre to".encode(Encoding::ISO8859_1) )
|
1190
1209
|
end
|
1191
1210
|
|
1192
1211
|
it "uses the previous string encoding for quote_ident" do
|
1193
|
-
original = "
|
1212
|
+
original = "Möhre to\0 escape".encode( "iso-8859-1" )
|
1194
1213
|
@conn.set_client_encoding( "euc_jp" )
|
1195
1214
|
escaped = described_class.quote_ident( original )
|
1196
1215
|
expect( escaped.encoding ).to eq( Encoding::ISO8859_1 )
|
1197
|
-
expect( escaped ).to eq( "\"
|
1216
|
+
expect( escaped.encode ).to eq( "\"Möhre to\"".encode(Encoding::ISO8859_1) )
|
1217
|
+
end
|
1218
|
+
end
|
1219
|
+
|
1220
|
+
describe "respect and convert character encoding of input strings" do
|
1221
|
+
before :each do
|
1222
|
+
@conn.internal_encoding = __ENCODING__
|
1223
|
+
end
|
1224
|
+
|
1225
|
+
it "should convert query string and parameters to #exec_params" do
|
1226
|
+
r = @conn.exec_params("VALUES( $1, $2, $1=$2, 'grün')".encode("utf-16le"),
|
1227
|
+
['grün'.encode('utf-16be'), 'grün'.encode('iso-8859-1')])
|
1228
|
+
expect( r.values ).to eq( [['grün', 'grün', 't', 'grün']] )
|
1229
|
+
end
|
1230
|
+
|
1231
|
+
it "should convert query string and parameters to #async_exec" do
|
1232
|
+
r = @conn.async_exec("VALUES( $1, $2, $1=$2, 'grün')".encode("cp936"),
|
1233
|
+
['grün'.encode('cp850'), 'grün'.encode('utf-16le')])
|
1234
|
+
expect( r.values ).to eq( [['grün', 'grün', 't', 'grün']] )
|
1235
|
+
end
|
1236
|
+
|
1237
|
+
it "should convert query string to #exec" do
|
1238
|
+
r = @conn.exec("SELECT 'grün'".encode("utf-16be"))
|
1239
|
+
expect( r.values ).to eq( [['grün']] )
|
1240
|
+
end
|
1241
|
+
|
1242
|
+
it "should convert query string to #async_exec" do
|
1243
|
+
r = @conn.async_exec("SELECT 'grün'".encode("utf-16le"))
|
1244
|
+
expect( r.values ).to eq( [['grün']] )
|
1245
|
+
end
|
1246
|
+
|
1247
|
+
it "should convert strings and parameters to #prepare and #exec_prepared" do
|
1248
|
+
@conn.prepare("weiß1".encode("utf-16be"), "VALUES( $1, $2, $1=$2, 'grün')".encode("cp850"))
|
1249
|
+
r = @conn.exec_prepared("weiß1".encode("utf-32le"),
|
1250
|
+
['grün'.encode('cp936'), 'grün'.encode('utf-16le')])
|
1251
|
+
expect( r.values ).to eq( [['grün', 'grün', 't', 'grün']] )
|
1252
|
+
end
|
1253
|
+
|
1254
|
+
it "should convert strings to #describe_prepared" do
|
1255
|
+
@conn.prepare("weiß2", "VALUES(123)")
|
1256
|
+
r = @conn.describe_prepared("weiß2".encode("utf-16be"))
|
1257
|
+
expect( r.nfields ).to eq( 1 )
|
1258
|
+
end
|
1259
|
+
|
1260
|
+
it "should convert strings to #describe_portal" do
|
1261
|
+
@conn.exec "DECLARE cörsör CURSOR FOR VALUES(1,2,3)"
|
1262
|
+
r = @conn.describe_portal("cörsör".encode("utf-16le"))
|
1263
|
+
expect( r.nfields ).to eq( 3 )
|
1264
|
+
end
|
1265
|
+
|
1266
|
+
it "should convert query string to #send_query" do
|
1267
|
+
@conn.send_query("VALUES('grün')".encode("utf-16be"))
|
1268
|
+
expect( @conn.get_last_result.values ).to eq( [['grün']] )
|
1269
|
+
end
|
1270
|
+
|
1271
|
+
it "should convert query string and parameters to #send_query" do
|
1272
|
+
@conn.send_query("VALUES( $1, $2, $1=$2, 'grün')".encode("utf-16le"),
|
1273
|
+
['grün'.encode('utf-32be'), 'grün'.encode('iso-8859-1')])
|
1274
|
+
expect( @conn.get_last_result.values ).to eq( [['grün', 'grün', 't', 'grün']] )
|
1275
|
+
end
|
1276
|
+
|
1277
|
+
it "should convert strings and parameters to #send_prepare and #send_query_prepared" do
|
1278
|
+
@conn.send_prepare("weiß3".encode("iso-8859-1"), "VALUES( $1, $2, $1=$2, 'grün')".encode("utf-16be"))
|
1279
|
+
@conn.get_last_result
|
1280
|
+
@conn.send_query_prepared("weiß3".encode("utf-32le"),
|
1281
|
+
['grün'.encode('utf-16le'), 'grün'.encode('iso-8859-1')])
|
1282
|
+
expect( @conn.get_last_result.values ).to eq( [['grün', 'grün', 't', 'grün']] )
|
1283
|
+
end
|
1284
|
+
|
1285
|
+
it "should convert strings to #send_describe_prepared" do
|
1286
|
+
@conn.prepare("weiß4", "VALUES(123)")
|
1287
|
+
@conn.send_describe_prepared("weiß4".encode("utf-16be"))
|
1288
|
+
expect( @conn.get_last_result.nfields ).to eq( 1 )
|
1289
|
+
end
|
1290
|
+
|
1291
|
+
it "should convert strings to #send_describe_portal" do
|
1292
|
+
@conn.exec "DECLARE cörsör CURSOR FOR VALUES(1,2,3)"
|
1293
|
+
@conn.send_describe_portal("cörsör".encode("utf-16le"))
|
1294
|
+
expect( @conn.get_last_result.nfields ).to eq( 3 )
|
1295
|
+
end
|
1296
|
+
|
1297
|
+
it "should convert error string to #put_copy_end" do
|
1298
|
+
@conn.exec( "CREATE TEMP TABLE copytable (col1 TEXT)" )
|
1299
|
+
@conn.exec( "COPY copytable FROM STDIN" )
|
1300
|
+
@conn.put_copy_end("grün".encode("utf-16be"))
|
1301
|
+
expect( @conn.get_result.error_message ).to match(/grün/)
|
1302
|
+
@conn.get_result
|
1198
1303
|
end
|
1199
1304
|
end
|
1200
1305
|
|
@@ -1463,15 +1568,15 @@ describe PG::Connection do
|
|
1463
1568
|
end
|
1464
1569
|
end
|
1465
1570
|
|
1466
|
-
it "can process #copy_data input queries with row encoder" do
|
1571
|
+
it "can process #copy_data input queries with row encoder and respects character encoding" do
|
1467
1572
|
@conn2.exec( "CREATE TEMP TABLE copytable (col1 TEXT)" )
|
1468
1573
|
res2 = @conn2.copy_data( "COPY copytable FROM STDOUT" ) do |res|
|
1469
1574
|
@conn2.put_copy_data [1]
|
1470
|
-
@conn2.put_copy_data ["
|
1575
|
+
@conn2.put_copy_data ["Möhre".encode("utf-16le")]
|
1471
1576
|
end
|
1472
1577
|
|
1473
1578
|
res = @conn2.exec( "SELECT * FROM copytable ORDER BY col1" )
|
1474
|
-
expect( res.values ).to eq( [["1"], ["
|
1579
|
+
expect( res.values ).to eq( [["1"], ["Möhre"]] )
|
1475
1580
|
end
|
1476
1581
|
end
|
1477
1582
|
|
@@ -1513,14 +1618,16 @@ describe PG::Connection do
|
|
1513
1618
|
end
|
1514
1619
|
end
|
1515
1620
|
|
1516
|
-
it "can process #copy_data output with row decoder" do
|
1621
|
+
it "can process #copy_data output with row decoder and respects character encoding" do
|
1622
|
+
@conn2.internal_encoding = Encoding::ISO8859_1
|
1517
1623
|
rows = []
|
1518
|
-
res2 = @conn2.copy_data( "COPY (
|
1624
|
+
res2 = @conn2.copy_data( "COPY (VALUES('1'), ('Möhre')) TO STDOUT".encode("utf-16le") ) do |res|
|
1519
1625
|
while row=@conn2.get_copy_data
|
1520
1626
|
rows << row
|
1521
1627
|
end
|
1522
1628
|
end
|
1523
|
-
expect( rows ).to eq(
|
1629
|
+
expect( rows.last.last.encoding ).to eq( Encoding::ISO8859_1 )
|
1630
|
+
expect( rows ).to eq( [["1"], ["Möhre".encode("iso-8859-1")]] )
|
1524
1631
|
end
|
1525
1632
|
|
1526
1633
|
it "can type cast #copy_data output with explicit decoder" do
|