pg 0.18.0 → 1.1.4

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 (80) hide show
  1. checksums.yaml +5 -5
  2. checksums.yaml.gz.sig +0 -0
  3. data/BSDL +2 -2
  4. data/ChangeLog +1221 -4
  5. data/History.rdoc +200 -0
  6. data/Manifest.txt +5 -18
  7. data/README-Windows.rdoc +15 -26
  8. data/README.rdoc +27 -10
  9. data/Rakefile +33 -24
  10. data/Rakefile.cross +57 -39
  11. data/ext/errorcodes.def +37 -0
  12. data/ext/errorcodes.rb +1 -1
  13. data/ext/errorcodes.txt +16 -1
  14. data/ext/extconf.rb +29 -35
  15. data/ext/gvl_wrappers.c +4 -0
  16. data/ext/gvl_wrappers.h +27 -39
  17. data/ext/pg.c +27 -53
  18. data/ext/pg.h +66 -83
  19. data/ext/pg_binary_decoder.c +75 -6
  20. data/ext/pg_binary_encoder.c +14 -12
  21. data/ext/pg_coder.c +83 -13
  22. data/ext/pg_connection.c +627 -351
  23. data/ext/pg_copy_coder.c +44 -9
  24. data/ext/pg_result.c +364 -134
  25. data/ext/pg_text_decoder.c +605 -46
  26. data/ext/pg_text_encoder.c +95 -76
  27. data/ext/pg_tuple.c +541 -0
  28. data/ext/pg_type_map.c +20 -13
  29. data/ext/pg_type_map_by_column.c +7 -7
  30. data/ext/pg_type_map_by_mri_type.c +2 -2
  31. data/ext/pg_type_map_in_ruby.c +4 -7
  32. data/ext/util.c +7 -7
  33. data/ext/util.h +3 -3
  34. data/lib/pg/basic_type_mapping.rb +105 -45
  35. data/lib/pg/binary_decoder.rb +22 -0
  36. data/lib/pg/coder.rb +1 -1
  37. data/lib/pg/connection.rb +109 -39
  38. data/lib/pg/constants.rb +1 -1
  39. data/lib/pg/exceptions.rb +1 -1
  40. data/lib/pg/result.rb +11 -6
  41. data/lib/pg/text_decoder.rb +25 -20
  42. data/lib/pg/text_encoder.rb +43 -1
  43. data/lib/pg/tuple.rb +30 -0
  44. data/lib/pg/type_map_by_column.rb +1 -1
  45. data/lib/pg.rb +21 -11
  46. data/spec/helpers.rb +50 -25
  47. data/spec/pg/basic_type_mapping_spec.rb +287 -30
  48. data/spec/pg/connection_spec.rb +695 -282
  49. data/spec/pg/connection_sync_spec.rb +41 -0
  50. data/spec/pg/result_spec.rb +59 -17
  51. data/spec/pg/tuple_spec.rb +280 -0
  52. data/spec/pg/type_map_by_class_spec.rb +3 -3
  53. data/spec/pg/type_map_by_column_spec.rb +1 -1
  54. data/spec/pg/type_map_by_mri_type_spec.rb +2 -2
  55. data/spec/pg/type_map_by_oid_spec.rb +1 -1
  56. data/spec/pg/type_map_in_ruby_spec.rb +1 -1
  57. data/spec/pg/type_map_spec.rb +1 -1
  58. data/spec/pg/type_spec.rb +319 -35
  59. data/spec/pg_spec.rb +2 -2
  60. data.tar.gz.sig +0 -0
  61. metadata +68 -68
  62. metadata.gz.sig +0 -0
  63. data/sample/array_insert.rb +0 -20
  64. data/sample/async_api.rb +0 -106
  65. data/sample/async_copyto.rb +0 -39
  66. data/sample/async_mixed.rb +0 -56
  67. data/sample/check_conn.rb +0 -21
  68. data/sample/copyfrom.rb +0 -81
  69. data/sample/copyto.rb +0 -19
  70. data/sample/cursor.rb +0 -21
  71. data/sample/disk_usage_report.rb +0 -186
  72. data/sample/issue-119.rb +0 -94
  73. data/sample/losample.rb +0 -69
  74. data/sample/minimal-testcase.rb +0 -17
  75. data/sample/notify_wait.rb +0 -72
  76. data/sample/pg_statistics.rb +0 -294
  77. data/sample/replication_monitor.rb +0 -231
  78. data/sample/test_binary_values.rb +0 -33
  79. data/sample/wal_shipper.rb +0 -434
  80. data/sample/warehouse_partitions.rb +0 -320
@@ -1,4 +1,7 @@
1
- #!/usr/bin/env ruby
1
+ # -*- ruby -*-
2
+
3
+ require 'json'
4
+ require 'ipaddr'
2
5
 
3
6
  module PG
4
7
  module TextEncoder
@@ -16,12 +19,51 @@ module PG
16
19
  end
17
20
  end
18
21
 
22
+ class TimestampUtc < SimpleEncoder
23
+ STRFTIME_ISO_DATETIME_WITHOUT_TIMEZONE_UTC = "%Y-%m-%d %H:%M:%S.%N".freeze
24
+ def encode(value)
25
+ value.respond_to?(:utc) ? value.utc.strftime(STRFTIME_ISO_DATETIME_WITHOUT_TIMEZONE_UTC) : value
26
+ end
27
+ end
28
+
19
29
  class TimestampWithTimeZone < SimpleEncoder
20
30
  STRFTIME_ISO_DATETIME_WITH_TIMEZONE = "%Y-%m-%d %H:%M:%S.%N %:z".freeze
21
31
  def encode(value)
22
32
  value.respond_to?(:strftime) ? value.strftime(STRFTIME_ISO_DATETIME_WITH_TIMEZONE) : value
23
33
  end
24
34
  end
35
+
36
+ class Numeric < SimpleEncoder
37
+ def encode(value)
38
+ value.is_a?(BigDecimal) ? value.to_s('F') : value
39
+ end
40
+ end
41
+
42
+ class JSON < SimpleEncoder
43
+ def encode(value)
44
+ ::JSON.generate(value, quirks_mode: true)
45
+ end
46
+ end
47
+
48
+ class Inet < SimpleEncoder
49
+ def encode(value)
50
+ case value
51
+ when IPAddr
52
+ default_prefix = (value.family == Socket::AF_INET ? 32 : 128)
53
+ s = value.to_s
54
+ if value.respond_to?(:prefix)
55
+ prefix = value.prefix
56
+ else
57
+ range = value.to_range
58
+ prefix = default_prefix - Math.log(((range.end.to_i - range.begin.to_i) + 1), 2).to_i
59
+ end
60
+ s << "/" << prefix.to_s if prefix != default_prefix
61
+ s
62
+ else
63
+ value
64
+ end
65
+ end
66
+ end
25
67
  end
26
68
  end # module PG
27
69
 
data/lib/pg/tuple.rb ADDED
@@ -0,0 +1,30 @@
1
+ # -*- ruby -*-
2
+ # frozen_string_literal: true
3
+
4
+ require 'pg' unless defined?( PG )
5
+
6
+
7
+ class PG::Tuple
8
+
9
+ ### Return a String representation of the object suitable for debugging.
10
+ def inspect
11
+ "#<#{self.class} #{self.map{|k,v| "#{k}: #{v.inspect}" }.join(", ") }>"
12
+ end
13
+
14
+ def has_key?(key)
15
+ field_map.has_key?(key)
16
+ end
17
+ alias key? has_key?
18
+
19
+ def keys
20
+ field_names || field_map.keys.freeze
21
+ end
22
+
23
+ def each_key(&block)
24
+ if fn=field_names
25
+ fn.each(&block)
26
+ else
27
+ field_map.each_key(&block)
28
+ end
29
+ end
30
+ end
@@ -1,4 +1,4 @@
1
- #!/usr/bin/env ruby
1
+ # -*- ruby -*-
2
2
 
3
3
  require 'pg' unless defined?( PG )
4
4
 
data/lib/pg.rb CHANGED
@@ -1,4 +1,4 @@
1
- #!/usr/bin/env ruby
1
+ # -*- ruby -*-
2
2
 
3
3
  begin
4
4
  require 'pg_ext'
@@ -8,11 +8,22 @@ rescue LoadError
8
8
  major_minor = RUBY_VERSION[ /^(\d+\.\d+)/ ] or
9
9
  raise "Oops, can't extract the major/minor version from #{RUBY_VERSION.dump}"
10
10
 
11
- # Set the PATH environment variable, so that libpq.dll can be found.
12
- old_path = ENV['PATH']
13
- ENV['PATH'] = "#{File.expand_path("../#{RUBY_PLATFORM}", __FILE__)};#{old_path}"
14
- require "#{major_minor}/pg_ext"
15
- ENV['PATH'] = old_path
11
+ add_dll_path = proc do |path, &block|
12
+ begin
13
+ require 'ruby_installer/runtime'
14
+ RubyInstaller::Runtime.add_dll_directory(path, &block)
15
+ rescue LoadError
16
+ old_path = ENV['PATH']
17
+ ENV['PATH'] = "#{path};#{old_path}"
18
+ block.call
19
+ ENV['PATH'] = old_path
20
+ end
21
+ end
22
+
23
+ # Temporary add this directory for DLL search, so that libpq.dll can be found.
24
+ add_dll_path.call(__dir__) do
25
+ require "#{major_minor}/pg_ext"
26
+ end
16
27
  else
17
28
  raise
18
29
  end
@@ -24,10 +35,10 @@ end
24
35
  module PG
25
36
 
26
37
  # Library version
27
- VERSION = '0.18.0'
38
+ VERSION = '1.1.4'
28
39
 
29
40
  # VCS revision
30
- REVISION = %q$Revision: b2bf034e3b9f $
41
+ REVISION = %q$Revision: 6f611e78845a $
31
42
 
32
43
  class NotAllCopyDataRetrieved < PG::Error
33
44
  end
@@ -49,16 +60,15 @@ module PG
49
60
  require 'pg/exceptions'
50
61
  require 'pg/constants'
51
62
  require 'pg/coder'
63
+ require 'pg/binary_decoder'
52
64
  require 'pg/text_encoder'
53
65
  require 'pg/text_decoder'
54
66
  require 'pg/basic_type_mapping'
55
67
  require 'pg/type_map_by_column'
56
68
  require 'pg/connection'
57
69
  require 'pg/result'
70
+ require 'pg/tuple'
58
71
 
59
72
  end # module PG
60
73
 
61
74
 
62
- # Backward-compatible aliase
63
- PGError = PG::Error
64
-
data/spec/helpers.rb CHANGED
@@ -1,11 +1,13 @@
1
- #!/usr/bin/env ruby
1
+ # -*- ruby -*-
2
2
 
3
3
  require 'pathname'
4
4
  require 'rspec'
5
5
  require 'shellwords'
6
6
  require 'pg'
7
7
 
8
- TEST_DIRECTORY = Pathname.getwd + "tmp_test_specs"
8
+ DEFAULT_TEST_DIR_STR = File.join(Dir.pwd, "tmp_test_specs")
9
+ TEST_DIR_STR = ENV['RUBY_PG_TEST_DIR'] || DEFAULT_TEST_DIR_STR
10
+ TEST_DIRECTORY = Pathname.new(TEST_DIR_STR)
9
11
 
10
12
  module PG::TestingHelpers
11
13
 
@@ -20,12 +22,11 @@ module PG::TestingHelpers
20
22
 
21
23
  mod.around( :each ) do |example|
22
24
  begin
25
+ @conn.set_default_encoding
23
26
  @conn.exec( 'BEGIN' ) unless example.metadata[:without_transaction]
24
- if PG.respond_to?( :library_version )
25
- desc = example.source_location.join(':')
26
- @conn.exec_params %Q{SET application_name TO '%s'} %
27
- [@conn.escape_string(desc.slice(-60))]
28
- end
27
+ desc = example.source_location.join(':')
28
+ @conn.exec %Q{SET application_name TO '%s'} %
29
+ [@conn.escape_string(desc.slice(-60))]
29
30
  example.run
30
31
  ensure
31
32
  @conn.exec( 'ROLLBACK' ) unless example.metadata[:without_transaction]
@@ -197,8 +198,8 @@ module PG::TestingHelpers
197
198
  @test_pgdata = TEST_DIRECTORY + 'data'
198
199
  @test_pgdata.mkpath
199
200
 
200
- @port = 54321
201
- ENV['PGPORT'] = @port.to_s
201
+ ENV['PGPORT'] ||= "54321"
202
+ @port = ENV['PGPORT'].to_i
202
203
  ENV['PGHOST'] = 'localhost'
203
204
  @conninfo = "host=localhost port=#{@port} dbname=test"
204
205
 
@@ -251,11 +252,11 @@ module PG::TestingHelpers
251
252
 
252
253
  def check_for_lingering_connections( conn )
253
254
  conn.exec( "SELECT * FROM pg_stat_activity" ) do |res|
254
- conns = res.find_all {|row| row['pid'].to_i != conn.backend_pid }
255
+ conns = res.find_all {|row| row['pid'].to_i != conn.backend_pid && ["client backend", nil].include?(row["backend_type"]) }
255
256
  unless conns.empty?
256
257
  puts "Lingering connections remain:"
257
258
  conns.each do |row|
258
- puts " [%d] {%s} %s -- %s" % row.values_at( 'pid', 'state', 'application_name', 'query' )
259
+ puts " [%s] {%s} %s -- %s" % row.values_at( 'pid', 'state', 'application_name', 'query' )
259
260
  end
260
261
  end
261
262
  end
@@ -264,7 +265,7 @@ module PG::TestingHelpers
264
265
 
265
266
  # Retrieve the names of the column types of a given result set.
266
267
  def result_typenames(res)
267
- @conn.exec( "SELECT " + res.nfields.times.map{|i| "format_type($#{i*2+1},$#{i*2+2})"}.join(","),
268
+ @conn.exec_params( "SELECT " + res.nfields.times.map{|i| "format_type($#{i*2+1},$#{i*2+2})"}.join(","),
268
269
  res.nfields.times.map{|i| [res.ftype(i), res.fmod(i)] }.flatten ).
269
270
  values[0]
270
271
  end
@@ -318,6 +319,39 @@ module PG::TestingHelpers
318
319
  return ConnStillUsableMatcher.new
319
320
  end
320
321
 
322
+ def wait_for_polling_ok(conn, meth = :connect_poll)
323
+ status = conn.send(meth)
324
+
325
+ while status != PG::PGRES_POLLING_OK
326
+ if status == PG::PGRES_POLLING_READING
327
+ select( [conn.socket_io], [], [], 5.0 ) or
328
+ raise "Asynchronous connection timed out!"
329
+
330
+ elsif status == PG::PGRES_POLLING_WRITING
331
+ select( [], [conn.socket_io], [], 5.0 ) or
332
+ raise "Asynchronous connection timed out!"
333
+ end
334
+ status = conn.send(meth)
335
+ end
336
+ end
337
+
338
+ def wait_for_query_result(conn)
339
+ result = nil
340
+ loop do
341
+ # Buffer any incoming data on the socket until a full result is ready.
342
+ conn.consume_input
343
+ while conn.is_busy
344
+ select( [conn.socket_io], nil, nil, 5.0 ) or
345
+ raise "Timeout waiting for query response."
346
+ conn.consume_input
347
+ end
348
+
349
+ # Fetch the next result. If there isn't one, the query is finished
350
+ result = conn.get_result || break
351
+ end
352
+ result
353
+ end
354
+
321
355
  end
322
356
 
323
357
 
@@ -339,17 +373,8 @@ RSpec.configure do |config|
339
373
  config.filter_run_excluding :socket_io unless
340
374
  PG::Connection.instance_methods.map( &:to_sym ).include?( :socket_io )
341
375
 
342
- config.filter_run_excluding :postgresql_90 unless
343
- PG::Connection.instance_methods.map( &:to_sym ).include?( :escape_literal )
344
-
345
- if !PG.respond_to?( :library_version )
346
- config.filter_run_excluding( :postgresql_91, :postgresql_92, :postgresql_93, :postgresql_94 )
347
- elsif PG.library_version < 90200
348
- config.filter_run_excluding( :postgresql_92, :postgresql_93, :postgresql_94 )
349
- elsif PG.library_version < 90300
350
- config.filter_run_excluding( :postgresql_93, :postgresql_94 )
351
- elsif PG.library_version < 90400
352
- config.filter_run_excluding( :postgresql_94 )
353
- end
376
+ config.filter_run_excluding( :postgresql_93 ) if PG.library_version < 90300
377
+ config.filter_run_excluding( :postgresql_94 ) if PG.library_version < 90400
378
+ config.filter_run_excluding( :postgresql_95 ) if PG.library_version < 90500
379
+ config.filter_run_excluding( :postgresql_10 ) if PG.library_version < 100000
354
380
  end
355
-