jruby-pg 0.1-java

Sign up to get free protection for your applications and to get access to all the features.
Files changed (51) hide show
  1. checksums.yaml +7 -0
  2. data/.gemtest +0 -0
  3. data/BSDL +22 -0
  4. data/ChangeLog +0 -0
  5. data/Contributors.rdoc +45 -0
  6. data/History.rdoc +270 -0
  7. data/LICENSE +56 -0
  8. data/Manifest.txt +44 -0
  9. data/POSTGRES +23 -0
  10. data/README-OS_X.rdoc +68 -0
  11. data/README-Windows.rdoc +67 -0
  12. data/README.ja.rdoc +14 -0
  13. data/README.rdoc +102 -0
  14. data/Rakefile +211 -0
  15. data/Rakefile.cross +273 -0
  16. data/ext/gvl_wrappers.c +13 -0
  17. data/ext/pg.c +545 -0
  18. data/ext/pg_connection.c +3643 -0
  19. data/ext/pg_errors.c +89 -0
  20. data/ext/pg_result.c +920 -0
  21. data/lib/pg.rb +52 -0
  22. data/lib/pg/connection.rb +179 -0
  23. data/lib/pg/constants.rb +11 -0
  24. data/lib/pg/exceptions.rb +11 -0
  25. data/lib/pg/result.rb +16 -0
  26. data/lib/pg_ext.jar +0 -0
  27. data/sample/array_insert.rb +20 -0
  28. data/sample/async_api.rb +106 -0
  29. data/sample/async_copyto.rb +39 -0
  30. data/sample/async_mixed.rb +56 -0
  31. data/sample/check_conn.rb +21 -0
  32. data/sample/copyfrom.rb +81 -0
  33. data/sample/copyto.rb +19 -0
  34. data/sample/cursor.rb +21 -0
  35. data/sample/disk_usage_report.rb +186 -0
  36. data/sample/issue-119.rb +94 -0
  37. data/sample/losample.rb +69 -0
  38. data/sample/minimal-testcase.rb +17 -0
  39. data/sample/notify_wait.rb +72 -0
  40. data/sample/pg_statistics.rb +294 -0
  41. data/sample/replication_monitor.rb +231 -0
  42. data/sample/test_binary_values.rb +33 -0
  43. data/sample/wal_shipper.rb +434 -0
  44. data/sample/warehouse_partitions.rb +320 -0
  45. data/spec/data/expected_trace.out +26 -0
  46. data/spec/data/random_binary_data +0 -0
  47. data/spec/lib/helpers.rb +350 -0
  48. data/spec/pg/connection_spec.rb +1276 -0
  49. data/spec/pg/result_spec.rb +345 -0
  50. data/spec/pg_spec.rb +44 -0
  51. metadata +190 -0
@@ -0,0 +1,52 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ begin
4
+ require 'pg_ext'
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
13
+ end
14
+ end
15
+
16
+ # The top-level PG namespace.
17
+ module PG
18
+
19
+ # Library version
20
+ VERSION = RUBY_ENGINE == 'jruby' ? '0.1' : '0.17.1'
21
+
22
+ # VCS revision
23
+ REVISION = %q$Revision$
24
+
25
+ class NotAllCopyDataRetrieved < PG::Error
26
+ end
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
33
+ end
34
+
35
+
36
+ ### Convenience alias for PG::Connection.new.
37
+ def self::connect( *args )
38
+ return PG::Connection.new( *args )
39
+ end
40
+
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
52
+
@@ -0,0 +1,179 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'pg' unless defined?( PG )
4
+
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
+ #
20
+ class PG::Connection
21
+
22
+ # The order the options are passed to the ::connect method.
23
+ CONNECT_ARGUMENT_ORDER = %w[host port options tty dbname user password]
24
+
25
+
26
+ ### Quote the given +value+ for use in a connection-parameter string.
27
+ def self::quote_connstr( value )
28
+ return "'" + value.to_s.gsub( /[\\']/ ) {|m| '\\' + m } + "'"
29
+ end
30
+
31
+
32
+ ### Parse the connection +args+ into a connection-parameter string. See PG::Connection.new
33
+ ### for valid arguments.
34
+ def self::parse_connect_args( *args )
35
+ return '' if args.empty?
36
+
37
+ # This will be swapped soon for code that makes options like those required for
38
+ # PQconnectdbParams()/PQconnectStartParams(). For now, stick to an options string for
39
+ # PQconnectdb()/PQconnectStart().
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
50
+
51
+ # Handle an options hash first
52
+ if args.last.is_a?( Hash )
53
+ opthash = args.pop
54
+ opthash.each do |key, val|
55
+ connopts.push( "%s=%s" % [key, PG::Connection.quote_connstr(val)] )
56
+ end
57
+ end
58
+
59
+ # Option string style
60
+ if args.length == 1 && args.first.to_s.index( '=' )
61
+ connopts.unshift( args.first )
62
+
63
+ # Append positional parameters
64
+ else
65
+ args.each_with_index do |val, i|
66
+ next unless val # Skip nil placeholders
67
+
68
+ key = CONNECT_ARGUMENT_ORDER[ i ] or
69
+ raise ArgumentError, "Extra positional parameter %d: %p" % [ i+1, val ]
70
+ connopts.push( "%s=%s" % [key, PG::Connection.quote_connstr(val.to_s)] )
71
+ end
72
+ end
73
+
74
+ return connopts.join(' ')
75
+ end
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
162
+
163
+ # Backward-compatibility aliases for stuff that's moved into PG.
164
+ class << self
165
+ define_method( :isthreadsafe, &PG.method(:isthreadsafe) )
166
+ end
167
+
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
+
175
+ end # class PG::Connection
176
+
177
+ # Backward-compatible alias
178
+ PGconn = PG::Connection
179
+
@@ -0,0 +1,11 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'pg' unless defined?( PG )
4
+
5
+
6
+ module PG::Constants
7
+
8
+ # Most of these are defined in the extension.
9
+
10
+ end # module PG::Constants
11
+
@@ -0,0 +1,11 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'pg' unless defined?( PG )
4
+
5
+
6
+ module PG
7
+
8
+ class Error < StandardError; end
9
+
10
+ end # module PG
11
+
@@ -0,0 +1,16 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'pg' unless defined?( PG )
4
+
5
+
6
+ class PG::Result
7
+
8
+ ### Returns all tuples as an array of arrays
9
+ def values
10
+ return enum_for(:each_row).to_a
11
+ end
12
+
13
+ end # class PG::Result
14
+
15
+ # Backward-compatible alias
16
+ PGresult = PG::Result
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
+
@@ -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
+