pg 1.1.4

Sign up to get free protection for your applications and to get access to all the features.
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