pg 1.2.3 → 1.3.5

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.
Files changed (106) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data/.appveyor.yml +36 -0
  4. data/.gems +6 -0
  5. data/.github/workflows/binary-gems.yml +86 -0
  6. data/.github/workflows/source-gem.yml +129 -0
  7. data/.gitignore +13 -0
  8. data/.hgsigs +34 -0
  9. data/.hgtags +41 -0
  10. data/.irbrc +23 -0
  11. data/.pryrc +23 -0
  12. data/.tm_properties +21 -0
  13. data/.travis.yml +49 -0
  14. data/Gemfile +14 -0
  15. data/History.rdoc +153 -7
  16. data/Manifest.txt +0 -1
  17. data/README.rdoc +7 -6
  18. data/Rakefile +27 -138
  19. data/Rakefile.cross +8 -5
  20. data/certs/ged.pem +24 -0
  21. data/certs/larskanis-2022.pem +26 -0
  22. data/ext/errorcodes.def +8 -0
  23. data/ext/errorcodes.rb +0 -0
  24. data/ext/errorcodes.txt +3 -1
  25. data/ext/extconf.rb +131 -25
  26. data/ext/gvl_wrappers.c +4 -0
  27. data/ext/gvl_wrappers.h +23 -0
  28. data/ext/pg.c +59 -4
  29. data/ext/pg.h +19 -1
  30. data/ext/pg_coder.c +82 -28
  31. data/ext/pg_connection.c +680 -508
  32. data/ext/pg_copy_coder.c +45 -16
  33. data/ext/pg_record_coder.c +45 -15
  34. data/ext/pg_result.c +77 -40
  35. data/ext/pg_text_decoder.c +1 -1
  36. data/ext/pg_text_encoder.c +6 -6
  37. data/ext/pg_tuple.c +49 -29
  38. data/ext/pg_type_map.c +41 -8
  39. data/ext/pg_type_map_all_strings.c +15 -1
  40. data/ext/pg_type_map_by_class.c +49 -24
  41. data/ext/pg_type_map_by_column.c +66 -28
  42. data/ext/pg_type_map_by_mri_type.c +47 -18
  43. data/ext/pg_type_map_by_oid.c +52 -23
  44. data/ext/pg_type_map_in_ruby.c +50 -19
  45. data/ext/pg_util.c +2 -2
  46. data/lib/pg/basic_type_map_based_on_result.rb +47 -0
  47. data/lib/pg/basic_type_map_for_queries.rb +193 -0
  48. data/lib/pg/basic_type_map_for_results.rb +81 -0
  49. data/lib/pg/basic_type_registry.rb +301 -0
  50. data/lib/pg/coder.rb +1 -1
  51. data/lib/pg/connection.rb +589 -58
  52. data/lib/pg/version.rb +4 -0
  53. data/lib/pg.rb +47 -32
  54. data/misc/openssl-pg-segfault.rb +31 -0
  55. data/misc/postgres/History.txt +9 -0
  56. data/misc/postgres/Manifest.txt +5 -0
  57. data/misc/postgres/README.txt +21 -0
  58. data/misc/postgres/Rakefile +21 -0
  59. data/misc/postgres/lib/postgres.rb +16 -0
  60. data/misc/ruby-pg/History.txt +9 -0
  61. data/misc/ruby-pg/Manifest.txt +5 -0
  62. data/misc/ruby-pg/README.txt +21 -0
  63. data/misc/ruby-pg/Rakefile +21 -0
  64. data/misc/ruby-pg/lib/ruby/pg.rb +16 -0
  65. data/pg.gemspec +32 -0
  66. data/rakelib/task_extension.rb +46 -0
  67. data/sample/array_insert.rb +20 -0
  68. data/sample/async_api.rb +102 -0
  69. data/sample/async_copyto.rb +39 -0
  70. data/sample/async_mixed.rb +56 -0
  71. data/sample/check_conn.rb +21 -0
  72. data/sample/copydata.rb +71 -0
  73. data/sample/copyfrom.rb +81 -0
  74. data/sample/copyto.rb +19 -0
  75. data/sample/cursor.rb +21 -0
  76. data/sample/disk_usage_report.rb +177 -0
  77. data/sample/issue-119.rb +94 -0
  78. data/sample/losample.rb +69 -0
  79. data/sample/minimal-testcase.rb +17 -0
  80. data/sample/notify_wait.rb +72 -0
  81. data/sample/pg_statistics.rb +285 -0
  82. data/sample/replication_monitor.rb +222 -0
  83. data/sample/test_binary_values.rb +33 -0
  84. data/sample/wal_shipper.rb +434 -0
  85. data/sample/warehouse_partitions.rb +311 -0
  86. data.tar.gz.sig +0 -0
  87. metadata +87 -224
  88. metadata.gz.sig +0 -0
  89. data/ChangeLog +0 -0
  90. data/lib/pg/basic_type_mapping.rb +0 -522
  91. data/spec/data/expected_trace.out +0 -26
  92. data/spec/data/random_binary_data +0 -0
  93. data/spec/helpers.rb +0 -380
  94. data/spec/pg/basic_type_mapping_spec.rb +0 -630
  95. data/spec/pg/connection_spec.rb +0 -1949
  96. data/spec/pg/connection_sync_spec.rb +0 -41
  97. data/spec/pg/result_spec.rb +0 -681
  98. data/spec/pg/tuple_spec.rb +0 -333
  99. data/spec/pg/type_map_by_class_spec.rb +0 -138
  100. data/spec/pg/type_map_by_column_spec.rb +0 -226
  101. data/spec/pg/type_map_by_mri_type_spec.rb +0 -136
  102. data/spec/pg/type_map_by_oid_spec.rb +0 -149
  103. data/spec/pg/type_map_in_ruby_spec.rb +0 -164
  104. data/spec/pg/type_map_spec.rb +0 -22
  105. data/spec/pg/type_spec.rb +0 -1123
  106. data/spec/pg_spec.rb +0 -50
data/lib/pg/version.rb ADDED
@@ -0,0 +1,4 @@
1
+ module PG
2
+ # Library version
3
+ VERSION = '1.3.5'
4
+ end
data/lib/pg.rb CHANGED
@@ -1,15 +1,28 @@
1
+
1
2
  # -*- ruby -*-
2
3
  # frozen_string_literal: true
3
4
 
4
- begin
5
- require 'pg_ext'
6
- rescue LoadError
7
- # If it's a Windows binary gem, try the <major>.<minor> subdirectory
8
- if RUBY_PLATFORM =~/(mswin|mingw)/i
9
- major_minor = RUBY_VERSION[ /^(\d+\.\d+)/ ] or
10
- raise "Oops, can't extract the major/minor version from #{RUBY_VERSION.dump}"
5
+ # The top-level PG namespace.
6
+ module PG
7
+
8
+ # Is this file part of a fat binary gem with bundled libpq?
9
+ bundled_libpq_path = File.join(__dir__, RUBY_PLATFORM.gsub(/^i386-/, "x86-"))
10
+ if File.exist?(bundled_libpq_path)
11
+ POSTGRESQL_LIB_PATH = bundled_libpq_path
12
+ else
13
+ bundled_libpq_path = nil
14
+ # Try to load libpq path as found by extconf.rb
15
+ begin
16
+ require "pg/postgresql_lib_path"
17
+ rescue LoadError
18
+ # rake-compiler doesn't use regular "make install", but uses it's own install tasks.
19
+ # It therefore doesn't copy pg/postgresql_lib_path.rb in case of "rake compile".
20
+ POSTGRESQL_LIB_PATH = false
21
+ end
22
+ end
11
23
 
12
- add_dll_path = proc do |path, &block|
24
+ add_dll_path = proc do |path, &block|
25
+ if RUBY_PLATFORM =~/(mswin|mingw)/i && path && File.exist?(path)
13
26
  begin
14
27
  require 'ruby_installer/runtime'
15
28
  RubyInstaller::Runtime.add_dll_directory(path, &block)
@@ -19,43 +32,41 @@ rescue LoadError
19
32
  block.call
20
33
  ENV['PATH'] = old_path
21
34
  end
35
+ else
36
+ # No need to set a load path manually - it's set as library rpath.
37
+ block.call
22
38
  end
39
+ end
23
40
 
24
- # Temporary add this directory for DLL search, so that libpq.dll can be found.
25
- # mingw32-platform strings differ (RUBY_PLATFORM=i386-mingw32 vs. x86-mingw32 for rubygems)
26
- add_dll_path.call(File.join(__dir__, RUBY_PLATFORM.gsub(/^i386-/, "x86-"))) do
41
+ # Add a load path to the one retrieved from pg_config
42
+ add_dll_path.call(POSTGRESQL_LIB_PATH) do
43
+ if bundled_libpq_path
44
+ # It's a Windows binary gem, try the <major>.<minor> subdirectory
45
+ major_minor = RUBY_VERSION[ /^(\d+\.\d+)/ ] or
46
+ raise "Oops, can't extract the major/minor version from #{RUBY_VERSION.dump}"
27
47
  require "#{major_minor}/pg_ext"
48
+ else
49
+ require 'pg_ext'
28
50
  end
29
- else
30
- raise
31
51
  end
32
52
 
33
- end
34
-
35
-
36
- # The top-level PG namespace.
37
- module PG
38
-
39
- # Library version
40
- VERSION = '1.2.3'
41
-
42
- # VCS revision
43
- REVISION = %q$Revision: 6f611e78845a $
44
53
 
45
54
  class NotAllCopyDataRetrieved < PG::Error
46
55
  end
56
+ class NotInBlockingMode < PG::Error
57
+ end
47
58
 
48
- ### Get the PG library version. If +include_buildnum+ is +true+, include the build ID.
49
- def self::version_string( include_buildnum=false )
50
- vstring = "%s %s" % [ self.name, VERSION ]
51
- vstring << " (build %s)" % [ REVISION[/: ([[:xdigit:]]+)/, 1] || '0' ] if include_buildnum
52
- return vstring
59
+ # Get the PG library version.
60
+ #
61
+ # +include_buildnum+ is no longer used and any value passed will be ignored.
62
+ def self::version_string( include_buildnum=nil )
63
+ return "%s %s" % [ self.name, VERSION ]
53
64
  end
54
65
 
55
66
 
56
67
  ### Convenience alias for PG::Connection.new.
57
- def self::connect( *args )
58
- return PG::Connection.new( *args )
68
+ def self::connect( *args, **kwargs )
69
+ return PG::Connection.new( *args, **kwargs )
59
70
  end
60
71
 
61
72
 
@@ -65,10 +76,14 @@ module PG
65
76
  require 'pg/binary_decoder'
66
77
  require 'pg/text_encoder'
67
78
  require 'pg/text_decoder'
68
- require 'pg/basic_type_mapping'
79
+ require 'pg/basic_type_registry'
80
+ require 'pg/basic_type_map_based_on_result'
81
+ require 'pg/basic_type_map_for_queries'
82
+ require 'pg/basic_type_map_for_results'
69
83
  require 'pg/type_map_by_column'
70
84
  require 'pg/connection'
71
85
  require 'pg/result'
72
86
  require 'pg/tuple'
87
+ require 'pg/version'
73
88
 
74
89
  end # module PG
@@ -0,0 +1,31 @@
1
+ # -*- 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 = PG.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
+
@@ -0,0 +1,9 @@
1
+ == v0.8.0 [2012-02-09] Michael Granger <ged@FaerieMUD.org>
2
+
3
+ This placeholder version.
4
+
5
+
6
+ == v0.7.9.2008.01.28 [2008-01-28] Jeff Davis <<ruby-pg@j-davis.com>>
7
+
8
+ The last actual version.
9
+
@@ -0,0 +1,5 @@
1
+ History.txt
2
+ Manifest.txt
3
+ README.txt
4
+ Rakefile
5
+ lib/postgres.rb
@@ -0,0 +1,21 @@
1
+ = postgres
2
+
3
+ * https://github.com/ged/ruby-pg
4
+
5
+ == Description
6
+
7
+ This is an old, deprecated version of the Ruby PostgreSQL driver that hasn't
8
+ been maintained or supported since early 2008.
9
+
10
+ You should install/require 'pg' instead.
11
+
12
+ If you need the 'postgres' gem for legacy code that can't be converted, you can
13
+ still install it using an explicit version, like so:
14
+
15
+ gem install postgres -v '0.7.9.2008.01.28'
16
+ gem uninstall postgres -v '>0.7.9.2008.01.28'
17
+
18
+ If you have any questions, the nice folks in the Google group can help:
19
+
20
+ http://goo.gl/OjOPP / ruby-pg@googlegroups.com
21
+
@@ -0,0 +1,21 @@
1
+ # -*- ruby -*-
2
+
3
+ require 'date'
4
+ require 'rubygems'
5
+ require 'hoe'
6
+ require 'pp'
7
+
8
+ Hoe.spec 'postgres' do
9
+ self.developer 'Michael Granger', 'ged@FaerieMUD.org'
10
+ self.dependency 'pg', '~> 0'
11
+ self.spec_extras[:date] = Date.parse( '2008/01/30' )
12
+
13
+ line = '-' * 75
14
+ msg = paragraphs_of( 'README.txt', 3..-1 )
15
+ msg.unshift( line )
16
+ msg.push( line )
17
+
18
+ self.spec_extras[:post_install_message] = msg.join( "\n\n" ) + "\n"
19
+ end
20
+
21
+ # vim: syntax=ruby
@@ -0,0 +1,16 @@
1
+ # -*- ruby -*-
2
+
3
+ require 'pathname'
4
+
5
+ module Postgres
6
+
7
+ VERSION = '0.8.1'
8
+
9
+ gemdir = Pathname( __FILE__ ).dirname.parent
10
+ readme = gemdir + 'README.txt'
11
+
12
+ header, message = readme.read.split( /^== Description/m )
13
+ abort( message.strip )
14
+
15
+ end
16
+
@@ -0,0 +1,9 @@
1
+ == v0.8.0 [2012-02-09] Michael Granger <ged@FaerieMUD.org>
2
+
3
+ This placeholder version.
4
+
5
+
6
+ == v0.7.9.2008.01.28 [2008-01-28] Jeff Davis <<ruby-pg@j-davis.com>>
7
+
8
+ The last actual version.
9
+
@@ -0,0 +1,5 @@
1
+ History.txt
2
+ Manifest.txt
3
+ README.txt
4
+ Rakefile
5
+ lib/ruby/pg.rb
@@ -0,0 +1,21 @@
1
+ = ruby-pg
2
+
3
+ * https://github.com/ged/ruby-pg
4
+
5
+ == Description
6
+
7
+ This is an old, deprecated version of the 'pg' gem that hasn't been
8
+ maintained or supported since early 2008.
9
+
10
+ You should install/require 'pg' instead.
11
+
12
+ If you need ruby-pg for legacy code that can't be converted, you can still
13
+ install it using an explicit version, like so:
14
+
15
+ gem install ruby-pg -v '0.7.9.2008.01.28'
16
+ gem uninstall ruby-pg -v '>0.7.9.2008.01.28'
17
+
18
+ If you have any questions, the nice folks in the Google group can help:
19
+
20
+ http://goo.gl/OjOPP / ruby-pg@googlegroups.com
21
+
@@ -0,0 +1,21 @@
1
+ # -*- ruby -*-
2
+
3
+ require 'date'
4
+ require 'rubygems'
5
+ require 'hoe'
6
+ require 'pp'
7
+
8
+ Hoe.spec 'ruby-pg' do
9
+ self.developer 'Michael Granger', 'ged@FaerieMUD.org'
10
+ self.dependency 'pg', '~> 0'
11
+ self.spec_extras[:date] = Date.parse( '2008/01/30' )
12
+
13
+ line = '-' * 75
14
+ msg = paragraphs_of( 'README.txt', 3..-1 )
15
+ msg.unshift( line )
16
+ msg.push( line )
17
+
18
+ self.spec_extras[:post_install_message] = msg.join( "\n\n" ) + "\n"
19
+ end
20
+
21
+ # vim: syntax=ruby
@@ -0,0 +1,16 @@
1
+ # -*- ruby -*-
2
+
3
+ require 'pathname'
4
+
5
+ module Pg
6
+
7
+ VERSION = '0.8.0'
8
+
9
+ gemdir = Pathname( __FILE__ ).dirname.parent.parent
10
+ readme = gemdir + 'README.txt'
11
+
12
+ header, message = readme.read.split( /^== Description/m )
13
+ abort( message.strip )
14
+
15
+ end
16
+
data/pg.gemspec ADDED
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+ # -*- encoding: utf-8 -*-
3
+
4
+ require_relative 'lib/pg/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "pg"
8
+ spec.version = PG::VERSION
9
+ spec.authors = ["Michael Granger", "Lars Kanis"]
10
+ spec.email = ["ged@FaerieMUD.org", "lars@greiz-reinsdorf.de"]
11
+
12
+ spec.summary = "Pg is the Ruby interface to the PostgreSQL RDBMS"
13
+ spec.description = "Pg is the Ruby interface to the PostgreSQL RDBMS. It works with PostgreSQL 9.3 and later."
14
+ spec.homepage = "https://github.com/ged/ruby-pg"
15
+ spec.license = "BSD-2-Clause"
16
+ spec.required_ruby_version = ">= 2.5"
17
+
18
+ spec.metadata["homepage_uri"] = spec.homepage
19
+ spec.metadata["source_code_uri"] = "https://github.com/ged/ruby-pg"
20
+ spec.metadata["changelog_uri"] = "https://github.com/ged/ruby-pg/blob/master/History.rdoc"
21
+ spec.metadata["documentation_uri"] = "http://deveiate.org/code/pg"
22
+
23
+ # Specify which files should be added to the gem when it is released.
24
+ # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
25
+ spec.files = Dir.chdir(File.expand_path(__dir__)) do
26
+ `git ls-files -z`.split("\x0").reject { |f| f.match(%r{\A(?:test|spec|features)/}) }
27
+ end
28
+ spec.extensions = ["ext/extconf.rb"]
29
+ spec.require_paths = ["lib"]
30
+ spec.cert_chain = ["certs/ged.pem"]
31
+ spec.rdoc_options = ["--main", "README.rdoc"]
32
+ end
@@ -0,0 +1,46 @@
1
+ # This source code is borrowed from:
2
+ # https://github.com/oneclick/rubyinstaller2/blob/b3dcbf69f131e44c78ea3a1c5e0041c223f266ce/lib/ruby_installer/build/utils.rb#L104-L144
3
+
4
+ module TaskExtension
5
+ # Extend rake's file task to be defined only once and to check the expected file is indeed generated
6
+ #
7
+ # The same as #task, but for #file.
8
+ # In addition this file task raises an error, if the file that is expected to be generated is not present after the block was executed.
9
+ def file(name, *args, &block)
10
+ task_once(name, block) do
11
+ super(name, *args) do |ta|
12
+ block.call(ta).tap do
13
+ raise "file #{ta.name} is missing after task executed" unless File.exist?(ta.name)
14
+ end
15
+ end
16
+ end
17
+ end
18
+
19
+ # Extend rake's task definition to be defined only once, even if called several times
20
+ #
21
+ # This allows to define common tasks next to specific tasks.
22
+ # It is expected that any variation of the task's block is reflected in the task name or namespace.
23
+ # If the task name is identical, the task block is executed only once, even if the file task definition is executed twice.
24
+ def task(name, *args, &block)
25
+ task_once(name, block) do
26
+ super
27
+ end
28
+ end
29
+
30
+ private def task_once(name, block)
31
+ name = name.keys.first if name.is_a?(Hash)
32
+ if block &&
33
+ Rake::Task.task_defined?(name) &&
34
+ Rake::Task[name].instance_variable_get('@task_block_location') == block.source_location
35
+ # task is already defined for this target and the same block
36
+ # So skip double definition of the same action
37
+ Rake::Task[name]
38
+ elsif block
39
+ yield.tap do
40
+ Rake::Task[name].instance_variable_set('@task_block_location', block.source_location)
41
+ end
42
+ else
43
+ yield
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,20 @@
1
+ # -*- 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,102 @@
1
+ # -*- 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
+ # Track the progress of the connection, waiting for the socket to become readable/writable
31
+ # before polling it
32
+ poll_status = PG::PGRES_POLLING_WRITING
33
+ until poll_status == PG::PGRES_POLLING_OK ||
34
+ poll_status == PG::PGRES_POLLING_FAILED
35
+
36
+ # If the socket needs to read, wait 'til it becomes readable to poll again
37
+ case poll_status
38
+ when PG::PGRES_POLLING_READING
39
+ output_progress " waiting for socket to become readable"
40
+ select( [conn.socket_io], nil, nil, TIMEOUT ) or
41
+ raise "Asynchronous connection timed out!"
42
+
43
+ # ...and the same for when the socket needs to write
44
+ when PG::PGRES_POLLING_WRITING
45
+ output_progress " waiting for socket to become writable"
46
+ select( nil, [conn.socket_io], nil, TIMEOUT ) or
47
+ raise "Asynchronous connection timed out!"
48
+ end
49
+
50
+ # Output a status message about the progress
51
+ case conn.status
52
+ when PG::CONNECTION_STARTED
53
+ output_progress " waiting for connection to be made."
54
+ when PG::CONNECTION_MADE
55
+ output_progress " connection OK; waiting to send."
56
+ when PG::CONNECTION_AWAITING_RESPONSE
57
+ output_progress " waiting for a response from the server."
58
+ when PG::CONNECTION_AUTH_OK
59
+ output_progress " received authentication; waiting for backend start-up to finish."
60
+ when PG::CONNECTION_SSL_STARTUP
61
+ output_progress " negotiating SSL encryption."
62
+ when PG::CONNECTION_SETENV
63
+ output_progress " negotiating environment-driven parameter settings."
64
+ when PG::CONNECTION_NEEDED
65
+ output_progress " internal state: connect() needed."
66
+ end
67
+
68
+ # Check to see if it's finished or failed yet
69
+ poll_status = conn.connect_poll
70
+ end
71
+
72
+ abort "Connect failed: %s" % [ conn.error_message ] unless conn.status == PG::CONNECTION_OK
73
+
74
+ output_progress "Sending query"
75
+ conn.send_query( "SELECT * FROM pg_stat_activity" )
76
+
77
+ # Fetch results until there aren't any more
78
+ loop do
79
+ output_progress " waiting for a response"
80
+
81
+ # Buffer any incoming data on the socket until a full result is ready.
82
+ conn.consume_input
83
+ while conn.is_busy
84
+ select( [conn.socket_io], nil, nil, TIMEOUT ) or
85
+ raise "Timeout waiting for query response."
86
+ conn.consume_input
87
+ end
88
+
89
+ # Fetch the next result. If there isn't one, the query is finished
90
+ result = conn.get_result or break
91
+
92
+ puts "\n\nQuery result:\n%p\n" % [ result.values ]
93
+ end
94
+
95
+ output_progress "Done."
96
+ conn.finish
97
+
98
+ if defined?( progress_thread )
99
+ progress_thread.kill
100
+ progress_thread.join
101
+ end
102
+
@@ -0,0 +1,39 @@
1
+ # -*- 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
+ # -*- 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
+
@@ -0,0 +1,21 @@
1
+ # -*- ruby -*-
2
+ # vim: set nosta noet ts=4 sw=4:
3
+ # encoding: utf-8
4
+
5
+ require 'pg'
6
+
7
+ # This is a minimal example of a function that can test an existing PG::Connection and
8
+ # reset it if necessary.
9
+
10
+ def check_connection( conn )
11
+ begin
12
+ conn.exec( "SELECT 1" )
13
+ rescue PG::Error => err
14
+ $stderr.puts "%p while testing connection: %s" % [ err.class, err.message ]
15
+ conn.reset
16
+ end
17
+ end
18
+
19
+ conn = PG.connect( dbname: 'test' )
20
+ check_connection( conn )
21
+