pg 0.18.4 → 0.19.0.pre20160409114042
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/ChangeLog +303 -5
- data/README.rdoc +2 -2
- data/Rakefile +10 -10
- data/Rakefile.cross +6 -6
- data/ext/errorcodes.def +16 -0
- data/ext/errorcodes.txt +5 -1
- data/ext/extconf.rb +6 -1
- data/ext/pg.h +6 -3
- data/ext/pg_binary_encoder.c +8 -8
- data/ext/pg_coder.c +30 -9
- data/ext/pg_connection.c +200 -74
- data/ext/pg_copy_coder.c +34 -4
- data/ext/pg_result.c +2 -2
- data/ext/pg_text_encoder.c +62 -42
- data/lib/pg.rb +2 -2
- data/lib/pg/basic_type_mapping.rb +30 -5
- data/lib/pg/connection.rb +46 -6
- data/lib/pg/result.rb +6 -2
- data/spec/helpers.rb +6 -9
- 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 +11 -13
- checksums.yaml.gz.sig +0 -0
- data.tar.gz.sig +0 -0
- data/.gemtest +0 -0
- metadata.gz.sig +0 -0
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/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
|
|
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
|
@@ -102,7 +102,7 @@ describe PG::TypeMapByClass do
|
|
102
102
|
|
103
103
|
it "should allow mixed type conversions" do
|
104
104
|
res = @conn.exec_params( "SELECT $1, $2, $3", [5, 1.23, :TestSymbol], 0, tm )
|
105
|
-
expect( res.values ).to eq([['5', '1.23',
|
105
|
+
expect( res.values ).to eq([['5', '1.23', "[:TestSymbol, #{@conn.internal_encoding.inspect}]"]])
|
106
106
|
expect( res.ftype(0) ).to eq(20)
|
107
107
|
end
|
108
108
|
|
@@ -116,7 +116,7 @@ describe PG::TypeMapByMriType do
|
|
116
116
|
|
117
117
|
it "should allow mixed type conversions" do
|
118
118
|
res = @conn.exec_params( "SELECT $1, $2, $3", [5, 1.23, :TestSymbol], 0, tm )
|
119
|
-
expect( res.values ).to eq([['5', '1.23',
|
119
|
+
expect( res.values ).to eq([['5', '1.23', "[:TestSymbol, #{@conn.internal_encoding.inspect}]"]])
|
120
120
|
expect( res.ftype(0) ).to eq(20)
|
121
121
|
end
|
122
122
|
|
data/spec/pg/type_spec.rb
CHANGED
@@ -39,6 +39,14 @@ describe "PG::Type derivations" do
|
|
39
39
|
end.new
|
40
40
|
end
|
41
41
|
|
42
|
+
let!(:intenc_incrementer_with_encoding) do
|
43
|
+
Class.new(PG::SimpleEncoder) do
|
44
|
+
def encode(value, encoding)
|
45
|
+
r = (value.to_i + 1).to_s + " #{encoding}"
|
46
|
+
r.encode!(encoding)
|
47
|
+
end
|
48
|
+
end.new
|
49
|
+
end
|
42
50
|
let!(:intenc_incrementer_with_int_result) do
|
43
51
|
Class.new(PG::SimpleEncoder) do
|
44
52
|
def encode(value)
|
@@ -127,6 +135,13 @@ describe "PG::Type derivations" do
|
|
127
135
|
expect( quoted_type.decode(%[a.b]) ).to eq( ['a','b'] )
|
128
136
|
expect( quoted_type.decode(%[a]) ).to eq( ['a'] )
|
129
137
|
end
|
138
|
+
|
139
|
+
it 'should split identifier string with correct character encoding' do
|
140
|
+
quoted_type = PG::TextDecoder::Identifier.new
|
141
|
+
v = quoted_type.decode(%[Héllo].encode("iso-8859-1")).first
|
142
|
+
expect( v.encoding ).to eq( Encoding::ISO_8859_1 )
|
143
|
+
expect( v ).to eq( %[Héllo].encode(Encoding::ISO_8859_1) )
|
144
|
+
end
|
130
145
|
end
|
131
146
|
|
132
147
|
it "should raise when decode method is called with wrong args" do
|
@@ -209,6 +224,13 @@ describe "PG::Type derivations" do
|
|
209
224
|
expect( quoted_type.encode( nil ) ).to be_nil
|
210
225
|
end
|
211
226
|
|
227
|
+
it 'should quote identifiers with correct character encoding' do
|
228
|
+
quoted_type = PG::TextEncoder::Identifier.new
|
229
|
+
v = quoted_type.encode(['Héllo'], "iso-8859-1")
|
230
|
+
expect( v ).to eq( %["Héllo"].encode(Encoding::ISO_8859_1) )
|
231
|
+
expect( v.encoding ).to eq( Encoding::ISO_8859_1 )
|
232
|
+
end
|
233
|
+
|
212
234
|
it "will raise a TypeError for invalid arguments to quote_ident" do
|
213
235
|
quoted_type = PG::TextEncoder::Identifier.new
|
214
236
|
expect{ quoted_type.encode( [nil] ) }.to raise_error(TypeError)
|
@@ -220,6 +242,12 @@ describe "PG::Type derivations" do
|
|
220
242
|
expect( intenc_incrementer.encode(3) ).to eq( "4 " )
|
221
243
|
end
|
222
244
|
|
245
|
+
it "should encode with ruby encoder and given character encoding" do
|
246
|
+
r = intenc_incrementer_with_encoding.encode(3, Encoding::CP850)
|
247
|
+
expect( r ).to eq( "4 CP850" )
|
248
|
+
expect( r.encoding ).to eq( Encoding::CP850 )
|
249
|
+
end
|
250
|
+
|
223
251
|
it "should return when ruby encoder returns non string values" do
|
224
252
|
expect( intenc_incrementer_with_int_result.encode(3) ).to eq( 4 )
|
225
253
|
end
|
@@ -447,9 +475,18 @@ describe "PG::Type derivations" do
|
|
447
475
|
end
|
448
476
|
|
449
477
|
context 'array of types with encoder in ruby space' do
|
450
|
-
it 'encodes with quotation' do
|
478
|
+
it 'encodes with quotation and default character encoding' do
|
479
|
+
array_type = PG::TextEncoder::Array.new elements_type: intenc_incrementer, needs_quotation: true
|
480
|
+
r = array_type.encode([3,4])
|
481
|
+
expect( r ).to eq( %[{"4 ","5 "}] )
|
482
|
+
expect( r.encoding ).to eq( Encoding::ASCII_8BIT )
|
483
|
+
end
|
484
|
+
|
485
|
+
it 'encodes with quotation and given character encoding' do
|
451
486
|
array_type = PG::TextEncoder::Array.new elements_type: intenc_incrementer, needs_quotation: true
|
452
|
-
|
487
|
+
r = array_type.encode([3,4], Encoding::CP850)
|
488
|
+
expect( r ).to eq( %[{"4 ","5 "}] )
|
489
|
+
expect( r.encoding ).to eq( Encoding::CP850 )
|
453
490
|
end
|
454
491
|
|
455
492
|
it 'encodes without quotation' do
|
@@ -457,6 +494,20 @@ describe "PG::Type derivations" do
|
|
457
494
|
expect( array_type.encode([3,4]) ).to eq( %[{4 ,5 }] )
|
458
495
|
end
|
459
496
|
|
497
|
+
it 'encodes with default character encoding' do
|
498
|
+
array_type = PG::TextEncoder::Array.new elements_type: intenc_incrementer_with_encoding
|
499
|
+
r = array_type.encode([3,4])
|
500
|
+
expect( r ).to eq( %[{"4 ASCII-8BIT","5 ASCII-8BIT"}] )
|
501
|
+
expect( r.encoding ).to eq( Encoding::ASCII_8BIT )
|
502
|
+
end
|
503
|
+
|
504
|
+
it 'encodes with given character encoding' do
|
505
|
+
array_type = PG::TextEncoder::Array.new elements_type: intenc_incrementer_with_encoding
|
506
|
+
r = array_type.encode([3,4], Encoding::CP850)
|
507
|
+
expect( r ).to eq( %[{"4 CP850","5 CP850"}] )
|
508
|
+
expect( r.encoding ).to eq( Encoding::CP850 )
|
509
|
+
end
|
510
|
+
|
460
511
|
it "should raise when ruby encoder returns non string values" do
|
461
512
|
array_type = PG::TextEncoder::Array.new elements_type: intenc_incrementer_with_int_result, needs_quotation: false
|
462
513
|
expect{ array_type.encode([3,4]) }.to raise_error(TypeError)
|
@@ -473,6 +524,13 @@ describe "PG::Type derivations" do
|
|
473
524
|
quoted_type = PG::TextEncoder::QuotedLiteral.new elements_type: textenc_string_array
|
474
525
|
expect( quoted_type.encode(["'A\",","\\B'"]) ).to eq( %['{"''A\\",","\\\\B''"}'] )
|
475
526
|
end
|
527
|
+
|
528
|
+
it 'should quote literals with correct character encoding' do
|
529
|
+
quoted_type = PG::TextEncoder::QuotedLiteral.new elements_type: textenc_string_array
|
530
|
+
v = quoted_type.encode(["Héllo"], "iso-8859-1")
|
531
|
+
expect( v.encoding ).to eq( Encoding::ISO_8859_1 )
|
532
|
+
expect( v ).to eq( %['{Héllo}'].encode(Encoding::ISO_8859_1) )
|
533
|
+
end
|
476
534
|
end
|
477
535
|
end
|
478
536
|
|
@@ -522,9 +580,19 @@ describe "PG::Type derivations" do
|
|
522
580
|
expect( e.encode("(\xFBm") ).to eq("KPtt")
|
523
581
|
end
|
524
582
|
|
583
|
+
it 'should encode Strings as base64 with correct character encoding' do
|
584
|
+
e = PG::TextEncoder::ToBase64.new
|
585
|
+
v = e.encode("Héllo".encode("utf-16le"), "iso-8859-1")
|
586
|
+
expect( v ).to eq("SOlsbG8=")
|
587
|
+
expect( v.encoding ).to eq(Encoding::ISO_8859_1)
|
588
|
+
end
|
589
|
+
|
525
590
|
it "should encode Strings as base64 in BinaryDecoder" do
|
526
591
|
e = PG::BinaryDecoder::ToBase64.new
|
527
592
|
expect( e.decode("x") ).to eq("eA==")
|
593
|
+
v = e.decode("Héllo".encode("utf-16le"))
|
594
|
+
expect( v ).to eq("SADpAGwAbABvAA==")
|
595
|
+
expect( v.encoding ).to eq(Encoding::ASCII_8BIT)
|
528
596
|
end
|
529
597
|
|
530
598
|
it "should encode Integers as base64" do
|
@@ -611,6 +679,12 @@ describe "PG::Type derivations" do
|
|
611
679
|
expect( encoder.encode([:xyz, 123, 2456, 34567, 456789, 5678901, [1,2,3], 12.1, "abcdefg", nil]) ).
|
612
680
|
to eq("xyz\t123\t2456\t34567\t456789\t5678901\t[1, 2, 3]\t12.1\tabcdefg\t\\N\n")
|
613
681
|
end
|
682
|
+
|
683
|
+
it 'should output a string with correct character encoding' do
|
684
|
+
v = encoder.encode(["Héllo"], "iso-8859-1")
|
685
|
+
expect( v.encoding ).to eq( Encoding::ISO_8859_1 )
|
686
|
+
expect( v ).to eq( "Héllo\n".encode(Encoding::ISO_8859_1) )
|
687
|
+
end
|
614
688
|
end
|
615
689
|
|
616
690
|
context "with TypeMapByClass" do
|
@@ -675,6 +749,12 @@ describe "PG::Type derivations" do
|
|
675
749
|
it "should decode different types of Ruby objects" do
|
676
750
|
expect( decoder.decode("123\t \0#\t#\n#\r#\\ \t234\t#\x01#\002\n".gsub("#", "\\"))).to eq( ["123", " \0\t\n\r\\ ", "234", "\x01\x02"] )
|
677
751
|
end
|
752
|
+
|
753
|
+
it 'should respect input character encoding' do
|
754
|
+
v = decoder.decode("Héllo\n".encode("iso-8859-1")).first
|
755
|
+
expect( v.encoding ).to eq(Encoding::ISO_8859_1)
|
756
|
+
expect( v ).to eq("Héllo".encode("iso-8859-1"))
|
757
|
+
end
|
678
758
|
end
|
679
759
|
end
|
680
760
|
|