pg 1.0.0 → 1.1.0.pre20180730144600
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- checksums.yaml.gz.sig +0 -0
- data.tar.gz.sig +0 -0
- data/ChangeLog +0 -6595
- data/History.rdoc +52 -0
- data/README.rdoc +11 -0
- data/Rakefile +1 -1
- data/Rakefile.cross +1 -1
- data/ext/errorcodes.rb +1 -1
- data/ext/extconf.rb +2 -0
- data/ext/pg.c +3 -2
- data/ext/pg.h +33 -5
- data/ext/pg_binary_decoder.c +69 -6
- data/ext/pg_binary_encoder.c +1 -1
- data/ext/pg_coder.c +52 -3
- data/ext/pg_connection.c +290 -103
- data/ext/pg_copy_coder.c +10 -5
- data/ext/pg_result.c +339 -113
- data/ext/pg_text_decoder.c +597 -37
- data/ext/pg_text_encoder.c +1 -1
- data/ext/pg_tuple.c +540 -0
- 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 +6 -6
- data/ext/util.h +2 -2
- data/lib/pg.rb +5 -3
- data/lib/pg/basic_type_mapping.rb +40 -7
- data/lib/pg/coder.rb +1 -1
- data/lib/pg/connection.rb +20 -1
- data/lib/pg/constants.rb +1 -1
- data/lib/pg/exceptions.rb +1 -1
- data/lib/pg/result.rb +1 -1
- data/lib/pg/text_decoder.rb +19 -23
- data/lib/pg/text_encoder.rb +35 -1
- data/lib/pg/type_map_by_column.rb +1 -1
- data/spec/helpers.rb +39 -7
- data/spec/pg/basic_type_mapping_spec.rb +230 -27
- data/spec/pg/connection_spec.rb +116 -77
- data/spec/pg/result_spec.rb +46 -11
- data/spec/pg/type_map_by_class_spec.rb +1 -1
- data/spec/pg/type_map_by_column_spec.rb +1 -1
- data/spec/pg/type_map_by_mri_type_spec.rb +1 -1
- data/spec/pg/type_map_by_oid_spec.rb +1 -1
- 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 +177 -11
- data/spec/pg_spec.rb +1 -1
- metadata +24 -28
- metadata.gz.sig +0 -0
data/spec/pg/result_spec.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
|
1
|
+
# -*- rspec -*-
|
2
2
|
# encoding: utf-8
|
3
3
|
|
4
4
|
require_relative '../helpers'
|
@@ -39,8 +39,8 @@ describe PG::Result do
|
|
39
39
|
expect( e.to_a ).to eq [{'a'=>'1', 'b'=>'2'}]
|
40
40
|
end
|
41
41
|
|
42
|
-
context "result streaming" do
|
43
|
-
it "can iterate over all
|
42
|
+
context "result streaming in single row mode" do
|
43
|
+
it "can iterate over all rows as Hash" do
|
44
44
|
@conn.send_query( "SELECT generate_series(2,4) AS a; SELECT 1 AS b, generate_series(5,6) AS c" )
|
45
45
|
@conn.set_single_row_mode
|
46
46
|
expect(
|
@@ -56,7 +56,7 @@ describe PG::Result do
|
|
56
56
|
expect( @conn.get_result ).to be_nil
|
57
57
|
end
|
58
58
|
|
59
|
-
it "can iterate over all rows
|
59
|
+
it "can iterate over all rows as Array" do
|
60
60
|
@conn.send_query( "SELECT generate_series(2,4) AS a; SELECT 1 AS b, generate_series(5,6) AS c" )
|
61
61
|
@conn.set_single_row_mode
|
62
62
|
expect(
|
@@ -72,6 +72,22 @@ describe PG::Result do
|
|
72
72
|
expect( @conn.get_result ).to be_nil
|
73
73
|
end
|
74
74
|
|
75
|
+
it "can iterate over all rows as PG::Tuple" do
|
76
|
+
@conn.send_query( "SELECT generate_series(2,4) AS a; SELECT 1 AS b, generate_series(5,6) AS c" )
|
77
|
+
@conn.set_single_row_mode
|
78
|
+
tuples = @conn.get_result.stream_each_tuple.to_a
|
79
|
+
expect( tuples[0][0] ).to eq( "2" )
|
80
|
+
expect( tuples[1]["a"] ).to eq( "3" )
|
81
|
+
expect( tuples.size ).to eq( 3 )
|
82
|
+
|
83
|
+
tuples = @conn.get_result.enum_for(:stream_each_tuple).to_a
|
84
|
+
expect( tuples[-1][-1] ).to eq( "6" )
|
85
|
+
expect( tuples[-2]["b"] ).to eq( "1" )
|
86
|
+
expect( tuples.size ).to eq( 2 )
|
87
|
+
|
88
|
+
expect( @conn.get_result ).to be_nil
|
89
|
+
end
|
90
|
+
|
75
91
|
it "complains when not in single row mode" do
|
76
92
|
@conn.send_query( "SELECT generate_series(2,4)" )
|
77
93
|
expect{
|
@@ -96,7 +112,7 @@ describe PG::Result do
|
|
96
112
|
end
|
97
113
|
|
98
114
|
it "inserts nil AS NULL and return NULL as nil" do
|
99
|
-
res = @conn.
|
115
|
+
res = @conn.exec_params("SELECT $1::int AS n", [nil])
|
100
116
|
expect( res[0]['n'] ).to be_nil()
|
101
117
|
end
|
102
118
|
|
@@ -161,7 +177,7 @@ describe PG::Result do
|
|
161
177
|
it "returns the same bytes in binary format that are sent in binary format" do
|
162
178
|
binary_file = File.join(Dir.pwd, 'spec/data', 'random_binary_data')
|
163
179
|
bytes = File.open(binary_file, 'rb').read
|
164
|
-
res = @conn.
|
180
|
+
res = @conn.exec_params('VALUES ($1::bytea)',
|
165
181
|
[ { :value => bytes, :format => 1 } ], 1)
|
166
182
|
expect( res[0]['column1'] ).to eq( bytes )
|
167
183
|
expect( res.getvalue(0,0) ).to eq( bytes )
|
@@ -173,7 +189,7 @@ describe PG::Result do
|
|
173
189
|
binary_file = File.join(Dir.pwd, 'spec/data', 'random_binary_data')
|
174
190
|
bytes = File.open(binary_file, 'rb').read
|
175
191
|
@conn.exec("SET standard_conforming_strings=on")
|
176
|
-
res = @conn.
|
192
|
+
res = @conn.exec_params("VALUES ('#{PG::Connection.escape_bytea(bytes)}'::bytea)", [], 1)
|
177
193
|
expect( res[0]['column1'] ).to eq( bytes )
|
178
194
|
expect( res.getvalue(0,0) ).to eq( bytes )
|
179
195
|
expect( res.values[0][0] ).to eq( bytes )
|
@@ -183,7 +199,7 @@ describe PG::Result do
|
|
183
199
|
it "returns the same bytes in text format that are sent in binary format" do
|
184
200
|
binary_file = File.join(Dir.pwd, 'spec/data', 'random_binary_data')
|
185
201
|
bytes = File.open(binary_file, 'rb').read
|
186
|
-
res = @conn.
|
202
|
+
res = @conn.exec_params('VALUES ($1::bytea)',
|
187
203
|
[ { :value => bytes, :format => 1 } ])
|
188
204
|
expect( PG::Connection.unescape_bytea(res[0]['column1']) ).to eq( bytes )
|
189
205
|
end
|
@@ -194,7 +210,7 @@ describe PG::Result do
|
|
194
210
|
|
195
211
|
out_bytes = nil
|
196
212
|
@conn.exec("SET standard_conforming_strings=on")
|
197
|
-
res = @conn.
|
213
|
+
res = @conn.exec_params("VALUES ('#{PG::Connection.escape_bytea(in_bytes)}'::bytea)", [], 0)
|
198
214
|
out_bytes = PG::Connection.unescape_bytea(res[0]['column1'])
|
199
215
|
expect( out_bytes ).to eq( in_bytes )
|
200
216
|
end
|
@@ -205,10 +221,10 @@ describe PG::Result do
|
|
205
221
|
res = @conn.describe_prepared( 'queryfinder' )
|
206
222
|
|
207
223
|
expect(
|
208
|
-
@conn.
|
224
|
+
@conn.exec_params( 'SELECT format_type($1, -1)', [res.paramtype(0)] ).getvalue( 0, 0 )
|
209
225
|
).to eq( 'name' )
|
210
226
|
expect(
|
211
|
-
@conn.
|
227
|
+
@conn.exec_params( 'SELECT format_type($1, -1)', [res.paramtype(1)] ).getvalue( 0, 0 )
|
212
228
|
).to eq( 'text' )
|
213
229
|
end
|
214
230
|
|
@@ -343,6 +359,24 @@ describe PG::Result do
|
|
343
359
|
expect{ res.field_values(:x) }.to raise_error(TypeError)
|
344
360
|
end
|
345
361
|
|
362
|
+
it "can return the values of a single tuple" do
|
363
|
+
res = @conn.exec( "SELECT 1 AS x, 'a' AS y UNION ALL SELECT 2, 'b'" )
|
364
|
+
expect( res.tuple_values(0) ).to eq( ['1', 'a'] )
|
365
|
+
expect( res.tuple_values(1) ).to eq( ['2', 'b'] )
|
366
|
+
expect{ res.tuple_values(2) }.to raise_error(IndexError)
|
367
|
+
expect{ res.tuple_values(-1) }.to raise_error(IndexError)
|
368
|
+
expect{ res.tuple_values("x") }.to raise_error(TypeError)
|
369
|
+
end
|
370
|
+
|
371
|
+
it "can return the values of a single vary lazy tuple" do
|
372
|
+
res = @conn.exec( "VALUES(1),(2)" )
|
373
|
+
expect( res.tuple(0) ).to be_kind_of( PG::Tuple )
|
374
|
+
expect( res.tuple(1) ).to be_kind_of( PG::Tuple )
|
375
|
+
expect{ res.tuple(2) }.to raise_error(IndexError)
|
376
|
+
expect{ res.tuple(-1) }.to raise_error(IndexError)
|
377
|
+
expect{ res.tuple("x") }.to raise_error(TypeError)
|
378
|
+
end
|
379
|
+
|
346
380
|
it "raises a proper exception for a nonexistant table" do
|
347
381
|
expect {
|
348
382
|
@conn.exec( "SELECT * FROM nonexistant_table" )
|
@@ -436,6 +470,7 @@ describe PG::Result do
|
|
436
470
|
expect( res.enum_for(:each).to_a ).to eq( [{'f' => 123}] )
|
437
471
|
expect( res.column_values(0) ).to eq( [123] )
|
438
472
|
expect( res.field_values('f') ).to eq( [123] )
|
473
|
+
expect( res.tuple_values(0) ).to eq( [123] )
|
439
474
|
end
|
440
475
|
|
441
476
|
it "should be usable for several querys" do
|
data/spec/pg/type_map_spec.rb
CHANGED
data/spec/pg/type_spec.rb
CHANGED
@@ -1,7 +1,8 @@
|
|
1
|
-
|
1
|
+
# -*- rspec -*-
|
2
2
|
# encoding: utf-8
|
3
3
|
|
4
4
|
require 'pg'
|
5
|
+
require 'time'
|
5
6
|
|
6
7
|
|
7
8
|
describe "PG::Type derivations" do
|
@@ -15,6 +16,9 @@ describe "PG::Type derivations" do
|
|
15
16
|
let!(:textdec_string) { PG::TextDecoder::String.new }
|
16
17
|
let!(:textenc_timestamp) { PG::TextEncoder::TimestampWithoutTimeZone.new }
|
17
18
|
let!(:textdec_timestamp) { PG::TextDecoder::TimestampWithoutTimeZone.new }
|
19
|
+
let!(:textenc_timestamputc) { PG::TextEncoder::TimestampUtc.new }
|
20
|
+
let!(:textdec_timestamputc) { PG::TextDecoder::TimestampUtc.new }
|
21
|
+
let!(:textdec_timestampul) { PG::TextDecoder::TimestampUtcToLocal.new }
|
18
22
|
let!(:textenc_timestamptz) { PG::TextEncoder::TimestampWithTimeZone.new }
|
19
23
|
let!(:textdec_timestamptz) { PG::TextDecoder::TimestampWithTimeZone.new }
|
20
24
|
let!(:textenc_bytea) { PG::TextEncoder::Bytea.new }
|
@@ -96,21 +100,35 @@ describe "PG::Type derivations" do
|
|
96
100
|
end
|
97
101
|
|
98
102
|
context 'timestamps' do
|
99
|
-
it 'decodes timestamps without timezone' do
|
100
|
-
expect( textdec_timestamp.decode('2016-01-02 23:23:59.123456') ).
|
101
|
-
to
|
103
|
+
it 'decodes timestamps without timezone as local time' do
|
104
|
+
expect( textdec_timestamp.decode('2016-01-02 23:23:59.123456').iso8601(5) ).
|
105
|
+
to eq( Time.new(2016,1,2, 23,23,59.123456).iso8601(5) )
|
106
|
+
expect( textdec_timestamp.decode('2016-08-02 23:23:59.123456').iso8601(5) ).
|
107
|
+
to eq( Time.new(2016,8,2, 23,23,59.123456).iso8601(5) )
|
108
|
+
end
|
109
|
+
it 'decodes timestamps with UTC time and returns UTC timezone' do
|
110
|
+
expect( textdec_timestamputc.decode('2016-01-02 23:23:59.123456').iso8601(5) ).
|
111
|
+
to eq( Time.utc(2016,1,2, 23,23,59.123456).iso8601(5) )
|
112
|
+
expect( textdec_timestamputc.decode('2016-08-02 23:23:59.123456').iso8601(5) ).
|
113
|
+
to eq( Time.utc(2016,8,2, 23,23,59.123456).iso8601(5) )
|
114
|
+
end
|
115
|
+
it 'decodes timestamps with UTC time and returns local timezone' do
|
116
|
+
expect( textdec_timestampul.decode('2016-01-02 23:23:59.123456').iso8601(5) ).
|
117
|
+
to eq( Time.utc(2016,1,2, 23,23,59.123456).getlocal.iso8601(5) )
|
118
|
+
expect( textdec_timestampul.decode('2016-08-02 23:23:59.123456').iso8601(5) ).
|
119
|
+
to eq( Time.utc(2016,8,2, 23,23,59.123456).getlocal.iso8601(5) )
|
102
120
|
end
|
103
121
|
it 'decodes timestamps with hour timezone' do
|
104
|
-
expect( textdec_timestamptz.decode('
|
105
|
-
to
|
106
|
-
expect( textdec_timestamptz.decode('
|
107
|
-
to
|
122
|
+
expect( textdec_timestamptz.decode('2016-01-02 23:23:59.123456-04').iso8601(5) ).
|
123
|
+
to eq( Time.new(2016,1,2, 23,23,59.123456, "-04:00").iso8601(5) )
|
124
|
+
expect( textdec_timestamptz.decode('2016-08-02 23:23:59.123456+10').iso8601(5) ).
|
125
|
+
to eq( Time.new(2016,8,2, 23,23,59.123456, "+10:00").iso8601(5) )
|
108
126
|
end
|
109
127
|
it 'decodes timestamps with hour:minute timezone' do
|
110
128
|
expect( textdec_timestamptz.decode('2015-01-26 17:26:42.691511-04:15') ).
|
111
129
|
to be_within(0.000001).of( Time.new(2015,01,26, 17, 26, 42.691511, "-04:15") )
|
112
|
-
expect( textdec_timestamptz.decode('2015-
|
113
|
-
to be_within(0.000001).of( Time.new(2015,
|
130
|
+
expect( textdec_timestamptz.decode('2015-07-26 17:26:42.691511-04:30') ).
|
131
|
+
to be_within(0.000001).of( Time.new(2015,07,26, 17, 26, 42.691511, "-04:30") )
|
114
132
|
expect( textdec_timestamptz.decode('2015-01-26 17:26:42.691511+10:45') ).
|
115
133
|
to be_within(0.000001).of( Time.new(2015,01,26, 17, 26, 42.691511, "+10:45") )
|
116
134
|
end
|
@@ -121,6 +139,81 @@ describe "PG::Type derivations" do
|
|
121
139
|
expect( textdec_timestamptz.decode('1916-01-01 00:00:00-00:25:21') ).
|
122
140
|
to be_within(0.000001).of( Time.new(1916, 1, 1, 0, 0, 0, "-00:25:21") )
|
123
141
|
end
|
142
|
+
it 'decodes timestamps with date before 1823' do
|
143
|
+
expect( textdec_timestamp.decode('1822-01-02 23:23:59.123456').iso8601(5) ).
|
144
|
+
to eq( Time.new(1822,01,02, 23, 23, 59.123456).iso8601(5) )
|
145
|
+
expect( textdec_timestamputc.decode('1822-01-02 23:23:59.123456').iso8601(5) ).
|
146
|
+
to eq( Time.utc(1822,01,02, 23, 23, 59.123456).iso8601(5) )
|
147
|
+
expect( textdec_timestampul.decode('1822-01-02 23:23:59.123456').iso8601(5) ).
|
148
|
+
to eq( Time.utc(1822,01,02, 23, 23, 59.123456).getlocal.iso8601(5) )
|
149
|
+
expect( textdec_timestamptz.decode('1822-01-02 23:23:59.123456+04').iso8601(5) ).
|
150
|
+
to eq( Time.new(1822,01,02, 23, 23, 59.123456, "+04:00").iso8601(5) )
|
151
|
+
end
|
152
|
+
it 'decodes timestamps with date after 2116' do
|
153
|
+
expect( textdec_timestamp.decode('2117-01-02 23:23:59.123456').iso8601(5) ).
|
154
|
+
to eq( Time.new(2117,01,02, 23, 23, 59.123456).iso8601(5) )
|
155
|
+
expect( textdec_timestamputc.decode('2117-01-02 23:23:59.123456').iso8601(5) ).
|
156
|
+
to eq( Time.utc(2117,01,02, 23, 23, 59.123456).iso8601(5) )
|
157
|
+
expect( textdec_timestampul.decode('2117-01-02 23:23:59.123456').iso8601(5) ).
|
158
|
+
to eq( Time.utc(2117,01,02, 23, 23, 59.123456).getlocal.iso8601(5) )
|
159
|
+
expect( textdec_timestamptz.decode('2117-01-02 23:23:59.123456+04').iso8601(5) ).
|
160
|
+
to eq( Time.new(2117,01,02, 23, 23, 59.123456, "+04:00").iso8601(5) )
|
161
|
+
end
|
162
|
+
it 'decodes timestamps with variable number of digits for the useconds part' do
|
163
|
+
sec = "59.12345678912345"
|
164
|
+
(4..sec.length).each do |i|
|
165
|
+
expect( textdec_timestamp.decode("2016-01-02 23:23:#{sec[0,i]}") ).
|
166
|
+
to be_within(0.000001).of( Time.new(2016,01,02, 23, 23, sec[0,i].to_f) )
|
167
|
+
end
|
168
|
+
end
|
169
|
+
it 'decodes timestamps with leap-second' do
|
170
|
+
expect( textdec_timestamp.decode('1998-12-31 23:59:60.1234') ).
|
171
|
+
to be_within(0.000001).of( Time.new(1998,12,31, 23, 59, 60.1234) )
|
172
|
+
end
|
173
|
+
|
174
|
+
def textdec_timestamptz_decode_should_fail(str)
|
175
|
+
expect(textdec_timestamptz.decode(str)).to eq(str)
|
176
|
+
end
|
177
|
+
|
178
|
+
it 'fails when the timestamp is an empty string' do
|
179
|
+
textdec_timestamptz_decode_should_fail('')
|
180
|
+
end
|
181
|
+
it 'fails when the timestamp contains values with less digits than expected' do
|
182
|
+
textdec_timestamptz_decode_should_fail('2016-0-02 23:23:59.123456+00:25:21')
|
183
|
+
textdec_timestamptz_decode_should_fail('2016-01-0 23:23:59.123456+00:25:21')
|
184
|
+
textdec_timestamptz_decode_should_fail('2016-01-02 2:23:59.123456+00:25:21')
|
185
|
+
textdec_timestamptz_decode_should_fail('2016-01-02 23:2:59.123456+00:25:21')
|
186
|
+
textdec_timestamptz_decode_should_fail('2016-01-02 23:23:5.123456+00:25:21')
|
187
|
+
textdec_timestamptz_decode_should_fail('2016-01-02 23:23:59.+00:25:21')
|
188
|
+
textdec_timestamptz_decode_should_fail('2016-01-02 23:23:59.123456+0:25:21')
|
189
|
+
textdec_timestamptz_decode_should_fail('2016-01-02 23:23:59.123456+00:2:21')
|
190
|
+
textdec_timestamptz_decode_should_fail('2016-01-02 23:23:59.123456+00:25:2')
|
191
|
+
end
|
192
|
+
it 'fails when the timestamp contains values with more digits than expected' do
|
193
|
+
textdec_timestamptz_decode_should_fail('2016-011-02 23:23:59.123456+00:25:21')
|
194
|
+
textdec_timestamptz_decode_should_fail('2016-01-022 23:23:59.123456+00:25:21')
|
195
|
+
textdec_timestamptz_decode_should_fail('2016-01-02 233:23:59.123456+00:25:21')
|
196
|
+
textdec_timestamptz_decode_should_fail('2016-01-02 23:233:59.123456+00:25:21')
|
197
|
+
textdec_timestamptz_decode_should_fail('2016-01-02 23:23:599.123456+00:25:21')
|
198
|
+
textdec_timestamptz_decode_should_fail('2016-01-02 23:23:59.123456+000:25:21')
|
199
|
+
textdec_timestamptz_decode_should_fail('2016-01-02 23:23:59.123456+00:255:21')
|
200
|
+
textdec_timestamptz_decode_should_fail('2016-01-02 23:23:59.123456+00:25:211')
|
201
|
+
end
|
202
|
+
it 'fails when the timestamp contains values with invalid characters' do
|
203
|
+
str = '2013-01-02 23:23:59.123456+00:25:21'
|
204
|
+
str.length.times do |i|
|
205
|
+
textdec_timestamptz_decode_should_fail(str[0,i] + "x" + str[i+1..-1])
|
206
|
+
end
|
207
|
+
end
|
208
|
+
it 'fails when the timestamp contains leading characters' do
|
209
|
+
textdec_timestamptz_decode_should_fail(' 2016-01-02 23:23:59.123456')
|
210
|
+
end
|
211
|
+
it 'fails when the timestamp contains trailing characters' do
|
212
|
+
textdec_timestamptz_decode_should_fail('2016-01-02 23:23:59.123456 ')
|
213
|
+
end
|
214
|
+
it 'fails when the timestamp contains non ASCII character' do
|
215
|
+
textdec_timestamptz_decode_should_fail('2016-01ª02 23:23:59.123456')
|
216
|
+
end
|
124
217
|
end
|
125
218
|
|
126
219
|
context 'identifier quotation' do
|
@@ -215,6 +308,27 @@ describe "PG::Type derivations" do
|
|
215
308
|
expect( textenc_bytea.encode("\x00\x01\x02\x03\xef".b) ).to eq( "\\x00010203ef" )
|
216
309
|
end
|
217
310
|
|
311
|
+
context 'timestamps' do
|
312
|
+
it 'encodes timestamps without timezone' do
|
313
|
+
expect( textenc_timestamp.encode(Time.new(2016,1,2, 23, 23, 59.123456, 3*60*60)) ).
|
314
|
+
to match( /^2016-01-02 23:23:59.12345\d+$/ )
|
315
|
+
expect( textenc_timestamp.encode(Time.new(2016,8,2, 23, 23, 59.123456, 3*60*60)) ).
|
316
|
+
to match( /^2016-08-02 23:23:59.12345\d+$/ )
|
317
|
+
end
|
318
|
+
it 'encodes timestamps with UTC timezone' do
|
319
|
+
expect( textenc_timestamputc.encode(Time.new(2016,1,2, 23, 23, 59.123456, 3*60*60)) ).
|
320
|
+
to match( /^2016-01-02 20:23:59.12345\d+$/ )
|
321
|
+
expect( textenc_timestamputc.encode(Time.new(2016,8,2, 23, 23, 59.123456, 3*60*60)) ).
|
322
|
+
to match( /^2016-08-02 20:23:59.12345\d+$/ )
|
323
|
+
end
|
324
|
+
it 'encodes timestamps with hour timezone' do
|
325
|
+
expect( textenc_timestamptz.encode(Time.new(2016,1,02, 23, 23, 59.123456, -4*60*60)) ).
|
326
|
+
to match( /^2016-01-02 23:23:59.12345\d+ \-04:00$/ )
|
327
|
+
expect( textenc_timestamptz.encode(Time.new(2016,8,02, 23, 23, 59.123456, 10*60*60)) ).
|
328
|
+
to match( /^2016-08-02 23:23:59.12345\d+ \+10:00$/ )
|
329
|
+
end
|
330
|
+
end
|
331
|
+
|
218
332
|
context 'identifier quotation' do
|
219
333
|
it 'should quote and escape identifier' do
|
220
334
|
quoted_type = PG::TextEncoder::Identifier.new
|
@@ -303,6 +417,7 @@ describe "PG::Type derivations" do
|
|
303
417
|
describe "Array types" do
|
304
418
|
let!(:textenc_string_array) { PG::TextEncoder::Array.new elements_type: textenc_string }
|
305
419
|
let!(:textdec_string_array) { PG::TextDecoder::Array.new elements_type: textdec_string }
|
420
|
+
let!(:textdec_string_array_raise) { PG::TextDecoder::Array.new elements_type: textdec_string, flags: PG::Coder:: FORMAT_ERROR_TO_RAISE }
|
306
421
|
let!(:textenc_int_array) { PG::TextEncoder::Array.new elements_type: textenc_int, needs_quotation: false }
|
307
422
|
let!(:textdec_int_array) { PG::TextDecoder::Array.new elements_type: textdec_int, needs_quotation: false }
|
308
423
|
let!(:textenc_float_array) { PG::TextEncoder::Array.new elements_type: textenc_float, needs_quotation: false }
|
@@ -368,6 +483,57 @@ describe "PG::Type derivations" do
|
|
368
483
|
it 'respects a different delimiter' do
|
369
484
|
expect( textdec_string_array_with_delimiter.decode(%[{1;2;3}]) ).to eq( ['1','2','3'] )
|
370
485
|
end
|
486
|
+
|
487
|
+
it 'ignores array dimensions' do
|
488
|
+
expect( textdec_string_array.decode(%[[2:4]={1,2,3}]) ).to eq( ['1','2','3'] )
|
489
|
+
expect( textdec_string_array.decode(%[[]={1,2,3}]) ).to eq( ['1','2','3'] )
|
490
|
+
expect( textdec_string_array.decode(%[ [-1:+2]= {4,3,2,1}]) ).to eq( ['4','3','2','1'] )
|
491
|
+
end
|
492
|
+
|
493
|
+
it 'ignores spaces after array' do
|
494
|
+
expect( textdec_string_array.decode(%[[2:4]={1,2,3} ]) ).to eq( ['1','2','3'] )
|
495
|
+
expect( textdec_string_array.decode(%[{1,2,3} ]) ).to eq( ['1','2','3'] )
|
496
|
+
end
|
497
|
+
|
498
|
+
describe "with malformed syntax are deprecated" do
|
499
|
+
it 'accepts broken array dimensions' do
|
500
|
+
expect( textdec_string_array.decode(%([2:4={1,2,3})) ).to eq([['1','2','3']])
|
501
|
+
expect( textdec_string_array.decode(%(2:4]={1,2,3})) ).to eq([['1','2','3']])
|
502
|
+
expect( textdec_string_array.decode(%(={1,2,3})) ).to eq([['1','2','3']])
|
503
|
+
expect( textdec_string_array.decode(%([x]={1,2,3})) ).to eq([['1','2','3']])
|
504
|
+
expect( textdec_string_array.decode(%([]{1,2,3})) ).to eq([['1','2','3']])
|
505
|
+
expect( textdec_string_array.decode(%(1,2,3)) ).to eq(['','2'])
|
506
|
+
end
|
507
|
+
|
508
|
+
it 'accepts malformed arrays' do
|
509
|
+
expect( textdec_string_array.decode(%({1,2,3)) ).to eq(['1','2'])
|
510
|
+
expect( textdec_string_array.decode(%({1,2,3}})) ).to eq(['1','2','3'])
|
511
|
+
expect( textdec_string_array.decode(%({1,2,3}x)) ).to eq(['1','2','3'])
|
512
|
+
expect( textdec_string_array.decode(%({{1,2},{2,3})) ).to eq([['1','2'],['2','3']])
|
513
|
+
expect( textdec_string_array.decode(%({{1,2},{2,3}}x)) ).to eq([['1','2'],['2','3']])
|
514
|
+
expect( textdec_string_array.decode(%({[1,2},{2,3}}})) ).to eq(['[1','2'])
|
515
|
+
end
|
516
|
+
end
|
517
|
+
|
518
|
+
describe "with malformed syntax are raised with pg-2.0+" do
|
519
|
+
it 'complains about broken array dimensions' do
|
520
|
+
expect{ textdec_string_array_raise.decode(%([2:4={1,2,3})) }.to raise_error(TypeError)
|
521
|
+
expect{ textdec_string_array_raise.decode(%(2:4]={1,2,3})) }.to raise_error(TypeError)
|
522
|
+
expect{ textdec_string_array_raise.decode(%(={1,2,3})) }.to raise_error(TypeError)
|
523
|
+
expect{ textdec_string_array_raise.decode(%([x]={1,2,3})) }.to raise_error(TypeError)
|
524
|
+
expect{ textdec_string_array_raise.decode(%([]{1,2,3})) }.to raise_error(TypeError)
|
525
|
+
expect{ textdec_string_array_raise.decode(%(1,2,3)) }.to raise_error(TypeError)
|
526
|
+
end
|
527
|
+
|
528
|
+
it 'complains about malformed array' do
|
529
|
+
expect{ textdec_string_array_raise.decode(%({1,2,3)) }.to raise_error(TypeError)
|
530
|
+
expect{ textdec_string_array_raise.decode(%({1,2,3}})) }.to raise_error(TypeError)
|
531
|
+
expect{ textdec_string_array_raise.decode(%({1,2,3}x)) }.to raise_error(TypeError)
|
532
|
+
expect{ textdec_string_array_raise.decode(%({{1,2},{2,3})) }.to raise_error(TypeError)
|
533
|
+
expect{ textdec_string_array_raise.decode(%({{1,2},{2,3}}x)) }.to raise_error(TypeError)
|
534
|
+
expect{ textdec_string_array_raise.decode(%({[1,2},{2,3}}})) }.to raise_error(TypeError)
|
535
|
+
end
|
536
|
+
end
|
371
537
|
end
|
372
538
|
|
373
539
|
context 'bytea' do
|
@@ -746,7 +912,7 @@ describe "PG::Type derivations" do
|
|
746
912
|
end
|
747
913
|
|
748
914
|
describe '#decode' do
|
749
|
-
it "should decode
|
915
|
+
it "should decode COPY text format to array of strings" do
|
750
916
|
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"] )
|
751
917
|
end
|
752
918
|
|
data/spec/pg_spec.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: pg
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0.
|
4
|
+
version: 1.1.0.pre20180730144600
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Michael Granger
|
@@ -11,32 +11,26 @@ bindir: bin
|
|
11
11
|
cert_chain:
|
12
12
|
- |
|
13
13
|
-----BEGIN CERTIFICATE-----
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
DuEzbEMfaOUYjU9RuB48vr4q8yRft0ww+3jq5iwNkrX1buL2pwBbyvgms6D/BV41
|
33
|
-
MaTVMjsHqJUwU2xVfhGtxGAWAer5S1HGYHkbio6mGVtiie0uWjmnzi7ppIlMr48a
|
34
|
-
7BNTsoZ+/JRk3iQWmmNsyFT7xfqBKye7cH11BX8V8P4MeGB5YWlMI+Myj5DZY3fQ
|
35
|
-
st2AGD4rb1l0ia7PfubcBThSIdz61eCb8gRi/RiZZwb3/7+eyEncLJzt2Ob9fGSF
|
36
|
-
X0qdrKi+2aZZ0NGuFj9AItBsVmAvkBGIpX4TEKQp5haEbPpmaqO5nIIhV26PXmyT
|
37
|
-
OMKv6pWsoS81vw5KAGBmfX8nht/Py90DQrbRvakATGI=
|
14
|
+
MIIDLjCCAhagAwIBAgIBBjANBgkqhkiG9w0BAQsFADA9MQ4wDAYDVQQDDAVrYW5p
|
15
|
+
czEXMBUGCgmSJomT8ixkARkWB2NvbWNhcmQxEjAQBgoJkiaJk/IsZAEZFgJkZTAe
|
16
|
+
Fw0xODAzMDUwOTEzNDdaFw0xOTAzMDUwOTEzNDdaMD0xDjAMBgNVBAMMBWthbmlz
|
17
|
+
MRcwFQYKCZImiZPyLGQBGRYHY29tY2FyZDESMBAGCgmSJomT8ixkARkWAmRlMIIB
|
18
|
+
IjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEApop+rNmg35bzRugZ21VMGqI6
|
19
|
+
HGzPLO4VHYncWn/xmgPU/ZMcZdfj6MzIaZJ/czXyt4eHpBk1r8QOV3gBXnRXEjVW
|
20
|
+
9xi+EdVOkTV2/AVFKThcbTAQGiF/bT1n2M+B1GTybRzMg6hyhOJeGPqIhLfJEpxn
|
21
|
+
lJi4+ENAVT4MpqHEAGB8yFoPC0GqiOHQsdHxQV3P3c2OZqG+yJey74QtwA2tLcLn
|
22
|
+
Q53c63+VLGsOjODl1yPn/2ejyq8qWu6ahfTxiIlSar2UbwtaQGBDFdb2CXgEufXT
|
23
|
+
L7oaPxlmj+Q2oLOfOnInd2Oxop59HoJCQPsg8f921J43NCQGA8VHK6paxIRDLQID
|
24
|
+
AQABozkwNzAJBgNVHRMEAjAAMAsGA1UdDwQEAwIEsDAdBgNVHQ4EFgQUvgTdT7fe
|
25
|
+
x17ugO3IOsjEJwW7KP4wDQYJKoZIhvcNAQELBQADggEBAEr2BqIKipd4rQ++Qmxw
|
26
|
+
TU0prQzjlcDLxhQAX4JgmTMbSg8uO+cSvgsROcHfA1Cpo8VDDkZMoGISmfzmMegL
|
27
|
+
QvZJp0Fr1TpeVxexhZq+MnC6OgqJSBfbhHh6DCMX1QAy8fvNzcmEOwRA5d3BYmWK
|
28
|
+
bM8sBrAJGwrNRimekkTGTpYh5+gpiXm9JY07swwL2tR/faH/17IOXxJQ9sMXHNQU
|
29
|
+
In/Pt5lKfMn+h+Ts8GhM91pEJnfwmBc0ksG8tDXAKAAUWIeizjL73bwtiXXeRRlA
|
30
|
+
KtR70pH8rQHNxC2EvqVpBmRChJgWVMlfQofqhU2QK4s+5h52OHGZqMqCAeJ5taum
|
31
|
+
Lvw=
|
38
32
|
-----END CERTIFICATE-----
|
39
|
-
date: 2018-
|
33
|
+
date: 2018-07-30 00:00:00.000000000 Z
|
40
34
|
dependencies:
|
41
35
|
- !ruby/object:Gem::Dependency
|
42
36
|
name: hoe-mercurial
|
@@ -218,6 +212,7 @@ extra_rdoc_files:
|
|
218
212
|
- ext/pg_result.c
|
219
213
|
- ext/pg_text_decoder.c
|
220
214
|
- ext/pg_text_encoder.c
|
215
|
+
- ext/pg_tuple.c
|
221
216
|
- ext/pg_type_map.c
|
222
217
|
- ext/pg_type_map_all_strings.c
|
223
218
|
- ext/pg_type_map_by_class.c
|
@@ -258,6 +253,7 @@ files:
|
|
258
253
|
- ext/pg_result.c
|
259
254
|
- ext/pg_text_decoder.c
|
260
255
|
- ext/pg_text_encoder.c
|
256
|
+
- ext/pg_tuple.c
|
261
257
|
- ext/pg_type_map.c
|
262
258
|
- ext/pg_type_map_all_strings.c
|
263
259
|
- ext/pg_type_map_by_class.c
|
@@ -311,9 +307,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
311
307
|
version: 2.0.0
|
312
308
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
313
309
|
requirements:
|
314
|
-
- - "
|
310
|
+
- - ">"
|
315
311
|
- !ruby/object:Gem::Version
|
316
|
-
version:
|
312
|
+
version: 1.3.1
|
317
313
|
requirements: []
|
318
314
|
rubyforge_project:
|
319
315
|
rubygems_version: 2.7.3
|