pg_jruby 0.14.1.rc2-java → 0.17.1-java
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.
- checksums.yaml +4 -4
- checksums.yaml.gz.sig +0 -0
- data.tar.gz.sig +2 -0
- data/BSDL +22 -0
- data/ChangeLog +0 -0
- data/Contributors.rdoc +45 -0
- data/History.rdoc +270 -0
- data/LICENSE +56 -0
- data/Manifest.txt +51 -5
- data/POSTGRES +23 -0
- data/README-OS_X.rdoc +68 -0
- data/README-Windows.rdoc +67 -0
- data/README.ja.rdoc +14 -0
- data/README.rdoc +52 -94
- data/Rakefile +181 -73
- data/Rakefile.cross +273 -0
- data/ext/errorcodes.def +931 -0
- data/ext/errorcodes.rb +99 -0
- data/ext/errorcodes.txt +463 -0
- data/ext/extconf.rb +97 -0
- data/ext/gvl_wrappers.c +13 -0
- data/ext/gvl_wrappers.h +253 -0
- data/ext/pg.c +545 -0
- data/ext/pg.h +156 -0
- data/ext/pg_connection.c +3643 -0
- data/ext/pg_errors.c +89 -0
- data/ext/pg_result.c +920 -0
- 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/pg.rb +12 -18
- data/lib/pg/connection.rb +117 -10
- data/lib/pg/exceptions.rb +2 -8
- data/lib/pg/result.rb +6 -1
- data/lib/pg_ext.jar +0 -0
- data/sample/array_insert.rb +20 -0
- data/sample/async_api.rb +106 -0
- data/sample/async_copyto.rb +39 -0
- data/sample/async_mixed.rb +56 -0
- data/sample/check_conn.rb +21 -0
- data/sample/copyfrom.rb +81 -0
- data/sample/copyto.rb +19 -0
- data/sample/cursor.rb +21 -0
- data/sample/disk_usage_report.rb +186 -0
- data/sample/issue-119.rb +94 -0
- data/sample/losample.rb +69 -0
- data/sample/minimal-testcase.rb +17 -0
- data/sample/notify_wait.rb +72 -0
- data/sample/pg_statistics.rb +294 -0
- data/sample/replication_monitor.rb +231 -0
- data/sample/test_binary_values.rb +33 -0
- data/sample/wal_shipper.rb +434 -0
- data/sample/warehouse_partitions.rb +320 -0
- data/spec/data/expected_trace.out +26 -0
- data/spec/data/random_binary_data +0 -0
- data/spec/lib/helpers.rb +350 -0
- data/spec/pg/connection_spec.rb +1276 -0
- data/spec/pg/result_spec.rb +345 -0
- data/spec/pg_spec.rb +44 -0
- metadata +136 -90
- metadata.gz.sig +0 -0
- data/CHANGELOG.rdoc +0 -7
- data/bin/pg +0 -3
data/lib/pg.rb
CHANGED
@@ -1,35 +1,29 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
|
3
|
-
|
3
|
+
begin
|
4
4
|
require 'pg_ext'
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
major_minor = RUBY_VERSION[ /^(\d+\.\d+)/ ] or
|
14
|
-
raise "Oops, can't extract the major/minor version from #{RUBY_VERSION.dump}"
|
15
|
-
require "#{major_minor}/pg_ext"
|
16
|
-
else
|
17
|
-
raise
|
18
|
-
end
|
19
|
-
|
5
|
+
rescue LoadError
|
6
|
+
# If it's a Windows binary gem, try the <major>.<minor> subdirectory
|
7
|
+
if RUBY_PLATFORM =~/(mswin|mingw)/i
|
8
|
+
major_minor = RUBY_VERSION[ /^(\d+\.\d+)/ ] or
|
9
|
+
raise "Oops, can't extract the major/minor version from #{RUBY_VERSION.dump}"
|
10
|
+
require "#{major_minor}/pg_ext"
|
11
|
+
else
|
12
|
+
raise
|
20
13
|
end
|
21
14
|
end
|
22
15
|
|
23
|
-
|
24
16
|
# The top-level PG namespace.
|
25
17
|
module PG
|
26
18
|
|
27
19
|
# Library version
|
28
|
-
VERSION = '0.
|
20
|
+
VERSION = '0.17.1'
|
29
21
|
|
30
22
|
# VCS revision
|
31
23
|
REVISION = %q$Revision$
|
32
24
|
|
25
|
+
class NotAllCopyDataRetrieved < PG::Error
|
26
|
+
end
|
33
27
|
|
34
28
|
### Get the PG library version. If +include_buildnum+ is +true+, include the build ID.
|
35
29
|
def self::version_string( include_buildnum=false )
|
data/lib/pg/connection.rb
CHANGED
@@ -2,7 +2,21 @@
|
|
2
2
|
|
3
3
|
require 'pg' unless defined?( PG )
|
4
4
|
|
5
|
-
# The
|
5
|
+
# The PostgreSQL connection class. The interface for this class is based on
|
6
|
+
# {libpq}[http://www.postgresql.org/docs/9.2/interactive/libpq.html], the C
|
7
|
+
# application programmer's interface to PostgreSQL. Some familiarity with libpq
|
8
|
+
# is recommended, but not necessary.
|
9
|
+
#
|
10
|
+
# For example, to send query to the database on the localhost:
|
11
|
+
#
|
12
|
+
# require 'pg'
|
13
|
+
# conn = PG::Connection.open(:dbname => 'test')
|
14
|
+
# res = conn.exec_params('SELECT $1 AS a, $2 AS b, $3 AS c', [1, 2, nil])
|
15
|
+
# # Equivalent to:
|
16
|
+
# # res = conn.exec('SELECT 1 AS a, 2 AS b, NULL AS c')
|
17
|
+
#
|
18
|
+
# See the PG::Result class for information on working with the results of a query.
|
19
|
+
#
|
6
20
|
class PG::Connection
|
7
21
|
|
8
22
|
# The order the options are passed to the ::connect method.
|
@@ -14,13 +28,6 @@ class PG::Connection
|
|
14
28
|
return "'" + value.to_s.gsub( /[\\']/ ) {|m| '\\' + m } + "'"
|
15
29
|
end
|
16
30
|
|
17
|
-
def escape_literal str
|
18
|
-
"'#{escape_literal_native str}'"
|
19
|
-
end
|
20
|
-
|
21
|
-
def escape_identifier str
|
22
|
-
"\"#{escape_literal_native str}\""
|
23
|
-
end
|
24
31
|
|
25
32
|
### Parse the connection +args+ into a connection-parameter string. See PG::Connection.new
|
26
33
|
### for valid arguments.
|
@@ -30,11 +37,20 @@ class PG::Connection
|
|
30
37
|
# This will be swapped soon for code that makes options like those required for
|
31
38
|
# PQconnectdbParams()/PQconnectStartParams(). For now, stick to an options string for
|
32
39
|
# PQconnectdb()/PQconnectStart().
|
33
|
-
|
40
|
+
|
41
|
+
# Parameter 'fallback_application_name' was introduced in PostgreSQL 9.0
|
42
|
+
# together with PQescapeLiteral().
|
43
|
+
if PG::Connection.instance_methods.find{|m| m.to_sym == :escape_literal }
|
44
|
+
appname = $0.sub(/^(.{30}).{4,}(.{30})$/){ $1+"..."+$2 }
|
45
|
+
appname = PG::Connection.quote_connstr( appname )
|
46
|
+
connopts = ["fallback_application_name=#{appname}"]
|
47
|
+
else
|
48
|
+
connopts = []
|
49
|
+
end
|
34
50
|
|
35
51
|
# Handle an options hash first
|
36
52
|
if args.last.is_a?( Hash )
|
37
|
-
opthash = args.pop
|
53
|
+
opthash = args.pop
|
38
54
|
opthash.each do |key, val|
|
39
55
|
connopts.push( "%s=%s" % [key, PG::Connection.quote_connstr(val)] )
|
40
56
|
end
|
@@ -58,6 +74,91 @@ class PG::Connection
|
|
58
74
|
return connopts.join(' ')
|
59
75
|
end
|
60
76
|
|
77
|
+
# call-seq:
|
78
|
+
# conn.copy_data( sql ) {|sql_result| ... } -> PG::Result
|
79
|
+
#
|
80
|
+
# Execute a copy process for transfering data to or from the server.
|
81
|
+
#
|
82
|
+
# This issues the SQL COPY command via #exec. The response to this
|
83
|
+
# (if there is no error in the command) is a PG::Result object that
|
84
|
+
# is passed to the block, bearing a status code of PGRES_COPY_OUT or
|
85
|
+
# PGRES_COPY_IN (depending on the specified copy direction).
|
86
|
+
# The application should then use #put_copy_data or #get_copy_data
|
87
|
+
# to receive or transmit data rows and should return from the block
|
88
|
+
# when finished.
|
89
|
+
#
|
90
|
+
# #copy_data returns another PG::Result object when the data transfer
|
91
|
+
# is complete. An exception is raised if some problem was encountered,
|
92
|
+
# so it isn't required to make use of any of them.
|
93
|
+
# At this point further SQL commands can be issued via #exec.
|
94
|
+
# (It is not possible to execute other SQL commands using the same
|
95
|
+
# connection while the COPY operation is in progress.)
|
96
|
+
#
|
97
|
+
# This method ensures, that the copy process is properly terminated
|
98
|
+
# in case of client side or server side failures. Therefore, in case
|
99
|
+
# of blocking mode of operation, #copy_data is preferred to raw calls
|
100
|
+
# of #put_copy_data, #get_copy_data and #put_copy_end.
|
101
|
+
#
|
102
|
+
# Example with CSV input format:
|
103
|
+
# conn.exec "create table my_table (a text,b text,c text,d text,e text)"
|
104
|
+
# conn.copy_data "COPY my_table FROM STDOUT CSV" do
|
105
|
+
# conn.put_copy_data "some,csv,data,to,copy\n"
|
106
|
+
# conn.put_copy_data "more,csv,data,to,copy\n"
|
107
|
+
# end
|
108
|
+
# This creates +my_table+ and inserts two rows.
|
109
|
+
#
|
110
|
+
# Example with CSV output format:
|
111
|
+
# conn.copy_data "COPY my_table TO STDOUT CSV" do
|
112
|
+
# while row=conn.get_copy_data
|
113
|
+
# p row
|
114
|
+
# end
|
115
|
+
# end
|
116
|
+
# This prints all rows of +my_table+ to stdout:
|
117
|
+
# "some,csv,data,to,copy\n"
|
118
|
+
# "more,csv,data,to,copy\n"
|
119
|
+
def copy_data( sql )
|
120
|
+
res = exec( sql )
|
121
|
+
|
122
|
+
case res.result_status
|
123
|
+
when PGRES_COPY_IN
|
124
|
+
begin
|
125
|
+
yield res
|
126
|
+
rescue Exception => err
|
127
|
+
errmsg = "%s while copy data: %s" % [ err.class.name, err.message ]
|
128
|
+
put_copy_end( errmsg )
|
129
|
+
get_result
|
130
|
+
raise
|
131
|
+
else
|
132
|
+
put_copy_end
|
133
|
+
get_last_result
|
134
|
+
end
|
135
|
+
|
136
|
+
when PGRES_COPY_OUT
|
137
|
+
begin
|
138
|
+
yield res
|
139
|
+
rescue Exception => err
|
140
|
+
cancel
|
141
|
+
while get_copy_data
|
142
|
+
end
|
143
|
+
while get_result
|
144
|
+
end
|
145
|
+
raise
|
146
|
+
else
|
147
|
+
res = get_last_result
|
148
|
+
if res.result_status != PGRES_COMMAND_OK
|
149
|
+
while get_copy_data
|
150
|
+
end
|
151
|
+
while get_result
|
152
|
+
end
|
153
|
+
raise PG::NotAllCopyDataRetrieved, "Not all COPY data retrieved"
|
154
|
+
end
|
155
|
+
res
|
156
|
+
end
|
157
|
+
|
158
|
+
else
|
159
|
+
raise ArgumentError, "SQL command is no COPY statement: #{sql}"
|
160
|
+
end
|
161
|
+
end
|
61
162
|
|
62
163
|
# Backward-compatibility aliases for stuff that's moved into PG.
|
63
164
|
class << self
|
@@ -65,6 +166,12 @@ class PG::Connection
|
|
65
166
|
end
|
66
167
|
|
67
168
|
|
169
|
+
### Returns an array of Hashes with connection defaults. See ::conndefaults
|
170
|
+
### for details.
|
171
|
+
def conndefaults
|
172
|
+
return self.class.conndefaults
|
173
|
+
end
|
174
|
+
|
68
175
|
end # class PG::Connection
|
69
176
|
|
70
177
|
# Backward-compatible alias
|
data/lib/pg/exceptions.rb
CHANGED
@@ -5,13 +5,7 @@ require 'pg' unless defined?( PG )
|
|
5
5
|
|
6
6
|
module PG
|
7
7
|
|
8
|
-
class Error < StandardError
|
9
|
-
attr_reader :result
|
10
|
-
|
11
|
-
def initialize msg = "", result = nil
|
12
|
-
super msg
|
13
|
-
@result = result
|
14
|
-
end
|
15
|
-
end
|
8
|
+
class Error < StandardError; end
|
16
9
|
|
17
10
|
end # module PG
|
11
|
+
|
data/lib/pg/result.rb
CHANGED
data/lib/pg_ext.jar
CHANGED
Binary file
|
@@ -0,0 +1,20 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'pg'
|
4
|
+
|
5
|
+
c = PG.connect( dbname: 'test' )
|
6
|
+
|
7
|
+
# this one works:
|
8
|
+
c.exec( "DROP TABLE IF EXISTS foo" )
|
9
|
+
c.exec( "CREATE TABLE foo (strings character varying[]);" )
|
10
|
+
|
11
|
+
# But using a prepared statement works:
|
12
|
+
c.set_error_verbosity( PG::PQERRORS_VERBOSE )
|
13
|
+
c.prepare( 'stmt', "INSERT INTO foo VALUES ($1);" )
|
14
|
+
|
15
|
+
# This won't work
|
16
|
+
#c.exec_prepared( 'stmt', ["ARRAY['this','that']"] )
|
17
|
+
|
18
|
+
# but this will:
|
19
|
+
c.exec_prepared( 'stmt', ["{'this','that'}"] )
|
20
|
+
|
data/sample/async_api.rb
ADDED
@@ -0,0 +1,106 @@
|
|
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 PG::Connection#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
|
+
|
12
|
+
# Print 'x' continuously to demonstrate that other threads aren't
|
13
|
+
# blocked while waiting for the connection, for the query to be sent,
|
14
|
+
# for results, etc. You might want to sleep inside the loop or
|
15
|
+
# comment this out entirely for cleaner output.
|
16
|
+
progress_thread = Thread.new { loop { print 'x' } }
|
17
|
+
|
18
|
+
# Output progress messages
|
19
|
+
def output_progress( msg )
|
20
|
+
puts "\n>>> #{msg}\n"
|
21
|
+
end
|
22
|
+
|
23
|
+
# Start the connection
|
24
|
+
output_progress "Starting connection..."
|
25
|
+
conn = PG::Connection.connect_start( :dbname => 'test' ) or
|
26
|
+
abort "Unable to create a new connection!"
|
27
|
+
abort "Connection failed: %s" % [ conn.error_message ] if
|
28
|
+
conn.status == PG::CONNECTION_BAD
|
29
|
+
|
30
|
+
# Now grab a reference to the underlying socket so we know when the
|
31
|
+
# connection is established
|
32
|
+
socket = conn.socket_io
|
33
|
+
|
34
|
+
# Track the progress of the connection, waiting for the socket to become readable/writable
|
35
|
+
# before polling it
|
36
|
+
poll_status = PG::PGRES_POLLING_WRITING
|
37
|
+
until poll_status == PG::PGRES_POLLING_OK ||
|
38
|
+
poll_status == PG::PGRES_POLLING_FAILED
|
39
|
+
|
40
|
+
# If the socket needs to read, wait 'til it becomes readable to poll again
|
41
|
+
case poll_status
|
42
|
+
when PG::PGRES_POLLING_READING
|
43
|
+
output_progress " waiting for socket to become readable"
|
44
|
+
select( [socket], nil, nil, TIMEOUT ) or
|
45
|
+
raise "Asynchronous connection timed out!"
|
46
|
+
|
47
|
+
# ...and the same for when the socket needs to write
|
48
|
+
when PG::PGRES_POLLING_WRITING
|
49
|
+
output_progress " waiting for socket to become writable"
|
50
|
+
select( nil, [socket], nil, TIMEOUT ) or
|
51
|
+
raise "Asynchronous connection timed out!"
|
52
|
+
end
|
53
|
+
|
54
|
+
# Output a status message about the progress
|
55
|
+
case conn.status
|
56
|
+
when PG::CONNECTION_STARTED
|
57
|
+
output_progress " waiting for connection to be made."
|
58
|
+
when PG::CONNECTION_MADE
|
59
|
+
output_progress " connection OK; waiting to send."
|
60
|
+
when PG::CONNECTION_AWAITING_RESPONSE
|
61
|
+
output_progress " waiting for a response from the server."
|
62
|
+
when PG::CONNECTION_AUTH_OK
|
63
|
+
output_progress " received authentication; waiting for backend start-up to finish."
|
64
|
+
when PG::CONNECTION_SSL_STARTUP
|
65
|
+
output_progress " negotiating SSL encryption."
|
66
|
+
when PG::CONNECTION_SETENV
|
67
|
+
output_progress " negotiating environment-driven parameter settings."
|
68
|
+
when PG::CONNECTION_NEEDED
|
69
|
+
output_progress " internal state: connect() needed."
|
70
|
+
end
|
71
|
+
|
72
|
+
# Check to see if it's finished or failed yet
|
73
|
+
poll_status = conn.connect_poll
|
74
|
+
end
|
75
|
+
|
76
|
+
abort "Connect failed: %s" % [ conn.error_message ] unless conn.status == PG::CONNECTION_OK
|
77
|
+
|
78
|
+
output_progress "Sending query"
|
79
|
+
conn.send_query( "SELECT * FROM pg_stat_activity" )
|
80
|
+
|
81
|
+
# Fetch results until there aren't any more
|
82
|
+
loop do
|
83
|
+
output_progress " waiting for a response"
|
84
|
+
|
85
|
+
# Buffer any incoming data on the socket until a full result is ready.
|
86
|
+
conn.consume_input
|
87
|
+
while conn.is_busy
|
88
|
+
select( [socket], nil, nil, TIMEOUT ) or
|
89
|
+
raise "Timeout waiting for query response."
|
90
|
+
conn.consume_input
|
91
|
+
end
|
92
|
+
|
93
|
+
# Fetch the next result. If there isn't one, the query is finished
|
94
|
+
result = conn.get_result or break
|
95
|
+
|
96
|
+
puts "\n\nQuery result:\n%p\n" % [ result.values ]
|
97
|
+
end
|
98
|
+
|
99
|
+
output_progress "Done."
|
100
|
+
conn.finish
|
101
|
+
|
102
|
+
if defined?( progress_thread )
|
103
|
+
progress_thread.kill
|
104
|
+
progress_thread.join
|
105
|
+
end
|
106
|
+
|
@@ -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 = PG.connect( :dbname => 'test' )
|
10
|
+
conn.setnonblocking( true )
|
11
|
+
|
12
|
+
socket = conn.socket_io
|
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
|
+
|
@@ -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 = conn.socket_io
|
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
|
+
|