pg 1.0.0 → 1.1.0.pre20180730144600
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- checksums.yaml.gz.sig +0 -0
- data.tar.gz.sig +0 -0
- data/ChangeLog +0 -6595
- data/History.rdoc +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
|