pg 1.1.3 → 1.2.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.
- checksums.yaml +4 -4
- checksums.yaml.gz.sig +0 -0
- data.tar.gz.sig +0 -0
- data/ChangeLog +0 -6595
- data/History.rdoc +70 -0
- data/Manifest.txt +3 -2
- data/README-Windows.rdoc +4 -4
- data/README.ja.rdoc +1 -2
- data/README.rdoc +43 -8
- data/Rakefile +4 -4
- data/Rakefile.cross +7 -4
- data/ext/errorcodes.def +68 -0
- data/ext/errorcodes.txt +19 -2
- data/ext/extconf.rb +6 -6
- data/ext/pg.c +132 -95
- data/ext/pg.h +24 -17
- data/ext/pg_binary_decoder.c +20 -16
- data/ext/pg_binary_encoder.c +13 -12
- data/ext/pg_coder.c +5 -5
- data/ext/pg_connection.c +395 -301
- data/ext/pg_copy_coder.c +5 -3
- data/ext/pg_record_coder.c +490 -0
- data/ext/pg_result.c +272 -124
- data/ext/pg_text_decoder.c +14 -8
- data/ext/pg_text_encoder.c +180 -48
- data/ext/pg_tuple.c +14 -6
- data/ext/pg_type_map.c +1 -1
- data/ext/pg_type_map_all_strings.c +4 -4
- data/ext/pg_type_map_by_class.c +4 -3
- data/ext/pg_type_map_by_column.c +7 -6
- data/ext/pg_type_map_by_mri_type.c +1 -1
- data/ext/pg_type_map_by_oid.c +3 -2
- data/ext/pg_type_map_in_ruby.c +1 -1
- data/ext/{util.c → pg_util.c} +5 -5
- data/ext/{util.h → pg_util.h} +0 -0
- data/lib/pg.rb +2 -3
- data/lib/pg/basic_type_mapping.rb +79 -16
- data/lib/pg/binary_decoder.rb +1 -0
- data/lib/pg/coder.rb +22 -1
- data/lib/pg/connection.rb +2 -2
- data/lib/pg/constants.rb +1 -0
- data/lib/pg/exceptions.rb +1 -0
- data/lib/pg/result.rb +13 -1
- data/lib/pg/text_decoder.rb +2 -3
- data/lib/pg/text_encoder.rb +8 -18
- data/lib/pg/type_map_by_column.rb +2 -1
- data/spec/helpers.rb +17 -16
- data/spec/pg/basic_type_mapping_spec.rb +151 -14
- data/spec/pg/connection_spec.rb +117 -55
- data/spec/pg/result_spec.rb +193 -3
- data/spec/pg/tuple_spec.rb +55 -2
- data/spec/pg/type_map_by_column_spec.rb +5 -1
- data/spec/pg/type_spec.rb +180 -6
- metadata +40 -45
- metadata.gz.sig +0 -0
    
        data/spec/pg/tuple_spec.rb
    CHANGED
    
    | @@ -8,10 +8,22 @@ require 'objspace' | |
| 8 8 | 
             
            describe PG::Tuple do
         | 
| 9 9 | 
             
            	let!(:typemap) { PG::BasicTypeMapForResults.new(@conn) }
         | 
| 10 10 | 
             
            	let!(:result2x2) { @conn.exec( "VALUES(1, 'a'), (2, 'b')" ) }
         | 
| 11 | 
            -
            	let!(: | 
| 11 | 
            +
            	let!(:result2x2sym) { @conn.exec( "VALUES(1, 'a'), (2, 'b')" ).field_names_as(:symbol) }
         | 
| 12 | 
            +
            	let!(:result2x3cast) do
         | 
| 13 | 
            +
            		@conn.exec( "SELECT * FROM (VALUES(1, TRUE, '3'), (2, FALSE, '4')) AS m (a, b, b)" )
         | 
| 14 | 
            +
            			.map_types!(typemap)
         | 
| 15 | 
            +
            	end
         | 
| 16 | 
            +
            	let!(:result2x3symcast) do
         | 
| 17 | 
            +
            		@conn.exec( "SELECT * FROM (VALUES(1, TRUE, '3'), (2, FALSE, '4')) AS m (a, b, b)" )
         | 
| 18 | 
            +
            			.map_types!(typemap)
         | 
| 19 | 
            +
            			.field_names_as(:symbol)
         | 
| 20 | 
            +
            	end
         | 
| 12 21 | 
             
            	let!(:tuple0) { result2x2.tuple(0) }
         | 
| 22 | 
            +
            	let!(:tuple0sym) { result2x2sym.tuple(0) }
         | 
| 13 23 | 
             
            	let!(:tuple1) { result2x2.tuple(1) }
         | 
| 24 | 
            +
            	let!(:tuple1sym) { result2x2sym.tuple(1) }
         | 
| 14 25 | 
             
            	let!(:tuple2) { result2x3cast.tuple(0) }
         | 
| 26 | 
            +
            	let!(:tuple2sym) { result2x3symcast.tuple(0) }
         | 
| 15 27 | 
             
            	let!(:tuple3) { str = Marshal.dump(result2x3cast.tuple(1)); Marshal.load(str) }
         | 
| 16 28 | 
             
            	let!(:tuple_empty) { PG::Tuple.new }
         | 
| 17 29 |  | 
| @@ -51,9 +63,19 @@ describe PG::Tuple do | |
| 51 63 | 
             
            			expect( tuple0["column2"] ).to eq( "a" )
         | 
| 52 64 | 
             
            			expect( tuple2["a"] ).to eq( 1 )
         | 
| 53 65 | 
             
            			expect( tuple2["b"] ).to eq( "3" )
         | 
| 66 | 
            +
            			expect( tuple0[:b] ).to be_nil
         | 
| 54 67 | 
             
            			expect( tuple0["x"] ).to be_nil
         | 
| 55 68 | 
             
            		end
         | 
| 56 69 |  | 
| 70 | 
            +
            		it "supports hash like access with symbols" do
         | 
| 71 | 
            +
            			expect( tuple0sym[:column1] ).to eq( "1" )
         | 
| 72 | 
            +
            			expect( tuple0sym[:column2] ).to eq( "a" )
         | 
| 73 | 
            +
            			expect( tuple2sym[:a] ).to eq( 1 )
         | 
| 74 | 
            +
            			expect( tuple2sym[:b] ).to eq( "3" )
         | 
| 75 | 
            +
            			expect( tuple2sym["b"] ).to be_nil
         | 
| 76 | 
            +
            			expect( tuple0sym[:x] ).to be_nil
         | 
| 77 | 
            +
            		end
         | 
| 78 | 
            +
             | 
| 57 79 | 
             
            		it "casts lazy and caches result" do
         | 
| 58 80 | 
             
            			a = []
         | 
| 59 81 | 
             
            			deco = Class.new(PG::SimpleDecoder) do
         | 
| @@ -138,6 +160,12 @@ describe PG::Tuple do | |
| 138 160 | 
             
            			expect{ tuple_empty.each }.to raise_error(TypeError)
         | 
| 139 161 | 
             
            		end
         | 
| 140 162 |  | 
| 163 | 
            +
            		it "can be used as an enumerator with symbols" do
         | 
| 164 | 
            +
            			expect( tuple0sym.each ).to be_kind_of(Enumerator)
         | 
| 165 | 
            +
            			expect( tuple0sym.each.to_a ).to eq( [[:column1, "1"], [:column2, "a"]] )
         | 
| 166 | 
            +
            			expect( tuple2sym.each.to_a ).to eq( [[:a, 1], [:b, true], [:b, "3"]] )
         | 
| 167 | 
            +
            		end
         | 
| 168 | 
            +
             | 
| 141 169 | 
             
            		it "can be used with block" do
         | 
| 142 170 | 
             
            			a = []
         | 
| 143 171 | 
             
            			tuple0.each do |*v|
         | 
| @@ -174,16 +202,30 @@ describe PG::Tuple do | |
| 174 202 |  | 
| 175 203 | 
             
            	it "responds to key?" do
         | 
| 176 204 | 
             
            		expect( tuple1.key?("column1") ).to eq( true )
         | 
| 205 | 
            +
            		expect( tuple1.key?(:column1) ).to eq( false )
         | 
| 177 206 | 
             
            		expect( tuple1.key?("other") ).to eq( false )
         | 
| 178 207 | 
             
            		expect( tuple1.has_key?("column1") ).to eq( true )
         | 
| 179 208 | 
             
            		expect( tuple1.has_key?("other") ).to eq( false )
         | 
| 180 209 | 
             
            	end
         | 
| 181 210 |  | 
| 211 | 
            +
            	it "responds to key? as symbol" do
         | 
| 212 | 
            +
            		expect( tuple1sym.key?(:column1) ).to eq( true )
         | 
| 213 | 
            +
            		expect( tuple1sym.key?("column1") ).to eq( false )
         | 
| 214 | 
            +
            		expect( tuple1sym.key?(:other) ).to eq( false )
         | 
| 215 | 
            +
            		expect( tuple1sym.has_key?(:column1) ).to eq( true )
         | 
| 216 | 
            +
            		expect( tuple1sym.has_key?(:other) ).to eq( false )
         | 
| 217 | 
            +
            	end
         | 
| 218 | 
            +
             | 
| 182 219 | 
             
            	it "responds to keys" do
         | 
| 183 220 | 
             
            		expect( tuple0.keys ).to eq( ["column1", "column2"] )
         | 
| 184 221 | 
             
            		expect( tuple2.keys ).to eq( ["a", "b", "b"] )
         | 
| 185 222 | 
             
            	end
         | 
| 186 223 |  | 
| 224 | 
            +
            	it "responds to keys as symbol" do
         | 
| 225 | 
            +
            		expect( tuple0sym.keys ).to eq( [:column1, :column2] )
         | 
| 226 | 
            +
            		expect( tuple2sym.keys ).to eq( [:a, :b, :b] )
         | 
| 227 | 
            +
            	end
         | 
| 228 | 
            +
             | 
| 187 229 | 
             
            	describe "each_key" do
         | 
| 188 230 | 
             
            		it "can be used as an enumerator" do
         | 
| 189 231 | 
             
            			expect( tuple0.each_key ).to be_kind_of(Enumerator)
         | 
| @@ -208,12 +250,22 @@ describe PG::Tuple do | |
| 208 250 |  | 
| 209 251 | 
             
            	it "responds to index" do
         | 
| 210 252 | 
             
            		expect( tuple0.index("column1") ).to eq( 0 )
         | 
| 253 | 
            +
            		expect( tuple0.index(:column1) ).to eq( nil )
         | 
| 211 254 | 
             
            		expect( tuple0.index("column2") ).to eq( 1 )
         | 
| 212 255 | 
             
            		expect( tuple0.index("x") ).to eq( nil )
         | 
| 213 256 | 
             
            		expect( tuple2.index("a") ).to eq( 0 )
         | 
| 214 257 | 
             
            		expect( tuple2.index("b") ).to eq( 2 )
         | 
| 215 258 | 
             
            	end
         | 
| 216 259 |  | 
| 260 | 
            +
            	it "responds to index with symbol" do
         | 
| 261 | 
            +
            		expect( tuple0sym.index(:column1) ).to eq( 0 )
         | 
| 262 | 
            +
            		expect( tuple0sym.index("column1") ).to eq( nil )
         | 
| 263 | 
            +
            		expect( tuple0sym.index(:column2) ).to eq( 1 )
         | 
| 264 | 
            +
            		expect( tuple0sym.index(:x) ).to eq( nil )
         | 
| 265 | 
            +
            		expect( tuple2sym.index(:a) ).to eq( 0 )
         | 
| 266 | 
            +
            		expect( tuple2sym.index(:b) ).to eq( 2 )
         | 
| 267 | 
            +
            	end
         | 
| 268 | 
            +
             | 
| 217 269 | 
             
            	it "can be used as Enumerable" do
         | 
| 218 270 | 
             
            		expect( tuple0.to_a ).to eq( [["column1", "1"], ["column2", "a"]] )
         | 
| 219 271 | 
             
            		expect( tuple1.to_a ).to eq( [["column1", "2"], ["column2", "b"]] )
         | 
| @@ -222,7 +274,7 @@ describe PG::Tuple do | |
| 222 274 | 
             
            	end
         | 
| 223 275 |  | 
| 224 276 | 
             
            	it "can be marshaled" do
         | 
| 225 | 
            -
            		[tuple0, tuple1, tuple2, tuple3].each do |t1|
         | 
| 277 | 
            +
            		[tuple0, tuple1, tuple2, tuple3, tuple0sym, tuple2sym].each do |t1|
         | 
| 226 278 | 
             
            			str = Marshal.dump(t1)
         | 
| 227 279 | 
             
            			t2 = Marshal.load(str)
         | 
| 228 280 |  | 
| @@ -253,6 +305,7 @@ describe PG::Tuple do | |
| 253 305 | 
             
            	it "should override #inspect" do
         | 
| 254 306 | 
             
            		expect( tuple1.inspect ).to eq('#<PG::Tuple column1: "2", column2: "b">')
         | 
| 255 307 | 
             
            		expect( tuple2.inspect ).to eq('#<PG::Tuple a: 1, b: true, b: "3">')
         | 
| 308 | 
            +
            		expect( tuple2sym.inspect ).to eq('#<PG::Tuple a: 1, b: true, b: "3">')
         | 
| 256 309 | 
             
            		expect{ tuple_empty.inspect }.to raise_error(TypeError)
         | 
| 257 310 | 
             
            	end
         | 
| 258 311 |  | 
| @@ -38,7 +38,11 @@ describe PG::TypeMapByColumn do | |
| 38 38 | 
             
            			pass_through_type,
         | 
| 39 39 | 
             
            			nil
         | 
| 40 40 | 
             
            		] )
         | 
| 41 | 
            -
             | 
| 41 | 
            +
            	end
         | 
| 42 | 
            +
             | 
| 43 | 
            +
            	it "should respond to inspect" do
         | 
| 44 | 
            +
            		cm = PG::TypeMapByColumn.new( [textdec_int, textenc_string, textdec_float, pass_through_type, PG::TextEncoder::Float.new, nil] )
         | 
| 45 | 
            +
            		expect( cm.inspect ).to eq( "#<PG::TypeMapByColumn INT4:TD TEXT:TE FLOAT4:TD pass_through:BD PG::TextEncoder::Float:TE nil>" )
         | 
| 42 46 | 
             
            	end
         | 
| 43 47 |  | 
| 44 48 | 
             
            	it "should retrieve it's oids" do
         | 
    
        data/spec/pg/type_spec.rb
    CHANGED
    
    | @@ -12,6 +12,7 @@ describe "PG::Type derivations" do | |
| 12 12 | 
             
            	let!(:textdec_boolean) { PG::TextDecoder::Boolean.new }
         | 
| 13 13 | 
             
            	let!(:textenc_float) { PG::TextEncoder::Float.new }
         | 
| 14 14 | 
             
            	let!(:textdec_float) { PG::TextDecoder::Float.new }
         | 
| 15 | 
            +
            	let!(:textenc_numeric) { PG::TextEncoder::Numeric.new }
         | 
| 15 16 | 
             
            	let!(:textenc_string) { PG::TextEncoder::String.new }
         | 
| 16 17 | 
             
            	let!(:textdec_string) { PG::TextDecoder::String.new }
         | 
| 17 18 | 
             
            	let!(:textenc_timestamp) { PG::TextEncoder::TimestampWithoutTimeZone.new }
         | 
| @@ -254,6 +255,11 @@ describe "PG::Type derivations" do | |
| 254 255 | 
             
            				expect( textdec_string.decode( nil )).to be_nil
         | 
| 255 256 | 
             
            				expect( textdec_int.decode( nil )).to be_nil
         | 
| 256 257 | 
             
            			end
         | 
| 258 | 
            +
             | 
| 259 | 
            +
            			it "should be defined on an encoder but not on a decoder instance" do
         | 
| 260 | 
            +
            				expect( textdec_int.respond_to?(:decode) ).to be_truthy
         | 
| 261 | 
            +
            				expect( textenc_int.respond_to?(:decode) ).to be_falsey
         | 
| 262 | 
            +
            			end
         | 
| 257 263 | 
             
            		end
         | 
| 258 264 |  | 
| 259 265 | 
             
            		describe '#encode' do
         | 
| @@ -304,12 +310,73 @@ describe "PG::Type derivations" do | |
| 304 310 | 
             
            				end
         | 
| 305 311 | 
             
            			end
         | 
| 306 312 |  | 
| 313 | 
            +
            			it "should encode floats" do
         | 
| 314 | 
            +
            				expect( textenc_float.encode(0) ).to eq( "0.0" )
         | 
| 315 | 
            +
            				expect( textenc_float.encode(-1) ).to eq( "-1.0" )
         | 
| 316 | 
            +
            				expect( textenc_float.encode(-1.234567890123456789) ).to eq( "-1.234567890123457" )
         | 
| 317 | 
            +
            				expect( textenc_float.encode(9) ).to eq( "9.0" )
         | 
| 318 | 
            +
            				expect( textenc_float.encode(10) ).to eq( "10.0" )
         | 
| 319 | 
            +
            				expect( textenc_float.encode(-99) ).to eq( "-99.0" )
         | 
| 320 | 
            +
            				expect( textenc_float.encode(-100) ).to eq( "-100.0" )
         | 
| 321 | 
            +
            				expect( textenc_float.encode(999) ).to eq( "999.0" )
         | 
| 322 | 
            +
            				expect( textenc_float.encode(-1000) ).to eq( "-1000.0" )
         | 
| 323 | 
            +
            				expect( textenc_float.encode(1234.567890123456789) ).to eq( "1234.567890123457" )
         | 
| 324 | 
            +
            				expect( textenc_float.encode(-9999) ).to eq( "-9999.0" )
         | 
| 325 | 
            +
            				expect( textenc_float.encode(10000) ).to eq( "10000.0" )
         | 
| 326 | 
            +
            				expect( textenc_float.encode(99999) ).to eq( "99999.0" )
         | 
| 327 | 
            +
            				expect( textenc_float.encode(-100000) ).to eq( "-100000.0" )
         | 
| 328 | 
            +
            				expect( textenc_float.encode(-999999) ).to eq( "-999999.0" )
         | 
| 329 | 
            +
            				expect( textenc_float.encode(1000000) ).to eq( "1000000.0" )
         | 
| 330 | 
            +
            				expect( textenc_float.encode(9999999) ).to eq( "9999999.0" )
         | 
| 331 | 
            +
            				expect( textenc_float.encode(-100000000000000) ).to eq( "-100000000000000.0" )
         | 
| 332 | 
            +
            				expect( textenc_float.encode(123456789012345) ).to eq( "123456789012345.0" )
         | 
| 333 | 
            +
            				expect( textenc_float.encode(-999999999999999) ).to eq( "-999999999999999.0" )
         | 
| 334 | 
            +
            				expect( textenc_float.encode(1000000000000000) ).to eq( "1e15" )
         | 
| 335 | 
            +
            				expect( textenc_float.encode(-1234567890123456) ).to eq( "-1.234567890123456e15" )
         | 
| 336 | 
            +
            				expect( textenc_float.encode(9999999999999999) ).to eq( "1e16" )
         | 
| 337 | 
            +
             | 
| 338 | 
            +
            				expect( textenc_float.encode(-0.0) ).to eq( "0.0" )
         | 
| 339 | 
            +
            				expect( textenc_float.encode(0.1) ).to eq( "0.1" )
         | 
| 340 | 
            +
            				expect( textenc_float.encode(0.1234567890123456789) ).to eq( "0.1234567890123457" )
         | 
| 341 | 
            +
            				expect( textenc_float.encode(-0.9) ).to eq( "-0.9" )
         | 
| 342 | 
            +
            				expect( textenc_float.encode(-0.01234567890123456789) ).to eq( "-0.01234567890123457" )
         | 
| 343 | 
            +
            				expect( textenc_float.encode(0.09) ).to eq( "0.09" )
         | 
| 344 | 
            +
            				expect( textenc_float.encode(0.001234567890123456789) ).to eq( "0.001234567890123457" )
         | 
| 345 | 
            +
            				expect( textenc_float.encode(-0.009) ).to eq( "-0.009" )
         | 
| 346 | 
            +
            				expect( textenc_float.encode(-0.0001234567890123456789) ).to eq( "-0.0001234567890123457" )
         | 
| 347 | 
            +
            				expect( textenc_float.encode(0.0009) ).to eq( "0.0009" )
         | 
| 348 | 
            +
            				expect( textenc_float.encode(0.00001) ).to eq( "1e-5" )
         | 
| 349 | 
            +
            				expect( textenc_float.encode(0.00001234567890123456789) ).to eq( "1.234567890123457e-5" )
         | 
| 350 | 
            +
            				expect( textenc_float.encode(-0.00009) ).to eq( "-9e-5" )
         | 
| 351 | 
            +
            				expect( textenc_float.encode(-0.11) ).to eq( "-0.11" )
         | 
| 352 | 
            +
            				expect( textenc_float.encode(10.11) ).to eq( "10.11" )
         | 
| 353 | 
            +
            				expect( textenc_float.encode(-1.234567890123456789E-280) ).to eq( "-1.234567890123457e-280" )
         | 
| 354 | 
            +
            				expect( textenc_float.encode(-1.234567890123456789E280) ).to eq( "-1.234567890123457e280" )
         | 
| 355 | 
            +
            				expect( textenc_float.encode(9876543210987654321E280) ).to eq( "9.87654321098765e298" )
         | 
| 356 | 
            +
            				expect( textenc_float.encode(9876543210987654321E-400) ).to eq( "0.0" )
         | 
| 357 | 
            +
            				expect( textenc_float.encode(9876543210987654321E400) ).to eq( "Infinity" )
         | 
| 358 | 
            +
            			end
         | 
| 359 | 
            +
             | 
| 307 360 | 
             
            			it "should encode special floats equally to Float#to_s" do
         | 
| 308 361 | 
             
            				expect( textenc_float.encode(Float::INFINITY) ).to eq( Float::INFINITY.to_s )
         | 
| 309 362 | 
             
            				expect( textenc_float.encode(-Float::INFINITY) ).to eq( (-Float::INFINITY).to_s )
         | 
| 310 363 | 
             
            				expect( textenc_float.encode(-Float::NAN) ).to eq( Float::NAN.to_s )
         | 
| 311 364 | 
             
            			end
         | 
| 312 365 |  | 
| 366 | 
            +
            			it "should encode various inputs to numeric format" do
         | 
| 367 | 
            +
            				expect( textenc_numeric.encode(0) ).to eq( "0" )
         | 
| 368 | 
            +
            				expect( textenc_numeric.encode(1) ).to eq( "1" )
         | 
| 369 | 
            +
            				expect( textenc_numeric.encode(-12345678901234567890123) ).to eq( "-12345678901234567890123" )
         | 
| 370 | 
            +
            				expect( textenc_numeric.encode(0.0) ).to eq( "0.0" )
         | 
| 371 | 
            +
            				expect( textenc_numeric.encode(1.0) ).to eq( "1.0" )
         | 
| 372 | 
            +
            				expect( textenc_numeric.encode(-1.23456789012e45) ).to eq( "-1.23456789012e45" )
         | 
| 373 | 
            +
            				expect( textenc_numeric.encode(Float::NAN) ).to eq( Float::NAN.to_s )
         | 
| 374 | 
            +
            				expect( textenc_numeric.encode(BigDecimal(0)) ).to eq( "0.0" )
         | 
| 375 | 
            +
            				expect( textenc_numeric.encode(BigDecimal(1)) ).to eq( "1.0" )
         | 
| 376 | 
            +
            				expect( textenc_numeric.encode(BigDecimal("-12345678901234567890.1234567")) ).to eq( "-12345678901234567890.1234567" )
         | 
| 377 | 
            +
            				expect( textenc_numeric.encode(" 123 ") ).to eq( " 123 " )
         | 
| 378 | 
            +
            			end
         | 
| 379 | 
            +
             | 
| 313 380 | 
             
            			it "encodes binary string to bytea" do
         | 
| 314 381 | 
             
            				expect( textenc_bytea.encode("\x00\x01\x02\x03\xef".b) ).to eq( "\\x00010203ef" )
         | 
| 315 382 | 
             
            			end
         | 
| @@ -376,6 +443,11 @@ describe "PG::Type derivations" do | |
| 376 443 | 
             
            				expect( textenc_string.encode( nil )).to be_nil
         | 
| 377 444 | 
             
            				expect( textenc_int.encode( nil )).to be_nil
         | 
| 378 445 | 
             
            			end
         | 
| 446 | 
            +
             | 
| 447 | 
            +
            			it "should be defined on a decoder but not on an encoder instance" do
         | 
| 448 | 
            +
            				expect( textenc_int.respond_to?(:encode) ).to be_truthy
         | 
| 449 | 
            +
            				expect( textdec_int.respond_to?(:encode) ).to be_falsey
         | 
| 450 | 
            +
            			end
         | 
| 379 451 | 
             
            		end
         | 
| 380 452 |  | 
| 381 453 | 
             
            		it "should be possible to marshal encoders" do
         | 
| @@ -392,7 +464,7 @@ describe "PG::Type derivations" do | |
| 392 464 |  | 
| 393 465 | 
             
            		it "should respond to to_h" do
         | 
| 394 466 | 
             
            			expect( textenc_int.to_h ).to eq( {
         | 
| 395 | 
            -
            				name: 'Integer', oid: 23, format: 0
         | 
| 467 | 
            +
            				name: 'Integer', oid: 23, format: 0, flags: 0
         | 
| 396 468 | 
             
            			} )
         | 
| 397 469 | 
             
            		end
         | 
| 398 470 |  | 
| @@ -624,7 +696,7 @@ describe "PG::Type derivations" do | |
| 624 696 | 
             
            						expect( textenc_int_array.encode(['1',['2'],'3']) ).to eq( %[{1,{2},3}] )
         | 
| 625 697 | 
             
            					end
         | 
| 626 698 | 
             
            					it 'encodes an array of float8 with sub arrays' do
         | 
| 627 | 
            -
            						expect( textenc_float_array.encode([1000.11,[-0. | 
| 699 | 
            +
            						expect( textenc_float_array.encode([1000.11,[-0.00000221,[3.31,-441]],[nil,6.61],-7.71]) ).to match(Regexp.new(%[^{1000.1*,{-2.2*e-*6,{3.3*,-441.0}},{NULL,6.6*},-7.7*}$].gsub(/([\.\+\{\}\,])/, "\\\\\\1").gsub(/\*/, "\\d*")))
         | 
| 628 700 | 
             
            					end
         | 
| 629 701 | 
             
            				end
         | 
| 630 702 | 
             
            				context 'two dimensional arrays' do
         | 
| @@ -712,15 +784,15 @@ describe "PG::Type derivations" do | |
| 712 784 | 
             
            				expect( lt.to_h ).to eq( textenc_int_array.to_h )
         | 
| 713 785 | 
             
            			end
         | 
| 714 786 |  | 
| 715 | 
            -
            			it "should be possible to marshal  | 
| 716 | 
            -
            				mt = Marshal.dump( | 
| 787 | 
            +
            			it "should be possible to marshal decoders" do
         | 
| 788 | 
            +
            				mt = Marshal.dump(textdec_string_array_raise)
         | 
| 717 789 | 
             
            				lt = Marshal.load(mt)
         | 
| 718 | 
            -
            				expect( lt.to_h ).to eq(  | 
| 790 | 
            +
            				expect( lt.to_h ).to eq( textdec_string_array_raise.to_h )
         | 
| 719 791 | 
             
            			end
         | 
| 720 792 |  | 
| 721 793 | 
             
            			it "should respond to to_h" do
         | 
| 722 794 | 
             
            				expect( textenc_int_array.to_h ).to eq( {
         | 
| 723 | 
            -
            					name: nil, oid: 0, format: 0,
         | 
| 795 | 
            +
            					name: nil, oid: 0, format: 0, flags: 0,
         | 
| 724 796 | 
             
            					elements_type: textenc_int, needs_quotation: false, delimiter: ','
         | 
| 725 797 | 
             
            				} )
         | 
| 726 798 | 
             
            			end
         | 
| @@ -946,4 +1018,106 @@ describe "PG::Type derivations" do | |
| 946 1018 | 
             
            			end
         | 
| 947 1019 | 
             
            		end
         | 
| 948 1020 | 
             
            	end
         | 
| 1021 | 
            +
             | 
| 1022 | 
            +
            	describe PG::RecordCoder do
         | 
| 1023 | 
            +
            		describe PG::TextEncoder::Record do
         | 
| 1024 | 
            +
            			context "with default typemap" do
         | 
| 1025 | 
            +
            				let!(:encoder) do
         | 
| 1026 | 
            +
            					PG::TextEncoder::Record.new
         | 
| 1027 | 
            +
            				end
         | 
| 1028 | 
            +
             | 
| 1029 | 
            +
            				it "should encode different types of Ruby objects" do
         | 
| 1030 | 
            +
            					expect( encoder.encode([:xyz, 123, 2456, 34567, 456789, 5678901, [1,2,3], 12.1, "abcdefg", nil]) ).
         | 
| 1031 | 
            +
            						to eq('("xyz","123","2456","34567","456789","5678901","[1, 2, 3]","12.1","abcdefg",)')
         | 
| 1032 | 
            +
            				end
         | 
| 1033 | 
            +
             | 
| 1034 | 
            +
            				it 'should output a string with correct character encoding' do
         | 
| 1035 | 
            +
            					v = encoder.encode(["Héllo"], "iso-8859-1")
         | 
| 1036 | 
            +
            					expect( v.encoding ).to eq( Encoding::ISO_8859_1 )
         | 
| 1037 | 
            +
            					expect( v ).to eq( '("Héllo")'.encode(Encoding::ISO_8859_1) )
         | 
| 1038 | 
            +
            				end
         | 
| 1039 | 
            +
            			end
         | 
| 1040 | 
            +
             | 
| 1041 | 
            +
            			context "with TypeMapByClass" do
         | 
| 1042 | 
            +
            				let!(:tm) do
         | 
| 1043 | 
            +
            					tm = PG::TypeMapByClass.new
         | 
| 1044 | 
            +
            					tm[Integer] = textenc_int
         | 
| 1045 | 
            +
            					tm[Float] = intenc_incrementer
         | 
| 1046 | 
            +
            					tm[Array] = PG::TextEncoder::Array.new elements_type: textenc_string
         | 
| 1047 | 
            +
            					tm
         | 
| 1048 | 
            +
            				end
         | 
| 1049 | 
            +
            				let!(:encoder) do
         | 
| 1050 | 
            +
            					PG::TextEncoder::Record.new type_map: tm
         | 
| 1051 | 
            +
            				end
         | 
| 1052 | 
            +
             | 
| 1053 | 
            +
            				it "should have reasonable default values" do
         | 
| 1054 | 
            +
            					expect( encoder.name ).to be_nil
         | 
| 1055 | 
            +
            				end
         | 
| 1056 | 
            +
             | 
| 1057 | 
            +
            				it "copies all attributes with #dup" do
         | 
| 1058 | 
            +
            					encoder.name = "test"
         | 
| 1059 | 
            +
            					encoder.type_map = PG::TypeMapByColumn.new []
         | 
| 1060 | 
            +
            					encoder2 = encoder.dup
         | 
| 1061 | 
            +
            					expect( encoder.object_id ).to_not eq( encoder2.object_id )
         | 
| 1062 | 
            +
            					expect( encoder2.name ).to eq( "test" )
         | 
| 1063 | 
            +
            					expect( encoder2.type_map ).to be_a_kind_of( PG::TypeMapByColumn )
         | 
| 1064 | 
            +
            				end
         | 
| 1065 | 
            +
             | 
| 1066 | 
            +
            				describe '#encode' do
         | 
| 1067 | 
            +
            					it "should encode different types of Ruby objects" do
         | 
| 1068 | 
            +
            						expect( encoder.encode([]) ).to eq("()")
         | 
| 1069 | 
            +
            						expect( encoder.encode(["a"]) ).to eq('("a")')
         | 
| 1070 | 
            +
            						expect( encoder.encode([:xyz, 123, 2456, 34567, 456789, 5678901, [1,2,3], 12.1, "abcdefg", nil]) ).
         | 
| 1071 | 
            +
            							to eq('("xyz","123","2456","34567","456789","5678901","{1,2,3}","13 ","abcdefg",)')
         | 
| 1072 | 
            +
            					end
         | 
| 1073 | 
            +
             | 
| 1074 | 
            +
            					it "should escape special characters" do
         | 
| 1075 | 
            +
            						expect( encoder.encode([" \"\t\n\\\r"]) ).to eq("(\" \"\"\t\n##\r\")".gsub("#", "\\"))
         | 
| 1076 | 
            +
            					end
         | 
| 1077 | 
            +
            				end
         | 
| 1078 | 
            +
            			end
         | 
| 1079 | 
            +
            		end
         | 
| 1080 | 
            +
             | 
| 1081 | 
            +
            		describe PG::TextDecoder::Record do
         | 
| 1082 | 
            +
            			context "with default typemap" do
         | 
| 1083 | 
            +
            				let!(:decoder) do
         | 
| 1084 | 
            +
            					PG::TextDecoder::Record.new
         | 
| 1085 | 
            +
            				end
         | 
| 1086 | 
            +
             | 
| 1087 | 
            +
            				describe '#decode' do
         | 
| 1088 | 
            +
            					it "should decode composite text format to array of strings" do
         | 
| 1089 | 
            +
            						expect( decoder.decode('("fuzzy dice",,"",42,)') ).to eq( ["fuzzy dice",nil, "", "42", nil] )
         | 
| 1090 | 
            +
            					end
         | 
| 1091 | 
            +
             | 
| 1092 | 
            +
            					it 'should respect input character encoding' do
         | 
| 1093 | 
            +
            						v = decoder.decode("(Héllo)".encode("iso-8859-1")).first
         | 
| 1094 | 
            +
            						expect( v.encoding ).to eq(Encoding::ISO_8859_1)
         | 
| 1095 | 
            +
            						expect( v ).to eq("Héllo".encode("iso-8859-1"))
         | 
| 1096 | 
            +
            					end
         | 
| 1097 | 
            +
             | 
| 1098 | 
            +
            					it 'should raise an error on malformed input' do
         | 
| 1099 | 
            +
            						expect{ decoder.decode('') }.to raise_error(ArgumentError, /"" - Missing left parenthesis/)
         | 
| 1100 | 
            +
            						expect{ decoder.decode('(') }.to raise_error(ArgumentError, /"\(" - Unexpected end of input/)
         | 
| 1101 | 
            +
            						expect{ decoder.decode('(\\') }.to raise_error(ArgumentError, /"\(\\" - Unexpected end of input/)
         | 
| 1102 | 
            +
            						expect{ decoder.decode('()x') }.to raise_error(ArgumentError, /"\(\)x" - Junk after right parenthesis/)
         | 
| 1103 | 
            +
            					end
         | 
| 1104 | 
            +
            				end
         | 
| 1105 | 
            +
            			end
         | 
| 1106 | 
            +
             | 
| 1107 | 
            +
            			context "with TypeMapByColumn" do
         | 
| 1108 | 
            +
            				let!(:tm) do
         | 
| 1109 | 
            +
            					PG::TypeMapByColumn.new [textdec_int, textdec_string, intdec_incrementer, nil]
         | 
| 1110 | 
            +
            				end
         | 
| 1111 | 
            +
            				let!(:decoder) do
         | 
| 1112 | 
            +
            					PG::TextDecoder::Record.new type_map: tm
         | 
| 1113 | 
            +
            				end
         | 
| 1114 | 
            +
             | 
| 1115 | 
            +
            				describe '#decode' do
         | 
| 1116 | 
            +
            					it "should decode different types of Ruby objects" do
         | 
| 1117 | 
            +
            						expect( decoder.decode("(123,\" #,#\n#\r#\\ \",234,#\x01#\002)".gsub("#", "\\"))).to eq( [123, " ,\n\r\\ ", 235, "\x01\x02"] )
         | 
| 1118 | 
            +
            					end
         | 
| 1119 | 
            +
            				end
         | 
| 1120 | 
            +
            			end
         | 
| 1121 | 
            +
            		end
         | 
| 1122 | 
            +
            	end
         | 
| 949 1123 | 
             
            end
         | 
    
        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. | 
| 4 | 
            +
              version: 1.2.0
         | 
| 5 5 | 
             
            platform: ruby
         | 
| 6 6 | 
             
            authors:
         | 
| 7 7 | 
             
            - Michael Granger
         | 
| @@ -11,32 +11,31 @@ 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 | 
            -
               | 
| 33 | 
            -
               | 
| 34 | 
            -
               | 
| 35 | 
            -
               | 
| 36 | 
            -
               | 
| 37 | 
            -
              OMKv6pWsoS81vw5KAGBmfX8nht/Py90DQrbRvakATGI=
         | 
| 14 | 
            +
              MIIENDCCApygAwIBAgIBATANBgkqhkiG9w0BAQsFADAiMSAwHgYDVQQDDBdnZWQv
         | 
| 15 | 
            +
              REM9RmFlcmllTVVEL0RDPW9yZzAeFw0xODExMjAxODI5NTlaFw0xOTExMjAxODI5
         | 
| 16 | 
            +
              NTlaMCIxIDAeBgNVBAMMF2dlZC9EQz1GYWVyaWVNVUQvREM9b3JnMIIBojANBgkq
         | 
| 17 | 
            +
              hkiG9w0BAQEFAAOCAY8AMIIBigKCAYEAvyVhkRzvlEs0fe7145BYLfN6njX9ih5H
         | 
| 18 | 
            +
              L60U0p0euIurpv84op9CNKF9tx+1WKwyQvQP7qFGuZxkSUuWcP/sFhDXL1lWUuIl
         | 
| 19 | 
            +
              M4uHbGCRmOshDrF4dgnBeOvkHr1fIhPlJm5FO+Vew8tSQmlDsosxLUx+VB7DrVFO
         | 
| 20 | 
            +
              5PU2AEbf04GGSrmqADGWXeaslaoRdb1fu/0M5qfPTRn5V39sWD9umuDAF9qqil/x
         | 
| 21 | 
            +
              Sl6phTvgBrG8GExHbNZpLARd3xrBYLEFsX7RvBn2UPfgsrtvpdXjsHGfpT3IPN+B
         | 
| 22 | 
            +
              vQ66lts4alKC69TE5cuKasWBm+16A4aEe3XdZBRNmtOu/g81gvwA7fkJHKllJuaI
         | 
| 23 | 
            +
              dXzdHqq+zbGZVSQ7pRYHYomD0IiDe1DbIouFnPWmagaBnGHwXkDT2bKKP+s2v21m
         | 
| 24 | 
            +
              ozilJg4aar2okb/RA6VS87o+d7g6LpDDMMQjH4G9OPnJENLdhu8KnPw/ivSVvQw7
         | 
| 25 | 
            +
              N2I4L/ZOIe2DIVuYH7aLHfjZDQv/mNgpAgMBAAGjdTBzMAkGA1UdEwQCMAAwCwYD
         | 
| 26 | 
            +
              VR0PBAQDAgSwMB0GA1UdDgQWBBRyjf55EbrHagiRLqt5YAd3yb8k4DAcBgNVHREE
         | 
| 27 | 
            +
              FTATgRFnZWRARmFlcmllTVVELm9yZzAcBgNVHRIEFTATgRFnZWRARmFlcmllTVVE
         | 
| 28 | 
            +
              Lm9yZzANBgkqhkiG9w0BAQsFAAOCAYEAP9Ffkvg4e8CjIWi8SykQ8oJSS8jbmbgF
         | 
| 29 | 
            +
              abke3vXWLG6V9kFiObuJd5wZRBluJANu7bEtjgc3fFaGVP2XxVdCpVjNbmMDg4Qp
         | 
| 30 | 
            +
              ovvczP53X6pQP2RSZgxF6Lblvy8y11RziUTVRG/Z2aJHsElo6gI7vQznE/OSDrhC
         | 
| 31 | 
            +
              gEhr8uaIUt7D+HZWRbU0+MkKPpL5uMqaFuJbqXEvSwPTuUuYkDfNfsjQO7ruWBac
         | 
| 32 | 
            +
              bxHCrvpZ6Tijc0nrlyXi6gPOCLeaqhau2xFnlvKgELwsGYSoKBJyDwqtQ5kwrOlU
         | 
| 33 | 
            +
              tkSyLrfZ+RZcH535Hyvif7ZxB0v5OxXXoec+N2vrUsEUMRDL9dg4/WFdN8hIOixF
         | 
| 34 | 
            +
              3IPKpZ1ho0Ya5q7yhygtBK9/NBFHw+nbJjcltfPDBXleRe8u73gnQo8AZIhStYSP
         | 
| 35 | 
            +
              v4qqqa27Bs468d6SoPxjSm8a2mM9HZ4OdWhq4tFsbTeXDVquCfi64OTEaTt2xQdR
         | 
| 36 | 
            +
              JnC4lpJfCP6aCXa5h2XAQfPSH636cQap
         | 
| 38 37 | 
             
              -----END CERTIFICATE-----
         | 
| 39 | 
            -
            date:  | 
| 38 | 
            +
            date: 2019-12-24 00:00:00.000000000 Z
         | 
| 40 39 | 
             
            dependencies:
         | 
| 41 40 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 42 41 | 
             
              name: hoe-mercurial
         | 
| @@ -100,20 +99,14 @@ dependencies: | |
| 100 99 | 
             
                requirements:
         | 
| 101 100 | 
             
                - - "~>"
         | 
| 102 101 | 
             
                  - !ruby/object:Gem::Version
         | 
| 103 | 
            -
                    version:  | 
| 104 | 
            -
                - - ">="
         | 
| 105 | 
            -
                  - !ruby/object:Gem::Version
         | 
| 106 | 
            -
                    version: 0.6.2
         | 
| 102 | 
            +
                    version: 0.7.0
         | 
| 107 103 | 
             
              type: :development
         | 
| 108 104 | 
             
              prerelease: false
         | 
| 109 105 | 
             
              version_requirements: !ruby/object:Gem::Requirement
         | 
| 110 106 | 
             
                requirements:
         | 
| 111 107 | 
             
                - - "~>"
         | 
| 112 108 | 
             
                  - !ruby/object:Gem::Version
         | 
| 113 | 
            -
                    version:  | 
| 114 | 
            -
                - - ">="
         | 
| 115 | 
            -
                  - !ruby/object:Gem::Version
         | 
| 116 | 
            -
                    version: 0.6.2
         | 
| 109 | 
            +
                    version: 0.7.0
         | 
| 117 110 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 118 111 | 
             
              name: hoe-bundler
         | 
| 119 112 | 
             
              requirement: !ruby/object:Gem::Requirement
         | 
| @@ -162,14 +155,14 @@ dependencies: | |
| 162 155 | 
             
                requirements:
         | 
| 163 156 | 
             
                - - "~>"
         | 
| 164 157 | 
             
                  - !ruby/object:Gem::Version
         | 
| 165 | 
            -
                    version: '3. | 
| 158 | 
            +
                    version: '3.20'
         | 
| 166 159 | 
             
              type: :development
         | 
| 167 160 | 
             
              prerelease: false
         | 
| 168 161 | 
             
              version_requirements: !ruby/object:Gem::Requirement
         | 
| 169 162 | 
             
                requirements:
         | 
| 170 163 | 
             
                - - "~>"
         | 
| 171 164 | 
             
                  - !ruby/object:Gem::Version
         | 
| 172 | 
            -
                    version: '3. | 
| 165 | 
            +
                    version: '3.20'
         | 
| 173 166 | 
             
            description: |-
         | 
| 174 167 | 
             
              Pg is the Ruby interface to the {PostgreSQL RDBMS}[http://www.postgresql.org/].
         | 
| 175 168 |  | 
| @@ -215,6 +208,7 @@ extra_rdoc_files: | |
| 215 208 | 
             
            - ext/pg_connection.c
         | 
| 216 209 | 
             
            - ext/pg_copy_coder.c
         | 
| 217 210 | 
             
            - ext/pg_errors.c
         | 
| 211 | 
            +
            - ext/pg_record_coder.c
         | 
| 218 212 | 
             
            - ext/pg_result.c
         | 
| 219 213 | 
             
            - ext/pg_text_decoder.c
         | 
| 220 214 | 
             
            - ext/pg_text_encoder.c
         | 
| @@ -226,7 +220,7 @@ extra_rdoc_files: | |
| 226 220 | 
             
            - ext/pg_type_map_by_mri_type.c
         | 
| 227 221 | 
             
            - ext/pg_type_map_by_oid.c
         | 
| 228 222 | 
             
            - ext/pg_type_map_in_ruby.c
         | 
| 229 | 
            -
            - ext/ | 
| 223 | 
            +
            - ext/pg_util.c
         | 
| 230 224 | 
             
            files:
         | 
| 231 225 | 
             
            - ".gemtest"
         | 
| 232 226 | 
             
            - BSDL
         | 
| @@ -256,6 +250,7 @@ files: | |
| 256 250 | 
             
            - ext/pg_connection.c
         | 
| 257 251 | 
             
            - ext/pg_copy_coder.c
         | 
| 258 252 | 
             
            - ext/pg_errors.c
         | 
| 253 | 
            +
            - ext/pg_record_coder.c
         | 
| 259 254 | 
             
            - ext/pg_result.c
         | 
| 260 255 | 
             
            - ext/pg_text_decoder.c
         | 
| 261 256 | 
             
            - ext/pg_text_encoder.c
         | 
| @@ -267,8 +262,8 @@ files: | |
| 267 262 | 
             
            - ext/pg_type_map_by_mri_type.c
         | 
| 268 263 | 
             
            - ext/pg_type_map_by_oid.c
         | 
| 269 264 | 
             
            - ext/pg_type_map_in_ruby.c
         | 
| 270 | 
            -
            - ext/ | 
| 271 | 
            -
            - ext/ | 
| 265 | 
            +
            - ext/pg_util.c
         | 
| 266 | 
            +
            - ext/pg_util.h
         | 
| 272 267 | 
             
            - ext/vc/pg.sln
         | 
| 273 268 | 
             
            - ext/vc/pg_18/pg.vcproj
         | 
| 274 269 | 
             
            - ext/vc/pg_19/pg_19.vcproj
         | 
| @@ -300,10 +295,11 @@ files: | |
| 300 295 | 
             
            - spec/pg/type_map_spec.rb
         | 
| 301 296 | 
             
            - spec/pg/type_spec.rb
         | 
| 302 297 | 
             
            - spec/pg_spec.rb
         | 
| 303 | 
            -
            homepage: https:// | 
| 298 | 
            +
            homepage: https://github.com/ged/ruby-pg
         | 
| 304 299 | 
             
            licenses:
         | 
| 305 | 
            -
            - BSD- | 
| 306 | 
            -
            metadata: | 
| 300 | 
            +
            - BSD-2-Clause
         | 
| 301 | 
            +
            metadata:
         | 
| 302 | 
            +
              homepage_uri: https://github.com/ged/ruby-pg
         | 
| 307 303 | 
             
            post_install_message: 
         | 
| 308 304 | 
             
            rdoc_options:
         | 
| 309 305 | 
             
            - "--main"
         | 
| @@ -314,15 +310,14 @@ required_ruby_version: !ruby/object:Gem::Requirement | |
| 314 310 | 
             
              requirements:
         | 
| 315 311 | 
             
              - - ">="
         | 
| 316 312 | 
             
                - !ruby/object:Gem::Version
         | 
| 317 | 
            -
                  version: 2. | 
| 313 | 
            +
                  version: '2.2'
         | 
| 318 314 | 
             
            required_rubygems_version: !ruby/object:Gem::Requirement
         | 
| 319 315 | 
             
              requirements:
         | 
| 320 316 | 
             
              - - ">="
         | 
| 321 317 | 
             
                - !ruby/object:Gem::Version
         | 
| 322 318 | 
             
                  version: '0'
         | 
| 323 319 | 
             
            requirements: []
         | 
| 324 | 
            -
             | 
| 325 | 
            -
            rubygems_version: 2.7.6
         | 
| 320 | 
            +
            rubygems_version: 3.0.6
         | 
| 326 321 | 
             
            signing_key: 
         | 
| 327 322 | 
             
            specification_version: 4
         | 
| 328 323 | 
             
            summary: Pg is the Ruby interface to the {PostgreSQL RDBMS}[http://www.postgresql.org/]
         |