pg 0.12.2-x86-mingw32 → 0.13.0-x86-mingw32
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/.hoerc +2 -0
- data/.tm_properties +12 -0
- data/ChangeLog +166 -59
- data/Contributors.rdoc +7 -0
- data/History.rdoc +29 -0
- data/LICENSE +12 -14
- data/Manifest.txt +15 -14
- data/{BSD → POSTGRES} +0 -0
- data/{README.OS_X.rdoc → README-OS_X.rdoc} +0 -0
- data/{README.windows.rdoc → README-Windows.rdoc} +0 -0
- data/README.ja.rdoc +1 -1
- data/README.rdoc +39 -27
- data/Rakefile +1 -5
- data/Rakefile.cross +2 -2
- data/ext/extconf.rb +8 -2
- data/ext/pg.c +232 -4297
- data/ext/pg.h +88 -23
- data/ext/pg_connection.c +3288 -0
- data/ext/pg_result.c +905 -0
- data/lib/1.8/pg_ext.so +0 -0
- data/lib/1.9/pg_ext.so +0 -0
- data/lib/pg.rb +26 -43
- data/lib/pg/connection.rb +58 -0
- data/lib/pg/constants.rb +11 -0
- data/lib/pg/exceptions.rb +11 -0
- data/lib/pg/result.rb +11 -0
- data/misc/openssl-pg-segfault.rb +1 -1
- data/sample/async_api.rb +16 -21
- data/sample/async_copyto.rb +1 -1
- data/sample/async_mixed.rb +56 -0
- data/sample/copyfrom.rb +1 -1
- data/sample/copyto.rb +1 -1
- data/sample/cursor.rb +1 -1
- data/sample/losample.rb +6 -6
- data/sample/notify_wait.rb +51 -22
- data/sample/test_binary_values.rb +4 -6
- data/spec/lib/helpers.rb +14 -10
- data/spec/{pgconn_spec.rb → pg/connection_spec.rb} +228 -60
- data/spec/{pgresult_spec.rb → pg/result_spec.rb} +31 -35
- data/spec/pg_spec.rb +22 -0
- metadata +52 -41
- data/GPL +0 -340
- data/ext/compat.c +0 -541
- data/ext/compat.h +0 -184
- data/sample/psql.rb +0 -1181
- data/sample/psqlHelp.rb +0 -158
- data/sample/test1.rb +0 -60
- data/sample/test2.rb +0 -44
- data/sample/test4.rb +0 -71
- data/spec/m17n_spec.rb +0 -170
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
@@ -14,56 +14,39 @@ rescue LoadError
|
|
14
14
|
|
15
15
|
end
|
16
16
|
|
17
|
-
#--
|
18
|
-
# The PG connection class.
|
19
|
-
class PGconn
|
20
17
|
|
21
|
-
|
22
|
-
|
18
|
+
# The top-level PG namespace.
|
19
|
+
module PG
|
23
20
|
|
21
|
+
# Library version
|
22
|
+
VERSION = '0.13.0'
|
24
23
|
|
25
|
-
|
26
|
-
|
27
|
-
|
24
|
+
# VCS revision
|
25
|
+
REVISION = %q$Revision$
|
26
|
+
|
27
|
+
|
28
|
+
### Get the PG library version. If +include_buildnum+ is +true+, include the build ID.
|
29
|
+
def self::version_string( include_buildnum=false )
|
30
|
+
vstring = "%s %s" % [ self.name, VERSION ]
|
31
|
+
vstring << " (build %s)" % [ REVISION[/: ([[:xdigit:]]+)/, 1] || '0' ] if include_buildnum
|
32
|
+
return vstring
|
28
33
|
end
|
29
34
|
|
30
35
|
|
31
|
-
###
|
32
|
-
|
33
|
-
|
34
|
-
return '' if args.empty?
|
35
|
-
|
36
|
-
# This will be swapped soon for code that makes options like those required for
|
37
|
-
# PQconnectdbParams()/PQconnectStartParams(). For now, stick to an options string for
|
38
|
-
# PQconnectdb()/PQconnectStart().
|
39
|
-
connopts = []
|
40
|
-
|
41
|
-
# Handle an options hash first
|
42
|
-
if args.last.is_a?( Hash )
|
43
|
-
opthash = args.pop
|
44
|
-
opthash.each do |key, val|
|
45
|
-
connopts.push( "%s=%s" % [key, PGconn.quote_connstr(val)] )
|
46
|
-
end
|
47
|
-
end
|
48
|
-
|
49
|
-
# Option string style
|
50
|
-
if args.length == 1 && args.first.to_s.index( '=' )
|
51
|
-
connopts.unshift( args.first )
|
52
|
-
|
53
|
-
# Append positional parameters
|
54
|
-
else
|
55
|
-
args.each_with_index do |val, i|
|
56
|
-
next unless val # Skip nil placeholders
|
57
|
-
|
58
|
-
key = CONNECT_ARGUMENT_ORDER[ i ] or
|
59
|
-
raise ArgumentError, "Extra positional parameter %d: %p" % [ i+1, val ]
|
60
|
-
connopts.push( "%s=%s" % [key, PGconn.quote_connstr(val.to_s)] )
|
61
|
-
end
|
62
|
-
end
|
63
|
-
|
64
|
-
return connopts.join(' ')
|
36
|
+
### Convenience alias for PG::Connection.new.
|
37
|
+
def self::connect( *args )
|
38
|
+
return PG::Connection.new( *args )
|
65
39
|
end
|
66
40
|
|
67
|
-
end # class PGconn
|
68
41
|
|
42
|
+
require 'pg/exceptions'
|
43
|
+
require 'pg/constants'
|
44
|
+
require 'pg/connection'
|
45
|
+
require 'pg/result'
|
46
|
+
|
47
|
+
end # module PG
|
48
|
+
|
49
|
+
|
50
|
+
# Backward-compatible aliase
|
51
|
+
PGError = PG::Error
|
69
52
|
|
@@ -0,0 +1,58 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'pg' unless defined?( PG )
|
4
|
+
|
5
|
+
# The PG connection class.
|
6
|
+
class PG::Connection
|
7
|
+
|
8
|
+
# The order the options are passed to the ::connect method.
|
9
|
+
CONNECT_ARGUMENT_ORDER = %w[host port options tty dbname user password]
|
10
|
+
|
11
|
+
|
12
|
+
### Quote the given +value+ for use in a connection-parameter string.
|
13
|
+
def self::quote_connstr( value )
|
14
|
+
return "'" + value.to_s.gsub( /[\\']/ ) {|m| '\\' + m } + "'"
|
15
|
+
end
|
16
|
+
|
17
|
+
|
18
|
+
### Parse the connection +args+ into a connection-parameter string. See PG::Connection.new
|
19
|
+
### for valid arguments.
|
20
|
+
def self::parse_connect_args( *args )
|
21
|
+
return '' if args.empty?
|
22
|
+
|
23
|
+
# This will be swapped soon for code that makes options like those required for
|
24
|
+
# PQconnectdbParams()/PQconnectStartParams(). For now, stick to an options string for
|
25
|
+
# PQconnectdb()/PQconnectStart().
|
26
|
+
connopts = []
|
27
|
+
|
28
|
+
# Handle an options hash first
|
29
|
+
if args.last.is_a?( Hash )
|
30
|
+
opthash = args.pop
|
31
|
+
opthash.each do |key, val|
|
32
|
+
connopts.push( "%s=%s" % [key, PG::Connection.quote_connstr(val)] )
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
# Option string style
|
37
|
+
if args.length == 1 && args.first.to_s.index( '=' )
|
38
|
+
connopts.unshift( args.first )
|
39
|
+
|
40
|
+
# Append positional parameters
|
41
|
+
else
|
42
|
+
args.each_with_index do |val, i|
|
43
|
+
next unless val # Skip nil placeholders
|
44
|
+
|
45
|
+
key = CONNECT_ARGUMENT_ORDER[ i ] or
|
46
|
+
raise ArgumentError, "Extra positional parameter %d: %p" % [ i+1, val ]
|
47
|
+
connopts.push( "%s=%s" % [key, PG::Connection.quote_connstr(val.to_s)] )
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
return connopts.join(' ')
|
52
|
+
end
|
53
|
+
|
54
|
+
end # class PG::Connection
|
55
|
+
|
56
|
+
# Backward-compatible alias
|
57
|
+
PGconn = PG::Connection
|
58
|
+
|
data/lib/pg/constants.rb
ADDED
data/lib/pg/result.rb
ADDED
data/misc/openssl-pg-segfault.rb
CHANGED
@@ -8,7 +8,7 @@ SOCKHOST = 'it-trac.laika.com'
|
|
8
8
|
# Load pg first, so the libssl.so that libpq is linked against is loaded.
|
9
9
|
require 'pg'
|
10
10
|
$stderr.puts "connecting to postgres://#{PGHOST}/#{PGDB}"
|
11
|
-
conn =
|
11
|
+
conn = PG.connect( PGHOST, :dbname => PGDB )
|
12
12
|
|
13
13
|
# Now load OpenSSL, which might be linked against a different libssl.
|
14
14
|
require 'socket'
|
data/sample/async_api.rb
CHANGED
@@ -4,16 +4,10 @@ require 'pg'
|
|
4
4
|
|
5
5
|
# This is a example of how to use the asynchronous API to query the
|
6
6
|
# server without blocking other threads. It's intentionally low-level;
|
7
|
-
# if you hooked up the
|
7
|
+
# if you hooked up the PG::Connection#socket to some kind of reactor, you
|
8
8
|
# could make this much nicer.
|
9
9
|
|
10
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
11
|
|
18
12
|
# Print 'x' continuously to demonstrate that other threads aren't
|
19
13
|
# blocked while waiting for the connection, for the query to be sent,
|
@@ -28,9 +22,10 @@ end
|
|
28
22
|
|
29
23
|
# Start the connection
|
30
24
|
output_progress "Starting connection..."
|
31
|
-
conn =
|
25
|
+
conn = PG::Connection.connect_start( :dbname => 'test' ) or
|
26
|
+
abort "Unable to create a new connection!"
|
32
27
|
abort "Connection failed: %s" % [ conn.error_message ] if
|
33
|
-
conn.status ==
|
28
|
+
conn.status == PG::CONNECTION_BAD
|
34
29
|
|
35
30
|
# Now grab a reference to the underlying socket so we know when the
|
36
31
|
# connection is established
|
@@ -38,19 +33,19 @@ socket = IO.for_fd( conn.socket )
|
|
38
33
|
|
39
34
|
# Track the progress of the connection, waiting for the socket to become readable/writable
|
40
35
|
# before polling it
|
41
|
-
poll_status =
|
42
|
-
until poll_status ==
|
43
|
-
poll_status ==
|
36
|
+
poll_status = PG::PGRES_POLLING_WRITING
|
37
|
+
until poll_status == PG::PGRES_POLLING_OK ||
|
38
|
+
poll_status == PG::PGRES_POLLING_FAILED
|
44
39
|
|
45
40
|
# If the socket needs to read, wait 'til it becomes readable to poll again
|
46
41
|
case poll_status
|
47
|
-
when
|
42
|
+
when PG::PGRES_POLLING_READING
|
48
43
|
output_progress " waiting for socket to become readable"
|
49
44
|
select( [socket], nil, nil, TIMEOUT ) or
|
50
45
|
raise "Asynchronous connection timed out!"
|
51
46
|
|
52
47
|
# ...and the same for when the socket needs to write
|
53
|
-
when
|
48
|
+
when PG::PGRES_POLLING_WRITING
|
54
49
|
output_progress " waiting for socket to become writable"
|
55
50
|
select( nil, [socket], nil, TIMEOUT ) or
|
56
51
|
raise "Asynchronous connection timed out!"
|
@@ -58,17 +53,17 @@ until poll_status == PGconn::PGRES_POLLING_OK ||
|
|
58
53
|
|
59
54
|
# Output a status message about the progress
|
60
55
|
case conn.status
|
61
|
-
when
|
56
|
+
when PG::CONNECTION_STARTED
|
62
57
|
output_progress " waiting for connection to be made."
|
63
|
-
when
|
58
|
+
when PG::CONNECTION_MADE
|
64
59
|
output_progress " connection OK; waiting to send."
|
65
|
-
when
|
60
|
+
when PG::CONNECTION_AWAITING_RESPONSE
|
66
61
|
output_progress " waiting for a response from the server."
|
67
|
-
when
|
62
|
+
when PG::CONNECTION_AUTH_OK
|
68
63
|
output_progress " received authentication; waiting for backend start-up to finish."
|
69
|
-
when
|
64
|
+
when PG::CONNECTION_SSL_STARTUP
|
70
65
|
output_progress " negotiating SSL encryption."
|
71
|
-
when
|
66
|
+
when PG::CONNECTION_SETENV
|
72
67
|
output_progress " negotiating environment-driven parameter settings."
|
73
68
|
end
|
74
69
|
|
@@ -76,7 +71,7 @@ until poll_status == PGconn::PGRES_POLLING_OK ||
|
|
76
71
|
poll_status = conn.connect_poll
|
77
72
|
end
|
78
73
|
|
79
|
-
abort "Connect failed: %s" % [ conn.error_message ] unless conn.status ==
|
74
|
+
abort "Connect failed: %s" % [ conn.error_message ] unless conn.status == PG::CONNECTION_OK
|
80
75
|
|
81
76
|
output_progress "Sending query"
|
82
77
|
conn.send_query( "SELECT * FROM pg_stat_activity" )
|
data/sample/async_copyto.rb
CHANGED
@@ -0,0 +1,56 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'pg'
|
4
|
+
|
5
|
+
$stdout.sync = true
|
6
|
+
|
7
|
+
# This is a example of how to mix and match synchronous and async APIs. In this case,
|
8
|
+
# the connection to the server is made syncrhonously, and then queries are
|
9
|
+
# asynchronous.
|
10
|
+
|
11
|
+
TIMEOUT = 5.0 # seconds to wait for an async operation to complete
|
12
|
+
CONN_OPTS = {
|
13
|
+
:host => 'localhost',
|
14
|
+
:dbname => 'test',
|
15
|
+
}
|
16
|
+
|
17
|
+
# Output progress messages
|
18
|
+
def output_progress( msg )
|
19
|
+
puts ">>> #{msg}\n"
|
20
|
+
end
|
21
|
+
|
22
|
+
# Start the (synchronous) connection
|
23
|
+
output_progress "Starting connection..."
|
24
|
+
conn = PG.connect( CONN_OPTS ) or abort "Unable to create a new connection!"
|
25
|
+
|
26
|
+
abort "Connect failed: %s" % [ conn.error_message ] unless conn.status == PG::CONNECTION_OK
|
27
|
+
|
28
|
+
# Now grab a reference to the underlying socket to select() on while the query is running
|
29
|
+
socket = IO.for_fd( conn.socket )
|
30
|
+
|
31
|
+
# Send the (asynchronous) query
|
32
|
+
output_progress "Sending query"
|
33
|
+
conn.send_query( "SELECT * FROM pg_stat_activity" )
|
34
|
+
|
35
|
+
# Fetch results until there aren't any more
|
36
|
+
loop do
|
37
|
+
output_progress " waiting for a response"
|
38
|
+
|
39
|
+
# Buffer any incoming data on the socket until a full result is ready.
|
40
|
+
conn.consume_input
|
41
|
+
while conn.is_busy
|
42
|
+
output_progress " waiting for data to be available on %p..." % [ socket ]
|
43
|
+
select( [socket], nil, nil, TIMEOUT ) or
|
44
|
+
raise "Timeout waiting for query response."
|
45
|
+
conn.consume_input
|
46
|
+
end
|
47
|
+
|
48
|
+
# Fetch the next result. If there isn't one, the query is finished
|
49
|
+
result = conn.get_result or break
|
50
|
+
|
51
|
+
output_progress "Query result:\n%p\n" % [ result.values ]
|
52
|
+
end
|
53
|
+
|
54
|
+
output_progress "Done."
|
55
|
+
conn.finish
|
56
|
+
|
data/sample/copyfrom.rb
CHANGED
data/sample/copyto.rb
CHANGED
@@ -6,7 +6,7 @@ require 'stringio'
|
|
6
6
|
# An example of how to stream data to your local host from the database as CSV.
|
7
7
|
|
8
8
|
$stderr.puts "Opening database connection ..."
|
9
|
-
conn =
|
9
|
+
conn = PG.connect( :dbname => 'test' )
|
10
10
|
|
11
11
|
$stderr.puts "Running COPY command ..."
|
12
12
|
buf = ''
|
data/sample/cursor.rb
CHANGED
data/sample/losample.rb
CHANGED
@@ -5,7 +5,7 @@ require 'pg'
|
|
5
5
|
SAMPLE_WRITE_DATA = 'some sample data'
|
6
6
|
SAMPLE_EXPORT_NAME = 'lowrite.txt'
|
7
7
|
|
8
|
-
conn =
|
8
|
+
conn = PG.connect( :dbname => 'test', :host => 'localhost', :port => 5432 )
|
9
9
|
puts "dbname: " + conn.db + "\thost: " + conn.host + "\tuser: " + conn.user
|
10
10
|
|
11
11
|
# Start a transaction, as all large object functions require one.
|
@@ -20,15 +20,15 @@ puts " imported as large object %d" % [ oid ]
|
|
20
20
|
|
21
21
|
# Read back 50 bytes of the imported data
|
22
22
|
puts "Read test:"
|
23
|
-
fd = conn.lo_open( oid,
|
24
|
-
conn.lo_lseek( fd, 0,
|
23
|
+
fd = conn.lo_open( oid, PG::INV_READ|PG::INV_WRITE )
|
24
|
+
conn.lo_lseek( fd, 0, PG::SEEK_SET )
|
25
25
|
buf = conn.lo_read( fd, 50 )
|
26
26
|
puts " read: %p" % [ buf ]
|
27
27
|
puts " read was ok!" if buf =~ /require 'pg'/
|
28
28
|
|
29
29
|
# Append some test data onto the end of the object
|
30
30
|
puts "Write test:"
|
31
|
-
conn.lo_lseek( fd, 0,
|
31
|
+
conn.lo_lseek( fd, 0, PG::SEEK_END )
|
32
32
|
buf = SAMPLE_WRITE_DATA.dup
|
33
33
|
totalbytes = 0
|
34
34
|
until buf.empty?
|
@@ -53,9 +53,9 @@ puts 'Testing read and delete from a new transaction:'
|
|
53
53
|
puts ' starting a new transaction'
|
54
54
|
conn.exec( 'BEGIN' )
|
55
55
|
|
56
|
-
fd = conn.lo_open( oid,
|
56
|
+
fd = conn.lo_open( oid, PG::INV_READ )
|
57
57
|
puts ' reopened okay.'
|
58
|
-
conn.lo_lseek( fd, 50,
|
58
|
+
conn.lo_lseek( fd, 50, PG::SEEK_END )
|
59
59
|
buf = conn.lo_read( fd, 50 )
|
60
60
|
puts ' read okay.' if buf == SAMPLE_WRITE_DATA
|
61
61
|
|
data/sample/notify_wait.rb
CHANGED
@@ -2,25 +2,6 @@
|
|
2
2
|
#
|
3
3
|
# Test script, demonstrating a non-poll notification for a table event.
|
4
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
5
|
|
25
6
|
BEGIN {
|
26
7
|
require 'pathname'
|
@@ -31,13 +12,61 @@ BEGIN {
|
|
31
12
|
|
32
13
|
require 'pg'
|
33
14
|
|
34
|
-
|
15
|
+
TRIGGER_TABLE = %{
|
16
|
+
CREATE TABLE IF NOT EXISTS test ( message text );
|
17
|
+
}
|
18
|
+
|
19
|
+
TRIGGER_FUNCTION = %{
|
20
|
+
CREATE OR REPLACE FUNCTION notify_test()
|
21
|
+
RETURNS TRIGGER
|
22
|
+
LANGUAGE plpgsql
|
23
|
+
AS $$
|
24
|
+
BEGIN
|
25
|
+
NOTIFY woo;
|
26
|
+
RETURN NULL;
|
27
|
+
END
|
28
|
+
$$
|
29
|
+
}
|
30
|
+
|
31
|
+
DROP_TRIGGER = %{
|
32
|
+
DROP TRIGGER IF EXISTS notify_trigger ON test
|
33
|
+
}
|
34
|
+
|
35
|
+
|
36
|
+
TRIGGER = %{
|
37
|
+
CREATE TRIGGER notify_trigger
|
38
|
+
AFTER UPDATE OR INSERT OR DELETE
|
39
|
+
ON test
|
40
|
+
FOR EACH STATEMENT
|
41
|
+
EXECUTE PROCEDURE notify_test();
|
42
|
+
}
|
43
|
+
|
44
|
+
conn = PG.connect( :dbname => 'test' )
|
45
|
+
|
46
|
+
conn.exec( TRIGGER_TABLE )
|
47
|
+
conn.exec( TRIGGER_FUNCTION )
|
48
|
+
conn.exec( DROP_TRIGGER )
|
49
|
+
conn.exec( TRIGGER )
|
50
|
+
|
35
51
|
conn.exec( 'LISTEN woo' ) # register interest in the 'woo' event
|
36
52
|
|
53
|
+
notifications = []
|
54
|
+
|
55
|
+
puts "Now switch to a different term and run:",
|
56
|
+
'',
|
57
|
+
%{ psql test -c "insert into test values ('A message.')"},
|
58
|
+
''
|
59
|
+
|
37
60
|
puts "Waiting up to 30 seconds for for an event!"
|
38
61
|
conn.wait_for_notify( 30 ) do |notify, pid|
|
39
|
-
|
62
|
+
notifications << [ pid, notify ]
|
63
|
+
end
|
64
|
+
|
65
|
+
if notifications.empty?
|
66
|
+
puts "Awww, I didn't see any events."
|
67
|
+
else
|
68
|
+
puts "I got one from pid %d: %s" % notifications.first
|
40
69
|
end
|
41
70
|
|
42
|
-
|
71
|
+
|
43
72
|
|