pg 1.1.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (77) hide show
  1. checksums.yaml +7 -0
  2. checksums.yaml.gz.sig +3 -0
  3. data.tar.gz.sig +0 -0
  4. data/.gemtest +0 -0
  5. data/BSDL +22 -0
  6. data/ChangeLog +6595 -0
  7. data/Contributors.rdoc +46 -0
  8. data/History.rdoc +492 -0
  9. data/LICENSE +56 -0
  10. data/Manifest.txt +72 -0
  11. data/POSTGRES +23 -0
  12. data/README-OS_X.rdoc +68 -0
  13. data/README-Windows.rdoc +56 -0
  14. data/README.ja.rdoc +14 -0
  15. data/README.rdoc +178 -0
  16. data/Rakefile +215 -0
  17. data/Rakefile.cross +298 -0
  18. data/ext/errorcodes.def +968 -0
  19. data/ext/errorcodes.rb +45 -0
  20. data/ext/errorcodes.txt +478 -0
  21. data/ext/extconf.rb +94 -0
  22. data/ext/gvl_wrappers.c +17 -0
  23. data/ext/gvl_wrappers.h +241 -0
  24. data/ext/pg.c +640 -0
  25. data/ext/pg.h +365 -0
  26. data/ext/pg_binary_decoder.c +229 -0
  27. data/ext/pg_binary_encoder.c +162 -0
  28. data/ext/pg_coder.c +549 -0
  29. data/ext/pg_connection.c +4252 -0
  30. data/ext/pg_copy_coder.c +596 -0
  31. data/ext/pg_errors.c +95 -0
  32. data/ext/pg_result.c +1501 -0
  33. data/ext/pg_text_decoder.c +981 -0
  34. data/ext/pg_text_encoder.c +682 -0
  35. data/ext/pg_tuple.c +541 -0
  36. data/ext/pg_type_map.c +166 -0
  37. data/ext/pg_type_map_all_strings.c +116 -0
  38. data/ext/pg_type_map_by_class.c +239 -0
  39. data/ext/pg_type_map_by_column.c +312 -0
  40. data/ext/pg_type_map_by_mri_type.c +284 -0
  41. data/ext/pg_type_map_by_oid.c +355 -0
  42. data/ext/pg_type_map_in_ruby.c +299 -0
  43. data/ext/util.c +149 -0
  44. data/ext/util.h +65 -0
  45. data/ext/vc/pg.sln +26 -0
  46. data/ext/vc/pg_18/pg.vcproj +216 -0
  47. data/ext/vc/pg_19/pg_19.vcproj +209 -0
  48. data/lib/pg.rb +74 -0
  49. data/lib/pg/basic_type_mapping.rb +459 -0
  50. data/lib/pg/binary_decoder.rb +22 -0
  51. data/lib/pg/coder.rb +83 -0
  52. data/lib/pg/connection.rb +291 -0
  53. data/lib/pg/constants.rb +11 -0
  54. data/lib/pg/exceptions.rb +11 -0
  55. data/lib/pg/result.rb +31 -0
  56. data/lib/pg/text_decoder.rb +47 -0
  57. data/lib/pg/text_encoder.rb +69 -0
  58. data/lib/pg/tuple.rb +30 -0
  59. data/lib/pg/type_map_by_column.rb +15 -0
  60. data/spec/data/expected_trace.out +26 -0
  61. data/spec/data/random_binary_data +0 -0
  62. data/spec/helpers.rb +380 -0
  63. data/spec/pg/basic_type_mapping_spec.rb +508 -0
  64. data/spec/pg/connection_spec.rb +1872 -0
  65. data/spec/pg/connection_sync_spec.rb +41 -0
  66. data/spec/pg/result_spec.rb +491 -0
  67. data/spec/pg/tuple_spec.rb +280 -0
  68. data/spec/pg/type_map_by_class_spec.rb +138 -0
  69. data/spec/pg/type_map_by_column_spec.rb +222 -0
  70. data/spec/pg/type_map_by_mri_type_spec.rb +136 -0
  71. data/spec/pg/type_map_by_oid_spec.rb +149 -0
  72. data/spec/pg/type_map_in_ruby_spec.rb +164 -0
  73. data/spec/pg/type_map_spec.rb +22 -0
  74. data/spec/pg/type_spec.rb +949 -0
  75. data/spec/pg_spec.rb +50 -0
  76. metadata +322 -0
  77. metadata.gz.sig +0 -0
@@ -0,0 +1,47 @@
1
+ # -*- ruby -*-
2
+
3
+ require 'date'
4
+ require 'json'
5
+
6
+ module PG
7
+ module TextDecoder
8
+ class Date < SimpleDecoder
9
+ ISO_DATE = /\A(\d{4})-(\d\d)-(\d\d)\z/
10
+
11
+ def decode(string, tuple=nil, field=nil)
12
+ if string =~ ISO_DATE
13
+ ::Date.new $1.to_i, $2.to_i, $3.to_i
14
+ else
15
+ string
16
+ end
17
+ end
18
+ end
19
+
20
+ class JSON < SimpleDecoder
21
+ def decode(string, tuple=nil, field=nil)
22
+ ::JSON.parse(string, quirks_mode: true)
23
+ end
24
+ end
25
+
26
+ # Convenience classes for timezone options
27
+ class TimestampUtc < Timestamp
28
+ def initialize(params={})
29
+ super(params.merge(flags: PG::Coder::TIMESTAMP_DB_UTC | PG::Coder::TIMESTAMP_APP_UTC))
30
+ end
31
+ end
32
+ class TimestampUtcToLocal < Timestamp
33
+ def initialize(params={})
34
+ super(params.merge(flags: PG::Coder::TIMESTAMP_DB_UTC | PG::Coder::TIMESTAMP_APP_LOCAL))
35
+ end
36
+ end
37
+ class TimestampLocal < Timestamp
38
+ def initialize(params={})
39
+ super(params.merge(flags: PG::Coder::TIMESTAMP_DB_LOCAL | PG::Coder::TIMESTAMP_APP_LOCAL))
40
+ end
41
+ end
42
+
43
+ # For backward compatibility:
44
+ TimestampWithoutTimeZone = TimestampLocal
45
+ TimestampWithTimeZone = Timestamp
46
+ end
47
+ end # module PG
@@ -0,0 +1,69 @@
1
+ # -*- ruby -*-
2
+
3
+ require 'json'
4
+ require 'ipaddr'
5
+
6
+ module PG
7
+ module TextEncoder
8
+ class Date < SimpleEncoder
9
+ STRFTIME_ISO_DATE = "%Y-%m-%d".freeze
10
+ def encode(value)
11
+ value.respond_to?(:strftime) ? value.strftime(STRFTIME_ISO_DATE) : value
12
+ end
13
+ end
14
+
15
+ class TimestampWithoutTimeZone < SimpleEncoder
16
+ STRFTIME_ISO_DATETIME_WITHOUT_TIMEZONE = "%Y-%m-%d %H:%M:%S.%N".freeze
17
+ def encode(value)
18
+ value.respond_to?(:strftime) ? value.strftime(STRFTIME_ISO_DATETIME_WITHOUT_TIMEZONE) : value
19
+ end
20
+ end
21
+
22
+ class TimestampUtc < SimpleEncoder
23
+ STRFTIME_ISO_DATETIME_WITHOUT_TIMEZONE_UTC = "%Y-%m-%d %H:%M:%S.%N".freeze
24
+ def encode(value)
25
+ value.respond_to?(:utc) ? value.utc.strftime(STRFTIME_ISO_DATETIME_WITHOUT_TIMEZONE_UTC) : value
26
+ end
27
+ end
28
+
29
+ class TimestampWithTimeZone < SimpleEncoder
30
+ STRFTIME_ISO_DATETIME_WITH_TIMEZONE = "%Y-%m-%d %H:%M:%S.%N %:z".freeze
31
+ def encode(value)
32
+ value.respond_to?(:strftime) ? value.strftime(STRFTIME_ISO_DATETIME_WITH_TIMEZONE) : value
33
+ end
34
+ end
35
+
36
+ class Numeric < SimpleEncoder
37
+ def encode(value)
38
+ value.is_a?(BigDecimal) ? value.to_s('F') : value
39
+ end
40
+ end
41
+
42
+ class JSON < SimpleEncoder
43
+ def encode(value)
44
+ ::JSON.generate(value, quirks_mode: true)
45
+ end
46
+ end
47
+
48
+ class Inet < SimpleEncoder
49
+ def encode(value)
50
+ case value
51
+ when IPAddr
52
+ default_prefix = (value.family == Socket::AF_INET ? 32 : 128)
53
+ s = value.to_s
54
+ if value.respond_to?(:prefix)
55
+ prefix = value.prefix
56
+ else
57
+ range = value.to_range
58
+ prefix = default_prefix - Math.log(((range.end.to_i - range.begin.to_i) + 1), 2).to_i
59
+ end
60
+ s << "/" << prefix.to_s if prefix != default_prefix
61
+ s
62
+ else
63
+ value
64
+ end
65
+ end
66
+ end
67
+ end
68
+ end # module PG
69
+
@@ -0,0 +1,30 @@
1
+ # -*- ruby -*-
2
+ # frozen_string_literal: true
3
+
4
+ require 'pg' unless defined?( PG )
5
+
6
+
7
+ class PG::Tuple
8
+
9
+ ### Return a String representation of the object suitable for debugging.
10
+ def inspect
11
+ "#<#{self.class} #{self.map{|k,v| "#{k}: #{v.inspect}" }.join(", ") }>"
12
+ end
13
+
14
+ def has_key?(key)
15
+ field_map.has_key?(key)
16
+ end
17
+ alias key? has_key?
18
+
19
+ def keys
20
+ field_names || field_map.keys.freeze
21
+ end
22
+
23
+ def each_key(&block)
24
+ if fn=field_names
25
+ fn.each(&block)
26
+ else
27
+ field_map.each_key(&block)
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,15 @@
1
+ # -*- ruby -*-
2
+
3
+ require 'pg' unless defined?( PG )
4
+
5
+ class PG::TypeMapByColumn
6
+ # Returns the type oids of the assigned coders.
7
+ def oids
8
+ coders.map{|c| c.oid if c }
9
+ end
10
+
11
+ def inspect
12
+ type_strings = coders.map{|c| c ? "#{c.name}:#{c.format}" : 'nil' }
13
+ "#<#{self.class} #{type_strings.join(' ')}>"
14
+ end
15
+ end
@@ -0,0 +1,26 @@
1
+ To backend> Msg Q
2
+ To backend> "SELECT 1 AS one"
3
+ To backend> Msg complete, length 21
4
+ From backend> T
5
+ From backend (#4)> 28
6
+ From backend (#2)> 1
7
+ From backend> "one"
8
+ From backend (#4)> 0
9
+ From backend (#2)> 0
10
+ From backend (#4)> 23
11
+ From backend (#2)> 4
12
+ From backend (#4)> -1
13
+ From backend (#2)> 0
14
+ From backend> D
15
+ From backend (#4)> 11
16
+ From backend (#2)> 1
17
+ From backend (#4)> 1
18
+ From backend (1)> 1
19
+ From backend> C
20
+ From backend (#4)> 11
21
+ From backend> "SELECT"
22
+ From backend> Z
23
+ From backend (#4)> 5
24
+ From backend> Z
25
+ From backend (#4)> 5
26
+ From backend> T
@@ -0,0 +1,380 @@
1
+ # -*- ruby -*-
2
+
3
+ require 'pathname'
4
+ require 'rspec'
5
+ require 'shellwords'
6
+ require 'pg'
7
+
8
+ DEFAULT_TEST_DIR_STR = File.join(Dir.pwd, "tmp_test_specs")
9
+ TEST_DIR_STR = ENV['RUBY_PG_TEST_DIR'] || DEFAULT_TEST_DIR_STR
10
+ TEST_DIRECTORY = Pathname.new(TEST_DIR_STR)
11
+
12
+ module PG::TestingHelpers
13
+
14
+ ### Automatically set up the database when it's used, and wrap a transaction around
15
+ ### examples that don't disable it.
16
+ def self::included( mod )
17
+ super
18
+
19
+ if mod.respond_to?( :around )
20
+
21
+ mod.before( :all ) { @conn = setup_testing_db(described_class ? described_class.name : mod.description) }
22
+
23
+ mod.around( :each ) do |example|
24
+ begin
25
+ @conn.set_default_encoding
26
+ @conn.exec( 'BEGIN' ) unless example.metadata[:without_transaction]
27
+ desc = example.source_location.join(':')
28
+ @conn.exec %Q{SET application_name TO '%s'} %
29
+ [@conn.escape_string(desc.slice(-60))]
30
+ example.run
31
+ ensure
32
+ @conn.exec( 'ROLLBACK' ) unless example.metadata[:without_transaction]
33
+ end
34
+ end
35
+
36
+ mod.after( :all ) { teardown_testing_db(@conn) }
37
+ end
38
+
39
+ end
40
+
41
+
42
+ #
43
+ # Examples
44
+ #
45
+
46
+ # Set some ANSI escape code constants (Shamelessly stolen from Perl's
47
+ # Term::ANSIColor by Russ Allbery <rra@stanford.edu> and Zenin <zenin@best.com>
48
+ ANSI_ATTRIBUTES = {
49
+ 'clear' => 0,
50
+ 'reset' => 0,
51
+ 'bold' => 1,
52
+ 'dark' => 2,
53
+ 'underline' => 4,
54
+ 'underscore' => 4,
55
+ 'blink' => 5,
56
+ 'reverse' => 7,
57
+ 'concealed' => 8,
58
+
59
+ 'black' => 30, 'on_black' => 40,
60
+ 'red' => 31, 'on_red' => 41,
61
+ 'green' => 32, 'on_green' => 42,
62
+ 'yellow' => 33, 'on_yellow' => 43,
63
+ 'blue' => 34, 'on_blue' => 44,
64
+ 'magenta' => 35, 'on_magenta' => 45,
65
+ 'cyan' => 36, 'on_cyan' => 46,
66
+ 'white' => 37, 'on_white' => 47
67
+ }
68
+
69
+
70
+ ###############
71
+ module_function
72
+ ###############
73
+
74
+ ### Create a string that contains the ANSI codes specified and return it
75
+ def ansi_code( *attributes )
76
+ attributes.flatten!
77
+ attributes.collect! {|at| at.to_s }
78
+
79
+ return '' unless /(?:vt10[03]|xterm(?:-color)?|linux|screen)/i =~ ENV['TERM']
80
+ attributes = ANSI_ATTRIBUTES.values_at( *attributes ).compact.join(';')
81
+
82
+ # $stderr.puts " attr is: %p" % [attributes]
83
+ if attributes.empty?
84
+ return ''
85
+ else
86
+ return "\e[%sm" % attributes
87
+ end
88
+ end
89
+
90
+
91
+ ### Colorize the given +string+ with the specified +attributes+ and return it, handling
92
+ ### line-endings, color reset, etc.
93
+ def colorize( *args )
94
+ string = ''
95
+
96
+ if block_given?
97
+ string = yield
98
+ else
99
+ string = args.shift
100
+ end
101
+
102
+ ending = string[/(\s)$/] || ''
103
+ string = string.rstrip
104
+
105
+ return ansi_code( args.flatten ) + string + ansi_code( 'reset' ) + ending
106
+ end
107
+
108
+
109
+ ### Output a message with highlighting.
110
+ def message( *msg )
111
+ $stderr.puts( colorize(:bold) { msg.flatten.join(' ') } )
112
+ end
113
+
114
+
115
+ ### Output a logging message if $VERBOSE is true
116
+ def trace( *msg )
117
+ return unless $VERBOSE
118
+ output = colorize( msg.flatten.join(' '), 'yellow' )
119
+ $stderr.puts( output )
120
+ end
121
+
122
+
123
+ ### Return the specified args as a string, quoting any that have a space.
124
+ def quotelist( *args )
125
+ return args.flatten.collect {|part| part.to_s =~ /\s/ ? part.to_s.inspect : part.to_s }
126
+ end
127
+
128
+
129
+ ### Run the specified command +cmd+ with system(), failing if the execution
130
+ ### fails.
131
+ def run( *cmd )
132
+ cmd.flatten!
133
+
134
+ if cmd.length > 1
135
+ trace( quotelist(*cmd) )
136
+ else
137
+ trace( cmd )
138
+ end
139
+
140
+ system( *cmd )
141
+ raise "Command failed: [%s]" % [cmd.join(' ')] unless $?.success?
142
+ end
143
+
144
+
145
+ ### Run the specified command +cmd+ after redirecting stdout and stderr to the specified
146
+ ### +logpath+, failing if the execution fails.
147
+ def log_and_run( logpath, *cmd )
148
+ cmd.flatten!
149
+
150
+ if cmd.length > 1
151
+ trace( quotelist(*cmd) )
152
+ else
153
+ trace( cmd )
154
+ end
155
+
156
+ # Eliminate the noise of creating/tearing down the database by
157
+ # redirecting STDERR/STDOUT to a logfile
158
+ logfh = File.open( logpath, File::WRONLY|File::CREAT|File::APPEND )
159
+ system( *cmd, [STDOUT, STDERR] => logfh )
160
+
161
+ raise "Command failed: [%s]" % [cmd.join(' ')] unless $?.success?
162
+ end
163
+
164
+
165
+ ### Check the current directory for directories that look like they're
166
+ ### testing directories from previous tests, and tell any postgres instances
167
+ ### running in them to shut down.
168
+ def stop_existing_postmasters
169
+ # tmp_test_0.22329534700318
170
+ pat = Pathname.getwd + 'tmp_test_*'
171
+ Pathname.glob( pat.to_s ).each do |testdir|
172
+ datadir = testdir + 'data'
173
+ pidfile = datadir + 'postmaster.pid'
174
+ if pidfile.exist? && pid = pidfile.read.chomp.to_i
175
+ $stderr.puts "pidfile (%p) exists: %d" % [ pidfile, pid ]
176
+ begin
177
+ Process.kill( 0, pid )
178
+ rescue Errno::ESRCH
179
+ $stderr.puts "No postmaster running for %s" % [ datadir ]
180
+ # Process isn't alive, so don't try to stop it
181
+ else
182
+ $stderr.puts "Stopping lingering database at PID %d" % [ pid ]
183
+ run 'pg_ctl', '-D', datadir.to_s, '-m', 'fast', 'stop'
184
+ end
185
+ else
186
+ $stderr.puts "No pidfile (%p)" % [ pidfile ]
187
+ end
188
+ end
189
+ end
190
+
191
+
192
+ ### Set up a PostgreSQL database instance for testing.
193
+ def setup_testing_db( description )
194
+ require 'pg'
195
+ stop_existing_postmasters()
196
+
197
+ puts "Setting up test database for #{description}"
198
+ @test_pgdata = TEST_DIRECTORY + 'data'
199
+ @test_pgdata.mkpath
200
+
201
+ ENV['PGPORT'] ||= "54321"
202
+ @port = ENV['PGPORT'].to_i
203
+ ENV['PGHOST'] = 'localhost'
204
+ @conninfo = "host=localhost port=#{@port} dbname=test"
205
+
206
+ @logfile = TEST_DIRECTORY + 'setup.log'
207
+ trace "Command output logged to #{@logfile}"
208
+
209
+ begin
210
+ unless (@test_pgdata+"postgresql.conf").exist?
211
+ FileUtils.rm_rf( @test_pgdata, :verbose => $DEBUG )
212
+ $stderr.puts "Running initdb"
213
+ log_and_run @logfile, 'initdb', '-E', 'UTF8', '--no-locale', '-D', @test_pgdata.to_s
214
+ end
215
+
216
+ trace "Starting postgres"
217
+ log_and_run @logfile, 'pg_ctl', '-w', '-o', "-k #{TEST_DIRECTORY.to_s.dump}",
218
+ '-D', @test_pgdata.to_s, 'start'
219
+ sleep 2
220
+
221
+ $stderr.puts "Creating the test DB"
222
+ log_and_run @logfile, 'psql', '-e', '-c', 'DROP DATABASE IF EXISTS test', 'postgres'
223
+ log_and_run @logfile, 'createdb', '-e', 'test'
224
+
225
+ rescue => err
226
+ $stderr.puts "%p during test setup: %s" % [ err.class, err.message ]
227
+ $stderr.puts "See #{@logfile} for details."
228
+ $stderr.puts *err.backtrace if $DEBUG
229
+ fail
230
+ end
231
+
232
+ conn = PG.connect( @conninfo )
233
+ conn.set_notice_processor do |message|
234
+ $stderr.puts( description + ':' + message ) if $DEBUG
235
+ end
236
+
237
+ return conn
238
+ end
239
+
240
+
241
+ def teardown_testing_db( conn )
242
+ puts "Tearing down test database"
243
+
244
+ if conn
245
+ check_for_lingering_connections( conn )
246
+ conn.finish
247
+ end
248
+
249
+ log_and_run @logfile, 'pg_ctl', '-D', @test_pgdata.to_s, 'stop'
250
+ end
251
+
252
+
253
+ def check_for_lingering_connections( conn )
254
+ conn.exec( "SELECT * FROM pg_stat_activity" ) do |res|
255
+ conns = res.find_all {|row| row['pid'].to_i != conn.backend_pid && ["client backend", nil].include?(row["backend_type"]) }
256
+ unless conns.empty?
257
+ puts "Lingering connections remain:"
258
+ conns.each do |row|
259
+ puts " [%s] {%s} %s -- %s" % row.values_at( 'pid', 'state', 'application_name', 'query' )
260
+ end
261
+ end
262
+ end
263
+ end
264
+
265
+
266
+ # Retrieve the names of the column types of a given result set.
267
+ def result_typenames(res)
268
+ @conn.exec_params( "SELECT " + res.nfields.times.map{|i| "format_type($#{i*2+1},$#{i*2+2})"}.join(","),
269
+ res.nfields.times.map{|i| [res.ftype(i), res.fmod(i)] }.flatten ).
270
+ values[0]
271
+ end
272
+
273
+
274
+ # A matcher for checking the status of a PG::Connection to ensure it's still
275
+ # usable.
276
+ class ConnStillUsableMatcher
277
+
278
+ def initialize
279
+ @conn = nil
280
+ @problem = nil
281
+ end
282
+
283
+ def matches?( conn )
284
+ @conn = conn
285
+ @problem = self.check_for_problems
286
+ return @problem.nil?
287
+ end
288
+
289
+ def check_for_problems
290
+ return "is finished" if @conn.finished?
291
+ return "has bad status" unless @conn.status == PG::CONNECTION_OK
292
+ return "has bad transaction status (%d)" % [ @conn.transaction_status ] unless
293
+ @conn.transaction_status.between?( PG::PQTRANS_IDLE, PG::PQTRANS_INTRANS )
294
+ return "is not usable." unless self.can_exec_query?
295
+ return nil
296
+ end
297
+
298
+ def can_exec_query?
299
+ @conn.send_query( "VALUES (1)" )
300
+ @conn.get_last_result.values == [["1"]]
301
+ end
302
+
303
+ def failure_message
304
+ return "expected %p to be usable, but it %s" % [ @conn, @problem ]
305
+ end
306
+
307
+ def failure_message_when_negated
308
+ "expected %p not to be usable, but it still is" % [ @conn ]
309
+ end
310
+
311
+ end
312
+
313
+
314
+ ### Return a ConnStillUsableMatcher to be used like:
315
+ ###
316
+ ### expect( pg_conn ).to still_be_usable
317
+ ###
318
+ def still_be_usable
319
+ return ConnStillUsableMatcher.new
320
+ end
321
+
322
+ def wait_for_polling_ok(conn, meth = :connect_poll)
323
+ status = conn.send(meth)
324
+
325
+ while status != PG::PGRES_POLLING_OK
326
+ if status == PG::PGRES_POLLING_READING
327
+ select( [conn.socket_io], [], [], 5.0 ) or
328
+ raise "Asynchronous connection timed out!"
329
+
330
+ elsif status == PG::PGRES_POLLING_WRITING
331
+ select( [], [conn.socket_io], [], 5.0 ) or
332
+ raise "Asynchronous connection timed out!"
333
+ end
334
+ status = conn.send(meth)
335
+ end
336
+ end
337
+
338
+ def wait_for_query_result(conn)
339
+ result = nil
340
+ loop do
341
+ # Buffer any incoming data on the socket until a full result is ready.
342
+ conn.consume_input
343
+ while conn.is_busy
344
+ select( [conn.socket_io], nil, nil, 5.0 ) or
345
+ raise "Timeout waiting for query response."
346
+ conn.consume_input
347
+ end
348
+
349
+ # Fetch the next result. If there isn't one, the query is finished
350
+ result = conn.get_result || break
351
+ end
352
+ result
353
+ end
354
+
355
+ end
356
+
357
+
358
+ RSpec.configure do |config|
359
+ config.include( PG::TestingHelpers )
360
+
361
+ config.run_all_when_everything_filtered = true
362
+ config.filter_run :focus
363
+ config.order = 'random'
364
+ config.mock_with( :rspec ) do |mock|
365
+ mock.syntax = :expect
366
+ end
367
+
368
+ if RUBY_PLATFORM =~ /mingw|mswin/
369
+ config.filter_run_excluding :unix
370
+ else
371
+ config.filter_run_excluding :windows
372
+ end
373
+ config.filter_run_excluding :socket_io unless
374
+ PG::Connection.instance_methods.map( &:to_sym ).include?( :socket_io )
375
+
376
+ config.filter_run_excluding( :postgresql_93 ) if PG.library_version < 90300
377
+ config.filter_run_excluding( :postgresql_94 ) if PG.library_version < 90400
378
+ config.filter_run_excluding( :postgresql_95 ) if PG.library_version < 90500
379
+ config.filter_run_excluding( :postgresql_10 ) if PG.library_version < 100000
380
+ end