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.
- checksums.yaml +5 -5
- checksums.yaml.gz.sig +0 -0
- data/BSDL +2 -2
- data/ChangeLog +1221 -4
- data/History.rdoc +200 -0
- data/Manifest.txt +5 -18
- data/README-Windows.rdoc +15 -26
- data/README.rdoc +27 -10
- data/Rakefile +33 -24
- data/Rakefile.cross +57 -39
- data/ext/errorcodes.def +37 -0
- data/ext/errorcodes.rb +1 -1
- data/ext/errorcodes.txt +16 -1
- data/ext/extconf.rb +29 -35
- data/ext/gvl_wrappers.c +4 -0
- data/ext/gvl_wrappers.h +27 -39
- data/ext/pg.c +27 -53
- data/ext/pg.h +66 -83
- data/ext/pg_binary_decoder.c +75 -6
- data/ext/pg_binary_encoder.c +14 -12
- data/ext/pg_coder.c +83 -13
- data/ext/pg_connection.c +627 -351
- data/ext/pg_copy_coder.c +44 -9
- data/ext/pg_result.c +364 -134
- data/ext/pg_text_decoder.c +605 -46
- data/ext/pg_text_encoder.c +95 -76
- data/ext/pg_tuple.c +541 -0
- data/ext/pg_type_map.c +20 -13
- data/ext/pg_type_map_by_column.c +7 -7
- data/ext/pg_type_map_by_mri_type.c +2 -2
- data/ext/pg_type_map_in_ruby.c +4 -7
- data/ext/util.c +7 -7
- data/ext/util.h +3 -3
- data/lib/pg/basic_type_mapping.rb +105 -45
- data/lib/pg/binary_decoder.rb +22 -0
- data/lib/pg/coder.rb +1 -1
- data/lib/pg/connection.rb +109 -39
- data/lib/pg/constants.rb +1 -1
- data/lib/pg/exceptions.rb +1 -1
- data/lib/pg/result.rb +11 -6
- data/lib/pg/text_decoder.rb +25 -20
- data/lib/pg/text_encoder.rb +43 -1
- data/lib/pg/tuple.rb +30 -0
- data/lib/pg/type_map_by_column.rb +1 -1
- data/lib/pg.rb +21 -11
- data/spec/helpers.rb +50 -25
- data/spec/pg/basic_type_mapping_spec.rb +287 -30
- data/spec/pg/connection_spec.rb +695 -282
- data/spec/pg/connection_sync_spec.rb +41 -0
- data/spec/pg/result_spec.rb +59 -17
- data/spec/pg/tuple_spec.rb +280 -0
- data/spec/pg/type_map_by_class_spec.rb +3 -3
- data/spec/pg/type_map_by_column_spec.rb +1 -1
- data/spec/pg/type_map_by_mri_type_spec.rb +2 -2
- data/spec/pg/type_map_by_oid_spec.rb +1 -1
- data/spec/pg/type_map_in_ruby_spec.rb +1 -1
- data/spec/pg/type_map_spec.rb +1 -1
- data/spec/pg/type_spec.rb +319 -35
- data/spec/pg_spec.rb +2 -2
- data.tar.gz.sig +0 -0
- metadata +68 -68
- metadata.gz.sig +0 -0
- data/sample/array_insert.rb +0 -20
- data/sample/async_api.rb +0 -106
- data/sample/async_copyto.rb +0 -39
- data/sample/async_mixed.rb +0 -56
- data/sample/check_conn.rb +0 -21
- data/sample/copyfrom.rb +0 -81
- data/sample/copyto.rb +0 -19
- data/sample/cursor.rb +0 -21
- data/sample/disk_usage_report.rb +0 -186
- data/sample/issue-119.rb +0 -94
- data/sample/losample.rb +0 -69
- data/sample/minimal-testcase.rb +0 -17
- data/sample/notify_wait.rb +0 -72
- data/sample/pg_statistics.rb +0 -294
- data/sample/replication_monitor.rb +0 -231
- data/sample/test_binary_values.rb +0 -33
- data/sample/wal_shipper.rb +0 -434
- data/sample/warehouse_partitions.rb +0 -320
data/lib/pg/text_encoder.rb
CHANGED
@@ -1,4 +1,7 @@
|
|
1
|
-
|
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
|
data/lib/pg.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
|
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
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
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 = '
|
38
|
+
VERSION = '1.1.4'
|
28
39
|
|
29
40
|
# VCS revision
|
30
|
-
REVISION = %q$Revision:
|
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
|
-
|
1
|
+
# -*- ruby -*-
|
2
2
|
|
3
3
|
require 'pathname'
|
4
4
|
require 'rspec'
|
5
5
|
require 'shellwords'
|
6
6
|
require 'pg'
|
7
7
|
|
8
|
-
|
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
|
-
|
25
|
-
|
26
|
-
@conn.
|
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
|
-
|
201
|
-
ENV['PGPORT']
|
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 " [%
|
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.
|
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 :
|
343
|
-
|
344
|
-
|
345
|
-
if
|
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
|
-
|