pg 0.11.0-x86-mingw32 → 0.12.0-x86-mingw32
Sign up to get free protection for your applications and to get access to all the features.
- data/.gemtest +0 -0
- data/ChangeLog +1647 -462
- data/Contributors.rdoc +39 -0
- data/History.rdoc +61 -0
- data/Manifest.txt +43 -0
- data/README.OS_X.rdoc +68 -0
- data/README.ja.rdoc +7 -0
- data/{README → README.rdoc} +38 -18
- data/{README.windows → README.windows.rdoc} +23 -31
- data/Rakefile +104 -318
- data/Rakefile.cross +234 -0
- data/ext/compat.c +2 -2
- data/ext/extconf.rb +10 -2
- data/ext/pg.c +223 -43
- data/ext/vc/pg.sln +26 -0
- data/ext/vc/pg_18/pg.vcproj +216 -0
- data/ext/vc/pg_19/pg_19.vcproj +209 -0
- data/lib/1.8/pg_ext.so +0 -0
- data/lib/1.9/pg_ext.so +0 -0
- data/lib/pg.rb +5 -7
- data/misc/openssl-pg-segfault.rb +31 -0
- data/sample/async_api.rb +109 -0
- data/sample/async_copyto.rb +39 -0
- data/sample/copyfrom.rb +81 -0
- data/sample/copyto.rb +19 -0
- data/sample/cursor.rb +21 -0
- data/sample/losample.rb +69 -0
- data/sample/notify_wait.rb +43 -0
- data/sample/psql.rb +1181 -0
- data/sample/psqlHelp.rb +158 -0
- data/sample/test1.rb +60 -0
- data/sample/test2.rb +44 -0
- data/sample/test4.rb +71 -0
- data/sample/test_binary_values.rb +35 -0
- data/spec/lib/helpers.rb +6 -4
- data/spec/m17n_spec.rb +2 -2
- data/spec/pgconn_spec.rb +51 -6
- data/spec/pgresult_spec.rb +30 -4
- metadata +147 -86
- data.tar.gz.sig +0 -3
- data/Contributors +0 -32
- data/README.OS_X +0 -19
- data/README.ja +0 -183
- data/Rakefile.local +0 -312
- data/rake/191_compat.rb +0 -26
- data/rake/dependencies.rb +0 -76
- data/rake/documentation.rb +0 -123
- data/rake/helpers.rb +0 -502
- data/rake/hg.rb +0 -318
- data/rake/manual.rb +0 -787
- data/rake/packaging.rb +0 -129
- data/rake/publishing.rb +0 -341
- data/rake/style.rb +0 -62
- data/rake/svn.rb +0 -668
- data/rake/testing.rb +0 -152
- data/rake/verifytask.rb +0 -64
- metadata.gz.sig +0 -3
data/lib/1.8/pg_ext.so
CHANGED
Binary file
|
data/lib/1.9/pg_ext.so
CHANGED
Binary file
|
data/lib/pg.rb
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
|
3
3
|
begin
|
4
4
|
require 'pg_ext'
|
5
|
-
rescue LoadError
|
5
|
+
rescue LoadError
|
6
6
|
# If it's a Windows binary gem, try the <major>.<minor> subdirectory
|
7
7
|
if RUBY_PLATFORM =~/(mswin|mingw)/i
|
8
8
|
major_minor = RUBY_VERSION[ /^(\d+\.\d+)/ ] or
|
@@ -14,7 +14,8 @@ rescue LoadError => err
|
|
14
14
|
|
15
15
|
end
|
16
16
|
|
17
|
-
|
17
|
+
#--
|
18
|
+
# The PG connection class.
|
18
19
|
class PGconn
|
19
20
|
|
20
21
|
# The order the options are passed to the ::connect method.
|
@@ -22,16 +23,13 @@ class PGconn
|
|
22
23
|
|
23
24
|
|
24
25
|
### Quote the given +value+ for use in a connection-parameter string.
|
25
|
-
### @param [String] value the option value to be quoted.
|
26
|
-
### @return [String]
|
27
26
|
def self::quote_connstr( value )
|
28
27
|
return "'" + value.to_s.gsub( /[\\']/ ) {|m| '\\' + m } + "'"
|
29
28
|
end
|
30
29
|
|
31
30
|
|
32
|
-
### Parse the connection +args+ into a connection-parameter string
|
33
|
-
###
|
34
|
-
### @return [String] a connection parameters string
|
31
|
+
### Parse the connection +args+ into a connection-parameter string. See PGconn.new
|
32
|
+
### for valid arguments.
|
35
33
|
def self::parse_connect_args( *args )
|
36
34
|
return '' if args.empty?
|
37
35
|
|
@@ -0,0 +1,31 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
PGHOST = 'localhost'
|
4
|
+
PGDB = 'test'
|
5
|
+
#SOCKHOST = 'github.com'
|
6
|
+
SOCKHOST = 'it-trac.laika.com'
|
7
|
+
|
8
|
+
# Load pg first, so the libssl.so that libpq is linked against is loaded.
|
9
|
+
require 'pg'
|
10
|
+
$stderr.puts "connecting to postgres://#{PGHOST}/#{PGDB}"
|
11
|
+
conn = PGconn.connect( PGHOST, :dbname => PGDB )
|
12
|
+
|
13
|
+
# Now load OpenSSL, which might be linked against a different libssl.
|
14
|
+
require 'socket'
|
15
|
+
require 'openssl'
|
16
|
+
$stderr.puts "Connecting to #{SOCKHOST}"
|
17
|
+
sock = TCPSocket.open( SOCKHOST, 443 )
|
18
|
+
ctx = OpenSSL::SSL::SSLContext.new
|
19
|
+
sock = OpenSSL::SSL::SSLSocket.new( sock, ctx )
|
20
|
+
sock.sync_close = true
|
21
|
+
|
22
|
+
# The moment of truth...
|
23
|
+
$stderr.puts "Attempting to connect..."
|
24
|
+
begin
|
25
|
+
sock.connect
|
26
|
+
rescue Errno
|
27
|
+
$stderr.puts "Got an error connecting, but no segfault."
|
28
|
+
else
|
29
|
+
$stderr.puts "Nope, no segfault!"
|
30
|
+
end
|
31
|
+
|
data/sample/async_api.rb
ADDED
@@ -0,0 +1,109 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'pg'
|
4
|
+
|
5
|
+
# This is a example of how to use the asynchronous API to query the
|
6
|
+
# server without blocking other threads. It's intentionally low-level;
|
7
|
+
# if you hooked up the PGconn#socket to some kind of reactor, you
|
8
|
+
# could make this much nicer.
|
9
|
+
|
10
|
+
TIMEOUT = 5.0 # seconds to wait for an async operation to complete
|
11
|
+
CONN_OPTS = {
|
12
|
+
:host => 'localhost',
|
13
|
+
:dbname => 'test',
|
14
|
+
:user => 'jrandom',
|
15
|
+
:password => 'banks!stealUR$',
|
16
|
+
}
|
17
|
+
|
18
|
+
# Print 'x' continuously to demonstrate that other threads aren't
|
19
|
+
# blocked while waiting for the connection, for the query to be sent,
|
20
|
+
# for results, etc. You might want to sleep inside the loop or
|
21
|
+
# comment this out entirely for cleaner output.
|
22
|
+
progress_thread = Thread.new { loop { print 'x' } }
|
23
|
+
|
24
|
+
# Output progress messages
|
25
|
+
def output_progress( msg )
|
26
|
+
puts "\n>>> #{msg}\n"
|
27
|
+
end
|
28
|
+
|
29
|
+
# Start the connection
|
30
|
+
output_progress "Starting connection..."
|
31
|
+
conn = PGconn.connect_start( CONN_OPTS ) or abort "Unable to create a new connection!"
|
32
|
+
abort "Connection failed: %s" % [ conn.error_message ] if
|
33
|
+
conn.status == PGconn::CONNECTION_BAD
|
34
|
+
|
35
|
+
# Now grab a reference to the underlying socket so we know when the
|
36
|
+
# connection is established
|
37
|
+
socket = IO.for_fd( conn.socket )
|
38
|
+
|
39
|
+
# Track the progress of the connection, waiting for the socket to become readable/writable
|
40
|
+
# before polling it
|
41
|
+
poll_status = PGconn::PGRES_POLLING_WRITING
|
42
|
+
until poll_status == PGconn::PGRES_POLLING_OK ||
|
43
|
+
poll_status == PGconn::PGRES_POLLING_FAILED
|
44
|
+
|
45
|
+
# If the socket needs to read, wait 'til it becomes readable to poll again
|
46
|
+
case poll_status
|
47
|
+
when PGconn::PGRES_POLLING_READING
|
48
|
+
output_progress " waiting for socket to become readable"
|
49
|
+
select( [socket], nil, nil, TIMEOUT ) or
|
50
|
+
raise "Asynchronous connection timed out!"
|
51
|
+
|
52
|
+
# ...and the same for when the socket needs to write
|
53
|
+
when PGconn::PGRES_POLLING_WRITING
|
54
|
+
output_progress " waiting for socket to become writable"
|
55
|
+
select( nil, [socket], nil, TIMEOUT ) or
|
56
|
+
raise "Asynchronous connection timed out!"
|
57
|
+
end
|
58
|
+
|
59
|
+
# Output a status message about the progress
|
60
|
+
case conn.status
|
61
|
+
when PGconn::CONNECTION_STARTED
|
62
|
+
output_progress " waiting for connection to be made."
|
63
|
+
when PGconn::CONNECTION_MADE
|
64
|
+
output_progress " connection OK; waiting to send."
|
65
|
+
when PGconn::CONNECTION_AWAITING_RESPONSE
|
66
|
+
output_progress " waiting for a response from the server."
|
67
|
+
when PGconn::CONNECTION_AUTH_OK
|
68
|
+
output_progress " received authentication; waiting for backend start-up to finish."
|
69
|
+
when PGconn::CONNECTION_SSL_STARTUP
|
70
|
+
output_progress " negotiating SSL encryption."
|
71
|
+
when PGconn::CONNECTION_SETENV
|
72
|
+
output_progress " negotiating environment-driven parameter settings."
|
73
|
+
end
|
74
|
+
|
75
|
+
# Check to see if it's finished or failed yet
|
76
|
+
poll_status = conn.connect_poll
|
77
|
+
end
|
78
|
+
|
79
|
+
abort "Connect failed: %s" % [ conn.error_message ] unless conn.status == PGconn::CONNECTION_OK
|
80
|
+
|
81
|
+
output_progress "Sending query"
|
82
|
+
conn.send_query( "SELECT * FROM pg_stat_activity" )
|
83
|
+
|
84
|
+
# Fetch results until there aren't any more
|
85
|
+
loop do
|
86
|
+
output_progress " waiting for a response"
|
87
|
+
|
88
|
+
# Buffer any incoming data on the socket until a full result is ready.
|
89
|
+
conn.consume_input
|
90
|
+
while conn.is_busy
|
91
|
+
select( [socket], nil, nil, TIMEOUT ) or
|
92
|
+
raise "Timeout waiting for query response."
|
93
|
+
conn.consume_input
|
94
|
+
end
|
95
|
+
|
96
|
+
# Fetch the next result. If there isn't one, the query is finished
|
97
|
+
result = conn.get_result or break
|
98
|
+
|
99
|
+
puts "\n\nQuery result:\n%p\n" % [ result.values ]
|
100
|
+
end
|
101
|
+
|
102
|
+
output_progress "Done."
|
103
|
+
conn.finish
|
104
|
+
|
105
|
+
if defined?( progress_thread )
|
106
|
+
progress_thread.kill
|
107
|
+
progress_thread.join
|
108
|
+
end
|
109
|
+
|
@@ -0,0 +1,39 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'pg'
|
4
|
+
require 'stringio'
|
5
|
+
|
6
|
+
# Using COPY asynchronously
|
7
|
+
|
8
|
+
$stderr.puts "Opening database connection ..."
|
9
|
+
conn = PGconn.connect( :dbname => 'test' )
|
10
|
+
conn.setnonblocking( true )
|
11
|
+
|
12
|
+
socket = IO.for_fd( conn.socket )
|
13
|
+
|
14
|
+
$stderr.puts "Running COPY command ..."
|
15
|
+
buf = ''
|
16
|
+
conn.transaction do
|
17
|
+
conn.send_query( "COPY logs TO STDOUT WITH csv" )
|
18
|
+
buf = nil
|
19
|
+
|
20
|
+
# #get_copy_data returns a row if there's a whole one to return, false
|
21
|
+
# if there isn't one but the COPY is still running, or nil when it's
|
22
|
+
# finished.
|
23
|
+
begin
|
24
|
+
$stderr.puts "COPY loop"
|
25
|
+
conn.consume_input
|
26
|
+
while conn.is_busy
|
27
|
+
$stderr.puts " ready loop"
|
28
|
+
select( [socket], nil, nil, 5.0 ) or
|
29
|
+
raise "Timeout (5s) waiting for query response."
|
30
|
+
conn.consume_input
|
31
|
+
end
|
32
|
+
|
33
|
+
buf = conn.get_copy_data
|
34
|
+
$stdout.puts( buf ) if buf
|
35
|
+
end until buf.nil?
|
36
|
+
end
|
37
|
+
|
38
|
+
conn.finish
|
39
|
+
|
data/sample/copyfrom.rb
ADDED
@@ -0,0 +1,81 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'pg'
|
4
|
+
require 'stringio'
|
5
|
+
|
6
|
+
$stderr.puts "Opening database connection ..."
|
7
|
+
conn = PGconn.connect( :dbname => 'test' )
|
8
|
+
|
9
|
+
conn.exec( <<END_SQL )
|
10
|
+
DROP TABLE IF EXISTS logs;
|
11
|
+
CREATE TABLE logs (
|
12
|
+
client_ip inet,
|
13
|
+
username text,
|
14
|
+
ts timestamp,
|
15
|
+
request text,
|
16
|
+
status smallint,
|
17
|
+
bytes int
|
18
|
+
);
|
19
|
+
END_SQL
|
20
|
+
|
21
|
+
copy_data = StringIO.new( <<"END_DATA" )
|
22
|
+
"127.0.0.1","","30/Aug/2010:08:21:24 -0700","GET /manual/ HTTP/1.1",404,205
|
23
|
+
"127.0.0.1","","30/Aug/2010:08:21:24 -0700","GET /favicon.ico HTTP/1.1",404,209
|
24
|
+
"127.0.0.1","","30/Aug/2010:08:21:24 -0700","GET /favicon.ico HTTP/1.1",404,209
|
25
|
+
"127.0.0.1","","30/Aug/2010:08:22:29 -0700","GET /manual/ HTTP/1.1",200,11094
|
26
|
+
"127.0.0.1","","30/Aug/2010:08:22:38 -0700","GET /manual/index.html HTTP/1.1",200,725
|
27
|
+
"127.0.0.1","","30/Aug/2010:08:27:56 -0700","GET /manual/ HTTP/1.1",200,11094
|
28
|
+
"127.0.0.1","","30/Aug/2010:08:27:57 -0700","GET /manual/ HTTP/1.1",200,11094
|
29
|
+
"127.0.0.1","","30/Aug/2010:08:28:06 -0700","GET /manual/index.html HTTP/1.1",200,7709
|
30
|
+
"127.0.0.1","","30/Aug/2010:08:28:06 -0700","GET /manual/images/feather.gif HTTP/1.1",200,6471
|
31
|
+
"127.0.0.1","","30/Aug/2010:08:28:06 -0700","GET /manual/images/left.gif HTTP/1.1",200,60
|
32
|
+
"127.0.0.1","","30/Aug/2010:08:28:06 -0700","GET /manual/style/css/manual.css HTTP/1.1",200,18674
|
33
|
+
"127.0.0.1","","30/Aug/2010:08:28:06 -0700","GET /manual/style/css/manual-print.css HTTP/1.1",200,13200
|
34
|
+
"127.0.0.1","","30/Aug/2010:08:28:06 -0700","GET /manual/images/favicon.ico HTTP/1.1",200,1078
|
35
|
+
"127.0.0.1","","30/Aug/2010:08:28:06 -0700","GET /manual/style/css/manual-loose-100pc.css HTTP/1.1",200,3065
|
36
|
+
"127.0.0.1","","30/Aug/2010:08:28:14 -0700","OPTIONS * HTTP/1.0",200,0
|
37
|
+
"127.0.0.1","","30/Aug/2010:08:28:15 -0700","OPTIONS * HTTP/1.0",200,0
|
38
|
+
"127.0.0.1","","30/Aug/2010:08:28:47 -0700","GET /manual/mod/directives.html HTTP/1.1",200,33561
|
39
|
+
"127.0.0.1","","30/Aug/2010:08:28:53 -0700","GET /manual/mod/mpm_common.html HTTP/1.1",200,67683
|
40
|
+
"127.0.0.1","","30/Aug/2010:08:28:53 -0700","GET /manual/images/down.gif HTTP/1.1",200,56
|
41
|
+
"127.0.0.1","","30/Aug/2010:08:28:53 -0700","GET /manual/images/up.gif HTTP/1.1",200,57
|
42
|
+
"127.0.0.1","","30/Aug/2010:09:19:58 -0700","GET /manual/mod/mod_log_config.html HTTP/1.1",200,28307
|
43
|
+
"127.0.0.1","","30/Aug/2010:09:20:19 -0700","GET /manual/mod/core.html HTTP/1.1",200,194144
|
44
|
+
"127.0.0.1","","30/Aug/2010:16:02:56 -0700","GET /manual/ HTTP/1.1",200,11094
|
45
|
+
"127.0.0.1","","30/Aug/2010:16:03:00 -0700","GET /manual/ HTTP/1.1",200,11094
|
46
|
+
"127.0.0.1","","30/Aug/2010:16:06:16 -0700","GET /manual/mod/mod_dir.html HTTP/1.1",200,10583
|
47
|
+
"127.0.0.1","","30/Aug/2010:16:06:44 -0700","GET /manual/ HTTP/1.1",200,7709
|
48
|
+
END_DATA
|
49
|
+
|
50
|
+
### You can test the error case from the database side easily by
|
51
|
+
### changing one of the numbers at the end of one of the above rows to
|
52
|
+
### something non-numeric like "-".
|
53
|
+
|
54
|
+
$stderr.puts "Running COPY command with data ..."
|
55
|
+
buf = ''
|
56
|
+
conn.transaction do
|
57
|
+
conn.exec( "COPY logs FROM STDIN WITH csv" )
|
58
|
+
begin
|
59
|
+
while copy_data.read( 256, buf )
|
60
|
+
### Uncomment this to test error-handling for exceptions from the reader side:
|
61
|
+
# raise Errno::ECONNRESET, "socket closed while reading"
|
62
|
+
$stderr.puts " sending %d bytes of data..." % [ buf.length ]
|
63
|
+
until conn.put_copy_data( buf )
|
64
|
+
$stderr.puts " waiting for connection to be writable..."
|
65
|
+
sleep 0.1
|
66
|
+
end
|
67
|
+
end
|
68
|
+
rescue Errno => err
|
69
|
+
errmsg = "%s while reading copy data: %s" % [ err.class.name, err.message ]
|
70
|
+
conn.put_copy_end( errmsg )
|
71
|
+
else
|
72
|
+
conn.put_copy_end
|
73
|
+
while res = conn.get_result
|
74
|
+
$stderr.puts "Result of COPY is: %s" % [ res.res_status(res.result_status) ]
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
|
80
|
+
conn.finish
|
81
|
+
|
data/sample/copyto.rb
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'pg'
|
4
|
+
require 'stringio'
|
5
|
+
|
6
|
+
# An example of how to stream data to your local host from the database as CSV.
|
7
|
+
|
8
|
+
$stderr.puts "Opening database connection ..."
|
9
|
+
conn = PGconn.connect( :dbname => 'test' )
|
10
|
+
|
11
|
+
$stderr.puts "Running COPY command ..."
|
12
|
+
buf = ''
|
13
|
+
conn.transaction do
|
14
|
+
conn.exec( "COPY logs TO STDOUT WITH csv" )
|
15
|
+
$stdout.puts( buf ) while buf = conn.get_copy_data
|
16
|
+
end
|
17
|
+
|
18
|
+
conn.finish
|
19
|
+
|
data/sample/cursor.rb
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'pg'
|
4
|
+
|
5
|
+
# An example of how to use SQL cursors. This is mostly a straight port of
|
6
|
+
# the cursor portion of testlibpq.c from src/test/examples.
|
7
|
+
|
8
|
+
$stderr.puts "Opening database connection ..."
|
9
|
+
conn = PGconn.connect( :dbname => 'test' )
|
10
|
+
|
11
|
+
#
|
12
|
+
conn.transaction do
|
13
|
+
conn.exec( "DECLARE myportal CURSOR FOR select * from pg_database" )
|
14
|
+
res = conn.exec( "FETCH ALL IN myportal" )
|
15
|
+
|
16
|
+
puts res.fields.collect {|fname| "%-15s" % [fname] }.join( '' )
|
17
|
+
res.values.collect do |row|
|
18
|
+
puts row.collect {|col| "%-15s" % [col] }.join( '' )
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
data/sample/losample.rb
ADDED
@@ -0,0 +1,69 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'pg'
|
4
|
+
|
5
|
+
SAMPLE_WRITE_DATA = 'some sample data'
|
6
|
+
SAMPLE_EXPORT_NAME = 'lowrite.txt'
|
7
|
+
|
8
|
+
conn = PGconn.connect( :dbname => 'test', :host => 'localhost', :port => 5432 )
|
9
|
+
puts "dbname: " + conn.db + "\thost: " + conn.host + "\tuser: " + conn.user
|
10
|
+
|
11
|
+
# Start a transaction, as all large object functions require one.
|
12
|
+
puts "Beginning transaction"
|
13
|
+
conn.exec( 'BEGIN' )
|
14
|
+
|
15
|
+
# Test importing from a file
|
16
|
+
puts "Import test:"
|
17
|
+
puts " importing %s" % [ __FILE__ ]
|
18
|
+
oid = conn.lo_import( __FILE__ )
|
19
|
+
puts " imported as large object %d" % [ oid ]
|
20
|
+
|
21
|
+
# Read back 50 bytes of the imported data
|
22
|
+
puts "Read test:"
|
23
|
+
fd = conn.lo_open( oid, PGconn::INV_READ|PGconn::INV_WRITE )
|
24
|
+
conn.lo_lseek( fd, 0, PGconn::SEEK_SET )
|
25
|
+
buf = conn.lo_read( fd, 50 )
|
26
|
+
puts " read: %p" % [ buf ]
|
27
|
+
puts " read was ok!" if buf =~ /require 'pg'/
|
28
|
+
|
29
|
+
# Append some test data onto the end of the object
|
30
|
+
puts "Write test:"
|
31
|
+
conn.lo_lseek( fd, 0, PGconn::SEEK_END )
|
32
|
+
buf = SAMPLE_WRITE_DATA.dup
|
33
|
+
totalbytes = 0
|
34
|
+
until buf.empty?
|
35
|
+
bytes = conn.lo_write( fd, buf )
|
36
|
+
buf.slice!( 0, bytes )
|
37
|
+
totalbytes += bytes
|
38
|
+
end
|
39
|
+
puts " appended %d bytes" % [ totalbytes ]
|
40
|
+
|
41
|
+
# Now export it
|
42
|
+
puts "Export test:"
|
43
|
+
File.unlink( SAMPLE_EXPORT_NAME ) if File.exist?( SAMPLE_EXPORT_NAME )
|
44
|
+
conn.lo_export( oid, SAMPLE_EXPORT_NAME )
|
45
|
+
puts " success!" if File.exist?( SAMPLE_EXPORT_NAME )
|
46
|
+
puts " exported as %s (%d bytes)" % [ SAMPLE_EXPORT_NAME, File.size(SAMPLE_EXPORT_NAME) ]
|
47
|
+
|
48
|
+
conn.exec( 'COMMIT' )
|
49
|
+
puts "End of transaction."
|
50
|
+
|
51
|
+
|
52
|
+
puts 'Testing read and delete from a new transaction:'
|
53
|
+
puts ' starting a new transaction'
|
54
|
+
conn.exec( 'BEGIN' )
|
55
|
+
|
56
|
+
fd = conn.lo_open( oid, PGconn::INV_READ )
|
57
|
+
puts ' reopened okay.'
|
58
|
+
conn.lo_lseek( fd, 50, PGconn::SEEK_END )
|
59
|
+
buf = conn.lo_read( fd, 50 )
|
60
|
+
puts ' read okay.' if buf == SAMPLE_WRITE_DATA
|
61
|
+
|
62
|
+
puts 'Closing and unlinking:'
|
63
|
+
conn.lo_close( fd )
|
64
|
+
puts ' closed.'
|
65
|
+
conn.lo_unlink( oid )
|
66
|
+
puts ' unlinked.'
|
67
|
+
conn.exec( 'COMMIT' )
|
68
|
+
puts 'Done.'
|
69
|
+
|
@@ -0,0 +1,43 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
#
|
3
|
+
# Test script, demonstrating a non-poll notification for a table event.
|
4
|
+
#
|
5
|
+
# To use, create a table called 'test', and attach a NOTIFY trigger to it
|
6
|
+
# like so:
|
7
|
+
#
|
8
|
+
# CREATE OR REPLACE FUNCTION notify_test()
|
9
|
+
# RETURNS TRIGGER
|
10
|
+
# LANGUAGE plpgsql
|
11
|
+
# AS $$
|
12
|
+
# BEGIN
|
13
|
+
# NOTIFY woo;
|
14
|
+
# RETURN NULL;
|
15
|
+
# END
|
16
|
+
# $$
|
17
|
+
#
|
18
|
+
# CREATE TRIGGER notify_trigger
|
19
|
+
# AFTER UPDATE OR INSERT OR DELETE
|
20
|
+
# ON test
|
21
|
+
# FOR EACH STATEMENT
|
22
|
+
# EXECUTE PROCEDURE notify_test()
|
23
|
+
#
|
24
|
+
|
25
|
+
BEGIN {
|
26
|
+
require 'pathname'
|
27
|
+
basedir = Pathname.new( __FILE__ ).expand_path.dirname.parent
|
28
|
+
libdir = basedir + 'lib'
|
29
|
+
$LOAD_PATH.unshift( libdir.to_s ) unless $LOAD_PATH.include?( libdir.to_s )
|
30
|
+
}
|
31
|
+
|
32
|
+
require 'pg'
|
33
|
+
|
34
|
+
conn = PGconn.connect( :dbname => 'test' )
|
35
|
+
conn.exec( 'LISTEN woo' ) # register interest in the 'woo' event
|
36
|
+
|
37
|
+
puts "Waiting up to 30 seconds for for an event!"
|
38
|
+
conn.wait_for_notify( 30 ) do |notify, pid|
|
39
|
+
puts "I got one from pid %d: %s" % [ pid, notify ]
|
40
|
+
end
|
41
|
+
|
42
|
+
puts "Awww, I didn't see any events."
|
43
|
+
|