postgresql-lambda 1.3.4.1
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 +7 -0
- data/BSDL +22 -0
- data/BUILD +1 -0
- data/CHANGELOG.md +10 -0
- data/Contributors.rdoc +46 -0
- data/Gemfile +14 -0
- data/History.rdoc +705 -0
- data/LICENSE +56 -0
- data/Manifest.txt +72 -0
- data/POSTGRES +23 -0
- data/README-OS_X.rdoc +68 -0
- data/README-Windows.rdoc +56 -0
- data/README.ja.rdoc +13 -0
- data/README.md +65 -0
- data/README.rdoc +214 -0
- data/Rakefile +106 -0
- data/Rakefile.cross +302 -0
- data/VERSION +1 -0
- data/certs/ged.pem +24 -0
- data/certs/larskanis-2022.pem +26 -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/binary_decoder.rb +23 -0
- data/lib/pg/coder.rb +104 -0
- data/lib/pg/connection.rb +822 -0
- data/lib/pg/constants.rb +12 -0
- data/lib/pg/exceptions.rb +12 -0
- data/lib/pg/postgresql_lib_path.rb +3 -0
- data/lib/pg/result.rb +43 -0
- data/lib/pg/text_decoder.rb +46 -0
- data/lib/pg/text_encoder.rb +59 -0
- data/lib/pg/tuple.rb +30 -0
- data/lib/pg/type_map_by_column.rb +16 -0
- data/lib/pg/version.rb +4 -0
- data/lib/pg.rb +89 -0
- data/lib/pg_ext.so +0 -0
- data/lib/postgresql-lambda.rb +16 -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/postgresql-lambda.gemspec +18 -0
- data/rakelib/task_extension.rb +46 -0
- data/sample/array_insert.rb +20 -0
- data/sample/async_api.rb +102 -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
- metadata +119 -0
data/Rakefile.cross
ADDED
@@ -0,0 +1,302 @@
|
|
1
|
+
# -*- rake -*-
|
2
|
+
|
3
|
+
require 'uri'
|
4
|
+
require 'tempfile'
|
5
|
+
require 'rbconfig'
|
6
|
+
require 'rake/clean'
|
7
|
+
require 'rake/extensiontask'
|
8
|
+
require 'rake/extensioncompiler'
|
9
|
+
require 'ostruct'
|
10
|
+
require_relative 'rakelib/task_extension'
|
11
|
+
|
12
|
+
MISCDIR = BASEDIR + 'misc'
|
13
|
+
|
14
|
+
NUM_CPUS = if File.exist?('/proc/cpuinfo')
|
15
|
+
File.read('/proc/cpuinfo').scan('processor').length
|
16
|
+
elsif RUBY_PLATFORM.include?( 'darwin' )
|
17
|
+
`system_profiler SPHardwareDataType | grep 'Cores' | awk '{print $5}'`.chomp
|
18
|
+
else
|
19
|
+
1
|
20
|
+
end
|
21
|
+
|
22
|
+
class CrossLibrary < OpenStruct
|
23
|
+
include Rake::DSL
|
24
|
+
prepend TaskExtension
|
25
|
+
|
26
|
+
def initialize(for_platform, openssl_config, toolchain)
|
27
|
+
super()
|
28
|
+
|
29
|
+
self.for_platform = for_platform
|
30
|
+
self.openssl_config = openssl_config
|
31
|
+
self.host_platform = toolchain
|
32
|
+
|
33
|
+
# Cross-compilation constants
|
34
|
+
self.openssl_version = ENV['OPENSSL_VERSION'] || '1.1.1m'
|
35
|
+
self.postgresql_version = ENV['POSTGRESQL_VERSION'] || '14.2'
|
36
|
+
|
37
|
+
# Check if symlinks work in the current working directory.
|
38
|
+
# This fails, if rake-compiler-dock is running on a Windows box.
|
39
|
+
begin
|
40
|
+
FileUtils.rm_f '.test_symlink'
|
41
|
+
FileUtils.ln_s '/', '.test_symlink'
|
42
|
+
rescue NotImplementedError, SystemCallError
|
43
|
+
# Symlinks don't work -> use home directory instead
|
44
|
+
self.compile_home = Pathname( "~/.ruby-pg-build" ).expand_path
|
45
|
+
else
|
46
|
+
self.compile_home = Pathname( "./build" ).expand_path
|
47
|
+
end
|
48
|
+
self.static_sourcesdir = compile_home + 'sources'
|
49
|
+
self.static_builddir = compile_home + 'builds' + for_platform
|
50
|
+
CLOBBER.include( static_sourcesdir )
|
51
|
+
CLEAN.include( static_builddir )
|
52
|
+
|
53
|
+
# Static OpenSSL build vars
|
54
|
+
self.static_openssl_builddir = static_builddir + "openssl-#{openssl_version}"
|
55
|
+
|
56
|
+
self.openssl_source_uri =
|
57
|
+
URI( "http://www.openssl.org/source/openssl-#{openssl_version}.tar.gz" )
|
58
|
+
self.openssl_tarball = static_sourcesdir + File.basename( openssl_source_uri.path )
|
59
|
+
self.openssl_makefile = static_openssl_builddir + 'Makefile'
|
60
|
+
|
61
|
+
self.libssl = static_openssl_builddir + 'libssl.a'
|
62
|
+
self.libcrypto = static_openssl_builddir + 'libcrypto.a'
|
63
|
+
|
64
|
+
self.openssl_patches = Rake::FileList[ (MISCDIR + "openssl-#{openssl_version}.*.patch").to_s ]
|
65
|
+
|
66
|
+
# Static PostgreSQL build vars
|
67
|
+
self.static_postgresql_builddir = static_builddir + "postgresql-#{postgresql_version}"
|
68
|
+
self.postgresql_source_uri = begin
|
69
|
+
uristring = "http://ftp.postgresql.org/pub/source/v%s/postgresql-%s.tar.bz2" %
|
70
|
+
[ postgresql_version, postgresql_version ]
|
71
|
+
URI( uristring )
|
72
|
+
end
|
73
|
+
self.postgresql_tarball = static_sourcesdir + File.basename( postgresql_source_uri.path )
|
74
|
+
|
75
|
+
self.static_postgresql_srcdir = static_postgresql_builddir + 'src'
|
76
|
+
self.static_postgresql_libdir = static_postgresql_srcdir + 'interfaces/libpq'
|
77
|
+
self.static_postgresql_incdir = static_postgresql_srcdir + 'include'
|
78
|
+
|
79
|
+
self.postgresql_global_makefile = static_postgresql_srcdir + 'Makefile.global'
|
80
|
+
self.postgresql_shlib_makefile = static_postgresql_srcdir + 'Makefile.shlib'
|
81
|
+
self.postgresql_shlib_mf_orig = static_postgresql_srcdir + 'Makefile.shlib.orig'
|
82
|
+
self.postgresql_lib = static_postgresql_libdir + 'libpq.dll'
|
83
|
+
self.postgresql_patches = Rake::FileList[ (MISCDIR + "postgresql-#{postgresql_version}.*.patch").to_s ]
|
84
|
+
|
85
|
+
# clean intermediate files and folders
|
86
|
+
CLEAN.include( static_builddir.to_s )
|
87
|
+
|
88
|
+
#####################################################################
|
89
|
+
### C R O S S - C O M P I L A T I O N - T A S K S
|
90
|
+
#####################################################################
|
91
|
+
|
92
|
+
|
93
|
+
directory static_sourcesdir.to_s
|
94
|
+
|
95
|
+
#
|
96
|
+
# Static OpenSSL build tasks
|
97
|
+
#
|
98
|
+
directory static_openssl_builddir.to_s
|
99
|
+
|
100
|
+
# openssl source file should be stored there
|
101
|
+
file openssl_tarball => static_sourcesdir do |t|
|
102
|
+
download( openssl_source_uri, t.name )
|
103
|
+
end
|
104
|
+
|
105
|
+
# Extract the openssl builds
|
106
|
+
file static_openssl_builddir => openssl_tarball do |t|
|
107
|
+
puts "extracting %s to %s" % [ openssl_tarball, static_openssl_builddir.parent ]
|
108
|
+
static_openssl_builddir.mkpath
|
109
|
+
run 'tar', '-xzf', openssl_tarball.to_s, '-C', static_openssl_builddir.parent.to_s
|
110
|
+
openssl_makefile.unlink if openssl_makefile.exist?
|
111
|
+
|
112
|
+
openssl_patches.each do |patchfile|
|
113
|
+
puts " applying patch #{patchfile}..."
|
114
|
+
run 'patch', '-Np1', '-d', static_openssl_builddir.to_s,
|
115
|
+
'-i', File.expand_path( patchfile, BASEDIR )
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
self.cmd_prelude = [
|
120
|
+
"env",
|
121
|
+
"CROSS_COMPILE=#{host_platform}-",
|
122
|
+
"CFLAGS=-DDSO_WIN32",
|
123
|
+
]
|
124
|
+
|
125
|
+
|
126
|
+
# generate the makefile in a clean build location
|
127
|
+
file openssl_makefile => static_openssl_builddir do |t|
|
128
|
+
chdir( static_openssl_builddir ) do
|
129
|
+
cmd = cmd_prelude.dup
|
130
|
+
cmd << "./Configure" << openssl_config
|
131
|
+
|
132
|
+
run( *cmd )
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
desc "compile static openssl libraries"
|
137
|
+
task "openssl_libs:#{for_platform}" => [ libssl, libcrypto ]
|
138
|
+
|
139
|
+
task "compile_static_openssl:#{for_platform}" => openssl_makefile do |t|
|
140
|
+
chdir( static_openssl_builddir ) do
|
141
|
+
cmd = cmd_prelude.dup
|
142
|
+
cmd << 'make' << "-j#{NUM_CPUS}" << 'build_libs'
|
143
|
+
|
144
|
+
run( *cmd )
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
148
|
+
desc "compile static #{libssl}"
|
149
|
+
file libssl => "compile_static_openssl:#{for_platform}" do |t|
|
150
|
+
rm t.name.gsub(/\.a$/, ".dll.a")
|
151
|
+
end
|
152
|
+
|
153
|
+
desc "compile static #{libcrypto}"
|
154
|
+
file libcrypto => "compile_static_openssl:#{for_platform}" do |t|
|
155
|
+
rm t.name.gsub(/\.a$/, ".dll.a")
|
156
|
+
end
|
157
|
+
|
158
|
+
|
159
|
+
|
160
|
+
#
|
161
|
+
# Static PostgreSQL build tasks
|
162
|
+
#
|
163
|
+
directory static_postgresql_builddir.to_s
|
164
|
+
|
165
|
+
|
166
|
+
# postgresql source file should be stored there
|
167
|
+
file postgresql_tarball => static_sourcesdir do |t|
|
168
|
+
download( postgresql_source_uri, t.name )
|
169
|
+
end
|
170
|
+
|
171
|
+
# Extract the postgresql sources
|
172
|
+
file static_postgresql_builddir => postgresql_tarball do |t|
|
173
|
+
puts "extracting %s to %s" % [ postgresql_tarball, static_postgresql_builddir.parent ]
|
174
|
+
static_postgresql_builddir.mkpath
|
175
|
+
run 'tar', '-xjf', postgresql_tarball.to_s, '-C', static_postgresql_builddir.parent.to_s
|
176
|
+
|
177
|
+
postgresql_patches.each do |patchfile|
|
178
|
+
puts " applying patch #{patchfile}..."
|
179
|
+
run 'patch', '-Np1', '-d', static_postgresql_builddir.to_s,
|
180
|
+
'-i', File.expand_path( patchfile, BASEDIR )
|
181
|
+
end
|
182
|
+
end
|
183
|
+
|
184
|
+
# generate the makefile in a clean build location
|
185
|
+
file postgresql_global_makefile => [ static_postgresql_builddir, "openssl_libs:#{for_platform}" ] do |t|
|
186
|
+
options = [
|
187
|
+
"--target=#{host_platform}",
|
188
|
+
"--host=#{host_platform}",
|
189
|
+
'--with-openssl',
|
190
|
+
'--without-zlib',
|
191
|
+
]
|
192
|
+
|
193
|
+
chdir( static_postgresql_builddir ) do
|
194
|
+
configure_path = static_postgresql_builddir + 'configure'
|
195
|
+
cmd = [ configure_path.to_s, *options ]
|
196
|
+
cmd << "CFLAGS=-L#{static_openssl_builddir}"
|
197
|
+
cmd << "LDFLAGS=-L#{static_openssl_builddir}"
|
198
|
+
cmd << "LDFLAGS_SL=-L#{static_openssl_builddir}"
|
199
|
+
cmd << "LIBS=-lwsock32 -lgdi32 -lws2_32"
|
200
|
+
cmd << "CPPFLAGS=-I#{static_openssl_builddir}/include"
|
201
|
+
|
202
|
+
run( *cmd )
|
203
|
+
end
|
204
|
+
end
|
205
|
+
|
206
|
+
|
207
|
+
# make libpq.dll
|
208
|
+
task postgresql_lib => [ postgresql_global_makefile ] do |t|
|
209
|
+
# Work around missing dependency to libcommon in PostgreSQL-9.4.0
|
210
|
+
chdir( static_postgresql_srcdir + "common" ) do
|
211
|
+
sh 'make', "-j#{NUM_CPUS}"
|
212
|
+
end
|
213
|
+
chdir( static_postgresql_srcdir + "port" ) do
|
214
|
+
sh 'make', "-j#{NUM_CPUS}"
|
215
|
+
end
|
216
|
+
|
217
|
+
chdir( postgresql_lib.dirname ) do
|
218
|
+
sh 'make',
|
219
|
+
"-j#{NUM_CPUS}",
|
220
|
+
postgresql_lib.basename.to_s,
|
221
|
+
'SHLIB_LINK=-lssl -lcrypto -lcrypt32 -lgdi32 -lsecur32 -lwsock32 -lws2_32'
|
222
|
+
end
|
223
|
+
end
|
224
|
+
|
225
|
+
|
226
|
+
#desc 'compile libpg.a'
|
227
|
+
task "native:#{for_platform}" => postgresql_lib
|
228
|
+
|
229
|
+
# copy libpq.dll to lib dir
|
230
|
+
dest_libpq = "lib/#{for_platform}/#{postgresql_lib.basename}"
|
231
|
+
directory File.dirname(dest_libpq)
|
232
|
+
file dest_libpq => [postgresql_lib, File.dirname(dest_libpq)] do
|
233
|
+
cp postgresql_lib, dest_libpq
|
234
|
+
end
|
235
|
+
|
236
|
+
stage_libpq = "tmp/#{for_platform}/stage/#{dest_libpq}"
|
237
|
+
directory File.dirname(stage_libpq)
|
238
|
+
file stage_libpq => [postgresql_lib, File.dirname(stage_libpq)] do |t|
|
239
|
+
cp postgresql_lib, stage_libpq
|
240
|
+
end
|
241
|
+
end
|
242
|
+
|
243
|
+
def download(url, save_to)
|
244
|
+
part = save_to+".part"
|
245
|
+
sh "wget #{url.to_s.inspect} -O #{part.inspect} || curl #{url.to_s.inspect} -o #{part.inspect}"
|
246
|
+
FileUtils.mv part, save_to
|
247
|
+
end
|
248
|
+
|
249
|
+
def run(*args)
|
250
|
+
sh(*args)
|
251
|
+
end
|
252
|
+
end
|
253
|
+
|
254
|
+
CrossLibraries = [
|
255
|
+
['x64-mingw-ucrt', 'mingw64', 'x86_64-w64-mingw32'],
|
256
|
+
['x86-mingw32', 'mingw', 'i686-w64-mingw32'],
|
257
|
+
['x64-mingw32', 'mingw64', 'x86_64-w64-mingw32'],
|
258
|
+
].map do |platform, openssl_config, toolchain|
|
259
|
+
CrossLibrary.new platform, openssl_config, toolchain
|
260
|
+
end
|
261
|
+
|
262
|
+
desc 'cross compile pg for win32'
|
263
|
+
task :cross => [ :mingw32 ]
|
264
|
+
|
265
|
+
task :mingw32 do
|
266
|
+
# Use Rake::ExtensionCompiler helpers to find the proper host
|
267
|
+
unless Rake::ExtensionCompiler.mingw_host then
|
268
|
+
warn "You need to install mingw32 cross compile functionality to be able to continue."
|
269
|
+
warn "Please refer to your distribution/package manager documentation about installation."
|
270
|
+
fail
|
271
|
+
end
|
272
|
+
end
|
273
|
+
|
274
|
+
task 'gem:windows:prepare' do
|
275
|
+
require 'io/console'
|
276
|
+
require 'rake_compiler_dock'
|
277
|
+
|
278
|
+
# Copy gem signing key and certs to be accessible from the docker container
|
279
|
+
mkdir_p 'build/gem'
|
280
|
+
sh "cp ~/.gem/gem-*.pem build/gem/ || true"
|
281
|
+
sh "bundle package"
|
282
|
+
begin
|
283
|
+
OpenSSL::PKey.read(File.read(File.expand_path("~/.gem/gem-private_key.pem")), ENV["GEM_PRIVATE_KEY_PASSPHRASE"] || "")
|
284
|
+
rescue OpenSSL::PKey::PKeyError
|
285
|
+
ENV["GEM_PRIVATE_KEY_PASSPHRASE"] = STDIN.getpass("Enter passphrase of gem signature key: ")
|
286
|
+
retry
|
287
|
+
end
|
288
|
+
end
|
289
|
+
|
290
|
+
CrossLibraries.each do |xlib|
|
291
|
+
platform = xlib.for_platform
|
292
|
+
desc "Build fat binary gem for platform #{platform}"
|
293
|
+
task "gem:windows:#{platform}" => ['gem:windows:prepare', xlib.openssl_tarball, xlib.postgresql_tarball] do
|
294
|
+
RakeCompilerDock.sh <<-EOT, platform: platform
|
295
|
+
(cp build/gem/gem-*.pem ~/.gem/ || true) &&
|
296
|
+
bundle install --local &&
|
297
|
+
rake native:#{platform} pkg/#{$gem_spec.full_name}-#{platform}.gem MAKE="make -j`nproc`" RUBY_CC_VERSION=3.1.0:3.0.0:2.7.0:2.6.0:2.5.0
|
298
|
+
EOT
|
299
|
+
end
|
300
|
+
desc "Build the windows binary gems"
|
301
|
+
multitask 'gem:windows' => "gem:windows:#{platform}"
|
302
|
+
end
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
1.3.4
|
data/certs/ged.pem
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
-----BEGIN CERTIFICATE-----
|
2
|
+
MIID+DCCAmCgAwIBAgIBBDANBgkqhkiG9w0BAQsFADAiMSAwHgYDVQQDDBdnZWQv
|
3
|
+
REM9RmFlcmllTVVEL0RDPW9yZzAeFw0yMjAxMDcyMzU4MTRaFw0yMzAxMDcyMzU4
|
4
|
+
MTRaMCIxIDAeBgNVBAMMF2dlZC9EQz1GYWVyaWVNVUQvREM9b3JnMIIBojANBgkq
|
5
|
+
hkiG9w0BAQEFAAOCAY8AMIIBigKCAYEAvyVhkRzvlEs0fe7145BYLfN6njX9ih5H
|
6
|
+
L60U0p0euIurpv84op9CNKF9tx+1WKwyQvQP7qFGuZxkSUuWcP/sFhDXL1lWUuIl
|
7
|
+
M4uHbGCRmOshDrF4dgnBeOvkHr1fIhPlJm5FO+Vew8tSQmlDsosxLUx+VB7DrVFO
|
8
|
+
5PU2AEbf04GGSrmqADGWXeaslaoRdb1fu/0M5qfPTRn5V39sWD9umuDAF9qqil/x
|
9
|
+
Sl6phTvgBrG8GExHbNZpLARd3xrBYLEFsX7RvBn2UPfgsrtvpdXjsHGfpT3IPN+B
|
10
|
+
vQ66lts4alKC69TE5cuKasWBm+16A4aEe3XdZBRNmtOu/g81gvwA7fkJHKllJuaI
|
11
|
+
dXzdHqq+zbGZVSQ7pRYHYomD0IiDe1DbIouFnPWmagaBnGHwXkDT2bKKP+s2v21m
|
12
|
+
ozilJg4aar2okb/RA6VS87o+d7g6LpDDMMQjH4G9OPnJENLdhu8KnPw/ivSVvQw7
|
13
|
+
N2I4L/ZOIe2DIVuYH7aLHfjZDQv/mNgpAgMBAAGjOTA3MAkGA1UdEwQCMAAwCwYD
|
14
|
+
VR0PBAQDAgSwMB0GA1UdDgQWBBRyjf55EbrHagiRLqt5YAd3yb8k4DANBgkqhkiG
|
15
|
+
9w0BAQsFAAOCAYEASrm1AbEoxACZ9WXJH3R5axV3U0CA4xaETlL2YT+2nOfVBMQ9
|
16
|
+
0ZlkPx6j4ghKJgAIi1TMfDM2JyPJsppQh8tiNccDjWc62UZRY/dq26cMqf/lcI+a
|
17
|
+
6YBuEYvzZfearwVs8tHnXtwYV3WSCoCOQaB+nq2lA1O+nkKNl41WOsVbNama5jx3
|
18
|
+
8cQtVSEEmZy6jIDJ8c5TmBJ7BQUDEUEWA/A3V42Xyctoj7DvUXWE0lP+X6ypAVSr
|
19
|
+
lFh3TS64D7NTvxkmg7natUoCvobl6kGl4yMaqE4YRTlfuzhpf91TSOntClqrAOsS
|
20
|
+
K1s56WndQj3IoBocdY9mQhDZLtLHofSkymoP8btBlj5SsN24TiF0VMSZlctSCYZg
|
21
|
+
GKyHim/MMlIfGOWsgfioq5jzwmql7W4CDubbb8Lkg70v+hN2E/MnNVAcNE3gyaGc
|
22
|
+
P5YP5BAbNW+gvd3QHRiWTTuhgHrdDnGdXg93N2M5KHn1ug8BtPLQwlcFwEpKnlLn
|
23
|
+
btEP+7EplFuoiMfd
|
24
|
+
-----END CERTIFICATE-----
|
@@ -0,0 +1,26 @@
|
|
1
|
+
-----BEGIN CERTIFICATE-----
|
2
|
+
MIIETTCCArWgAwIBAgIBATANBgkqhkiG9w0BAQsFADAoMSYwJAYDVQQDDB1sYXJz
|
3
|
+
L0RDPWdyZWl6LXJlaW5zZG9yZi9EQz1kZTAeFw0yMjAyMTQxMzMwNTZaFw0yMzAy
|
4
|
+
MTQxMzMwNTZaMCgxJjAkBgNVBAMMHWxhcnMvREM9Z3JlaXotcmVpbnNkb3JmL0RD
|
5
|
+
PWRlMIIBojANBgkqhkiG9w0BAQEFAAOCAY8AMIIBigKCAYEAwum6Y1KznfpzXOT/
|
6
|
+
mZgJTBbxZuuZF49Fq3K0WA67YBzNlDv95qzSp7V/7Ek3NCcnT7G+2kSuhNo1FhdN
|
7
|
+
eSDO/moYebZNAcu3iqLsuzuULXPLuoU0GsMnVMqV9DZPh7cQHE5EBZ7hlzDBK7k/
|
8
|
+
8nBMvR0mHo77kIkapHc26UzVq/G0nKLfDsIHXVylto3PjzOumjG6GhmFN4r3cP6e
|
9
|
+
SDfl1FSeRYVpt4kmQULz/zdSaOH3AjAq7PM2Z91iGwQvoUXMANH2v89OWjQO/NHe
|
10
|
+
JMNDFsmHK/6Ji4Kk48Z3TyscHQnipAID5GhS1oD21/WePdj7GhmbF5gBzkV5uepd
|
11
|
+
eJQPgWGwrQW/Z2oPjRuJrRofzWfrMWqbOahj9uth6WSxhNexUtbjk6P8emmXOJi5
|
12
|
+
chQPnWX+N3Gj+jjYxqTFdwT7Mj3pv1VHa+aNUbqSPpvJeDyxRIuo9hvzDaBHb/Cg
|
13
|
+
9qRVcm8a96n4t7y2lrX1oookY6bkBaxWOMtWlqIprq8JZXM9AgMBAAGjgYEwfzAJ
|
14
|
+
BgNVHRMEAjAAMAsGA1UdDwQEAwIEsDAdBgNVHQ4EFgQUOIdbSMr3VFrTCO9/cTM0
|
15
|
+
0exHzBcwIgYDVR0RBBswGYEXbGFyc0BncmVpei1yZWluc2RvcmYuZGUwIgYDVR0S
|
16
|
+
BBswGYEXbGFyc0BncmVpei1yZWluc2RvcmYuZGUwDQYJKoZIhvcNAQELBQADggGB
|
17
|
+
AFWP7F/y3Oq3NgrqUOnjKOeDaBa7AqNhHS+PZg+C90lnJzMgOs4KKgZYxqSQVSab
|
18
|
+
SCEmzIO/StkXY4NpJ4fYLrHemf/fJy1wPyu+fNdp5SEEUwEo+2toRFlzTe4u4LdS
|
19
|
+
QC636nPPTMt8H3xz2wf/lUIUeo2Qc95Qt2BQM465ibbG9kmA3c7Sopx6yOabYOAl
|
20
|
+
KPRbOSEPiWYcF9Suuz8Gdf8jxEtPlnZiwRvnYJ+IHMq3XQCJWPpMzdDMbtlgHbXE
|
21
|
+
vq1zOTLMSYAS0UB3uionR4yo1hLz60odwkCm7qf0o2Ci/5OjtB0a89VuyqRU2vUJ
|
22
|
+
QH95WBjDJ6lCCW7J0mrMPnJQSUFTmufsU6jOChvPaCeAzW1YwrsP/YKnvwueG7ip
|
23
|
+
VOdW6RitjtFxhS7evRL0201+KUvLz12zZWWjOcujlQs64QprxOtiv/MiisKb1Ng+
|
24
|
+
oL1mUdzB8KrZL4/WbG5YNX6UTtJbIOu9qEFbBAy4/jtIkJX+dlNoFwd4GXQW1YNO
|
25
|
+
nA==
|
26
|
+
-----END CERTIFICATE-----
|
@@ -0,0 +1,47 @@
|
|
1
|
+
# -*- ruby -*-
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
require 'pg' unless defined?( PG )
|
5
|
+
|
6
|
+
# Simple set of rules for type casting common PostgreSQL types from Ruby
|
7
|
+
# to PostgreSQL.
|
8
|
+
#
|
9
|
+
# OIDs of supported type casts are not hard-coded in the sources, but are retrieved from the
|
10
|
+
# PostgreSQL's +pg_type+ table in PG::BasicTypeMapBasedOnResult.new .
|
11
|
+
#
|
12
|
+
# This class works equal to PG::BasicTypeMapForResults, but does not define decoders for
|
13
|
+
# the given result OIDs, but encoders. So it can be used to type cast field values based on
|
14
|
+
# the type OID retrieved by a separate SQL query.
|
15
|
+
#
|
16
|
+
# PG::TypeMapByOid#build_column_map(result) can be used to generate a result independent
|
17
|
+
# PG::TypeMapByColumn type map, which can subsequently be used to cast query bind parameters
|
18
|
+
# or #put_copy_data fields.
|
19
|
+
#
|
20
|
+
# Example:
|
21
|
+
# conn.exec( "CREATE TEMP TABLE copytable (t TEXT, i INT, ai INT[])" )
|
22
|
+
#
|
23
|
+
# # Retrieve table OIDs per empty result set.
|
24
|
+
# res = conn.exec( "SELECT * FROM copytable LIMIT 0" )
|
25
|
+
# # Build a type map for common ruby to database type encoders.
|
26
|
+
# btm = PG::BasicTypeMapBasedOnResult.new(conn)
|
27
|
+
# # Build a PG::TypeMapByColumn with encoders suitable for copytable.
|
28
|
+
# tm = btm.build_column_map( res )
|
29
|
+
# row_encoder = PG::TextEncoder::CopyRow.new type_map: tm
|
30
|
+
#
|
31
|
+
# conn.copy_data( "COPY copytable FROM STDIN", row_encoder ) do |res|
|
32
|
+
# conn.put_copy_data ['a', 123, [5,4,3]]
|
33
|
+
# end
|
34
|
+
# This inserts a single row into copytable with type casts from ruby to
|
35
|
+
# database types.
|
36
|
+
class PG::BasicTypeMapBasedOnResult < PG::TypeMapByOid
|
37
|
+
include PG::BasicTypeRegistry::Checker
|
38
|
+
|
39
|
+
def initialize(connection_or_coder_maps, registry: nil)
|
40
|
+
@coder_maps = build_coder_maps(connection_or_coder_maps, registry: registry)
|
41
|
+
|
42
|
+
# Populate TypeMapByOid hash with encoders
|
43
|
+
@coder_maps.each_format(:encoder).flat_map{|f| f.coders }.each do |coder|
|
44
|
+
add_coder(coder)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,193 @@
|
|
1
|
+
# -*- ruby -*-
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
require 'pg' unless defined?( PG )
|
5
|
+
|
6
|
+
# Simple set of rules for type casting common Ruby types to PostgreSQL.
|
7
|
+
#
|
8
|
+
# OIDs of supported type casts are not hard-coded in the sources, but are retrieved from the
|
9
|
+
# PostgreSQL's pg_type table in PG::BasicTypeMapForQueries.new .
|
10
|
+
#
|
11
|
+
# Query params are type casted based on the class of the given value.
|
12
|
+
#
|
13
|
+
# Higher level libraries will most likely not make use of this class, but use their
|
14
|
+
# own derivation of PG::TypeMapByClass or another set of rules to choose suitable
|
15
|
+
# encoders and decoders for the values to be sent.
|
16
|
+
#
|
17
|
+
# Example:
|
18
|
+
# conn = PG::Connection.new
|
19
|
+
# # Assign a default ruleset for type casts of input and output values.
|
20
|
+
# conn.type_map_for_queries = PG::BasicTypeMapForQueries.new(conn)
|
21
|
+
# # Execute a query. The Integer param value is typecasted internally by PG::BinaryEncoder::Int8.
|
22
|
+
# # The format of the parameter is set to 0 (text) and the OID of this parameter is set to 20 (int8).
|
23
|
+
# res = conn.exec_params( "SELECT $1", [5] )
|
24
|
+
class PG::BasicTypeMapForQueries < PG::TypeMapByClass
|
25
|
+
# Helper class for submission of binary strings into bytea columns.
|
26
|
+
#
|
27
|
+
# Since PG::BasicTypeMapForQueries chooses the encoder to be used by the class of the submitted value,
|
28
|
+
# it's necessary to send binary strings as BinaryData.
|
29
|
+
# That way they're distinct from text strings.
|
30
|
+
# Please note however that PG::BasicTypeMapForResults delivers bytea columns as plain String
|
31
|
+
# with binary encoding.
|
32
|
+
#
|
33
|
+
# conn.type_map_for_queries = PG::BasicTypeMapForQueries.new(conn)
|
34
|
+
# conn.exec("CREATE TEMP TABLE test (data bytea)")
|
35
|
+
# bd = PG::BasicTypeMapForQueries::BinaryData.new("ab\xff\0cd")
|
36
|
+
# conn.exec_params("INSERT INTO test (data) VALUES ($1)", [bd])
|
37
|
+
class BinaryData < String
|
38
|
+
end
|
39
|
+
|
40
|
+
class UndefinedEncoder < RuntimeError
|
41
|
+
end
|
42
|
+
|
43
|
+
include PG::BasicTypeRegistry::Checker
|
44
|
+
|
45
|
+
# Create a new type map for query submission
|
46
|
+
#
|
47
|
+
# Options:
|
48
|
+
# * +registry+: Custom type registry, nil for default global registry
|
49
|
+
# * +if_undefined+: Optional +Proc+ object which is called, if no type for an parameter class is not defined in the registry.
|
50
|
+
def initialize(connection_or_coder_maps, registry: nil, if_undefined: nil)
|
51
|
+
@coder_maps = build_coder_maps(connection_or_coder_maps, registry: registry)
|
52
|
+
@array_encoders_by_klass = array_encoders_by_klass
|
53
|
+
@encode_array_as = :array
|
54
|
+
@if_undefined = if_undefined || proc { |oid_name, format|
|
55
|
+
raise UndefinedEncoder, "no encoder defined for type #{oid_name.inspect} format #{format}"
|
56
|
+
}
|
57
|
+
init_encoders
|
58
|
+
end
|
59
|
+
|
60
|
+
# Change the mechanism that is used to encode ruby array values
|
61
|
+
#
|
62
|
+
# Possible values:
|
63
|
+
# * +:array+ : Encode the ruby array as a PostgreSQL array.
|
64
|
+
# The array element type is inferred from the class of the first array element. This is the default.
|
65
|
+
# * +:json+ : Encode the ruby array as a JSON document.
|
66
|
+
# * +:record+ : Encode the ruby array as a composite type row.
|
67
|
+
# * <code>"_type"</code> : Encode the ruby array as a particular PostgreSQL type.
|
68
|
+
# All PostgreSQL array types are supported.
|
69
|
+
# If there's an encoder registered for the elements +type+, it will be used.
|
70
|
+
# Otherwise a string conversion (by +value.to_s+) is done.
|
71
|
+
def encode_array_as=(pg_type)
|
72
|
+
case pg_type
|
73
|
+
when :array
|
74
|
+
when :json
|
75
|
+
when :record
|
76
|
+
when /\A_/
|
77
|
+
else
|
78
|
+
raise ArgumentError, "invalid pg_type #{pg_type.inspect}"
|
79
|
+
end
|
80
|
+
|
81
|
+
@encode_array_as = pg_type
|
82
|
+
|
83
|
+
init_encoders
|
84
|
+
end
|
85
|
+
|
86
|
+
attr_reader :encode_array_as
|
87
|
+
|
88
|
+
private
|
89
|
+
|
90
|
+
def init_encoders
|
91
|
+
coders.each { |kl, c| self[kl] = nil } # Clear type map
|
92
|
+
populate_encoder_list
|
93
|
+
@textarray_encoder = coder_by_name(0, :encoder, '_text')
|
94
|
+
end
|
95
|
+
|
96
|
+
def coder_by_name(format, direction, name)
|
97
|
+
check_format_and_direction(format, direction)
|
98
|
+
@coder_maps.map_for(format, direction).coder_by_name(name)
|
99
|
+
end
|
100
|
+
|
101
|
+
def undefined(name, format)
|
102
|
+
@if_undefined.call(name, format)
|
103
|
+
end
|
104
|
+
|
105
|
+
def populate_encoder_list
|
106
|
+
DEFAULT_TYPE_MAP.each do |klass, selector|
|
107
|
+
if Array === selector
|
108
|
+
format, name, oid_name = selector
|
109
|
+
coder = coder_by_name(format, :encoder, name).dup
|
110
|
+
if coder
|
111
|
+
if oid_name
|
112
|
+
oid_coder = coder_by_name(format, :encoder, oid_name)
|
113
|
+
if oid_coder
|
114
|
+
coder.oid = oid_coder.oid
|
115
|
+
else
|
116
|
+
undefined(oid_name, format)
|
117
|
+
end
|
118
|
+
else
|
119
|
+
coder.oid = 0
|
120
|
+
end
|
121
|
+
self[klass] = coder
|
122
|
+
else
|
123
|
+
undefined(name, format)
|
124
|
+
end
|
125
|
+
else
|
126
|
+
|
127
|
+
case @encode_array_as
|
128
|
+
when :array
|
129
|
+
self[klass] = selector
|
130
|
+
when :json
|
131
|
+
self[klass] = PG::TextEncoder::JSON.new
|
132
|
+
when :record
|
133
|
+
self[klass] = PG::TextEncoder::Record.new type_map: self
|
134
|
+
when /\A_/
|
135
|
+
coder = coder_by_name(0, :encoder, @encode_array_as)
|
136
|
+
if coder
|
137
|
+
self[klass] = coder
|
138
|
+
else
|
139
|
+
undefined(@encode_array_as, format)
|
140
|
+
end
|
141
|
+
else
|
142
|
+
raise ArgumentError, "invalid pg_type #{@encode_array_as.inspect}"
|
143
|
+
end
|
144
|
+
end
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
148
|
+
def array_encoders_by_klass
|
149
|
+
DEFAULT_ARRAY_TYPE_MAP.inject({}) do |h, (klass, (format, name))|
|
150
|
+
h[klass] = coder_by_name(format, :encoder, name)
|
151
|
+
h
|
152
|
+
end
|
153
|
+
end
|
154
|
+
|
155
|
+
def get_array_type(value)
|
156
|
+
elem = value
|
157
|
+
while elem.kind_of?(Array)
|
158
|
+
elem = elem.first
|
159
|
+
end
|
160
|
+
@array_encoders_by_klass[elem.class] ||
|
161
|
+
elem.class.ancestors.lazy.map{|ancestor| @array_encoders_by_klass[ancestor] }.find{|a| a } ||
|
162
|
+
@textarray_encoder
|
163
|
+
end
|
164
|
+
|
165
|
+
DEFAULT_TYPE_MAP = {
|
166
|
+
TrueClass => [1, 'bool', 'bool'],
|
167
|
+
FalseClass => [1, 'bool', 'bool'],
|
168
|
+
# We use text format and no type OID for numbers, because setting the OID can lead
|
169
|
+
# to unnecessary type conversions on server side.
|
170
|
+
Integer => [0, 'int8'],
|
171
|
+
Float => [0, 'float8'],
|
172
|
+
BigDecimal => [0, 'numeric'],
|
173
|
+
Time => [0, 'timestamptz'],
|
174
|
+
# We use text format and no type OID for IPAddr, because setting the OID can lead
|
175
|
+
# to unnecessary inet/cidr conversions on the server side.
|
176
|
+
IPAddr => [0, 'inet'],
|
177
|
+
Hash => [0, 'json'],
|
178
|
+
Array => :get_array_type,
|
179
|
+
BinaryData => [1, 'bytea'],
|
180
|
+
}
|
181
|
+
|
182
|
+
DEFAULT_ARRAY_TYPE_MAP = {
|
183
|
+
TrueClass => [0, '_bool'],
|
184
|
+
FalseClass => [0, '_bool'],
|
185
|
+
Integer => [0, '_int8'],
|
186
|
+
String => [0, '_text'],
|
187
|
+
Float => [0, '_float8'],
|
188
|
+
BigDecimal => [0, '_numeric'],
|
189
|
+
Time => [0, '_timestamptz'],
|
190
|
+
IPAddr => [0, '_inet'],
|
191
|
+
}
|
192
|
+
|
193
|
+
end
|
@@ -0,0 +1,81 @@
|
|
1
|
+
# -*- ruby -*-
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
require 'pg' unless defined?( PG )
|
5
|
+
|
6
|
+
# Simple set of rules for type casting common PostgreSQL types to Ruby.
|
7
|
+
#
|
8
|
+
# OIDs of supported type casts are not hard-coded in the sources, but are retrieved from the
|
9
|
+
# PostgreSQL's +pg_type+ table in PG::BasicTypeMapForResults.new .
|
10
|
+
#
|
11
|
+
# Result values are type casted based on the type OID of the given result column.
|
12
|
+
#
|
13
|
+
# Higher level libraries will most likely not make use of this class, but use their
|
14
|
+
# own set of rules to choose suitable encoders and decoders.
|
15
|
+
#
|
16
|
+
# Example:
|
17
|
+
# conn = PG::Connection.new
|
18
|
+
# # Assign a default ruleset for type casts of output values.
|
19
|
+
# conn.type_map_for_results = PG::BasicTypeMapForResults.new(conn)
|
20
|
+
# # Execute a query.
|
21
|
+
# res = conn.exec_params( "SELECT $1::INT", ['5'] )
|
22
|
+
# # Retrieve and cast the result value. Value format is 0 (text) and OID is 20. Therefore typecasting
|
23
|
+
# # is done by PG::TextDecoder::Integer internally for all value retrieval methods.
|
24
|
+
# res.values # => [[5]]
|
25
|
+
#
|
26
|
+
# PG::TypeMapByOid#build_column_map(result) can be used to generate
|
27
|
+
# a result independent PG::TypeMapByColumn type map, which can subsequently be used
|
28
|
+
# to cast #get_copy_data fields:
|
29
|
+
#
|
30
|
+
# For the following table:
|
31
|
+
# conn.exec( "CREATE TABLE copytable AS VALUES('a', 123, '{5,4,3}'::INT[])" )
|
32
|
+
#
|
33
|
+
# # Retrieve table OIDs per empty result set.
|
34
|
+
# res = conn.exec( "SELECT * FROM copytable LIMIT 0" )
|
35
|
+
# # Build a type map for common database to ruby type decoders.
|
36
|
+
# btm = PG::BasicTypeMapForResults.new(conn)
|
37
|
+
# # Build a PG::TypeMapByColumn with decoders suitable for copytable.
|
38
|
+
# tm = btm.build_column_map( res )
|
39
|
+
# row_decoder = PG::TextDecoder::CopyRow.new type_map: tm
|
40
|
+
#
|
41
|
+
# conn.copy_data( "COPY copytable TO STDOUT", row_decoder ) do |res|
|
42
|
+
# while row=conn.get_copy_data
|
43
|
+
# p row
|
44
|
+
# end
|
45
|
+
# end
|
46
|
+
# This prints the rows with type casted columns:
|
47
|
+
# ["a", 123, [5, 4, 3]]
|
48
|
+
#
|
49
|
+
# See also PG::BasicTypeMapBasedOnResult for the encoder direction and PG::BasicTypeRegistry for the definition of additional types.
|
50
|
+
class PG::BasicTypeMapForResults < PG::TypeMapByOid
|
51
|
+
include PG::BasicTypeRegistry::Checker
|
52
|
+
|
53
|
+
class WarningTypeMap < PG::TypeMapInRuby
|
54
|
+
def initialize(typenames)
|
55
|
+
@already_warned = Hash.new{|h, k| h[k] = {} }
|
56
|
+
@typenames_by_oid = typenames
|
57
|
+
end
|
58
|
+
|
59
|
+
def typecast_result_value(result, _tuple, field)
|
60
|
+
format = result.fformat(field)
|
61
|
+
oid = result.ftype(field)
|
62
|
+
unless @already_warned[format][oid]
|
63
|
+
warn "Warning: no type cast defined for type #{@typenames_by_oid[oid].inspect} format #{format} with oid #{oid}. Please cast this type explicitly to TEXT to be safe for future changes."
|
64
|
+
@already_warned[format][oid] = true
|
65
|
+
end
|
66
|
+
super
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
def initialize(connection_or_coder_maps, registry: nil)
|
71
|
+
@coder_maps = build_coder_maps(connection_or_coder_maps, registry: registry)
|
72
|
+
|
73
|
+
# Populate TypeMapByOid hash with decoders
|
74
|
+
@coder_maps.each_format(:decoder).flat_map{|f| f.coders }.each do |coder|
|
75
|
+
add_coder(coder)
|
76
|
+
end
|
77
|
+
|
78
|
+
typenames = @coder_maps.typenames_by_oid
|
79
|
+
self.default_type_map = WarningTypeMap.new(typenames)
|
80
|
+
end
|
81
|
+
end
|