pg 1.2.1-x64-mingw32 → 1.3.0.rc2-x64-mingw32
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/.appveyor.yml +36 -0
- data/.gems +6 -0
- data/.github/workflows/binary-gems.yml +85 -0
- data/.github/workflows/source-gem.yml +130 -0
- data/.gitignore +13 -0
- data/.hgsigs +34 -0
- data/.hgtags +41 -0
- data/.irbrc +23 -0
- data/.pryrc +23 -0
- data/.tm_properties +21 -0
- data/.travis.yml +49 -0
- data/Gemfile +14 -0
- data/History.rdoc +93 -7
- data/Manifest.txt +0 -1
- data/README.rdoc +8 -7
- data/Rakefile +31 -140
- data/Rakefile.cross +55 -56
- data/certs/ged.pem +24 -0
- data/ext/errorcodes.def +8 -0
- data/ext/errorcodes.txt +3 -1
- data/ext/extconf.rb +90 -19
- data/ext/gvl_wrappers.c +4 -0
- data/ext/gvl_wrappers.h +23 -0
- data/ext/pg.c +59 -4
- data/ext/pg.h +18 -0
- data/ext/pg_coder.c +90 -24
- data/ext/pg_connection.c +606 -533
- data/ext/pg_copy_coder.c +45 -15
- data/ext/pg_record_coder.c +38 -9
- data/ext/pg_result.c +61 -31
- data/ext/pg_text_decoder.c +1 -1
- data/ext/pg_text_encoder.c +6 -6
- data/ext/pg_tuple.c +47 -21
- data/ext/pg_type_map.c +41 -8
- data/ext/pg_type_map_all_strings.c +14 -1
- data/ext/pg_type_map_by_class.c +50 -21
- data/ext/pg_type_map_by_column.c +64 -28
- data/ext/pg_type_map_by_mri_type.c +47 -18
- data/ext/pg_type_map_by_oid.c +52 -23
- data/ext/pg_type_map_in_ruby.c +50 -19
- data/ext/pg_util.c +2 -2
- data/lib/2.5/pg_ext.so +0 -0
- data/lib/2.6/pg_ext.so +0 -0
- data/lib/2.7/pg_ext.so +0 -0
- data/lib/3.0/pg_ext.so +0 -0
- data/lib/pg/basic_type_map_based_on_result.rb +47 -0
- data/lib/pg/basic_type_map_for_queries.rb +193 -0
- data/lib/pg/basic_type_map_for_results.rb +81 -0
- data/lib/pg/basic_type_registry.rb +296 -0
- data/lib/pg/coder.rb +1 -1
- data/lib/pg/connection.rb +579 -57
- data/lib/pg/version.rb +4 -0
- data/lib/pg.rb +38 -24
- data/lib/x64-mingw32/libpq.dll +0 -0
- data/misc/openssl-pg-segfault.rb +31 -0
- data/misc/postgres/History.txt +9 -0
- data/misc/postgres/Manifest.txt +5 -0
- data/misc/postgres/README.txt +21 -0
- data/misc/postgres/Rakefile +21 -0
- data/misc/postgres/lib/postgres.rb +16 -0
- data/misc/ruby-pg/History.txt +9 -0
- data/misc/ruby-pg/Manifest.txt +5 -0
- data/misc/ruby-pg/README.txt +21 -0
- data/misc/ruby-pg/Rakefile +21 -0
- data/misc/ruby-pg/lib/ruby/pg.rb +16 -0
- data/pg.gemspec +32 -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/copydata.rb +71 -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 +177 -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 +285 -0
- data/sample/replication_monitor.rb +222 -0
- data/sample/test_binary_values.rb +33 -0
- data/sample/wal_shipper.rb +434 -0
- data/sample/warehouse_partitions.rb +311 -0
- data.tar.gz.sig +0 -0
- metadata +94 -235
- metadata.gz.sig +0 -0
- data/ChangeLog +0 -0
- data/lib/2.2/pg_ext.so +0 -0
- data/lib/2.3/pg_ext.so +0 -0
- data/lib/2.4/pg_ext.so +0 -0
- data/lib/libpq.dll +0 -0
- data/lib/pg/basic_type_mapping.rb +0 -522
- data/spec/data/expected_trace.out +0 -26
- data/spec/data/random_binary_data +0 -0
- data/spec/helpers.rb +0 -382
- data/spec/pg/basic_type_mapping_spec.rb +0 -645
- data/spec/pg/connection_spec.rb +0 -1911
- data/spec/pg/connection_sync_spec.rb +0 -41
- data/spec/pg/result_spec.rb +0 -681
- data/spec/pg/tuple_spec.rb +0 -333
- data/spec/pg/type_map_by_class_spec.rb +0 -138
- data/spec/pg/type_map_by_column_spec.rb +0 -226
- data/spec/pg/type_map_by_mri_type_spec.rb +0 -136
- data/spec/pg/type_map_by_oid_spec.rb +0 -149
- data/spec/pg/type_map_in_ruby_spec.rb +0 -164
- data/spec/pg/type_map_spec.rb +0 -22
- data/spec/pg/type_spec.rb +0 -1123
- data/spec/pg_spec.rb +0 -50
@@ -0,0 +1,296 @@
|
|
1
|
+
# -*- ruby -*-
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
require 'pg' unless defined?( PG )
|
5
|
+
|
6
|
+
# This class defines the mapping between PostgreSQL types and encoder/decoder classes for PG::BasicTypeMapForResults, PG::BasicTypeMapForQueries and PG::BasicTypeMapBasedOnResult.
|
7
|
+
#
|
8
|
+
# Additional types can be added like so:
|
9
|
+
#
|
10
|
+
# require 'pg'
|
11
|
+
# require 'ipaddr'
|
12
|
+
#
|
13
|
+
# class InetDecoder < PG::SimpleDecoder
|
14
|
+
# def decode(string, tuple=nil, field=nil)
|
15
|
+
# IPAddr.new(string)
|
16
|
+
# end
|
17
|
+
# end
|
18
|
+
# class InetEncoder < PG::SimpleEncoder
|
19
|
+
# def encode(ip_addr)
|
20
|
+
# ip_addr.to_s
|
21
|
+
# end
|
22
|
+
# end
|
23
|
+
#
|
24
|
+
# conn = PG.connect
|
25
|
+
# regi = PG::BasicTypeRegistry.new.define_default_types
|
26
|
+
# regi.register_type(0, 'inet', InetEncoder, InetDecoder)
|
27
|
+
# conn.type_map_for_results = PG::BasicTypeMapForResults.new(conn, registry: regi)
|
28
|
+
class PG::BasicTypeRegistry
|
29
|
+
# An instance of this class stores the coders that should be used for a particular wire format (text or binary)
|
30
|
+
# and type cast direction (encoder or decoder).
|
31
|
+
#
|
32
|
+
# Each coder object is filled with the PostgreSQL type name, OID, wire format and array coders are filled with the base elements_type.
|
33
|
+
class CoderMap
|
34
|
+
# Hash of text types that don't require quotation, when used within composite types.
|
35
|
+
# type.name => true
|
36
|
+
DONT_QUOTE_TYPES = %w[
|
37
|
+
int2 int4 int8
|
38
|
+
float4 float8
|
39
|
+
oid
|
40
|
+
bool
|
41
|
+
date timestamp timestamptz
|
42
|
+
].inject({}){|h,e| h[e] = true; h }
|
43
|
+
|
44
|
+
def initialize(result, coders_by_name, format, arraycoder)
|
45
|
+
coder_map = {}
|
46
|
+
|
47
|
+
arrays, nodes = result.partition { |row| row['typinput'] == 'array_in' }
|
48
|
+
|
49
|
+
# populate the base types
|
50
|
+
nodes.find_all { |row| coders_by_name.key?(row['typname']) }.each do |row|
|
51
|
+
coder = coders_by_name[row['typname']].dup
|
52
|
+
coder.oid = row['oid'].to_i
|
53
|
+
coder.name = row['typname']
|
54
|
+
coder.format = format
|
55
|
+
coder_map[coder.oid] = coder
|
56
|
+
end
|
57
|
+
|
58
|
+
if arraycoder
|
59
|
+
# populate array types
|
60
|
+
arrays.each do |row|
|
61
|
+
elements_coder = coder_map[row['typelem'].to_i]
|
62
|
+
next unless elements_coder
|
63
|
+
|
64
|
+
coder = arraycoder.new
|
65
|
+
coder.oid = row['oid'].to_i
|
66
|
+
coder.name = row['typname']
|
67
|
+
coder.format = format
|
68
|
+
coder.elements_type = elements_coder
|
69
|
+
coder.needs_quotation = !DONT_QUOTE_TYPES[elements_coder.name]
|
70
|
+
coder_map[coder.oid] = coder
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
@coders = coder_map.values
|
75
|
+
@coders_by_name = @coders.inject({}){|h, t| h[t.name] = t; h }
|
76
|
+
@coders_by_oid = @coders.inject({}){|h, t| h[t.oid] = t; h }
|
77
|
+
end
|
78
|
+
|
79
|
+
attr_reader :coders
|
80
|
+
attr_reader :coders_by_oid
|
81
|
+
attr_reader :coders_by_name
|
82
|
+
|
83
|
+
def coder_by_name(name)
|
84
|
+
@coders_by_name[name]
|
85
|
+
end
|
86
|
+
|
87
|
+
def coder_by_oid(oid)
|
88
|
+
@coders_by_oid[oid]
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
# An instance of this class stores CoderMap instances to be used for text and binary wire formats
|
93
|
+
# as well as encoder and decoder directions.
|
94
|
+
#
|
95
|
+
# A PG::BasicTypeRegistry::CoderMapsBundle instance retrieves all type definitions from the PostgreSQL server and matches them with the coder definitions of the global PG::BasicTypeRegistry .
|
96
|
+
# It provides 4 separate CoderMap instances for the combinations of the two formats and directions.
|
97
|
+
#
|
98
|
+
# A PG::BasicTypeRegistry::CoderMapsBundle instance can be used to initialize an instance of
|
99
|
+
# * PG::BasicTypeMapForResults
|
100
|
+
# * PG::BasicTypeMapForQueries
|
101
|
+
# * PG::BasicTypeMapBasedOnResult
|
102
|
+
# by passing it instead of the connection object like so:
|
103
|
+
#
|
104
|
+
# conn = PG::Connection.new
|
105
|
+
# maps = PG::BasicTypeRegistry::CoderMapsBundle.new(conn)
|
106
|
+
# conn.type_map_for_results = PG::BasicTypeMapForResults.new(maps)
|
107
|
+
#
|
108
|
+
class CoderMapsBundle
|
109
|
+
attr_reader :typenames_by_oid
|
110
|
+
|
111
|
+
def initialize(connection, registry: nil)
|
112
|
+
registry ||= DEFAULT_TYPE_REGISTRY
|
113
|
+
|
114
|
+
result = connection.exec(<<-SQL).to_a
|
115
|
+
SELECT t.oid, t.typname, t.typelem, t.typdelim, ti.proname AS typinput
|
116
|
+
FROM pg_type as t
|
117
|
+
JOIN pg_proc as ti ON ti.oid = t.typinput
|
118
|
+
SQL
|
119
|
+
|
120
|
+
@maps = [
|
121
|
+
[0, :encoder, PG::TextEncoder::Array],
|
122
|
+
[0, :decoder, PG::TextDecoder::Array],
|
123
|
+
[1, :encoder, nil],
|
124
|
+
[1, :decoder, nil],
|
125
|
+
].inject([]) do |h, (format, direction, arraycoder)|
|
126
|
+
coders = registry.coders_for(format, direction) || {}
|
127
|
+
h[format] ||= {}
|
128
|
+
h[format][direction] = CoderMap.new(result, coders, format, arraycoder)
|
129
|
+
h
|
130
|
+
end
|
131
|
+
|
132
|
+
@typenames_by_oid = result.inject({}){|h, t| h[t['oid'].to_i] = t['typname']; h }
|
133
|
+
end
|
134
|
+
|
135
|
+
def each_format(direction)
|
136
|
+
@maps.map { |f| f[direction] }
|
137
|
+
end
|
138
|
+
|
139
|
+
def map_for(format, direction)
|
140
|
+
@maps[format][direction]
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
144
|
+
module Checker
|
145
|
+
ValidFormats = { 0 => true, 1 => true }
|
146
|
+
ValidDirections = { :encoder => true, :decoder => true }
|
147
|
+
|
148
|
+
protected def check_format_and_direction(format, direction)
|
149
|
+
raise(ArgumentError, "Invalid format value %p" % format) unless ValidFormats[format]
|
150
|
+
raise(ArgumentError, "Invalid direction %p" % direction) unless ValidDirections[direction]
|
151
|
+
end
|
152
|
+
|
153
|
+
protected def build_coder_maps(conn_or_maps, registry: nil)
|
154
|
+
if conn_or_maps.is_a?(PG::BasicTypeRegistry::CoderMapsBundle)
|
155
|
+
raise ArgumentError, "registry argument must be given to CoderMapsBundle" if registry
|
156
|
+
conn_or_maps
|
157
|
+
else
|
158
|
+
PG::BasicTypeRegistry::CoderMapsBundle.new(conn_or_maps, registry: registry)
|
159
|
+
end
|
160
|
+
end
|
161
|
+
end
|
162
|
+
|
163
|
+
include Checker
|
164
|
+
|
165
|
+
def initialize
|
166
|
+
# The key of these hashs maps to the `typname` column from the table pg_type.
|
167
|
+
@coders_by_name = []
|
168
|
+
end
|
169
|
+
|
170
|
+
# Retrieve a Hash of all en- or decoders for a given wire format.
|
171
|
+
# The hash key is the name as defined in table +pg_type+.
|
172
|
+
# The hash value is the registered coder object.
|
173
|
+
def coders_for(format, direction)
|
174
|
+
check_format_and_direction(format, direction)
|
175
|
+
@coders_by_name[format]&.[](direction)
|
176
|
+
end
|
177
|
+
|
178
|
+
# Register an encoder or decoder instance for casting a PostgreSQL type.
|
179
|
+
#
|
180
|
+
# Coder#name must correspond to the +typname+ column in the +pg_type+ table.
|
181
|
+
# Coder#format can be 0 for text format and 1 for binary.
|
182
|
+
def register_coder(coder)
|
183
|
+
h = @coders_by_name[coder.format] ||= { encoder: {}, decoder: {} }
|
184
|
+
name = coder.name || raise(ArgumentError, "name of #{coder.inspect} must be defined")
|
185
|
+
h[:encoder][name] = coder if coder.respond_to?(:encode)
|
186
|
+
h[:decoder][name] = coder if coder.respond_to?(:decode)
|
187
|
+
end
|
188
|
+
|
189
|
+
# Register the given +encoder_class+ and/or +decoder_class+ for casting a PostgreSQL type.
|
190
|
+
#
|
191
|
+
# +name+ must correspond to the +typname+ column in the +pg_type+ table.
|
192
|
+
# +format+ can be 0 for text format and 1 for binary.
|
193
|
+
def register_type(format, name, encoder_class, decoder_class)
|
194
|
+
register_coder(encoder_class.new(name: name, format: format)) if encoder_class
|
195
|
+
register_coder(decoder_class.new(name: name, format: format)) if decoder_class
|
196
|
+
end
|
197
|
+
|
198
|
+
# Alias the +old+ type to the +new+ type.
|
199
|
+
def alias_type(format, new, old)
|
200
|
+
[:encoder, :decoder].each do |ende|
|
201
|
+
enc = @coders_by_name[format][ende][old]
|
202
|
+
if enc
|
203
|
+
@coders_by_name[format][ende][new] = enc
|
204
|
+
else
|
205
|
+
@coders_by_name[format][ende].delete(new)
|
206
|
+
end
|
207
|
+
end
|
208
|
+
end
|
209
|
+
|
210
|
+
# Populate the registry with all builtin types of ruby-pg
|
211
|
+
def define_default_types
|
212
|
+
register_type 0, 'int2', PG::TextEncoder::Integer, PG::TextDecoder::Integer
|
213
|
+
alias_type 0, 'int4', 'int2'
|
214
|
+
alias_type 0, 'int8', 'int2'
|
215
|
+
alias_type 0, 'oid', 'int2'
|
216
|
+
|
217
|
+
register_type 0, 'numeric', PG::TextEncoder::Numeric, PG::TextDecoder::Numeric
|
218
|
+
register_type 0, 'text', PG::TextEncoder::String, PG::TextDecoder::String
|
219
|
+
alias_type 0, 'varchar', 'text'
|
220
|
+
alias_type 0, 'char', 'text'
|
221
|
+
alias_type 0, 'bpchar', 'text'
|
222
|
+
alias_type 0, 'xml', 'text'
|
223
|
+
alias_type 0, 'name', 'text'
|
224
|
+
|
225
|
+
# FIXME: why are we keeping these types as strings?
|
226
|
+
# alias_type 'tsvector', 'text'
|
227
|
+
# alias_type 'interval', 'text'
|
228
|
+
# alias_type 'macaddr', 'text'
|
229
|
+
# alias_type 'uuid', 'text'
|
230
|
+
#
|
231
|
+
# register_type 'money', OID::Money.new
|
232
|
+
# There is no PG::TextEncoder::Bytea, because it's simple and more efficient to send bytea-data
|
233
|
+
# in binary format, either with PG::BinaryEncoder::Bytea or in Hash param format.
|
234
|
+
register_type 0, 'bytea', nil, PG::TextDecoder::Bytea
|
235
|
+
register_type 0, 'bool', PG::TextEncoder::Boolean, PG::TextDecoder::Boolean
|
236
|
+
# register_type 'bit', OID::Bit.new
|
237
|
+
# register_type 'varbit', OID::Bit.new
|
238
|
+
|
239
|
+
register_type 0, 'float4', PG::TextEncoder::Float, PG::TextDecoder::Float
|
240
|
+
alias_type 0, 'float8', 'float4'
|
241
|
+
|
242
|
+
register_type 0, 'timestamp', PG::TextEncoder::TimestampWithoutTimeZone, PG::TextDecoder::TimestampWithoutTimeZone
|
243
|
+
register_type 0, 'timestamptz', PG::TextEncoder::TimestampWithTimeZone, PG::TextDecoder::TimestampWithTimeZone
|
244
|
+
register_type 0, 'date', PG::TextEncoder::Date, PG::TextDecoder::Date
|
245
|
+
# register_type 'time', OID::Time.new
|
246
|
+
#
|
247
|
+
# register_type 'path', OID::Text.new
|
248
|
+
# register_type 'point', OID::Point.new
|
249
|
+
# register_type 'polygon', OID::Text.new
|
250
|
+
# register_type 'circle', OID::Text.new
|
251
|
+
# register_type 'hstore', OID::Hstore.new
|
252
|
+
register_type 0, 'json', PG::TextEncoder::JSON, PG::TextDecoder::JSON
|
253
|
+
alias_type 0, 'jsonb', 'json'
|
254
|
+
# register_type 'citext', OID::Text.new
|
255
|
+
# register_type 'ltree', OID::Text.new
|
256
|
+
#
|
257
|
+
register_type 0, 'inet', PG::TextEncoder::Inet, PG::TextDecoder::Inet
|
258
|
+
alias_type 0, 'cidr', 'inet'
|
259
|
+
|
260
|
+
|
261
|
+
|
262
|
+
register_type 1, 'int2', PG::BinaryEncoder::Int2, PG::BinaryDecoder::Integer
|
263
|
+
register_type 1, 'int4', PG::BinaryEncoder::Int4, PG::BinaryDecoder::Integer
|
264
|
+
register_type 1, 'int8', PG::BinaryEncoder::Int8, PG::BinaryDecoder::Integer
|
265
|
+
alias_type 1, 'oid', 'int2'
|
266
|
+
|
267
|
+
register_type 1, 'text', PG::BinaryEncoder::String, PG::BinaryDecoder::String
|
268
|
+
alias_type 1, 'varchar', 'text'
|
269
|
+
alias_type 1, 'char', 'text'
|
270
|
+
alias_type 1, 'bpchar', 'text'
|
271
|
+
alias_type 1, 'xml', 'text'
|
272
|
+
alias_type 1, 'name', 'text'
|
273
|
+
|
274
|
+
register_type 1, 'bytea', PG::BinaryEncoder::Bytea, PG::BinaryDecoder::Bytea
|
275
|
+
register_type 1, 'bool', PG::BinaryEncoder::Boolean, PG::BinaryDecoder::Boolean
|
276
|
+
register_type 1, 'float4', nil, PG::BinaryDecoder::Float
|
277
|
+
register_type 1, 'float8', nil, PG::BinaryDecoder::Float
|
278
|
+
register_type 1, 'timestamp', nil, PG::BinaryDecoder::TimestampUtc
|
279
|
+
register_type 1, 'timestamptz', nil, PG::BinaryDecoder::TimestampUtcToLocal
|
280
|
+
|
281
|
+
self
|
282
|
+
end
|
283
|
+
|
284
|
+
# @private
|
285
|
+
DEFAULT_TYPE_REGISTRY = PG::BasicTypeRegistry.new.define_default_types
|
286
|
+
|
287
|
+
# Delegate class method calls to DEFAULT_TYPE_REGISTRY
|
288
|
+
class << self
|
289
|
+
%i[ register_coder register_type alias_type ].each do |meth|
|
290
|
+
define_method(meth) do |*args|
|
291
|
+
warn "PG::BasicTypeRegistry.#{meth} is deprecated. Please use your own instance by PG::BasicTypeRegistry.new instead!"
|
292
|
+
DEFAULT_TYPE_REGISTRY.send(meth, *args)
|
293
|
+
end
|
294
|
+
end
|
295
|
+
end
|
296
|
+
end
|