pg 1.1.4 → 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 +63 -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 +3 -3
- data/Rakefile.cross +6 -3
- data/ext/errorcodes.def +64 -0
- data/ext/errorcodes.txt +18 -2
- data/ext/extconf.rb +6 -6
- data/ext/pg.c +132 -95
- data/ext/pg.h +20 -18
- data/ext/pg_binary_decoder.c +9 -9
- data/ext/pg_binary_encoder.c +13 -12
- data/ext/pg_coder.c +5 -5
- data/ext/pg_connection.c +388 -298
- data/ext/pg_copy_coder.c +5 -3
- data/ext/pg_record_coder.c +490 -0
- data/ext/pg_result.c +269 -123
- 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 +10 -8
- data/spec/pg/basic_type_mapping_spec.rb +150 -13
- data/spec/pg/connection_spec.rb +89 -50
- 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 +17 -15
- metadata.gz.sig +0 -0
    
        data/lib/pg/constants.rb
    CHANGED
    
    
    
        data/lib/pg/exceptions.rb
    CHANGED
    
    
    
        data/lib/pg/result.rb
    CHANGED
    
    | @@ -1,4 +1,5 @@ | |
| 1 1 | 
             
            # -*- ruby -*-
         | 
| 2 | 
            +
            # frozen_string_literal: true
         | 
| 2 3 |  | 
| 3 4 | 
             
            require 'pg' unless defined?( PG )
         | 
| 4 5 |  | 
| @@ -9,12 +10,23 @@ class PG::Result | |
| 9 10 | 
             
            	#
         | 
| 10 11 | 
             
            	# +type_map+: a PG::TypeMap instance.
         | 
| 11 12 | 
             
            	#
         | 
| 12 | 
            -
            	#  | 
| 13 | 
            +
            	# This method is equal to #type_map= , but returns self, so that calls can be chained.
         | 
| 14 | 
            +
            	#
         | 
| 15 | 
            +
            	# See also PG::BasicTypeMapForResults
         | 
| 13 16 | 
             
            	def map_types!(type_map)
         | 
| 14 17 | 
             
            		self.type_map = type_map
         | 
| 15 18 | 
             
            		return self
         | 
| 16 19 | 
             
            	end
         | 
| 17 20 |  | 
| 21 | 
            +
            	# Set the data type for all field name returning methods.
         | 
| 22 | 
            +
            	#
         | 
| 23 | 
            +
            	# +type+: a Symbol defining the field name type.
         | 
| 24 | 
            +
            	#
         | 
| 25 | 
            +
            	# This method is equal to #field_name_type= , but returns self, so that calls can be chained.
         | 
| 26 | 
            +
            	def field_names_as(type)
         | 
| 27 | 
            +
            		self.field_name_type = type
         | 
| 28 | 
            +
            		return self
         | 
| 29 | 
            +
            	end
         | 
| 18 30 |  | 
| 19 31 | 
             
            	### Return a String representation of the object suitable for debugging.
         | 
| 20 32 | 
             
            	def inspect
         | 
    
        data/lib/pg/text_decoder.rb
    CHANGED
    
    | @@ -1,4 +1,5 @@ | |
| 1 1 | 
             
            # -*- ruby -*-
         | 
| 2 | 
            +
            # frozen_string_literal: true
         | 
| 2 3 |  | 
| 3 4 | 
             
            require 'date'
         | 
| 4 5 | 
             
            require 'json'
         | 
| @@ -6,10 +7,8 @@ require 'json' | |
| 6 7 | 
             
            module PG
         | 
| 7 8 | 
             
            	module TextDecoder
         | 
| 8 9 | 
             
            		class Date < SimpleDecoder
         | 
| 9 | 
            -
            			ISO_DATE = /\A(\d{4})-(\d\d)-(\d\d)\z/
         | 
| 10 | 
            -
             | 
| 11 10 | 
             
            			def decode(string, tuple=nil, field=nil)
         | 
| 12 | 
            -
            				if string =~  | 
| 11 | 
            +
            				if string =~ /\A(\d{4})-(\d\d)-(\d\d)\z/
         | 
| 13 12 | 
             
            					::Date.new $1.to_i, $2.to_i, $3.to_i
         | 
| 14 13 | 
             
            				else
         | 
| 15 14 | 
             
            					string
         | 
    
        data/lib/pg/text_encoder.rb
    CHANGED
    
    | @@ -1,4 +1,5 @@ | |
| 1 1 | 
             
            # -*- ruby -*-
         | 
| 2 | 
            +
            # frozen_string_literal: true
         | 
| 2 3 |  | 
| 3 4 | 
             
            require 'json'
         | 
| 4 5 | 
             
            require 'ipaddr'
         | 
| @@ -6,36 +7,26 @@ require 'ipaddr' | |
| 6 7 | 
             
            module PG
         | 
| 7 8 | 
             
            	module TextEncoder
         | 
| 8 9 | 
             
            		class Date < SimpleEncoder
         | 
| 9 | 
            -
            			STRFTIME_ISO_DATE = "%Y-%m-%d".freeze
         | 
| 10 10 | 
             
            			def encode(value)
         | 
| 11 | 
            -
            				value.respond_to?(:strftime) ? value.strftime( | 
| 11 | 
            +
            				value.respond_to?(:strftime) ? value.strftime("%Y-%m-%d") : value
         | 
| 12 12 | 
             
            			end
         | 
| 13 13 | 
             
            		end
         | 
| 14 14 |  | 
| 15 15 | 
             
            		class TimestampWithoutTimeZone < SimpleEncoder
         | 
| 16 | 
            -
            			STRFTIME_ISO_DATETIME_WITHOUT_TIMEZONE = "%Y-%m-%d %H:%M:%S.%N".freeze
         | 
| 17 16 | 
             
            			def encode(value)
         | 
| 18 | 
            -
            				value.respond_to?(:strftime) ? value.strftime( | 
| 17 | 
            +
            				value.respond_to?(:strftime) ? value.strftime("%Y-%m-%d %H:%M:%S.%N") : value
         | 
| 19 18 | 
             
            			end
         | 
| 20 19 | 
             
            		end
         | 
| 21 20 |  | 
| 22 21 | 
             
            		class TimestampUtc < SimpleEncoder
         | 
| 23 | 
            -
            			STRFTIME_ISO_DATETIME_WITHOUT_TIMEZONE_UTC = "%Y-%m-%d %H:%M:%S.%N".freeze
         | 
| 24 22 | 
             
            			def encode(value)
         | 
| 25 | 
            -
            				value.respond_to?(:utc) ? value.utc.strftime( | 
| 23 | 
            +
            				value.respond_to?(:utc) ? value.utc.strftime("%Y-%m-%d %H:%M:%S.%N") : value
         | 
| 26 24 | 
             
            			end
         | 
| 27 25 | 
             
            		end
         | 
| 28 26 |  | 
| 29 27 | 
             
            		class TimestampWithTimeZone < SimpleEncoder
         | 
| 30 | 
            -
            			STRFTIME_ISO_DATETIME_WITH_TIMEZONE = "%Y-%m-%d %H:%M:%S.%N %:z".freeze
         | 
| 31 28 | 
             
            			def encode(value)
         | 
| 32 | 
            -
            				value.respond_to?(:strftime) ? value.strftime( | 
| 33 | 
            -
            			end
         | 
| 34 | 
            -
            		end
         | 
| 35 | 
            -
             | 
| 36 | 
            -
            		class Numeric < SimpleEncoder
         | 
| 37 | 
            -
            			def encode(value)
         | 
| 38 | 
            -
            				value.is_a?(BigDecimal) ? value.to_s('F') : value
         | 
| 29 | 
            +
            				value.respond_to?(:strftime) ? value.strftime("%Y-%m-%d %H:%M:%S.%N %:z") : value
         | 
| 39 30 | 
             
            			end
         | 
| 40 31 | 
             
            		end
         | 
| 41 32 |  | 
| @@ -51,12 +42,12 @@ module PG | |
| 51 42 | 
             
            				when IPAddr
         | 
| 52 43 | 
             
            					default_prefix = (value.family == Socket::AF_INET ? 32 : 128)
         | 
| 53 44 | 
             
            					s = value.to_s
         | 
| 54 | 
            -
             | 
| 45 | 
            +
            					if value.respond_to?(:prefix)
         | 
| 55 46 | 
             
            						prefix = value.prefix
         | 
| 56 | 
            -
             | 
| 47 | 
            +
            					else
         | 
| 57 48 | 
             
            						range = value.to_range
         | 
| 58 49 | 
             
            						prefix  = default_prefix - Math.log(((range.end.to_i - range.begin.to_i) + 1), 2).to_i
         | 
| 59 | 
            -
             | 
| 50 | 
            +
            					end
         | 
| 60 51 | 
             
            					s << "/" << prefix.to_s if prefix != default_prefix
         | 
| 61 52 | 
             
            					s
         | 
| 62 53 | 
             
            				else
         | 
| @@ -66,4 +57,3 @@ module PG | |
| 66 57 | 
             
            		end
         | 
| 67 58 | 
             
            	end
         | 
| 68 59 | 
             
            end # module PG
         | 
| 69 | 
            -
             | 
| @@ -1,4 +1,5 @@ | |
| 1 1 | 
             
            # -*- ruby -*-
         | 
| 2 | 
            +
            # frozen_string_literal: true
         | 
| 2 3 |  | 
| 3 4 | 
             
            require 'pg' unless defined?( PG )
         | 
| 4 5 |  | 
| @@ -9,7 +10,7 @@ class PG::TypeMapByColumn | |
| 9 10 | 
             
            	end
         | 
| 10 11 |  | 
| 11 12 | 
             
            	def inspect
         | 
| 12 | 
            -
            		type_strings = coders.map{|c| c ?  | 
| 13 | 
            +
            		type_strings = coders.map{|c| c ? c.inspect_short : 'nil' }
         | 
| 13 14 | 
             
            		"#<#{self.class} #{type_strings.join(' ')}>"
         | 
| 14 15 | 
             
            	end
         | 
| 15 16 | 
             
            end
         | 
    
        data/spec/helpers.rb
    CHANGED
    
    | @@ -172,18 +172,18 @@ module PG::TestingHelpers | |
| 172 172 | 
             
            			datadir = testdir + 'data'
         | 
| 173 173 | 
             
            			pidfile = datadir + 'postmaster.pid'
         | 
| 174 174 | 
             
            			if pidfile.exist? && pid = pidfile.read.chomp.to_i
         | 
| 175 | 
            -
            				 | 
| 175 | 
            +
            				trace "pidfile (%p) exists: %d" % [ pidfile, pid ]
         | 
| 176 176 | 
             
            				begin
         | 
| 177 177 | 
             
            					Process.kill( 0, pid )
         | 
| 178 178 | 
             
            				rescue Errno::ESRCH
         | 
| 179 | 
            -
            					 | 
| 179 | 
            +
            					trace "No postmaster running for %s" % [ datadir ]
         | 
| 180 180 | 
             
            					# Process isn't alive, so don't try to stop it
         | 
| 181 181 | 
             
            				else
         | 
| 182 | 
            -
            					 | 
| 182 | 
            +
            					trace "Stopping lingering database at PID %d" % [ pid ]
         | 
| 183 183 | 
             
            					run 'pg_ctl', '-D', datadir.to_s, '-m', 'fast', 'stop'
         | 
| 184 184 | 
             
            				end
         | 
| 185 185 | 
             
            			else
         | 
| 186 | 
            -
            				 | 
| 186 | 
            +
            				trace "No pidfile (%p)" % [ pidfile ]
         | 
| 187 187 | 
             
            			end
         | 
| 188 188 | 
             
            		end
         | 
| 189 189 | 
             
            	end
         | 
| @@ -194,7 +194,7 @@ module PG::TestingHelpers | |
| 194 194 | 
             
            		require 'pg'
         | 
| 195 195 | 
             
            		stop_existing_postmasters()
         | 
| 196 196 |  | 
| 197 | 
            -
            		 | 
| 197 | 
            +
            		trace "Setting up test database for #{description}"
         | 
| 198 198 | 
             
            		@test_pgdata = TEST_DIRECTORY + 'data'
         | 
| 199 199 | 
             
            		@test_pgdata.mkpath
         | 
| 200 200 |  | 
| @@ -209,7 +209,7 @@ module PG::TestingHelpers | |
| 209 209 | 
             
            		begin
         | 
| 210 210 | 
             
            			unless (@test_pgdata+"postgresql.conf").exist?
         | 
| 211 211 | 
             
            				FileUtils.rm_rf( @test_pgdata, :verbose => $DEBUG )
         | 
| 212 | 
            -
            				 | 
| 212 | 
            +
            				trace "Running initdb"
         | 
| 213 213 | 
             
            				log_and_run @logfile, 'initdb', '-E', 'UTF8', '--no-locale', '-D', @test_pgdata.to_s
         | 
| 214 214 | 
             
            			end
         | 
| 215 215 |  | 
| @@ -218,7 +218,7 @@ module PG::TestingHelpers | |
| 218 218 | 
             
            				'-D', @test_pgdata.to_s, 'start'
         | 
| 219 219 | 
             
            			sleep 2
         | 
| 220 220 |  | 
| 221 | 
            -
            			 | 
| 221 | 
            +
            			trace "Creating the test DB"
         | 
| 222 222 | 
             
            			log_and_run @logfile, 'psql', '-e', '-c', 'DROP DATABASE IF EXISTS test', 'postgres'
         | 
| 223 223 | 
             
            			log_and_run @logfile, 'createdb', '-e', 'test'
         | 
| 224 224 |  | 
| @@ -239,7 +239,7 @@ module PG::TestingHelpers | |
| 239 239 |  | 
| 240 240 |  | 
| 241 241 | 
             
            	def teardown_testing_db( conn )
         | 
| 242 | 
            -
            		 | 
| 242 | 
            +
            		trace "Tearing down test database"
         | 
| 243 243 |  | 
| 244 244 | 
             
            		if conn
         | 
| 245 245 | 
             
            			check_for_lingering_connections( conn )
         | 
| @@ -376,5 +376,7 @@ RSpec.configure do |config| | |
| 376 376 | 
             
            	config.filter_run_excluding( :postgresql_93 ) if PG.library_version <  90300
         | 
| 377 377 | 
             
            	config.filter_run_excluding( :postgresql_94 ) if PG.library_version <  90400
         | 
| 378 378 | 
             
            	config.filter_run_excluding( :postgresql_95 ) if PG.library_version <  90500
         | 
| 379 | 
            +
            	config.filter_run_excluding( :postgresql_96 ) if PG.library_version <  90600
         | 
| 379 380 | 
             
            	config.filter_run_excluding( :postgresql_10 ) if PG.library_version < 100000
         | 
| 381 | 
            +
            	config.filter_run_excluding( :postgresql_12 ) if PG.library_version < 120000
         | 
| 380 382 | 
             
            end
         | 
| @@ -21,6 +21,14 @@ ensure | |
| 21 21 | 
             
            	end
         | 
| 22 22 | 
             
            end
         | 
| 23 23 |  | 
| 24 | 
            +
            def expect_to_typecase_result_value_warning
         | 
| 25 | 
            +
            	warning = 'Warning: no type cast defined for type "name" with oid 19. '\
         | 
| 26 | 
            +
            		"Please cast this type explicitly to TEXT to be safe for future changes.\n"\
         | 
| 27 | 
            +
            		'Warning: no type cast defined for type "regproc" with oid 24. '\
         | 
| 28 | 
            +
            		"Please cast this type explicitly to TEXT to be safe for future changes.\n"
         | 
| 29 | 
            +
            	expect { yield }.to output(warning).to_stderr
         | 
| 30 | 
            +
            end
         | 
| 31 | 
            +
             | 
| 24 32 | 
             
            describe 'Basic type mapping' do
         | 
| 25 33 |  | 
| 26 34 | 
             
            	describe PG::BasicTypeMapForQueries do
         | 
| @@ -32,8 +40,8 @@ describe 'Basic type mapping' do | |
| 32 40 | 
             
            		# Encoding Examples
         | 
| 33 41 | 
             
            		#
         | 
| 34 42 |  | 
| 35 | 
            -
            		it "should do basic param encoding" | 
| 36 | 
            -
            			res = @conn.exec_params( "SELECT $1::int8 | 
| 43 | 
            +
            		it "should do basic param encoding" do
         | 
| 44 | 
            +
            			res = @conn.exec_params( "SELECT $1::int8, $2::float, $3, $4::TEXT",
         | 
| 37 45 | 
             
            				[1, 2.1, true, "b"], nil, basic_type_mapping )
         | 
| 38 46 |  | 
| 39 47 | 
             
            			expect( res.values ).to eq( [
         | 
| @@ -43,20 +51,126 @@ describe 'Basic type mapping' do | |
| 43 51 | 
             
            			expect( result_typenames(res) ).to eq( ['bigint', 'double precision', 'boolean', 'text'] )
         | 
| 44 52 | 
             
            		end
         | 
| 45 53 |  | 
| 46 | 
            -
            		it "should do  | 
| 47 | 
            -
            			res = @conn.exec_params( "SELECT $1 | 
| 48 | 
            -
             | 
| 49 | 
            -
             | 
| 50 | 
            -
             | 
| 54 | 
            +
            		it "should do basic Time encoding" do
         | 
| 55 | 
            +
            			res = @conn.exec_params( "SELECT $1 AT TIME ZONE '-02'",
         | 
| 56 | 
            +
            				[Time.new(2019, 12, 8, 20, 38, 12.123, "-01:00")], nil, basic_type_mapping )
         | 
| 57 | 
            +
             | 
| 58 | 
            +
            			expect( res.values ).to eq( [[ "2019-12-08 23:38:12.123" ]] )
         | 
| 59 | 
            +
            		end
         | 
| 60 | 
            +
             | 
| 61 | 
            +
            		it "should do basic param encoding of various float values" do
         | 
| 62 | 
            +
            			res = @conn.exec_params( "SELECT $1::float, $2::float, $3::float, $4::float, $5::float, $6::float, $7::float, $8::float, $9::float, $10::float, $11::float, $12::float",
         | 
| 63 | 
            +
            				[0, 7, 9, 0.1, 0.9, -0.11, 10.11,
         | 
| 64 | 
            +
            			   9876543210987654321e-400,
         | 
| 65 | 
            +
            			   9876543210987654321e400,
         | 
| 66 | 
            +
            			   -1.234567890123456789e-280,
         | 
| 67 | 
            +
            			   -1.234567890123456789e280,
         | 
| 68 | 
            +
            			   9876543210987654321e280
         | 
| 69 | 
            +
            			  ], nil, basic_type_mapping )
         | 
| 70 | 
            +
             | 
| 71 | 
            +
            			expect( res.values[0][0, 9] ).to eq(
         | 
| 72 | 
            +
            					[ "0", "7", "9", "0.1", "0.9", "-0.11", "10.11", "0", "Infinity" ]
         | 
| 73 | 
            +
            			)
         | 
| 74 | 
            +
             | 
| 75 | 
            +
            			expect( res.values[0][9]  ).to match( /^-1\.2345678901234\d*e\-280$/ )
         | 
| 76 | 
            +
            			expect( res.values[0][10] ).to match( /^-1\.2345678901234\d*e\+280$/ )
         | 
| 77 | 
            +
            			expect( res.values[0][11] ).to match(  /^9\.8765432109876\d*e\+298$/ )
         | 
| 78 | 
            +
             | 
| 79 | 
            +
            			expect( result_typenames(res) ).to eq( ['double precision'] * 12 )
         | 
| 80 | 
            +
            		end
         | 
| 81 | 
            +
             | 
| 82 | 
            +
            		it "should do default array-as-array param encoding" do
         | 
| 83 | 
            +
            			expect( basic_type_mapping.encode_array_as).to eq(:array)
         | 
| 84 | 
            +
            			res = @conn.exec_params( "SELECT $1,$2,$3,$4,$5,$6", [
         | 
| 85 | 
            +
            					[1, 2, 3], # Integer -> bigint[]
         | 
| 86 | 
            +
            					[[1, 2], [3, nil]], # Integer two dimensions -> bigint[]
         | 
| 87 | 
            +
            					[1.11, 2.21], # Float -> double precision[]
         | 
| 88 | 
            +
            					['/,"'.gsub("/", "\\"), nil, 'abcäöü'], # String -> text[]
         | 
| 89 | 
            +
            					[BigDecimal("123.45")], # BigDecimal -> numeric[]
         | 
| 90 | 
            +
            					[IPAddr.new('1234::5678')], # IPAddr -> inet[]
         | 
| 51 91 | 
             
            				], nil, basic_type_mapping )
         | 
| 52 92 |  | 
| 53 93 | 
             
            			expect( res.values ).to eq( [[
         | 
| 54 | 
            -
            					'{1,2,3}', | 
| 94 | 
            +
            					'{1,2,3}',
         | 
| 95 | 
            +
            					'{{1,2},{3,NULL}}',
         | 
| 55 96 | 
             
            					'{1.11,2.21}',
         | 
| 56 97 | 
             
            					'{"//,/"",NULL,abcäöü}'.gsub("/", "\\"),
         | 
| 98 | 
            +
            					'{123.45}',
         | 
| 99 | 
            +
            					'{1234::5678}',
         | 
| 57 100 | 
             
            			]] )
         | 
| 58 101 |  | 
| 59 | 
            -
            			expect( result_typenames(res) ).to eq( ['bigint[]', 'bigint[]', 'double precision[]', 'text[]'] )
         | 
| 102 | 
            +
            			expect( result_typenames(res) ).to eq( ['bigint[]', 'bigint[]', 'double precision[]', 'text[]', 'numeric[]', 'inet[]'] )
         | 
| 103 | 
            +
            		end
         | 
| 104 | 
            +
             | 
| 105 | 
            +
            		it "should do default array-as-array param encoding with Time objects" do
         | 
| 106 | 
            +
            			res = @conn.exec_params( "SELECT $1", [
         | 
| 107 | 
            +
            					[Time.new(2019, 12, 8, 20, 38, 12.123, "-01:00")], # Time -> timestamptz[]
         | 
| 108 | 
            +
            				], nil, basic_type_mapping )
         | 
| 109 | 
            +
             | 
| 110 | 
            +
            			expect( res.values[0][0] ).to match( /\{\"2019-12-08 \d\d:38:12.123[+-]\d\d\"\}/ )
         | 
| 111 | 
            +
            			expect( result_typenames(res) ).to eq( ['timestamp with time zone[]'] )
         | 
| 112 | 
            +
            		end
         | 
| 113 | 
            +
             | 
| 114 | 
            +
            		it "should do array-as-json encoding" do
         | 
| 115 | 
            +
            			basic_type_mapping.encode_array_as = :json
         | 
| 116 | 
            +
            			expect( basic_type_mapping.encode_array_as).to eq(:json)
         | 
| 117 | 
            +
             | 
| 118 | 
            +
            			res = @conn.exec_params( "SELECT $1::JSON, $2::JSON", [
         | 
| 119 | 
            +
            					[1, {a: 5}, true, ["a", 2], [3.4, nil]],
         | 
| 120 | 
            +
            					['/,"'.gsub("/", "\\"), nil, 'abcäöü'],
         | 
| 121 | 
            +
            				], nil, basic_type_mapping )
         | 
| 122 | 
            +
             | 
| 123 | 
            +
            			expect( res.values ).to eq( [[
         | 
| 124 | 
            +
            					'[1,{"a":5},true,["a",2],[3.4,null]]',
         | 
| 125 | 
            +
            					'["//,/"",null,"abcäöü"]'.gsub("/", "\\"),
         | 
| 126 | 
            +
            			]] )
         | 
| 127 | 
            +
             | 
| 128 | 
            +
            			expect( result_typenames(res) ).to eq( ['json', 'json'] )
         | 
| 129 | 
            +
            		end
         | 
| 130 | 
            +
             | 
| 131 | 
            +
            		it "should do hash-as-json encoding" do
         | 
| 132 | 
            +
            			res = @conn.exec_params( "SELECT $1::JSON, $2::JSON", [
         | 
| 133 | 
            +
            					{a: 5, b: ["a", 2], c: nil},
         | 
| 134 | 
            +
            					{qu: '/,"'.gsub("/", "\\"), ni: nil, uml: 'abcäöü'},
         | 
| 135 | 
            +
            				], nil, basic_type_mapping )
         | 
| 136 | 
            +
             | 
| 137 | 
            +
            			expect( res.values ).to eq( [[
         | 
| 138 | 
            +
            					'{"a":5,"b":["a",2],"c":null}',
         | 
| 139 | 
            +
            					'{"qu":"//,/"","ni":null,"uml":"abcäöü"}'.gsub("/", "\\"),
         | 
| 140 | 
            +
            			]] )
         | 
| 141 | 
            +
             | 
| 142 | 
            +
            			expect( result_typenames(res) ).to eq( ['json', 'json'] )
         | 
| 143 | 
            +
            		end
         | 
| 144 | 
            +
             | 
| 145 | 
            +
            		describe "Record encoding" do
         | 
| 146 | 
            +
            			before :all do
         | 
| 147 | 
            +
            				@conn.exec("CREATE TYPE test_record1 AS (i int, d float, t text)")
         | 
| 148 | 
            +
            				@conn.exec("CREATE TYPE test_record2 AS (i int, r test_record1)")
         | 
| 149 | 
            +
            			end
         | 
| 150 | 
            +
             | 
| 151 | 
            +
            			after :all do
         | 
| 152 | 
            +
            				@conn.exec("DROP TYPE IF EXISTS test_record2 CASCADE")
         | 
| 153 | 
            +
            				@conn.exec("DROP TYPE IF EXISTS test_record1 CASCADE")
         | 
| 154 | 
            +
            			end
         | 
| 155 | 
            +
             | 
| 156 | 
            +
            			it "should do array-as-record encoding" do
         | 
| 157 | 
            +
            				basic_type_mapping.encode_array_as = :record
         | 
| 158 | 
            +
            				expect( basic_type_mapping.encode_array_as).to eq(:record)
         | 
| 159 | 
            +
             | 
| 160 | 
            +
            				res = @conn.exec_params( "SELECT $1::test_record1, $2::test_record2, $3::text", [
         | 
| 161 | 
            +
            						[5, 3.4, "txt"],
         | 
| 162 | 
            +
            				    [1, [2, 4.5, "bcd"]],
         | 
| 163 | 
            +
            				    [4, 5, 6],
         | 
| 164 | 
            +
            					], nil, basic_type_mapping )
         | 
| 165 | 
            +
             | 
| 166 | 
            +
            				expect( res.values ).to eq( [[
         | 
| 167 | 
            +
            						'(5,3.4,txt)',
         | 
| 168 | 
            +
            				    '(1,"(2,4.5,bcd)")',
         | 
| 169 | 
            +
            						'("4","5","6")',
         | 
| 170 | 
            +
            				]] )
         | 
| 171 | 
            +
             | 
| 172 | 
            +
            				expect( result_typenames(res) ).to eq( ['test_record1', 'test_record2', 'text'] )
         | 
| 173 | 
            +
            			end
         | 
| 60 174 | 
             
            		end
         | 
| 61 175 |  | 
| 62 176 | 
             
            		it "should do bigdecimal param encoding" do
         | 
| @@ -82,6 +196,23 @@ describe 'Basic type mapping' do | |
| 82 196 | 
             
            			expect( result_typenames(res) ).to eq( ['inet', 'inet', 'cidr', 'cidr'] )
         | 
| 83 197 | 
             
            		end
         | 
| 84 198 |  | 
| 199 | 
            +
            		it "should do array of string encoding on unknown classes" do
         | 
| 200 | 
            +
            			iv = Class.new do
         | 
| 201 | 
            +
            				def to_s
         | 
| 202 | 
            +
            					"abc"
         | 
| 203 | 
            +
            				end
         | 
| 204 | 
            +
            			end.new
         | 
| 205 | 
            +
            			res = @conn.exec_params( "SELECT $1", [
         | 
| 206 | 
            +
            					[iv, iv], # Unknown -> text[]
         | 
| 207 | 
            +
            				], nil, basic_type_mapping )
         | 
| 208 | 
            +
             | 
| 209 | 
            +
            			expect( res.values ).to eq( [[
         | 
| 210 | 
            +
            					'{abc,abc}',
         | 
| 211 | 
            +
            			]] )
         | 
| 212 | 
            +
             | 
| 213 | 
            +
            			expect( result_typenames(res) ).to eq( ['text[]'] )
         | 
| 214 | 
            +
            		end
         | 
| 215 | 
            +
             | 
| 85 216 | 
             
            	end
         | 
| 86 217 |  | 
| 87 218 |  | 
| @@ -95,7 +226,7 @@ describe 'Basic type mapping' do | |
| 95 226 | 
             
            		# Decoding Examples
         | 
| 96 227 | 
             
            		#
         | 
| 97 228 |  | 
| 98 | 
            -
            		it "should do OID based type conversions" | 
| 229 | 
            +
            		it "should do OID based type conversions" do
         | 
| 99 230 | 
             
            			res = @conn.exec( "SELECT 1, 'a', 2.0::FLOAT, TRUE, '2013-06-30'::DATE, generate_series(4,5)" )
         | 
| 100 231 | 
             
            			expect( res.map_types!(basic_type_mapping).values ).to eq( [
         | 
| 101 232 | 
             
            					[ 1, 'a', 2.0, true, Date.new(2013,6,30), 4 ],
         | 
| @@ -187,7 +318,9 @@ describe 'Basic type mapping' do | |
| 187 318 | 
             
            				it "should convert format #{format} timestamps per TimestampUtc" do
         | 
| 188 319 | 
             
            					restore_type("timestamp") do
         | 
| 189 320 | 
             
            						PG::BasicTypeRegistry.register_type 0, 'timestamp', nil, PG::TextDecoder::TimestampUtc
         | 
| 190 | 
            -
            						 | 
| 321 | 
            +
            						expect_to_typecase_result_value_warning do
         | 
| 322 | 
            +
            							@conn.type_map_for_results = PG::BasicTypeMapForResults.new(@conn)
         | 
| 323 | 
            +
            						end
         | 
| 191 324 | 
             
            						res = @conn.exec_params( "SELECT CAST('2013-07-31 23:58:59+02' AS TIMESTAMP WITHOUT TIME ZONE),
         | 
| 192 325 | 
             
            																			CAST('1913-12-31 23:58:59.1231-03' AS TIMESTAMP WITHOUT TIME ZONE),
         | 
| 193 326 | 
             
            																			CAST('4714-11-24 23:58:59.1231-03 BC' AS TIMESTAMP WITHOUT TIME ZONE),
         | 
| @@ -209,7 +342,9 @@ describe 'Basic type mapping' do | |
| 209 342 | 
             
            					restore_type("timestamp") do
         | 
| 210 343 | 
             
            						PG::BasicTypeRegistry.register_type 0, 'timestamp', nil, PG::TextDecoder::TimestampUtcToLocal
         | 
| 211 344 | 
             
            						PG::BasicTypeRegistry.register_type 1, 'timestamp', nil, PG::BinaryDecoder::TimestampUtcToLocal
         | 
| 212 | 
            -
            						 | 
| 345 | 
            +
            						expect_to_typecase_result_value_warning do
         | 
| 346 | 
            +
            							@conn.type_map_for_results = PG::BasicTypeMapForResults.new(@conn)
         | 
| 347 | 
            +
            						end
         | 
| 213 348 | 
             
            						res = @conn.exec_params( "SELECT CAST('2013-07-31 23:58:59+02' AS TIMESTAMP WITHOUT TIME ZONE),
         | 
| 214 349 | 
             
            																			CAST('1913-12-31 23:58:59.1231-03' AS TIMESTAMP WITHOUT TIME ZONE),
         | 
| 215 350 | 
             
            																			CAST('4714-11-24 23:58:59.1231-03 BC' AS TIMESTAMP WITHOUT TIME ZONE),
         | 
| @@ -231,7 +366,9 @@ describe 'Basic type mapping' do | |
| 231 366 | 
             
            					restore_type("timestamp") do
         | 
| 232 367 | 
             
            						PG::BasicTypeRegistry.register_type 0, 'timestamp', nil, PG::TextDecoder::TimestampLocal
         | 
| 233 368 | 
             
            						PG::BasicTypeRegistry.register_type 1, 'timestamp', nil, PG::BinaryDecoder::TimestampLocal
         | 
| 234 | 
            -
            						 | 
| 369 | 
            +
            						expect_to_typecase_result_value_warning do
         | 
| 370 | 
            +
            							@conn.type_map_for_results = PG::BasicTypeMapForResults.new(@conn)
         | 
| 371 | 
            +
            						end
         | 
| 235 372 | 
             
            						res = @conn.exec_params( "SELECT CAST('2013-07-31 23:58:59' AS TIMESTAMP WITHOUT TIME ZONE),
         | 
| 236 373 | 
             
            																			CAST('1913-12-31 23:58:59.1231' AS TIMESTAMP WITHOUT TIME ZONE),
         | 
| 237 374 | 
             
            																			CAST('4714-11-24 23:58:59.1231-03 BC' AS TIMESTAMP WITHOUT TIME ZONE),
         | 
    
        data/spec/pg/connection_spec.rb
    CHANGED
    
    | @@ -288,7 +288,20 @@ describe PG::Connection do | |
| 288 288 | 
             
            		expect( @conn.host ).to eq( "localhost" )
         | 
| 289 289 | 
             
            	end
         | 
| 290 290 |  | 
| 291 | 
            -
            	 | 
| 291 | 
            +
            	it "can set error verbosity" do
         | 
| 292 | 
            +
            		old = @conn.set_error_verbosity( PG::PQERRORS_TERSE )
         | 
| 293 | 
            +
            		new = @conn.set_error_verbosity( old )
         | 
| 294 | 
            +
            		expect( new ).to eq( PG::PQERRORS_TERSE )
         | 
| 295 | 
            +
            	end
         | 
| 296 | 
            +
             | 
| 297 | 
            +
            	it "can set error context visibility", :postgresql_96 do
         | 
| 298 | 
            +
            		old = @conn.set_error_context_visibility( PG::PQSHOW_CONTEXT_NEVER )
         | 
| 299 | 
            +
            		new = @conn.set_error_context_visibility( old )
         | 
| 300 | 
            +
            		expect( new ).to eq( PG::PQSHOW_CONTEXT_NEVER )
         | 
| 301 | 
            +
            	end
         | 
| 302 | 
            +
             | 
| 303 | 
            +
            	let(:expected_trace_output) do
         | 
| 304 | 
            +
            		%{
         | 
| 292 305 | 
             
            		To backend> Msg Q
         | 
| 293 306 | 
             
            		To backend> "SELECT 1 AS one"
         | 
| 294 307 | 
             
            		To backend> Msg complete, length 21
         | 
| @@ -316,6 +329,7 @@ describe PG::Connection do | |
| 316 329 | 
             
            		From backend (#4)> 5
         | 
| 317 330 | 
             
            		From backend> T
         | 
| 318 331 | 
             
            		}.gsub( /^\t{2}/, '' ).lstrip
         | 
| 332 | 
            +
            	end
         | 
| 319 333 |  | 
| 320 334 | 
             
            	it "trace and untrace client-server communication", :unix do
         | 
| 321 335 | 
             
            			# be careful to explicitly close files so that the
         | 
| @@ -341,7 +355,7 @@ describe PG::Connection do | |
| 341 355 | 
             
            			#  From backend> T
         | 
| 342 356 | 
             
            			trace_data.sub!( /(From backend> Z\nFrom backend \(#4\)> 5\n){3}/m, '\\1\\1' )
         | 
| 343 357 |  | 
| 344 | 
            -
            			expect( trace_data ).to eq(  | 
| 358 | 
            +
            			expect( trace_data ).to eq( expected_trace_output )
         | 
| 345 359 | 
             
            		end
         | 
| 346 360 |  | 
| 347 361 | 
             
            	it "allows a query to be cancelled" do
         | 
| @@ -356,8 +370,6 @@ describe PG::Connection do | |
| 356 370 | 
             
            	end
         | 
| 357 371 |  | 
| 358 372 | 
             
            	it "can stop a thread that runs a blocking query with async_exec" do
         | 
| 359 | 
            -
            		pending "this does not work on Rubinius" if RUBY_ENGINE=='rbx'
         | 
| 360 | 
            -
             | 
| 361 373 | 
             
            		start = Time.now
         | 
| 362 374 | 
             
            		t = Thread.new do
         | 
| 363 375 | 
             
            			@conn.async_exec( 'select pg_sleep(10)' )
         | 
| @@ -371,24 +383,16 @@ describe PG::Connection do | |
| 371 383 |  | 
| 372 384 | 
             
            	it "should work together with signal handlers", :unix do
         | 
| 373 385 | 
             
            		signal_received = false
         | 
| 374 | 
            -
            		trap ' | 
| 386 | 
            +
            		trap 'USR2' do
         | 
| 375 387 | 
             
            			signal_received = true
         | 
| 376 388 | 
             
            		end
         | 
| 377 389 |  | 
| 378 390 | 
             
            		Thread.new do
         | 
| 379 391 | 
             
            			sleep 0.1
         | 
| 380 | 
            -
            			Process.kill(" | 
| 392 | 
            +
            			Process.kill("USR2", Process.pid)
         | 
| 381 393 | 
             
            		end
         | 
| 382 394 | 
             
            		@conn.exec("select pg_sleep(0.3)")
         | 
| 383 395 | 
             
            		expect( signal_received ).to be_truthy
         | 
| 384 | 
            -
             | 
| 385 | 
            -
            		signal_received = false
         | 
| 386 | 
            -
            		Thread.new do
         | 
| 387 | 
            -
            			sleep 0.1
         | 
| 388 | 
            -
            			Process.kill("USR1", Process.pid)
         | 
| 389 | 
            -
            		end
         | 
| 390 | 
            -
            		@conn.async_exec("select pg_sleep(0.3)")
         | 
| 391 | 
            -
            		expect( signal_received ).to be_truthy
         | 
| 392 396 | 
             
            	end
         | 
| 393 397 |  | 
| 394 398 |  | 
| @@ -571,7 +575,7 @@ describe PG::Connection do | |
| 571 575 | 
             
            		expect( @conn.wait_for_notify( 1 ) ).to be_nil
         | 
| 572 576 | 
             
            		expect( notices.first ).to_not be_nil
         | 
| 573 577 | 
             
            		et = Time.now
         | 
| 574 | 
            -
            		expect( (et - notices.first[1]) ).to be >= 0. | 
| 578 | 
            +
            		expect( (et - notices.first[1]) ).to be >= 0.3
         | 
| 575 579 | 
             
            		expect( (et - st) ).to be >= 0.9
         | 
| 576 580 | 
             
            		expect( (et - st) ).to be < 1.4
         | 
| 577 581 | 
             
            	end
         | 
| @@ -675,7 +679,7 @@ describe PG::Connection do | |
| 675 679 | 
             
            				@conn.copy_data( "COPY copytable FROM STDOUT" ) do |res|
         | 
| 676 680 | 
             
            					@conn.put_copy_data "xyz\n"
         | 
| 677 681 | 
             
            				end
         | 
| 678 | 
            -
            			}.to raise_error(PG::Error, /invalid input syntax for integer/)
         | 
| 682 | 
            +
            			}.to raise_error(PG::Error, /invalid input syntax for .*integer/)
         | 
| 679 683 | 
             
            		end
         | 
| 680 684 | 
             
            		expect( @conn ).to still_be_usable
         | 
| 681 685 | 
             
            	end
         | 
| @@ -1233,53 +1237,41 @@ describe PG::Connection do | |
| 1233 1237 |  | 
| 1234 1238 | 
             
            	end
         | 
| 1235 1239 |  | 
| 1236 | 
            -
            	context "multinationalization support" | 
| 1240 | 
            +
            	context "multinationalization support" do
         | 
| 1237 1241 |  | 
| 1238 1242 | 
             
            		describe "rubyforge #22925: m17n support" do
         | 
| 1239 1243 | 
             
            			it "should return results in the same encoding as the client (iso-8859-1)" do
         | 
| 1240 | 
            -
            				 | 
| 1241 | 
            -
            				@conn. | 
| 1242 | 
            -
             | 
| 1243 | 
            -
            					res = conn.exec_params("VALUES ('fantasia')", [], 0)
         | 
| 1244 | 
            -
            					out_string = res[0]['column1']
         | 
| 1245 | 
            -
            				end
         | 
| 1244 | 
            +
            				@conn.internal_encoding = 'iso8859-1'
         | 
| 1245 | 
            +
            				res = @conn.exec_params("VALUES ('fantasia')", [], 0)
         | 
| 1246 | 
            +
            				out_string = res[0]['column1']
         | 
| 1246 1247 | 
             
            				expect( out_string ).to eq( 'fantasia' )
         | 
| 1247 1248 | 
             
            				expect( out_string.encoding ).to eq( Encoding::ISO8859_1 )
         | 
| 1248 1249 | 
             
            			end
         | 
| 1249 1250 |  | 
| 1250 1251 | 
             
            			it "should return results in the same encoding as the client (utf-8)" do
         | 
| 1251 | 
            -
            				 | 
| 1252 | 
            -
            				@conn. | 
| 1253 | 
            -
             | 
| 1254 | 
            -
            					res = conn.exec_params("VALUES ('世界線航跡蔵')", [], 0)
         | 
| 1255 | 
            -
            					out_string = res[0]['column1']
         | 
| 1256 | 
            -
            				end
         | 
| 1252 | 
            +
            				@conn.internal_encoding = 'utf-8'
         | 
| 1253 | 
            +
            				res = @conn.exec_params("VALUES ('世界線航跡蔵')", [], 0)
         | 
| 1254 | 
            +
            				out_string = res[0]['column1']
         | 
| 1257 1255 | 
             
            				expect( out_string ).to eq( '世界線航跡蔵' )
         | 
| 1258 1256 | 
             
            				expect( out_string.encoding ).to eq( Encoding::UTF_8 )
         | 
| 1259 1257 | 
             
            			end
         | 
| 1260 1258 |  | 
| 1261 1259 | 
             
            			it "should return results in the same encoding as the client (EUC-JP)" do
         | 
| 1262 | 
            -
            				 | 
| 1263 | 
            -
            				 | 
| 1264 | 
            -
             | 
| 1265 | 
            -
             | 
| 1266 | 
            -
            					res = conn.exec_params(stmt, [], 0)
         | 
| 1267 | 
            -
            					out_string = res[0]['column1']
         | 
| 1268 | 
            -
            				end
         | 
| 1260 | 
            +
            				@conn.internal_encoding = 'EUC-JP'
         | 
| 1261 | 
            +
            				stmt = "VALUES ('世界線航跡蔵')".encode('EUC-JP')
         | 
| 1262 | 
            +
            				res = @conn.exec_params(stmt, [], 0)
         | 
| 1263 | 
            +
            				out_string = res[0]['column1']
         | 
| 1269 1264 | 
             
            				expect( out_string ).to eq( '世界線航跡蔵'.encode('EUC-JP') )
         | 
| 1270 1265 | 
             
            				expect( out_string.encoding ).to eq( Encoding::EUC_JP )
         | 
| 1271 1266 | 
             
            			end
         | 
| 1272 1267 |  | 
| 1273 1268 | 
             
            			it "returns the results in the correct encoding even if the client_encoding has " +
         | 
| 1274 1269 | 
             
            			   "changed since the results were fetched" do
         | 
| 1275 | 
            -
            				 | 
| 1276 | 
            -
            				 | 
| 1277 | 
            -
             | 
| 1278 | 
            -
             | 
| 1279 | 
            -
             | 
| 1280 | 
            -
            					conn.internal_encoding = 'utf-8'
         | 
| 1281 | 
            -
            					out_string = res[0]['column1']
         | 
| 1282 | 
            -
            				end
         | 
| 1270 | 
            +
            				@conn.internal_encoding = 'EUC-JP'
         | 
| 1271 | 
            +
            				stmt = "VALUES ('世界線航跡蔵')".encode('EUC-JP')
         | 
| 1272 | 
            +
            				res = @conn.exec_params(stmt, [], 0)
         | 
| 1273 | 
            +
            				@conn.internal_encoding = 'utf-8'
         | 
| 1274 | 
            +
            				out_string = res[0]['column1']
         | 
| 1283 1275 | 
             
            				expect( out_string ).to eq( '世界線航跡蔵'.encode('EUC-JP') )
         | 
| 1284 1276 | 
             
            				expect( out_string.encoding ).to eq( Encoding::EUC_JP )
         | 
| 1285 1277 | 
             
            			end
         | 
| @@ -1358,6 +1350,21 @@ describe PG::Connection do | |
| 1358 1350 | 
             
            				expect { @conn.set_client_encoding( :invalid ) }.to raise_error(TypeError)
         | 
| 1359 1351 | 
             
            				expect { @conn.set_client_encoding( nil ) }.to raise_error(TypeError)
         | 
| 1360 1352 | 
             
            			end
         | 
| 1353 | 
            +
             | 
| 1354 | 
            +
            			it "can use an encoding with high index for client encoding" do
         | 
| 1355 | 
            +
            				# Allocate a lot of encoding indices, so that MRI's ENCODING_INLINE_MAX is exceeded
         | 
| 1356 | 
            +
            				unless Encoding.name_list.include?("pgtest-0")
         | 
| 1357 | 
            +
            					256.times do |eidx|
         | 
| 1358 | 
            +
            						Encoding::UTF_8.replicate("pgtest-#{eidx}")
         | 
| 1359 | 
            +
            					end
         | 
| 1360 | 
            +
            				end
         | 
| 1361 | 
            +
             | 
| 1362 | 
            +
            				# Now allocate the JOHAB encoding with an unusual high index
         | 
| 1363 | 
            +
            				@conn.set_client_encoding "JOHAB"
         | 
| 1364 | 
            +
            				val = @conn.exec("SELECT chr(x'3391'::int)").values[0][0]
         | 
| 1365 | 
            +
            				expect( val.encoding.name ).to eq( "JOHAB" )
         | 
| 1366 | 
            +
            			end
         | 
| 1367 | 
            +
             | 
| 1361 1368 | 
             
            		end
         | 
| 1362 1369 |  | 
| 1363 1370 | 
             
            		describe "respect and convert character encoding of input strings" do
         | 
| @@ -1501,7 +1508,7 @@ describe PG::Connection do | |
| 1501 1508 |  | 
| 1502 1509 | 
             
            		describe "Ruby 1.9.x default_internal encoding" do
         | 
| 1503 1510 |  | 
| 1504 | 
            -
            			it "honors the Encoding.default_internal if it's set and the synchronous interface is used" do
         | 
| 1511 | 
            +
            			it "honors the Encoding.default_internal if it's set and the synchronous interface is used", :without_transaction do
         | 
| 1505 1512 | 
             
            				@conn.transaction do |txn_conn|
         | 
| 1506 1513 | 
             
            					txn_conn.internal_encoding = Encoding::ISO8859_1
         | 
| 1507 1514 | 
             
            					txn_conn.exec( "CREATE TABLE defaultinternaltest ( foo text )" )
         | 
| @@ -1603,9 +1610,8 @@ describe PG::Connection do | |
| 1603 1610 | 
             
            			end
         | 
| 1604 1611 | 
             
            		end
         | 
| 1605 1612 |  | 
| 1606 | 
            -
            		it "receives properly encoded text from wait_for_notify" do
         | 
| 1613 | 
            +
            		it "receives properly encoded text from wait_for_notify", :without_transaction do
         | 
| 1607 1614 | 
             
            			@conn.internal_encoding = 'utf-8'
         | 
| 1608 | 
            -
            			@conn.exec( 'ROLLBACK' )
         | 
| 1609 1615 | 
             
            			@conn.exec( 'LISTEN "Möhre"' )
         | 
| 1610 1616 | 
             
            			@conn.exec( %Q{NOTIFY "Möhre", '世界線航跡蔵'} )
         | 
| 1611 1617 | 
             
            			event, pid, msg = nil
         | 
| @@ -1620,9 +1626,8 @@ describe PG::Connection do | |
| 1620 1626 | 
             
            			expect( msg.encoding ).to eq( Encoding::UTF_8 )
         | 
| 1621 1627 | 
             
            		end
         | 
| 1622 1628 |  | 
| 1623 | 
            -
            		it "returns properly encoded text from notifies" do
         | 
| 1629 | 
            +
            		it "returns properly encoded text from notifies", :without_transaction do
         | 
| 1624 1630 | 
             
            			@conn.internal_encoding = 'utf-8'
         | 
| 1625 | 
            -
            			@conn.exec( 'ROLLBACK' )
         | 
| 1626 1631 | 
             
            			@conn.exec( 'LISTEN "Möhre"' )
         | 
| 1627 1632 | 
             
            			@conn.exec( %Q{NOTIFY "Möhre", '世界線航跡蔵'} )
         | 
| 1628 1633 | 
             
            			@conn.exec( 'UNLISTEN "Möhre"' )
         | 
| @@ -1636,7 +1641,7 @@ describe PG::Connection do | |
| 1636 1641 | 
             
            		end
         | 
| 1637 1642 | 
             
            	end
         | 
| 1638 1643 |  | 
| 1639 | 
            -
            	context "OS thread support" | 
| 1644 | 
            +
            	context "OS thread support" do
         | 
| 1640 1645 | 
             
            		it "Connection#exec shouldn't block a second thread" do
         | 
| 1641 1646 | 
             
            			t = Thread.new do
         | 
| 1642 1647 | 
             
            				@conn.exec( "select pg_sleep(1)" )
         | 
| @@ -1831,6 +1836,40 @@ describe PG::Connection do | |
| 1831 1836 | 
             
            		end
         | 
| 1832 1837 | 
             
            	end
         | 
| 1833 1838 |  | 
| 1839 | 
            +
            	describe :field_name_type do
         | 
| 1840 | 
            +
            		before :each do
         | 
| 1841 | 
            +
            			@conn2 = PG.connect(@conninfo)
         | 
| 1842 | 
            +
            		end
         | 
| 1843 | 
            +
            		after :each do
         | 
| 1844 | 
            +
            			@conn2.close
         | 
| 1845 | 
            +
            		end
         | 
| 1846 | 
            +
             | 
| 1847 | 
            +
            		it "uses string field names per default" do
         | 
| 1848 | 
            +
            			expect(@conn2.field_name_type).to eq(:string)
         | 
| 1849 | 
            +
            		end
         | 
| 1850 | 
            +
             | 
| 1851 | 
            +
            		it "can set string field names" do
         | 
| 1852 | 
            +
            			@conn2.field_name_type = :string
         | 
| 1853 | 
            +
            			expect(@conn2.field_name_type).to eq(:string)
         | 
| 1854 | 
            +
            			res = @conn2.exec("SELECT 1 as az")
         | 
| 1855 | 
            +
            			expect(res.field_name_type).to eq(:string)
         | 
| 1856 | 
            +
            			expect(res.fields).to eq(["az"])
         | 
| 1857 | 
            +
            		end
         | 
| 1858 | 
            +
             | 
| 1859 | 
            +
            		it "can set symbol field names" do
         | 
| 1860 | 
            +
            			@conn2.field_name_type = :symbol
         | 
| 1861 | 
            +
            			expect(@conn2.field_name_type).to eq(:symbol)
         | 
| 1862 | 
            +
            			res = @conn2.exec("SELECT 1 as az")
         | 
| 1863 | 
            +
            			expect(res.field_name_type).to eq(:symbol)
         | 
| 1864 | 
            +
            			expect(res.fields).to eq([:az])
         | 
| 1865 | 
            +
            		end
         | 
| 1866 | 
            +
             | 
| 1867 | 
            +
            		it "can't set invalid values" do
         | 
| 1868 | 
            +
            			expect{ @conn2.field_name_type = :sym }.to raise_error(ArgumentError, /invalid argument :sym/)
         | 
| 1869 | 
            +
            			expect{ @conn2.field_name_type = "symbol" }.to raise_error(ArgumentError, /invalid argument "symbol"/)
         | 
| 1870 | 
            +
            		end
         | 
| 1871 | 
            +
            	end
         | 
| 1872 | 
            +
             | 
| 1834 1873 | 
             
            	describe "deprecated forms of methods" do
         | 
| 1835 1874 | 
             
            		it "should forward exec to exec_params" do
         | 
| 1836 1875 | 
             
            			res = @conn.exec("VALUES($1::INT)", [7]).values
         |