pg 0.9.0-x86-mswin32 → 0.11.0pre229-x86-mswin32
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.
- data.tar.gz.sig +0 -0
- data/ChangeLog +214 -1
- data/Contributors +2 -0
- data/README +2 -2
- data/README.windows +7 -4
- data/Rakefile +51 -29
- data/Rakefile.local +229 -160
- data/ext/compat.c +2 -2
- data/ext/compat.h +4 -0
- data/ext/extconf.rb +27 -94
- data/ext/pg.c +300 -121
- data/ext/pg.h +4 -0
- data/lib/1.8/pg_ext.so +0 -0
- data/lib/1.9/pg_ext.so +0 -0
- data/lib/pg.rb +11 -6
- data/rake/documentation.rb +123 -0
- data/rake/helpers.rb +375 -308
- data/rake/hg.rb +51 -6
- data/rake/manual.rb +11 -6
- data/rake/packaging.rb +7 -1
- data/rake/publishing.rb +158 -91
- data/rake/testing.rb +53 -88
- data/spec/lib/helpers.rb +40 -18
- data/spec/m17n_spec.rb +36 -24
- data/spec/pgconn_spec.rb +276 -20
- data/spec/pgresult_spec.rb +12 -6
- metadata +61 -20
- metadata.gz.sig +0 -0
- data/rake/rdoc.rb +0 -30
data/rake/testing.rb
CHANGED
@@ -16,7 +16,7 @@ end
|
|
16
16
|
SPEC_FILES = [] unless defined?( SPEC_FILES )
|
17
17
|
TEST_FILES = [] unless defined?( TEST_FILES )
|
18
18
|
|
19
|
-
|
19
|
+
COMMON_RSPEC_OPTS = [] unless defined?( COMMON_RSPEC_OPTS )
|
20
20
|
|
21
21
|
COVERAGE_TARGETDIR = BASEDIR + 'coverage' unless defined?( COVERAGE_TARGETDIR )
|
22
22
|
RCOV_EXCLUDES = 'spec,tests,/Library/Ruby,/var/lib,/usr/local/lib' unless
|
@@ -39,149 +39,114 @@ end
|
|
39
39
|
|
40
40
|
### RSpec specifications
|
41
41
|
begin
|
42
|
-
gem 'rspec', '>=
|
42
|
+
gem 'rspec', '>= 2.0.0'
|
43
43
|
|
44
|
-
require '
|
45
|
-
require '
|
44
|
+
require 'rspec'
|
45
|
+
require 'rspec/core/rake_task'
|
46
46
|
|
47
47
|
### Task: spec
|
48
48
|
desc "Run specs"
|
49
49
|
task :spec => 'spec:doc'
|
50
|
+
task :specs => :spec
|
50
51
|
|
51
52
|
namespace :spec do
|
52
53
|
desc "Run rspec every time there's a change to one of the files"
|
53
54
|
task :autotest do
|
54
|
-
require 'autotest
|
55
|
-
|
56
|
-
|
57
|
-
autotester.run
|
55
|
+
require 'autotest'
|
56
|
+
Autotest.add_discovery { "rspec2" }
|
57
|
+
Autotest.run
|
58
58
|
end
|
59
59
|
|
60
60
|
desc "Generate regular color 'doc' spec output"
|
61
|
-
|
62
|
-
task.
|
63
|
-
task.spec_opts = COMMON_SPEC_OPTS + ['-f', 's', '-c']
|
61
|
+
RSpec::Core::RakeTask.new( :doc ) do |task|
|
62
|
+
task.rspec_opts = COMMON_RSPEC_OPTS + ['-f', 'd', '-c']
|
64
63
|
end
|
65
64
|
|
66
65
|
desc "Generate spec output with profiling"
|
67
|
-
|
68
|
-
task.
|
69
|
-
task.spec_opts = COMMON_SPEC_OPTS + ['-f', 'o']
|
66
|
+
RSpec::Core::RakeTask.new( :profile ) do |task|
|
67
|
+
task.rspec_opts = COMMON_RSPEC_OPTS + ['-f', 'p', '-p']
|
70
68
|
end
|
71
69
|
|
72
70
|
desc "Generate quiet non-colored plain-text output"
|
73
|
-
|
74
|
-
task.
|
75
|
-
task.spec_opts = COMMON_SPEC_OPTS + ['-f', 'p']
|
71
|
+
RSpec::Core::RakeTask.new( :quiet ) do |task|
|
72
|
+
task.rspec_opts = COMMON_RSPEC_OPTS + ['-f', 'p']
|
76
73
|
end
|
77
74
|
|
78
75
|
desc "Generate HTML output"
|
79
|
-
|
80
|
-
task.
|
81
|
-
task.spec_opts = COMMON_SPEC_OPTS + ['-f', 'h']
|
76
|
+
RSpec::Core::RakeTask.new( :html ) do |task|
|
77
|
+
task.rspec_opts = COMMON_RSPEC_OPTS + ['-f', 'h']
|
82
78
|
end
|
83
79
|
|
84
|
-
end
|
85
|
-
rescue LoadError => err
|
86
|
-
task :no_rspec do
|
87
|
-
$stderr.puts "Specification tasks not defined: %s" % [ err.message ]
|
88
|
-
end
|
89
|
-
|
90
|
-
task :spec => :no_rspec
|
91
|
-
namespace :spec do
|
92
|
-
task :autotest => :no_rspec
|
93
|
-
task :doc => :no_rspec
|
94
|
-
task :profile => :no_rspec
|
95
|
-
task :quiet => :no_rspec
|
96
|
-
task :html => :no_rspec
|
97
|
-
end
|
98
|
-
end
|
99
|
-
|
100
|
-
|
101
|
-
### Test::Unit tests
|
102
|
-
begin
|
103
|
-
require 'rake/testtask'
|
104
|
-
|
105
|
-
Rake::TestTask.new( :unittests ) do |task|
|
106
|
-
task.libs += [LIBDIR]
|
107
|
-
task.test_files = TEST_FILES
|
108
|
-
task.verbose = true
|
109
|
-
end
|
110
80
|
|
111
|
-
rescue LoadError => err
|
112
|
-
task :no_test do
|
113
|
-
$stderr.puts "Test tasks not defined: %s" % [ err.message ]
|
114
81
|
end
|
115
82
|
|
116
|
-
task :unittests => :no_rspec
|
117
|
-
end
|
118
|
-
|
119
|
-
|
120
|
-
### RCov (via RSpec) tasks
|
121
|
-
begin
|
122
|
-
gem 'rcov'
|
123
|
-
gem 'rspec', '>= 1.1.3'
|
124
|
-
|
125
|
-
require 'spec'
|
126
|
-
require 'rcov'
|
127
|
-
|
128
83
|
### Task: coverage (via RCov)
|
129
84
|
desc "Build test coverage reports"
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
task.rcov_opts = RCOV_OPTS
|
136
|
-
task.rcov = true
|
137
|
-
end
|
85
|
+
RSpec::Core::RakeTask.new( :coverage ) do |task|
|
86
|
+
task.ruby_opts = [ "-I#{LIBDIR}" ]
|
87
|
+
task.rspec_opts = ['-f', 'p', '-b']
|
88
|
+
task.rcov_opts = RCOV_OPTS
|
89
|
+
task.rcov = true
|
138
90
|
end
|
139
91
|
|
140
|
-
|
141
92
|
### Task: rcov
|
142
93
|
task :rcov => :coverage
|
143
94
|
|
144
95
|
### Other coverage tasks
|
145
96
|
namespace :coverage do
|
146
97
|
desc "Generate a detailed text coverage report"
|
147
|
-
|
148
|
-
task.spec_files = SPEC_FILES
|
98
|
+
RSpec::Core::RakeTask.new( :text ) do |task|
|
149
99
|
task.rcov_opts = RCOV_OPTS + ['--text-report']
|
150
100
|
task.rcov = true
|
151
101
|
end
|
152
102
|
|
153
103
|
desc "Show differences in coverage from last run"
|
154
|
-
|
155
|
-
task.
|
156
|
-
task.spec_opts = ['-f', 'p', '-b']
|
104
|
+
RSpec::Core::RakeTask.new( :diff ) do |task|
|
105
|
+
task.rspec_opts = ['-f', 'p', '-b']
|
157
106
|
task.rcov_opts = RCOV_OPTS - ['--save'] + ['--text-coverage-diff']
|
158
107
|
task.rcov = true
|
159
108
|
end
|
160
109
|
|
161
110
|
desc "Run RCov in 'spec-only' mode to check coverage from specs"
|
162
|
-
|
163
|
-
task.spec_files = SPEC_FILES
|
111
|
+
RSpec::Core::RakeTask.new( :speconly ) do |task|
|
164
112
|
task.rcov_opts = ['--exclude', RCOV_EXCLUDES, '--text-report', '--save']
|
165
113
|
task.rcov = true
|
166
114
|
end
|
167
115
|
end
|
168
116
|
|
169
117
|
CLOBBER.include( COVERAGE_TARGETDIR )
|
170
|
-
|
171
118
|
rescue LoadError => err
|
172
|
-
task :
|
173
|
-
$stderr.puts "
|
174
|
-
[ err.message ]
|
119
|
+
task :no_rspec do
|
120
|
+
$stderr.puts "Specification tasks not defined: %s" % [ err.message ]
|
175
121
|
end
|
176
122
|
|
177
|
-
task :
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
task :
|
182
|
-
task :
|
123
|
+
task :spec => :no_rspec
|
124
|
+
namespace :spec do
|
125
|
+
task :autotest => :no_rspec
|
126
|
+
task :doc => :no_rspec
|
127
|
+
task :profile => :no_rspec
|
128
|
+
task :quiet => :no_rspec
|
129
|
+
task :html => :no_rspec
|
183
130
|
end
|
184
|
-
|
131
|
+
end
|
132
|
+
|
133
|
+
|
134
|
+
### Test::Unit tests
|
135
|
+
begin
|
136
|
+
require 'rake/testtask'
|
137
|
+
|
138
|
+
Rake::TestTask.new( :unittests ) do |task|
|
139
|
+
task.libs += [LIBDIR]
|
140
|
+
task.test_files = TEST_FILES
|
141
|
+
task.verbose = true
|
142
|
+
end
|
143
|
+
|
144
|
+
rescue LoadError => err
|
145
|
+
task :no_test do
|
146
|
+
$stderr.puts "Test tasks not defined: %s" % [ err.message ]
|
147
|
+
end
|
148
|
+
|
149
|
+
task :unittests => :no_rspec
|
185
150
|
end
|
186
151
|
|
187
152
|
|
data/spec/lib/helpers.rb
CHANGED
@@ -1,9 +1,19 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
|
3
3
|
require 'pathname'
|
4
|
+
require 'rspec'
|
5
|
+
|
6
|
+
|
7
|
+
RSpec.configure do |config|
|
8
|
+
ruby_version_vec = RUBY_VERSION.split('.').map {|c| c.to_i }.pack( "N*" )
|
9
|
+
|
10
|
+
config.mock_with :rspec
|
11
|
+
config.filter_run_excluding :ruby_19 => true if ruby_version_vec <= [1,9,1].pack( "N*" )
|
12
|
+
end
|
4
13
|
|
5
14
|
module PgTestingHelpers
|
6
15
|
|
16
|
+
|
7
17
|
# Set some ANSI escape code constants (Shamelessly stolen from Perl's
|
8
18
|
# Term::ANSIColor by Russ Allbery <rra@stanford.edu> and Zenin <zenin@best.com>
|
9
19
|
ANSI_ATTRIBUTES = {
|
@@ -104,6 +114,8 @@ module PgTestingHelpers
|
|
104
114
|
end
|
105
115
|
|
106
116
|
|
117
|
+
NOFORK_PLATFORMS = %w{java}
|
118
|
+
|
107
119
|
### Run the specified command +cmd+ after redirecting stdout and stderr to the specified
|
108
120
|
### +logpath+, failing if the execution fails.
|
109
121
|
def log_and_run( logpath, *cmd )
|
@@ -115,16 +127,24 @@ module PgTestingHelpers
|
|
115
127
|
trace( cmd )
|
116
128
|
end
|
117
129
|
|
118
|
-
|
119
|
-
if
|
120
|
-
|
121
|
-
|
130
|
+
# Eliminate the noise of creating/tearing down the database by
|
131
|
+
# redirecting STDERR/STDOUT to a logfile if the Ruby interpreter
|
132
|
+
# supports fork()
|
133
|
+
if NOFORK_PLATFORMS.include?( RUBY_PLATFORM )
|
134
|
+
system( *cmd )
|
122
135
|
else
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
136
|
+
logfh = File.open( logpath, File::WRONLY|File::CREAT|File::APPEND )
|
137
|
+
if pid = fork
|
138
|
+
logfh.close
|
139
|
+
else
|
140
|
+
$stdout.reopen( logfh )
|
141
|
+
$stderr.reopen( $stdout )
|
142
|
+
exec( *cmd )
|
143
|
+
$stderr.puts "After the exec()?!??!"
|
144
|
+
exit!
|
145
|
+
end
|
146
|
+
|
147
|
+
Process.wait( pid )
|
128
148
|
end
|
129
149
|
|
130
150
|
raise "Command failed: [%s]" % [cmd.join(' ')] unless $?.success?
|
@@ -141,15 +161,18 @@ module PgTestingHelpers
|
|
141
161
|
datadir = testdir + 'data'
|
142
162
|
pidfile = datadir + 'postmaster.pid'
|
143
163
|
if pidfile.exist? && pid = pidfile.read.chomp.to_i
|
164
|
+
$stderr.puts "pidfile (%p) exists: %d" % [ pidfile, pid ]
|
144
165
|
begin
|
145
166
|
Process.kill( 0, pid )
|
146
167
|
rescue Errno::ESRCH
|
147
|
-
|
168
|
+
$stderr.puts "No postmaster running for %s" % [ datadir ]
|
148
169
|
# Process isn't alive, so don't try to stop it
|
149
170
|
else
|
150
|
-
|
171
|
+
$stderr.puts "Stopping lingering database at PID %d" % [ pid ]
|
151
172
|
run 'pg_ctl', '-D', datadir.to_s, '-m', 'fast', 'stop'
|
152
173
|
end
|
174
|
+
else
|
175
|
+
$stderr.puts "No pidfile (%p)" % [ pidfile ]
|
153
176
|
end
|
154
177
|
end
|
155
178
|
end
|
@@ -176,20 +199,19 @@ module PgTestingHelpers
|
|
176
199
|
begin
|
177
200
|
unless (@test_pgdata+"postgresql.conf").exist?
|
178
201
|
FileUtils.rm_rf( @test_pgdata, :verbose => $DEBUG )
|
179
|
-
|
202
|
+
$stderr.puts "Running initdb"
|
180
203
|
log_and_run @logfile, 'initdb', '--no-locale', '-D', @test_pgdata.to_s
|
181
204
|
end
|
182
205
|
|
183
206
|
trace "Starting postgres"
|
184
207
|
log_and_run @logfile, 'pg_ctl', '-w', '-o', "-k #{@test_directory.to_s.inspect}",
|
185
208
|
'-D', @test_pgdata.to_s, 'start'
|
209
|
+
sleep 2
|
210
|
+
|
211
|
+
$stderr.puts "Creating the test DB"
|
212
|
+
log_and_run @logfile, 'psql', '-e', '-c', 'DROP DATABASE IF EXISTS test', 'postgres'
|
213
|
+
log_and_run @logfile, 'createdb', '-e', 'test'
|
186
214
|
|
187
|
-
if `psql -l` =~ /^\s*test\s/
|
188
|
-
trace "Dropping the test DB"
|
189
|
-
log_and_run @logfile, 'dropdb', 'test'
|
190
|
-
end
|
191
|
-
trace "Creating the test DB"
|
192
|
-
log_and_run @logfile, 'createdb', 'test'
|
193
215
|
rescue => err
|
194
216
|
$stderr.puts "%p during test setup: %s" % [ err.class, err.message ]
|
195
217
|
$stderr.puts "See #{@logfile} for details."
|
data/spec/m17n_spec.rb
CHANGED
@@ -9,33 +9,21 @@ BEGIN {
|
|
9
9
|
libdir = basedir + 'lib'
|
10
10
|
archlib = libdir + Config::CONFIG['sitearch']
|
11
11
|
|
12
|
+
$LOAD_PATH.unshift( basedir.to_s ) unless $LOAD_PATH.include?( basedir.to_s )
|
12
13
|
$LOAD_PATH.unshift( libdir.to_s ) unless $LOAD_PATH.include?( libdir.to_s )
|
13
14
|
$LOAD_PATH.unshift( archlib.to_s ) unless $LOAD_PATH.include?( archlib.to_s )
|
14
15
|
}
|
15
16
|
|
16
|
-
require '
|
17
|
-
|
18
|
-
require 'rubygems'
|
19
|
-
require 'spec'
|
17
|
+
require 'rspec'
|
20
18
|
require 'spec/lib/helpers'
|
19
|
+
require 'pg'
|
21
20
|
|
22
|
-
describe "multinationalization support" do
|
21
|
+
describe "multinationalization support", :ruby_19 => true do
|
23
22
|
include PgTestingHelpers
|
24
23
|
|
25
|
-
RUBY_VERSION_VEC = RUBY_VERSION.split('.').map {|c| c.to_i }.pack("N*")
|
26
|
-
MIN_RUBY_VERSION_VEC = [1,9,1].pack('N*')
|
27
|
-
|
28
|
-
|
29
24
|
before( :all ) do
|
30
|
-
@conn =
|
31
|
-
|
32
|
-
@conn = setup_testing_db( "m17n" )
|
33
|
-
@conn.exec( 'BEGIN' )
|
34
|
-
end
|
35
|
-
end
|
36
|
-
|
37
|
-
before( :each ) do
|
38
|
-
pending "depends on m17n support in Ruby >= 1.9.1" if @conn.nil?
|
25
|
+
@conn = setup_testing_db( "m17n" )
|
26
|
+
@conn.exec( 'BEGIN' )
|
39
27
|
end
|
40
28
|
|
41
29
|
|
@@ -49,7 +37,7 @@ describe "multinationalization support" do
|
|
49
37
|
res = conn.exec("VALUES ('#{PGconn.escape_bytea(in_bytes)}'::bytea)", [], 0)
|
50
38
|
out_bytes = PGconn.unescape_bytea(res[0]['column1'])
|
51
39
|
end
|
52
|
-
out_bytes.should== in_bytes
|
40
|
+
out_bytes.should == in_bytes
|
53
41
|
end
|
54
42
|
|
55
43
|
describe "rubyforge #22925: m17n support" do
|
@@ -114,17 +102,41 @@ describe "multinationalization support" do
|
|
114
102
|
res = conn.exec( stmt, [], 0 )
|
115
103
|
out_string = res[0]['column1']
|
116
104
|
end
|
117
|
-
out_string.should == 'foo'.encode(Encoding::ASCII_8BIT)
|
105
|
+
out_string.should == 'foo'.encode( Encoding::ASCII_8BIT )
|
118
106
|
out_string.encoding.should == Encoding::ASCII_8BIT
|
119
107
|
end
|
120
108
|
end
|
121
109
|
|
122
|
-
it "
|
123
|
-
original = "string to escape".force_encoding("euc-jp")
|
124
|
-
@conn.set_client_encoding("euc_jp")
|
125
|
-
escaped = @conn.escape(original)
|
110
|
+
it "uses the client encoding for escaped string" do
|
111
|
+
original = "string to escape".force_encoding( "euc-jp" )
|
112
|
+
@conn.set_client_encoding( "euc_jp" )
|
113
|
+
escaped = @conn.escape( original )
|
126
114
|
escaped.encoding.should == Encoding::EUC_JP
|
127
115
|
end
|
116
|
+
end
|
117
|
+
|
118
|
+
describe "Ruby 1.9.x default_internal encoding" do
|
119
|
+
|
120
|
+
it "honors the Encoding.default_internal if it's set and the synchronous interface is used" do
|
121
|
+
@conn.transaction do |txn_conn|
|
122
|
+
txn_conn.internal_encoding = Encoding::ISO8859_1
|
123
|
+
txn_conn.exec( "CREATE TABLE defaultinternaltest ( foo text )" )
|
124
|
+
txn_conn.exec( "INSERT INTO defaultinternaltest VALUES ('Grün und Weiß')" )
|
125
|
+
end
|
126
|
+
|
127
|
+
begin
|
128
|
+
prev_encoding = Encoding.default_internal
|
129
|
+
Encoding.default_internal = Encoding::UTF_8
|
130
|
+
|
131
|
+
conn = PGconn.connect( @conninfo )
|
132
|
+
conn.internal_encoding.should == Encoding::UTF_8
|
133
|
+
res = conn.exec( "SELECT foo FROM defaultinternaltest" )
|
134
|
+
res[0]['foo'].encoding.should == Encoding::UTF_8
|
135
|
+
ensure
|
136
|
+
conn.finish if conn
|
137
|
+
Encoding.default_internal = prev_encoding
|
138
|
+
end
|
139
|
+
end
|
128
140
|
|
129
141
|
end
|
130
142
|
|
data/spec/pgconn_spec.rb
CHANGED
@@ -9,15 +9,14 @@ BEGIN {
|
|
9
9
|
libdir = basedir + 'lib'
|
10
10
|
archlib = libdir + Config::CONFIG['sitearch']
|
11
11
|
|
12
|
+
$LOAD_PATH.unshift( basedir.to_s ) unless $LOAD_PATH.include?( basedir.to_s )
|
12
13
|
$LOAD_PATH.unshift( libdir.to_s ) unless $LOAD_PATH.include?( libdir.to_s )
|
13
14
|
$LOAD_PATH.unshift( archlib.to_s ) unless $LOAD_PATH.include?( archlib.to_s )
|
14
15
|
}
|
15
16
|
|
16
|
-
require '
|
17
|
-
|
18
|
-
require 'rubygems'
|
19
|
-
require 'spec'
|
17
|
+
require 'rspec'
|
20
18
|
require 'spec/lib/helpers'
|
19
|
+
require 'pg'
|
21
20
|
require 'timeout'
|
22
21
|
|
23
22
|
describe PGconn do
|
@@ -82,27 +81,69 @@ describe PGconn do
|
|
82
81
|
res[0]['n'].should == '1'
|
83
82
|
end
|
84
83
|
|
84
|
+
|
85
|
+
EXPECTED_TRACE_OUTPUT = %{
|
86
|
+
To backend> Msg Q
|
87
|
+
To backend> "SELECT 1 AS one"
|
88
|
+
To backend> Msg complete, length 21
|
89
|
+
From backend> T
|
90
|
+
From backend (#4)> 28
|
91
|
+
From backend (#2)> 1
|
92
|
+
From backend> "one"
|
93
|
+
From backend (#4)> 0
|
94
|
+
From backend (#2)> 0
|
95
|
+
From backend (#4)> 23
|
96
|
+
From backend (#2)> 4
|
97
|
+
From backend (#4)> -1
|
98
|
+
From backend (#2)> 0
|
99
|
+
From backend> D
|
100
|
+
From backend (#4)> 11
|
101
|
+
From backend (#2)> 1
|
102
|
+
From backend (#4)> 1
|
103
|
+
From backend (1)> 1
|
104
|
+
From backend> C
|
105
|
+
From backend (#4)> 13
|
106
|
+
From backend> "SELECT 1"
|
107
|
+
From backend> Z
|
108
|
+
From backend (#4)> 5
|
109
|
+
From backend> Z
|
110
|
+
From backend (#4)> 5
|
111
|
+
From backend> T
|
112
|
+
}.gsub( /^\t{2}/, '' ).lstrip
|
113
|
+
|
85
114
|
unless RUBY_PLATFORM =~ /mswin|mingw/
|
86
115
|
it "should trace and untrace client-server communication" do
|
87
116
|
# be careful to explicitly close files so that the
|
88
117
|
# directory can be removed and we don't have to wait for
|
89
118
|
# the GC to run.
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
119
|
+
trace_file = @test_directory + "test_trace.out"
|
120
|
+
trace_io = trace_file.open( 'w', 0600 )
|
121
|
+
@conn.trace( trace_io )
|
122
|
+
trace_io.close
|
123
|
+
|
95
124
|
res = @conn.exec("SELECT 1 AS one")
|
96
125
|
@conn.untrace
|
126
|
+
|
97
127
|
res = @conn.exec("SELECT 2 AS two")
|
98
|
-
|
128
|
+
|
99
129
|
trace_data = trace_file.read
|
100
|
-
|
101
|
-
|
130
|
+
|
131
|
+
expected_trace_output = EXPECTED_TRACE_OUTPUT.dup
|
132
|
+
# For PostgreSQL < 9.0, the output will be different:
|
133
|
+
# -From backend (#4)> 13
|
134
|
+
# -From backend> "SELECT 1"
|
135
|
+
# +From backend (#4)> 11
|
136
|
+
# +From backend> "SELECT"
|
137
|
+
if @conn.server_version < 90000
|
138
|
+
expected_trace_output.sub!( /From backend \(#4\)> 13/, 'From backend (#4)> 11' )
|
139
|
+
expected_trace_output.sub!( /From backend> "SELECT 1"/, 'From backend> "SELECT"' )
|
140
|
+
end
|
141
|
+
|
142
|
+
trace_data.should == expected_trace_output
|
102
143
|
end
|
103
144
|
end
|
104
145
|
|
105
|
-
it "
|
146
|
+
it "allows a query to be cancelled" do
|
106
147
|
error = false
|
107
148
|
@conn.send_query("SELECT pg_sleep(1000)")
|
108
149
|
@conn.cancel
|
@@ -113,6 +154,25 @@ describe PGconn do
|
|
113
154
|
error.should == true
|
114
155
|
end
|
115
156
|
|
157
|
+
it "automatically rolls back a transaction started with PGconn#transaction if an exception " +
|
158
|
+
"is raised" do
|
159
|
+
# abort the per-example transaction so we can test our own
|
160
|
+
@conn.exec( 'ROLLBACK' )
|
161
|
+
|
162
|
+
res = nil
|
163
|
+
@conn.exec( "CREATE TABLE pie ( flavor TEXT )" )
|
164
|
+
|
165
|
+
expect {
|
166
|
+
res = @conn.transaction do
|
167
|
+
@conn.exec( "INSERT INTO pie VALUES ('rhubarb'), ('cherry'), ('schizophrenia')" )
|
168
|
+
raise "Oh noes! All pie is gone!"
|
169
|
+
end
|
170
|
+
}.to raise_exception( RuntimeError, /all pie is gone/i )
|
171
|
+
|
172
|
+
res = @conn.exec( "SELECT * FROM pie" )
|
173
|
+
res.ntuples.should == 0
|
174
|
+
end
|
175
|
+
|
116
176
|
it "should not read past the end of a large object" do
|
117
177
|
@conn.transaction do
|
118
178
|
oid = @conn.lo_create( 0 )
|
@@ -125,16 +185,19 @@ describe PGconn do
|
|
125
185
|
end
|
126
186
|
|
127
187
|
|
128
|
-
it "
|
188
|
+
it "can wait for NOTIFY events" do
|
129
189
|
@conn.exec( 'ROLLBACK' )
|
130
190
|
@conn.exec( 'LISTEN woo' )
|
131
191
|
|
132
192
|
pid = fork do
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
193
|
+
begin
|
194
|
+
conn = PGconn.connect( @conninfo )
|
195
|
+
sleep 1
|
196
|
+
conn.exec( 'NOTIFY woo' )
|
197
|
+
ensure
|
198
|
+
conn.finish
|
199
|
+
exit!
|
200
|
+
end
|
138
201
|
end
|
139
202
|
|
140
203
|
@conn.wait_for_notify( 10 ).should == 'woo'
|
@@ -143,6 +206,199 @@ describe PGconn do
|
|
143
206
|
Process.wait( pid )
|
144
207
|
end
|
145
208
|
|
209
|
+
it "calls a block for NOTIFY events if one is given" do
|
210
|
+
@conn.exec( 'ROLLBACK' )
|
211
|
+
@conn.exec( 'LISTEN woo' )
|
212
|
+
|
213
|
+
pid = fork do
|
214
|
+
begin
|
215
|
+
conn = PGconn.connect( @conninfo )
|
216
|
+
sleep 1
|
217
|
+
conn.exec( 'NOTIFY woo' )
|
218
|
+
ensure
|
219
|
+
conn.finish
|
220
|
+
exit!
|
221
|
+
end
|
222
|
+
end
|
223
|
+
|
224
|
+
eventpid = event = nil
|
225
|
+
@conn.wait_for_notify( 10 ) {|*args| event, eventpid = args }
|
226
|
+
event.should == 'woo'
|
227
|
+
eventpid.should be_an( Integer )
|
228
|
+
|
229
|
+
@conn.exec( 'UNLISTEN woo' )
|
230
|
+
|
231
|
+
Process.wait( pid )
|
232
|
+
end
|
233
|
+
|
234
|
+
it "doesn't collapse sequential notifications" do
|
235
|
+
@conn.exec( 'ROLLBACK' )
|
236
|
+
@conn.exec( 'LISTEN woo' )
|
237
|
+
@conn.exec( 'LISTEN war' )
|
238
|
+
@conn.exec( 'LISTEN woz' )
|
239
|
+
|
240
|
+
pid = fork do
|
241
|
+
begin
|
242
|
+
conn = PGconn.connect( @conninfo )
|
243
|
+
conn.exec( 'NOTIFY woo' )
|
244
|
+
conn.exec( 'NOTIFY war' )
|
245
|
+
conn.exec( 'NOTIFY woz' )
|
246
|
+
ensure
|
247
|
+
conn.finish
|
248
|
+
exit!
|
249
|
+
end
|
250
|
+
end
|
251
|
+
|
252
|
+
Process.wait( pid )
|
253
|
+
|
254
|
+
channels = []
|
255
|
+
3.times do
|
256
|
+
channels << @conn.wait_for_notify( 2 )
|
257
|
+
end
|
258
|
+
|
259
|
+
channels.should have( 3 ).members
|
260
|
+
channels.should include( 'woo', 'war', 'woz' )
|
261
|
+
|
262
|
+
@conn.exec( 'UNLISTEN woz' )
|
263
|
+
@conn.exec( 'UNLISTEN war' )
|
264
|
+
@conn.exec( 'UNLISTEN woo' )
|
265
|
+
end
|
266
|
+
|
267
|
+
it "returns notifications which are already in the queue before wait_for_notify is called " +
|
268
|
+
"without waiting for the socket to become readable" do
|
269
|
+
@conn.exec( 'ROLLBACK' )
|
270
|
+
@conn.exec( 'LISTEN woo' )
|
271
|
+
|
272
|
+
pid = fork do
|
273
|
+
begin
|
274
|
+
conn = PGconn.connect( @conninfo )
|
275
|
+
conn.exec( 'NOTIFY woo' )
|
276
|
+
ensure
|
277
|
+
conn.finish
|
278
|
+
exit!
|
279
|
+
end
|
280
|
+
end
|
281
|
+
|
282
|
+
# Wait for the forked child to send the notification
|
283
|
+
Process.wait( pid )
|
284
|
+
|
285
|
+
# Cause the notification to buffer, but not be read yet
|
286
|
+
@conn.exec( 'SELECT 1' )
|
287
|
+
|
288
|
+
@conn.wait_for_notify( 10 ).should == 'woo'
|
289
|
+
@conn.exec( 'UNLISTEN woo' )
|
290
|
+
end
|
291
|
+
|
292
|
+
context "under PostgreSQL 9" do
|
293
|
+
|
294
|
+
before( :each ) do
|
295
|
+
pending "only works under PostgreSQL 9" if @conn.server_version < 9_00_00
|
296
|
+
end
|
297
|
+
|
298
|
+
it "calls the block supplied to wait_for_notify with the notify payload if it accepts " +
|
299
|
+
"any number of arguments" do
|
300
|
+
|
301
|
+
@conn.exec( 'ROLLBACK' )
|
302
|
+
@conn.exec( 'LISTEN knees' )
|
303
|
+
|
304
|
+
pid = fork do
|
305
|
+
conn = PGconn.connect( @conninfo )
|
306
|
+
conn.exec( %Q{NOTIFY knees, 'skirt and boots'} )
|
307
|
+
conn.finish
|
308
|
+
exit!
|
309
|
+
end
|
310
|
+
|
311
|
+
Process.wait( pid )
|
312
|
+
|
313
|
+
event, pid, msg = nil
|
314
|
+
@conn.wait_for_notify( 10 ) do |*args|
|
315
|
+
event, pid, msg = *args
|
316
|
+
end
|
317
|
+
@conn.exec( 'UNLISTEN woo' )
|
318
|
+
|
319
|
+
event.should == 'knees'
|
320
|
+
pid.should be_a_kind_of( Integer )
|
321
|
+
msg.should == 'skirt and boots'
|
322
|
+
end
|
323
|
+
|
324
|
+
it "calls the block supplied to wait_for_notify with the notify payload if it accepts " +
|
325
|
+
"two arguments" do
|
326
|
+
|
327
|
+
@conn.exec( 'ROLLBACK' )
|
328
|
+
@conn.exec( 'LISTEN knees' )
|
329
|
+
|
330
|
+
pid = fork do
|
331
|
+
conn = PGconn.connect( @conninfo )
|
332
|
+
conn.exec( %Q{NOTIFY knees, 'skirt and boots'} )
|
333
|
+
conn.finish
|
334
|
+
exit!
|
335
|
+
end
|
336
|
+
|
337
|
+
Process.wait( pid )
|
338
|
+
|
339
|
+
event, pid, msg = nil
|
340
|
+
@conn.wait_for_notify( 10 ) do |arg1, arg2|
|
341
|
+
event, pid, msg = arg1, arg2
|
342
|
+
end
|
343
|
+
@conn.exec( 'UNLISTEN woo' )
|
344
|
+
|
345
|
+
event.should == 'knees'
|
346
|
+
pid.should be_a_kind_of( Integer )
|
347
|
+
msg.should be_nil()
|
348
|
+
end
|
349
|
+
|
350
|
+
it "calls the block supplied to wait_for_notify with the notify payload if it " +
|
351
|
+
"doesn't accept arguments" do
|
352
|
+
|
353
|
+
@conn.exec( 'ROLLBACK' )
|
354
|
+
@conn.exec( 'LISTEN knees' )
|
355
|
+
|
356
|
+
pid = fork do
|
357
|
+
conn = PGconn.connect( @conninfo )
|
358
|
+
conn.exec( %Q{NOTIFY knees, 'skirt and boots'} )
|
359
|
+
conn.finish
|
360
|
+
exit!
|
361
|
+
end
|
362
|
+
|
363
|
+
Process.wait( pid )
|
364
|
+
|
365
|
+
notification_received = false
|
366
|
+
@conn.wait_for_notify( 10 ) do
|
367
|
+
notification_received = true
|
368
|
+
end
|
369
|
+
@conn.exec( 'UNLISTEN woo' )
|
370
|
+
|
371
|
+
notification_received.should be_true()
|
372
|
+
end
|
373
|
+
|
374
|
+
it "calls the block supplied to wait_for_notify with the notify payload if it accepts " +
|
375
|
+
"three arguments" do
|
376
|
+
|
377
|
+
@conn.exec( 'ROLLBACK' )
|
378
|
+
@conn.exec( 'LISTEN knees' )
|
379
|
+
|
380
|
+
pid = fork do
|
381
|
+
conn = PGconn.connect( @conninfo )
|
382
|
+
conn.exec( %Q{NOTIFY knees, 'skirt and boots'} )
|
383
|
+
conn.finish
|
384
|
+
exit!
|
385
|
+
end
|
386
|
+
|
387
|
+
Process.wait( pid )
|
388
|
+
|
389
|
+
event, pid, msg = nil
|
390
|
+
@conn.wait_for_notify( 10 ) do |arg1, arg2, arg3|
|
391
|
+
event, pid, msg = arg1, arg2, arg3
|
392
|
+
end
|
393
|
+
@conn.exec( 'UNLISTEN woo' )
|
394
|
+
|
395
|
+
event.should == 'knees'
|
396
|
+
pid.should be_a_kind_of( Integer )
|
397
|
+
msg.should == 'skirt and boots'
|
398
|
+
end
|
399
|
+
|
400
|
+
end
|
401
|
+
|
146
402
|
it "yields the result if block is given to exec" do
|
147
403
|
rval = @conn.exec( "select 1234::int as a union select 5678::int as a" ) do |result|
|
148
404
|
values = []
|
@@ -197,7 +453,7 @@ describe PGconn do
|
|
197
453
|
@conn.block( 0.1 )
|
198
454
|
finish = Time.now
|
199
455
|
|
200
|
-
(finish - start).should
|
456
|
+
(finish - start).should be_within( 0.05 ).of( 0.1 )
|
201
457
|
end
|
202
458
|
|
203
459
|
|