pg 0.19.0 → 1.1.0

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.
Files changed (74) hide show
  1. checksums.yaml +5 -5
  2. checksums.yaml.gz.sig +0 -0
  3. data/ChangeLog +218 -1
  4. data/History.rdoc +106 -0
  5. data/Manifest.txt +5 -18
  6. data/README.rdoc +15 -5
  7. data/Rakefile +8 -9
  8. data/Rakefile.cross +19 -22
  9. data/ext/errorcodes.def +17 -0
  10. data/ext/errorcodes.rb +1 -1
  11. data/ext/errorcodes.txt +11 -1
  12. data/ext/extconf.rb +14 -32
  13. data/ext/gvl_wrappers.c +4 -0
  14. data/ext/gvl_wrappers.h +23 -39
  15. data/ext/pg.c +19 -48
  16. data/ext/pg.h +46 -81
  17. data/ext/pg_binary_decoder.c +69 -6
  18. data/ext/pg_coder.c +53 -4
  19. data/ext/pg_connection.c +401 -253
  20. data/ext/pg_copy_coder.c +10 -5
  21. data/ext/pg_result.c +359 -131
  22. data/ext/pg_text_decoder.c +597 -37
  23. data/ext/pg_text_encoder.c +6 -7
  24. data/ext/pg_tuple.c +541 -0
  25. data/ext/pg_type_map.c +14 -7
  26. data/ext/util.c +6 -6
  27. data/ext/util.h +2 -2
  28. data/lib/pg/basic_type_mapping.rb +40 -7
  29. data/lib/pg/binary_decoder.rb +22 -0
  30. data/lib/pg/coder.rb +1 -1
  31. data/lib/pg/connection.rb +27 -7
  32. data/lib/pg/constants.rb +1 -1
  33. data/lib/pg/exceptions.rb +1 -1
  34. data/lib/pg/result.rb +6 -5
  35. data/lib/pg/text_decoder.rb +19 -23
  36. data/lib/pg/text_encoder.rb +36 -2
  37. data/lib/pg/tuple.rb +30 -0
  38. data/lib/pg/type_map_by_column.rb +1 -1
  39. data/lib/pg.rb +21 -11
  40. data/spec/helpers.rb +47 -19
  41. data/spec/pg/basic_type_mapping_spec.rb +230 -27
  42. data/spec/pg/connection_spec.rb +402 -275
  43. data/spec/pg/connection_sync_spec.rb +41 -0
  44. data/spec/pg/result_spec.rb +59 -17
  45. data/spec/pg/tuple_spec.rb +280 -0
  46. data/spec/pg/type_map_by_class_spec.rb +2 -2
  47. data/spec/pg/type_map_by_column_spec.rb +1 -1
  48. data/spec/pg/type_map_by_mri_type_spec.rb +1 -1
  49. data/spec/pg/type_map_by_oid_spec.rb +1 -1
  50. data/spec/pg/type_map_in_ruby_spec.rb +1 -1
  51. data/spec/pg/type_map_spec.rb +1 -1
  52. data/spec/pg/type_spec.rb +184 -12
  53. data/spec/pg_spec.rb +2 -2
  54. data.tar.gz.sig +0 -0
  55. metadata +47 -53
  56. metadata.gz.sig +0 -0
  57. data/sample/array_insert.rb +0 -20
  58. data/sample/async_api.rb +0 -106
  59. data/sample/async_copyto.rb +0 -39
  60. data/sample/async_mixed.rb +0 -56
  61. data/sample/check_conn.rb +0 -21
  62. data/sample/copyfrom.rb +0 -81
  63. data/sample/copyto.rb +0 -19
  64. data/sample/cursor.rb +0 -21
  65. data/sample/disk_usage_report.rb +0 -186
  66. data/sample/issue-119.rb +0 -94
  67. data/sample/losample.rb +0 -69
  68. data/sample/minimal-testcase.rb +0 -17
  69. data/sample/notify_wait.rb +0 -72
  70. data/sample/pg_statistics.rb +0 -294
  71. data/sample/replication_monitor.rb +0 -231
  72. data/sample/test_binary_values.rb +0 -33
  73. data/sample/wal_shipper.rb +0 -434
  74. data/sample/warehouse_partitions.rb +0 -320
data/spec/pg/type_spec.rb CHANGED
@@ -1,7 +1,8 @@
1
- #!/usr/bin/env rspec
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 }
@@ -75,7 +79,7 @@ describe "PG::Type derivations" do
75
79
  expect( intdec_incrementer.decode("3") ).to eq( 4 )
76
80
  end
77
81
 
78
- it "should decode integers of different lengths form text format" do
82
+ it "should decode integers of different lengths from text format" do
79
83
  30.times do |zeros|
80
84
  expect( textdec_int.decode("1" + "0"*zeros) ).to eq( 10 ** zeros )
81
85
  expect( textdec_int.decode(zeros==0 ? "0" : "9"*zeros) ).to eq( 10 ** zeros - 1 )
@@ -96,21 +100,41 @@ 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 be_within(0.000001).of( Time.new(2016,01,02, 23, 23, 59.123456) )
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('2015-01-26 17:26:42.691511-04') ).
105
- to be_within(0.000001).of( Time.new(2015,01,26, 17, 26, 42.691511, "-04:00") )
106
- expect( textdec_timestamptz.decode('2015-01-26 17:26:42.691511+10') ).
107
- to be_within(0.000001).of( Time.new(2015,01,26, 17, 26, 42.691511, "+10:00") )
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) )
126
+ expect( textdec_timestamptz.decode('1913-12-31 23:58:59.1231-03').iso8601(5) ).
127
+ to eq( Time.new(1913, 12, 31, 23, 58, 59.1231, "-03:00").iso8601(5) )
128
+ expect( textdec_timestamptz.decode('4714-11-24 23:58:59.1231-03 BC').iso8601(5) ).
129
+ to eq( Time.new(-4713, 11, 24, 23, 58, 59.1231, "-03:00").iso8601(5) )
130
+ expect( textdec_timestamptz.decode('294276-12-31 23:58:59.1231+03').iso8601(5) ).
131
+ to eq( Time.new(294276, 12, 31, 23, 58, 59.1231, "+03:00").iso8601(5) )
108
132
  end
109
133
  it 'decodes timestamps with hour:minute timezone' do
110
134
  expect( textdec_timestamptz.decode('2015-01-26 17:26:42.691511-04:15') ).
111
135
  to be_within(0.000001).of( Time.new(2015,01,26, 17, 26, 42.691511, "-04:15") )
112
- expect( textdec_timestamptz.decode('2015-01-26 17:26:42.691511-0430') ).
113
- to be_within(0.000001).of( Time.new(2015,01,26, 17, 26, 42.691511, "-04:30") )
136
+ expect( textdec_timestamptz.decode('2015-07-26 17:26:42.691511-04:30') ).
137
+ to be_within(0.000001).of( Time.new(2015,07,26, 17, 26, 42.691511, "-04:30") )
114
138
  expect( textdec_timestamptz.decode('2015-01-26 17:26:42.691511+10:45') ).
115
139
  to be_within(0.000001).of( Time.new(2015,01,26, 17, 26, 42.691511, "+10:45") )
116
140
  end
@@ -121,6 +145,81 @@ describe "PG::Type derivations" do
121
145
  expect( textdec_timestamptz.decode('1916-01-01 00:00:00-00:25:21') ).
122
146
  to be_within(0.000001).of( Time.new(1916, 1, 1, 0, 0, 0, "-00:25:21") )
123
147
  end
148
+ it 'decodes timestamps with date before 1823' do
149
+ expect( textdec_timestamp.decode('1822-01-02 23:23:59.123456').iso8601(5) ).
150
+ to eq( Time.new(1822,01,02, 23, 23, 59.123456).iso8601(5) )
151
+ expect( textdec_timestamputc.decode('1822-01-02 23:23:59.123456').iso8601(5) ).
152
+ to eq( Time.utc(1822,01,02, 23, 23, 59.123456).iso8601(5) )
153
+ expect( textdec_timestampul.decode('1822-01-02 23:23:59.123456').iso8601(5) ).
154
+ to eq( Time.utc(1822,01,02, 23, 23, 59.123456).getlocal.iso8601(5) )
155
+ expect( textdec_timestamptz.decode('1822-01-02 23:23:59.123456+04').iso8601(5) ).
156
+ to eq( Time.new(1822,01,02, 23, 23, 59.123456, "+04:00").iso8601(5) )
157
+ end
158
+ it 'decodes timestamps with date after 2116' do
159
+ expect( textdec_timestamp.decode('2117-01-02 23:23:59.123456').iso8601(5) ).
160
+ to eq( Time.new(2117,01,02, 23, 23, 59.123456).iso8601(5) )
161
+ expect( textdec_timestamputc.decode('2117-01-02 23:23:59.123456').iso8601(5) ).
162
+ to eq( Time.utc(2117,01,02, 23, 23, 59.123456).iso8601(5) )
163
+ expect( textdec_timestampul.decode('2117-01-02 23:23:59.123456').iso8601(5) ).
164
+ to eq( Time.utc(2117,01,02, 23, 23, 59.123456).getlocal.iso8601(5) )
165
+ expect( textdec_timestamptz.decode('2117-01-02 23:23:59.123456+04').iso8601(5) ).
166
+ to eq( Time.new(2117,01,02, 23, 23, 59.123456, "+04:00").iso8601(5) )
167
+ end
168
+ it 'decodes timestamps with variable number of digits for the useconds part' do
169
+ sec = "59.12345678912345"
170
+ (4..sec.length).each do |i|
171
+ expect( textdec_timestamp.decode("2016-01-02 23:23:#{sec[0,i]}") ).
172
+ to be_within(0.000001).of( Time.new(2016,01,02, 23, 23, sec[0,i].to_f) )
173
+ end
174
+ end
175
+ it 'decodes timestamps with leap-second' do
176
+ expect( textdec_timestamp.decode('1998-12-31 23:59:60.1234') ).
177
+ to be_within(0.000001).of( Time.new(1998,12,31, 23, 59, 60.1234) )
178
+ end
179
+
180
+ def textdec_timestamptz_decode_should_fail(str)
181
+ expect(textdec_timestamptz.decode(str)).to eq(str)
182
+ end
183
+
184
+ it 'fails when the timestamp is an empty string' do
185
+ textdec_timestamptz_decode_should_fail('')
186
+ end
187
+ it 'fails when the timestamp contains values with less digits than expected' do
188
+ textdec_timestamptz_decode_should_fail('2016-0-02 23:23:59.123456+00:25:21')
189
+ textdec_timestamptz_decode_should_fail('2016-01-0 23:23:59.123456+00:25:21')
190
+ textdec_timestamptz_decode_should_fail('2016-01-02 2:23:59.123456+00:25:21')
191
+ textdec_timestamptz_decode_should_fail('2016-01-02 23:2:59.123456+00:25:21')
192
+ textdec_timestamptz_decode_should_fail('2016-01-02 23:23:5.123456+00:25:21')
193
+ textdec_timestamptz_decode_should_fail('2016-01-02 23:23:59.+00:25:21')
194
+ textdec_timestamptz_decode_should_fail('2016-01-02 23:23:59.123456+0:25:21')
195
+ textdec_timestamptz_decode_should_fail('2016-01-02 23:23:59.123456+00:2:21')
196
+ textdec_timestamptz_decode_should_fail('2016-01-02 23:23:59.123456+00:25:2')
197
+ end
198
+ it 'fails when the timestamp contains values with more digits than expected' do
199
+ textdec_timestamptz_decode_should_fail('2016-011-02 23:23:59.123456+00:25:21')
200
+ textdec_timestamptz_decode_should_fail('2016-01-022 23:23:59.123456+00:25:21')
201
+ textdec_timestamptz_decode_should_fail('2016-01-02 233:23:59.123456+00:25:21')
202
+ textdec_timestamptz_decode_should_fail('2016-01-02 23:233:59.123456+00:25:21')
203
+ textdec_timestamptz_decode_should_fail('2016-01-02 23:23:599.123456+00:25:21')
204
+ textdec_timestamptz_decode_should_fail('2016-01-02 23:23:59.123456+000:25:21')
205
+ textdec_timestamptz_decode_should_fail('2016-01-02 23:23:59.123456+00:255:21')
206
+ textdec_timestamptz_decode_should_fail('2016-01-02 23:23:59.123456+00:25:211')
207
+ end
208
+ it 'fails when the timestamp contains values with invalid characters' do
209
+ str = '2013-01-02 23:23:59.123456+00:25:21'
210
+ str.length.times do |i|
211
+ textdec_timestamptz_decode_should_fail(str[0,i] + "x" + str[i+1..-1])
212
+ end
213
+ end
214
+ it 'fails when the timestamp contains leading characters' do
215
+ textdec_timestamptz_decode_should_fail(' 2016-01-02 23:23:59.123456')
216
+ end
217
+ it 'fails when the timestamp contains trailing characters' do
218
+ textdec_timestamptz_decode_should_fail('2016-01-02 23:23:59.123456 ')
219
+ end
220
+ it 'fails when the timestamp contains non ASCII character' do
221
+ textdec_timestamptz_decode_should_fail('2016-01ª02 23:23:59.123456')
222
+ end
124
223
  end
125
224
 
126
225
  context 'identifier quotation' do
@@ -215,6 +314,27 @@ describe "PG::Type derivations" do
215
314
  expect( textenc_bytea.encode("\x00\x01\x02\x03\xef".b) ).to eq( "\\x00010203ef" )
216
315
  end
217
316
 
317
+ context 'timestamps' do
318
+ it 'encodes timestamps without timezone' do
319
+ expect( textenc_timestamp.encode(Time.new(2016,1,2, 23, 23, 59.123456, 3*60*60)) ).
320
+ to match( /^2016-01-02 23:23:59.12345\d+$/ )
321
+ expect( textenc_timestamp.encode(Time.new(2016,8,2, 23, 23, 59.123456, 3*60*60)) ).
322
+ to match( /^2016-08-02 23:23:59.12345\d+$/ )
323
+ end
324
+ it 'encodes timestamps with UTC timezone' do
325
+ expect( textenc_timestamputc.encode(Time.new(2016,1,2, 23, 23, 59.123456, 3*60*60)) ).
326
+ to match( /^2016-01-02 20:23:59.12345\d+$/ )
327
+ expect( textenc_timestamputc.encode(Time.new(2016,8,2, 23, 23, 59.123456, 3*60*60)) ).
328
+ to match( /^2016-08-02 20:23:59.12345\d+$/ )
329
+ end
330
+ it 'encodes timestamps with hour timezone' do
331
+ expect( textenc_timestamptz.encode(Time.new(2016,1,02, 23, 23, 59.123456, -4*60*60)) ).
332
+ to match( /^2016-01-02 23:23:59.12345\d+ \-04:00$/ )
333
+ expect( textenc_timestamptz.encode(Time.new(2016,8,02, 23, 23, 59.123456, 10*60*60)) ).
334
+ to match( /^2016-08-02 23:23:59.12345\d+ \+10:00$/ )
335
+ end
336
+ end
337
+
218
338
  context 'identifier quotation' do
219
339
  it 'should quote and escape identifier' do
220
340
  quoted_type = PG::TextEncoder::Identifier.new
@@ -303,6 +423,7 @@ describe "PG::Type derivations" do
303
423
  describe "Array types" do
304
424
  let!(:textenc_string_array) { PG::TextEncoder::Array.new elements_type: textenc_string }
305
425
  let!(:textdec_string_array) { PG::TextDecoder::Array.new elements_type: textdec_string }
426
+ let!(:textdec_string_array_raise) { PG::TextDecoder::Array.new elements_type: textdec_string, flags: PG::Coder:: FORMAT_ERROR_TO_RAISE }
306
427
  let!(:textenc_int_array) { PG::TextEncoder::Array.new elements_type: textenc_int, needs_quotation: false }
307
428
  let!(:textdec_int_array) { PG::TextDecoder::Array.new elements_type: textdec_int, needs_quotation: false }
308
429
  let!(:textenc_float_array) { PG::TextEncoder::Array.new elements_type: textenc_float, needs_quotation: false }
@@ -368,6 +489,57 @@ describe "PG::Type derivations" do
368
489
  it 'respects a different delimiter' do
369
490
  expect( textdec_string_array_with_delimiter.decode(%[{1;2;3}]) ).to eq( ['1','2','3'] )
370
491
  end
492
+
493
+ it 'ignores array dimensions' 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
+ expect( textdec_string_array.decode(%[ [-1:+2]= {4,3,2,1}]) ).to eq( ['4','3','2','1'] )
497
+ end
498
+
499
+ it 'ignores spaces after array' do
500
+ expect( textdec_string_array.decode(%[[2:4]={1,2,3} ]) ).to eq( ['1','2','3'] )
501
+ expect( textdec_string_array.decode(%[{1,2,3} ]) ).to eq( ['1','2','3'] )
502
+ end
503
+
504
+ describe "with malformed syntax are deprecated" do
505
+ it 'accepts broken array dimensions' do
506
+ expect( textdec_string_array.decode(%([2:4={1,2,3})) ).to eq([['1','2','3']])
507
+ expect( textdec_string_array.decode(%(2:4]={1,2,3})) ).to eq([['1','2','3']])
508
+ expect( textdec_string_array.decode(%(={1,2,3})) ).to eq([['1','2','3']])
509
+ expect( textdec_string_array.decode(%([x]={1,2,3})) ).to eq([['1','2','3']])
510
+ expect( textdec_string_array.decode(%([]{1,2,3})) ).to eq([['1','2','3']])
511
+ expect( textdec_string_array.decode(%(1,2,3)) ).to eq(['','2'])
512
+ end
513
+
514
+ it 'accepts malformed arrays' do
515
+ expect( textdec_string_array.decode(%({1,2,3)) ).to eq(['1','2'])
516
+ expect( textdec_string_array.decode(%({1,2,3}})) ).to eq(['1','2','3'])
517
+ expect( textdec_string_array.decode(%({1,2,3}x)) ).to eq(['1','2','3'])
518
+ expect( textdec_string_array.decode(%({{1,2},{2,3})) ).to eq([['1','2'],['2','3']])
519
+ expect( textdec_string_array.decode(%({{1,2},{2,3}}x)) ).to eq([['1','2'],['2','3']])
520
+ expect( textdec_string_array.decode(%({[1,2},{2,3}}})) ).to eq(['[1','2'])
521
+ end
522
+ end
523
+
524
+ describe "with malformed syntax are raised with pg-2.0+" do
525
+ it 'complains about broken array dimensions' do
526
+ expect{ textdec_string_array_raise.decode(%([2:4={1,2,3})) }.to raise_error(TypeError)
527
+ expect{ textdec_string_array_raise.decode(%(2:4]={1,2,3})) }.to raise_error(TypeError)
528
+ expect{ textdec_string_array_raise.decode(%(={1,2,3})) }.to raise_error(TypeError)
529
+ expect{ textdec_string_array_raise.decode(%([x]={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)) }.to raise_error(TypeError)
532
+ end
533
+
534
+ it 'complains about malformed array' do
535
+ expect{ textdec_string_array_raise.decode(%({1,2,3)) }.to raise_error(TypeError)
536
+ expect{ textdec_string_array_raise.decode(%({1,2,3}})) }.to raise_error(TypeError)
537
+ expect{ textdec_string_array_raise.decode(%({1,2,3}x)) }.to raise_error(TypeError)
538
+ expect{ textdec_string_array_raise.decode(%({{1,2},{2,3})) }.to raise_error(TypeError)
539
+ expect{ textdec_string_array_raise.decode(%({{1,2},{2,3}}x)) }.to raise_error(TypeError)
540
+ expect{ textdec_string_array_raise.decode(%({[1,2},{2,3}}})) }.to raise_error(TypeError)
541
+ end
542
+ end
371
543
  end
372
544
 
373
545
  context 'bytea' do
@@ -746,7 +918,7 @@ describe "PG::Type derivations" do
746
918
  end
747
919
 
748
920
  describe '#decode' do
749
- it "should decode different types of Ruby objects" do
921
+ it "should decode COPY text format to array of strings" do
750
922
  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
923
  end
752
924
 
data/spec/pg_spec.rb CHANGED
@@ -1,4 +1,4 @@
1
- #!/usr/bin/env rspec
1
+ # -*- rspec -*-
2
2
  # encoding: utf-8
3
3
 
4
4
  require_relative 'helpers'
@@ -7,7 +7,7 @@ require 'pg'
7
7
 
8
8
  describe PG do
9
9
 
10
- it "knows what version of the libpq library is loaded", :postgresql_91 do
10
+ it "knows what version of the libpq library is loaded" do
11
11
  expect( PG.library_version ).to be_an( Integer )
12
12
  expect( PG.library_version ).to be >= 90100
13
13
  end
data.tar.gz.sig CHANGED
Binary file
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: 0.19.0
4
+ version: 1.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Michael Granger
@@ -11,9 +11,9 @@ bindir: bin
11
11
  cert_chain:
12
12
  - |
13
13
  -----BEGIN CERTIFICATE-----
14
- MIIEbDCCAtSgAwIBAgIBATANBgkqhkiG9w0BAQsFADA+MQwwCgYDVQQDDANnZWQx
14
+ MIIEbDCCAtSgAwIBAgIBATANBgkqhkiG9w0BAQUFADA+MQwwCgYDVQQDDANnZWQx
15
15
  GTAXBgoJkiaJk/IsZAEZFglGYWVyaWVNVUQxEzARBgoJkiaJk/IsZAEZFgNvcmcw
16
- HhcNMTYwODIwMTgxNzQyWhcNMTcwODIwMTgxNzQyWjA+MQwwCgYDVQQDDANnZWQx
16
+ HhcNMTcwOTI3MDAzMDQ0WhcNMTgwOTI3MDAzMDQ0WjA+MQwwCgYDVQQDDANnZWQx
17
17
  GTAXBgoJkiaJk/IsZAEZFglGYWVyaWVNVUQxEzARBgoJkiaJk/IsZAEZFgNvcmcw
18
18
  ggGiMA0GCSqGSIb3DQEBAQUAA4IBjwAwggGKAoIBgQC/JWGRHO+USzR97vXjkFgt
19
19
  83qeNf2KHkcvrRTSnR64i6um/ziin0I0oX23H7VYrDJC9A/uoUa5nGRJS5Zw/+wW
@@ -26,17 +26,17 @@ cert_chain:
26
26
  /D+K9JW9DDs3Yjgv9k4h7YMhW5gftosd+NkNC/+Y2CkCAwEAAaN1MHMwCQYDVR0T
27
27
  BAIwADALBgNVHQ8EBAMCBLAwHQYDVR0OBBYEFHKN/nkRusdqCJEuq3lgB3fJvyTg
28
28
  MBwGA1UdEQQVMBOBEWdlZEBGYWVyaWVNVUQub3JnMBwGA1UdEgQVMBOBEWdlZEBG
29
- YWVyaWVNVUQub3JnMA0GCSqGSIb3DQEBCwUAA4IBgQAPJzKiT0zBU7kpqe0aS2qb
30
- FI0PJ4y5I8buU4IZGUD5NEt/N7pZNfOyBxkrZkXhS44Fp+xwBH5ebLbq/WY78Bqd
31
- db0z6ZgW4LMYMpWFfbXsRbd9TU2f52L8oMAhxOvF7Of5qJMVWuFQ8FPagk2iHrdH
32
- inYLQagqAF6goWTXgAJCdPd6SNeeSNqA6vlY7CV1Jh5kfNJJ6xu/CVij1GzCLu/5
33
- DMOr26DBv+qLJRRC/2h34uX71q5QgeOyxvMg+7V3u/Q06DXyQ2VgeeqiwDFFpEH0
34
- PFkdPO6ZqbTRcLfNH7mFgCBJjsfSjJrn0sPBlYyOXgCoByfZnZyrIMH/UY+lgQqS
35
- 6Von1VDsfQm0eJh5zYZD64ZF86phSR7mUX3mXItwH04HrZwkWpvgd871DZVR3i1n
36
- w8aNA5re5+Rt/Vvjxj5AcEnZnZiz5x959NaddQocX32Z1unHw44pzRNUur1GInfW
37
- p4vpx2kUSFSAGjtCbDGTNV2AH8w9OU4xEmNz8c5lyoA=
29
+ YWVyaWVNVUQub3JnMA0GCSqGSIb3DQEBBQUAA4IBgQB/qyi5pCjK8ceoKalfVAjS
30
+ vG64FEnLnD1bm39T5UaFIRmo+abZtfpg2QhwKvPbPjOicau2+m+MDQ2Cc3tgyaC3
31
+ dZxcP6w8APFg4AId09uWAZKf0xajvBMS2aOz8Bbmag6fwqRRkTMqsNYnmqcF7aRT
32
+ DuEzbEMfaOUYjU9RuB48vr4q8yRft0ww+3jq5iwNkrX1buL2pwBbyvgms6D/BV41
33
+ MaTVMjsHqJUwU2xVfhGtxGAWAer5S1HGYHkbio6mGVtiie0uWjmnzi7ppIlMr48a
34
+ 7BNTsoZ+/JRk3iQWmmNsyFT7xfqBKye7cH11BX8V8P4MeGB5YWlMI+Myj5DZY3fQ
35
+ st2AGD4rb1l0ia7PfubcBThSIdz61eCb8gRi/RiZZwb3/7+eyEncLJzt2Ob9fGSF
36
+ X0qdrKi+2aZZ0NGuFj9AItBsVmAvkBGIpX4TEKQp5haEbPpmaqO5nIIhV26PXmyT
37
+ OMKv6pWsoS81vw5KAGBmfX8nht/Py90DQrbRvakATGI=
38
38
  -----END CERTIFICATE-----
39
- date: 2016-09-22 00:00:00.000000000 Z
39
+ date: 2018-08-24 00:00:00.000000000 Z
40
40
  dependencies:
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: hoe-mercurial
@@ -58,14 +58,14 @@ dependencies:
58
58
  requirements:
59
59
  - - "~>"
60
60
  - !ruby/object:Gem::Version
61
- version: '0.7'
61
+ version: '0.9'
62
62
  type: :development
63
63
  prerelease: false
64
64
  version_requirements: !ruby/object:Gem::Requirement
65
65
  requirements:
66
66
  - - "~>"
67
67
  - !ruby/object:Gem::Version
68
- version: '0.7'
68
+ version: '0.9'
69
69
  - !ruby/object:Gem::Dependency
70
70
  name: hoe-highline
71
71
  requirement: !ruby/object:Gem::Requirement
@@ -81,93 +81,99 @@ dependencies:
81
81
  - !ruby/object:Gem::Version
82
82
  version: '0.2'
83
83
  - !ruby/object:Gem::Dependency
84
- name: rdoc
84
+ name: rake-compiler
85
85
  requirement: !ruby/object:Gem::Requirement
86
86
  requirements:
87
87
  - - "~>"
88
88
  - !ruby/object:Gem::Version
89
- version: '4.0'
89
+ version: '1.0'
90
90
  type: :development
91
91
  prerelease: false
92
92
  version_requirements: !ruby/object:Gem::Requirement
93
93
  requirements:
94
94
  - - "~>"
95
95
  - !ruby/object:Gem::Version
96
- version: '4.0'
96
+ version: '1.0'
97
97
  - !ruby/object:Gem::Dependency
98
- name: rake-compiler
98
+ name: rake-compiler-dock
99
99
  requirement: !ruby/object:Gem::Requirement
100
100
  requirements:
101
101
  - - "~>"
102
102
  - !ruby/object:Gem::Version
103
- version: '0.9'
103
+ version: '0.6'
104
+ - - ">="
105
+ - !ruby/object:Gem::Version
106
+ version: 0.6.2
104
107
  type: :development
105
108
  prerelease: false
106
109
  version_requirements: !ruby/object:Gem::Requirement
107
110
  requirements:
108
111
  - - "~>"
109
112
  - !ruby/object:Gem::Version
110
- version: '0.9'
113
+ version: '0.6'
114
+ - - ">="
115
+ - !ruby/object:Gem::Version
116
+ version: 0.6.2
111
117
  - !ruby/object:Gem::Dependency
112
- name: rake-compiler-dock
118
+ name: hoe-bundler
113
119
  requirement: !ruby/object:Gem::Requirement
114
120
  requirements:
115
121
  - - "~>"
116
122
  - !ruby/object:Gem::Version
117
- version: '0.5'
123
+ version: '1.0'
118
124
  type: :development
119
125
  prerelease: false
120
126
  version_requirements: !ruby/object:Gem::Requirement
121
127
  requirements:
122
128
  - - "~>"
123
129
  - !ruby/object:Gem::Version
124
- version: '0.5'
130
+ version: '1.0'
125
131
  - !ruby/object:Gem::Dependency
126
- name: hoe
132
+ name: rspec
127
133
  requirement: !ruby/object:Gem::Requirement
128
134
  requirements:
129
135
  - - "~>"
130
136
  - !ruby/object:Gem::Version
131
- version: '3.12'
137
+ version: '3.5'
132
138
  type: :development
133
139
  prerelease: false
134
140
  version_requirements: !ruby/object:Gem::Requirement
135
141
  requirements:
136
142
  - - "~>"
137
143
  - !ruby/object:Gem::Version
138
- version: '3.12'
144
+ version: '3.5'
139
145
  - !ruby/object:Gem::Dependency
140
- name: hoe-bundler
146
+ name: rdoc
141
147
  requirement: !ruby/object:Gem::Requirement
142
148
  requirements:
143
149
  - - "~>"
144
150
  - !ruby/object:Gem::Version
145
- version: '1.0'
151
+ version: '5.1'
146
152
  type: :development
147
153
  prerelease: false
148
154
  version_requirements: !ruby/object:Gem::Requirement
149
155
  requirements:
150
156
  - - "~>"
151
157
  - !ruby/object:Gem::Version
152
- version: '1.0'
158
+ version: '5.1'
153
159
  - !ruby/object:Gem::Dependency
154
- name: rspec
160
+ name: hoe
155
161
  requirement: !ruby/object:Gem::Requirement
156
162
  requirements:
157
163
  - - "~>"
158
164
  - !ruby/object:Gem::Version
159
- version: '3.0'
165
+ version: '3.16'
160
166
  type: :development
161
167
  prerelease: false
162
168
  version_requirements: !ruby/object:Gem::Requirement
163
169
  requirements:
164
170
  - - "~>"
165
171
  - !ruby/object:Gem::Version
166
- version: '3.0'
172
+ version: '3.16'
167
173
  description: |-
168
174
  Pg is the Ruby interface to the {PostgreSQL RDBMS}[http://www.postgresql.org/].
169
175
 
170
- It works with {PostgreSQL 9.1 and later}[http://www.postgresql.org/support/versioning/].
176
+ It works with {PostgreSQL 9.2 and later}[http://www.postgresql.org/support/versioning/].
171
177
 
172
178
  A small example usage:
173
179
 
@@ -212,6 +218,7 @@ extra_rdoc_files:
212
218
  - ext/pg_result.c
213
219
  - ext/pg_text_decoder.c
214
220
  - ext/pg_text_encoder.c
221
+ - ext/pg_tuple.c
215
222
  - ext/pg_type_map.c
216
223
  - ext/pg_type_map_all_strings.c
217
224
  - ext/pg_type_map_by_class.c
@@ -252,6 +259,7 @@ files:
252
259
  - ext/pg_result.c
253
260
  - ext/pg_text_decoder.c
254
261
  - ext/pg_text_encoder.c
262
+ - ext/pg_tuple.c
255
263
  - ext/pg_type_map.c
256
264
  - ext/pg_type_map_all_strings.c
257
265
  - ext/pg_type_map_by_class.c
@@ -266,6 +274,7 @@ files:
266
274
  - ext/vc/pg_19/pg_19.vcproj
267
275
  - lib/pg.rb
268
276
  - lib/pg/basic_type_mapping.rb
277
+ - lib/pg/binary_decoder.rb
269
278
  - lib/pg/coder.rb
270
279
  - lib/pg/connection.rb
271
280
  - lib/pg/constants.rb
@@ -273,31 +282,16 @@ files:
273
282
  - lib/pg/result.rb
274
283
  - lib/pg/text_decoder.rb
275
284
  - lib/pg/text_encoder.rb
285
+ - lib/pg/tuple.rb
276
286
  - lib/pg/type_map_by_column.rb
277
- - sample/array_insert.rb
278
- - sample/async_api.rb
279
- - sample/async_copyto.rb
280
- - sample/async_mixed.rb
281
- - sample/check_conn.rb
282
- - sample/copyfrom.rb
283
- - sample/copyto.rb
284
- - sample/cursor.rb
285
- - sample/disk_usage_report.rb
286
- - sample/issue-119.rb
287
- - sample/losample.rb
288
- - sample/minimal-testcase.rb
289
- - sample/notify_wait.rb
290
- - sample/pg_statistics.rb
291
- - sample/replication_monitor.rb
292
- - sample/test_binary_values.rb
293
- - sample/wal_shipper.rb
294
- - sample/warehouse_partitions.rb
295
287
  - spec/data/expected_trace.out
296
288
  - spec/data/random_binary_data
297
289
  - spec/helpers.rb
298
290
  - spec/pg/basic_type_mapping_spec.rb
299
291
  - spec/pg/connection_spec.rb
292
+ - spec/pg/connection_sync_spec.rb
300
293
  - spec/pg/result_spec.rb
294
+ - spec/pg/tuple_spec.rb
301
295
  - spec/pg/type_map_by_class_spec.rb
302
296
  - spec/pg/type_map_by_column_spec.rb
303
297
  - spec/pg/type_map_by_mri_type_spec.rb
@@ -328,7 +322,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
328
322
  version: '0'
329
323
  requirements: []
330
324
  rubyforge_project:
331
- rubygems_version: 2.6.2
325
+ rubygems_version: 2.7.6
332
326
  signing_key:
333
327
  specification_version: 4
334
328
  summary: Pg is the Ruby interface to the {PostgreSQL RDBMS}[http://www.postgresql.org/]
metadata.gz.sig CHANGED
Binary file
@@ -1,20 +0,0 @@
1
- #!/usr/bin/env ruby
2
-
3
- require 'pg'
4
-
5
- c = PG.connect( dbname: 'test' )
6
-
7
- # this one works:
8
- c.exec( "DROP TABLE IF EXISTS foo" )
9
- c.exec( "CREATE TABLE foo (strings character varying[]);" )
10
-
11
- # But using a prepared statement works:
12
- c.set_error_verbosity( PG::PQERRORS_VERBOSE )
13
- c.prepare( 'stmt', "INSERT INTO foo VALUES ($1);" )
14
-
15
- # This won't work
16
- #c.exec_prepared( 'stmt', ["ARRAY['this','that']"] )
17
-
18
- # but this will:
19
- c.exec_prepared( 'stmt', ["{'this','that'}"] )
20
-
data/sample/async_api.rb DELETED
@@ -1,106 +0,0 @@
1
- #!/usr/bin/env ruby
2
-
3
- require 'pg'
4
-
5
- # This is a example of how to use the asynchronous API to query the
6
- # server without blocking other threads. It's intentionally low-level;
7
- # if you hooked up the PG::Connection#socket to some kind of reactor, you
8
- # could make this much nicer.
9
-
10
- TIMEOUT = 5.0 # seconds to wait for an async operation to complete
11
-
12
- # Print 'x' continuously to demonstrate that other threads aren't
13
- # blocked while waiting for the connection, for the query to be sent,
14
- # for results, etc. You might want to sleep inside the loop or
15
- # comment this out entirely for cleaner output.
16
- progress_thread = Thread.new { loop { print 'x' } }
17
-
18
- # Output progress messages
19
- def output_progress( msg )
20
- puts "\n>>> #{msg}\n"
21
- end
22
-
23
- # Start the connection
24
- output_progress "Starting connection..."
25
- conn = PG::Connection.connect_start( :dbname => 'test' ) or
26
- abort "Unable to create a new connection!"
27
- abort "Connection failed: %s" % [ conn.error_message ] if
28
- conn.status == PG::CONNECTION_BAD
29
-
30
- # Now grab a reference to the underlying socket so we know when the
31
- # connection is established
32
- socket = conn.socket_io
33
-
34
- # Track the progress of the connection, waiting for the socket to become readable/writable
35
- # before polling it
36
- poll_status = PG::PGRES_POLLING_WRITING
37
- until poll_status == PG::PGRES_POLLING_OK ||
38
- poll_status == PG::PGRES_POLLING_FAILED
39
-
40
- # If the socket needs to read, wait 'til it becomes readable to poll again
41
- case poll_status
42
- when PG::PGRES_POLLING_READING
43
- output_progress " waiting for socket to become readable"
44
- select( [socket], nil, nil, TIMEOUT ) or
45
- raise "Asynchronous connection timed out!"
46
-
47
- # ...and the same for when the socket needs to write
48
- when PG::PGRES_POLLING_WRITING
49
- output_progress " waiting for socket to become writable"
50
- select( nil, [socket], nil, TIMEOUT ) or
51
- raise "Asynchronous connection timed out!"
52
- end
53
-
54
- # Output a status message about the progress
55
- case conn.status
56
- when PG::CONNECTION_STARTED
57
- output_progress " waiting for connection to be made."
58
- when PG::CONNECTION_MADE
59
- output_progress " connection OK; waiting to send."
60
- when PG::CONNECTION_AWAITING_RESPONSE
61
- output_progress " waiting for a response from the server."
62
- when PG::CONNECTION_AUTH_OK
63
- output_progress " received authentication; waiting for backend start-up to finish."
64
- when PG::CONNECTION_SSL_STARTUP
65
- output_progress " negotiating SSL encryption."
66
- when PG::CONNECTION_SETENV
67
- output_progress " negotiating environment-driven parameter settings."
68
- when PG::CONNECTION_NEEDED
69
- output_progress " internal state: connect() needed."
70
- end
71
-
72
- # Check to see if it's finished or failed yet
73
- poll_status = conn.connect_poll
74
- end
75
-
76
- abort "Connect failed: %s" % [ conn.error_message ] unless conn.status == PG::CONNECTION_OK
77
-
78
- output_progress "Sending query"
79
- conn.send_query( "SELECT * FROM pg_stat_activity" )
80
-
81
- # Fetch results until there aren't any more
82
- loop do
83
- output_progress " waiting for a response"
84
-
85
- # Buffer any incoming data on the socket until a full result is ready.
86
- conn.consume_input
87
- while conn.is_busy
88
- select( [socket], nil, nil, TIMEOUT ) or
89
- raise "Timeout waiting for query response."
90
- conn.consume_input
91
- end
92
-
93
- # Fetch the next result. If there isn't one, the query is finished
94
- result = conn.get_result or break
95
-
96
- puts "\n\nQuery result:\n%p\n" % [ result.values ]
97
- end
98
-
99
- output_progress "Done."
100
- conn.finish
101
-
102
- if defined?( progress_thread )
103
- progress_thread.kill
104
- progress_thread.join
105
- end
106
-