pg 1.5.4 → 1.6.3
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/{History.md → CHANGELOG.md} +132 -4
- data/Gemfile +15 -6
- data/README-Windows.rdoc +1 -1
- data/README.ja.md +4 -4
- data/README.md +66 -23
- data/Rakefile +81 -14
- data/certs/kanis@comcard.de.pem +20 -0
- data/certs/larskanis-2024.pem +24 -0
- data/ext/errorcodes.def +11 -3
- data/ext/errorcodes.rb +1 -1
- data/ext/errorcodes.txt +9 -5
- data/ext/extconf.rb +192 -15
- data/ext/gvl_wrappers.c +13 -2
- data/ext/gvl_wrappers.h +33 -0
- data/ext/pg.c +17 -6
- data/ext/pg.h +15 -13
- data/ext/pg_binary_decoder.c +153 -1
- data/ext/pg_binary_encoder.c +213 -10
- data/ext/pg_cancel_connection.c +360 -0
- data/ext/pg_coder.c +54 -5
- data/ext/pg_connection.c +431 -169
- data/ext/pg_copy_coder.c +19 -15
- data/ext/pg_record_coder.c +7 -7
- data/ext/pg_result.c +106 -54
- data/ext/pg_text_decoder.c +5 -2
- data/ext/pg_text_encoder.c +39 -20
- data/ext/pg_tuple.c +8 -8
- data/ext/pg_type_map.c +4 -2
- data/ext/pg_type_map_all_strings.c +1 -1
- data/ext/pg_type_map_by_class.c +1 -1
- data/ext/pg_type_map_by_column.c +2 -1
- data/ext/pg_type_map_by_mri_type.c +1 -1
- data/ext/pg_type_map_by_oid.c +3 -1
- data/ext/pg_type_map_in_ruby.c +1 -1
- data/ext/pg_util.c +2 -2
- data/ext/pg_util.h +2 -2
- data/lib/pg/basic_type_map_for_queries.rb +15 -7
- data/lib/pg/basic_type_registry.rb +16 -4
- data/lib/pg/cancel_connection.rb +53 -0
- data/lib/pg/coder.rb +4 -2
- data/lib/pg/connection.rb +310 -167
- data/lib/pg/exceptions.rb +6 -0
- data/lib/pg/text_decoder/date.rb +3 -0
- data/lib/pg/text_decoder/json.rb +3 -0
- data/lib/pg/text_encoder/date.rb +1 -0
- data/lib/pg/text_encoder/inet.rb +3 -0
- data/lib/pg/text_encoder/json.rb +3 -0
- data/lib/pg/version.rb +2 -1
- data/lib/pg.rb +156 -120
- data/misc/glibc/Dockerfile +20 -0
- data/misc/glibc/docker-compose.yml +9 -0
- data/misc/glibc/glibc_spec.rb +5 -0
- data/misc/yugabyte/Dockerfile +9 -0
- data/misc/yugabyte/docker-compose.yml +28 -0
- data/misc/yugabyte/pg-test.rb +45 -0
- data/pg.gemspec +8 -4
- data/ports/patches/krb5/1.22.1/0001-Allow-static-linking-krb5-library.patch +30 -0
- data/ports/patches/krb5/1.22.1/0002-unknown-command-line-option-on-clang.patch +12 -0
- data/ports/patches/openssl/3.5.2/0001-aarch64-mingw.patch +21 -0
- data/ports/patches/postgresql/18.1/0001-Use-workaround-of-__builtin_setjmp-only-on-MINGW-on-.patch +42 -0
- data/ports/patches/postgresql/18.1/0001-libpq-Process-buffered-SSL-read-bytes-to-support-rec.patch +52 -0
- data/rakelib/pg_gem_helper.rb +64 -0
- data.tar.gz.sig +0 -0
- metadata +49 -47
- metadata.gz.sig +0 -0
- data/.appveyor.yml +0 -42
- data/.gems +0 -6
- data/.gemtest +0 -0
- data/.github/workflows/binary-gems.yml +0 -117
- data/.github/workflows/source-gem.yml +0 -141
- data/.gitignore +0 -22
- data/.hgsigs +0 -34
- data/.hgtags +0 -41
- data/.irbrc +0 -23
- data/.pryrc +0 -23
- data/.tm_properties +0 -21
- data/.travis.yml +0 -49
- data/Manifest.txt +0 -72
- data/Rakefile.cross +0 -298
- data/translation/.po4a-version +0 -7
- data/translation/po/all.pot +0 -936
- data/translation/po/ja.po +0 -1036
- data/translation/po4a.cfg +0 -12
data/ext/errorcodes.def
CHANGED
|
@@ -87,6 +87,11 @@
|
|
|
87
87
|
VALUE klass = define_error_class( "StackedDiagnosticsAccessedWithoutActiveHandler", "0Z" );
|
|
88
88
|
register_error_class( "0Z002", klass );
|
|
89
89
|
}
|
|
90
|
+
{
|
|
91
|
+
VALUE klass = define_error_class( "InvalidArgumentForXquery", NULL );
|
|
92
|
+
register_error_class( "10608", klass );
|
|
93
|
+
register_error_class( "10", klass );
|
|
94
|
+
}
|
|
90
95
|
{
|
|
91
96
|
VALUE klass = define_error_class( "CaseNotFound", NULL );
|
|
92
97
|
register_error_class( "20000", klass );
|
|
@@ -453,6 +458,10 @@
|
|
|
453
458
|
VALUE klass = define_error_class( "IdleInTransactionSessionTimeout", "25" );
|
|
454
459
|
register_error_class( "25P03", klass );
|
|
455
460
|
}
|
|
461
|
+
{
|
|
462
|
+
VALUE klass = define_error_class( "TransactionTimeout", "25" );
|
|
463
|
+
register_error_class( "25P04", klass );
|
|
464
|
+
}
|
|
456
465
|
{
|
|
457
466
|
VALUE klass = define_error_class( "InvalidSqlStatementName", NULL );
|
|
458
467
|
register_error_class( "26000", klass );
|
|
@@ -886,9 +895,8 @@
|
|
|
886
895
|
register_error_class( "58P02", klass );
|
|
887
896
|
}
|
|
888
897
|
{
|
|
889
|
-
VALUE klass = define_error_class( "
|
|
890
|
-
register_error_class( "
|
|
891
|
-
register_error_class( "72", klass );
|
|
898
|
+
VALUE klass = define_error_class( "FileNameTooLong", "58" );
|
|
899
|
+
register_error_class( "58P03", klass );
|
|
892
900
|
}
|
|
893
901
|
{
|
|
894
902
|
VALUE klass = define_error_class( "ConfigFileError", NULL );
|
data/ext/errorcodes.rb
CHANGED
|
@@ -28,7 +28,7 @@ EOCODE
|
|
|
28
28
|
sqlstate, ews, errcode_macro_name = $1, $2, $3
|
|
29
29
|
next unless ews=='E'
|
|
30
30
|
|
|
31
|
-
is_sqlclass = sqlstate[2..-1] == '000'
|
|
31
|
+
is_sqlclass = sqlstate[2..-1] == '000' || sqlstate == '10608'
|
|
32
32
|
class_code = sqlstate[0,2]
|
|
33
33
|
baseclass_code = is_sqlclass ? 'NULL' : class_code.inspect
|
|
34
34
|
class_name = camelize(errcode_macro_name.sub('ERRCODE_', '').downcase)
|
data/ext/errorcodes.txt
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
# errcodes.txt
|
|
3
3
|
# PostgreSQL error codes
|
|
4
4
|
#
|
|
5
|
-
# Copyright (c) 2003-
|
|
5
|
+
# Copyright (c) 2003-2025, PostgreSQL Global Development Group
|
|
6
6
|
#
|
|
7
7
|
# This list serves as the basis for generating source files containing error
|
|
8
8
|
# codes. It is kept in a common format to make sure all these source files have
|
|
@@ -141,6 +141,12 @@ Section: Class 0Z - Diagnostics Exception
|
|
|
141
141
|
0Z000 E ERRCODE_DIAGNOSTICS_EXCEPTION diagnostics_exception
|
|
142
142
|
0Z002 E ERRCODE_STACKED_DIAGNOSTICS_ACCESSED_WITHOUT_ACTIVE_HANDLER stacked_diagnostics_accessed_without_active_handler
|
|
143
143
|
|
|
144
|
+
Section: Class 10 - XQuery Error
|
|
145
|
+
|
|
146
|
+
# recent SQL versions define quite a few codes in this class, but for now
|
|
147
|
+
# we are only using this generic one
|
|
148
|
+
10608 E ERRCODE_INVALID_ARGUMENT_FOR_XQUERY invalid_argument_for_xquery
|
|
149
|
+
|
|
144
150
|
Section: Class 20 - Case Not Found
|
|
145
151
|
|
|
146
152
|
20000 E ERRCODE_CASE_NOT_FOUND case_not_found
|
|
@@ -252,6 +258,7 @@ Section: Class 25 - Invalid Transaction State
|
|
|
252
258
|
25P01 E ERRCODE_NO_ACTIVE_SQL_TRANSACTION no_active_sql_transaction
|
|
253
259
|
25P02 E ERRCODE_IN_FAILED_SQL_TRANSACTION in_failed_sql_transaction
|
|
254
260
|
25P03 E ERRCODE_IDLE_IN_TRANSACTION_SESSION_TIMEOUT idle_in_transaction_session_timeout
|
|
261
|
+
25P04 E ERRCODE_TRANSACTION_TIMEOUT transaction_timeout
|
|
255
262
|
|
|
256
263
|
Section: Class 26 - Invalid SQL Statement Name
|
|
257
264
|
|
|
@@ -438,10 +445,7 @@ Section: Class 58 - System Error (errors external to PostgreSQL itself)
|
|
|
438
445
|
58030 E ERRCODE_IO_ERROR io_error
|
|
439
446
|
58P01 E ERRCODE_UNDEFINED_FILE undefined_file
|
|
440
447
|
58P02 E ERRCODE_DUPLICATE_FILE duplicate_file
|
|
441
|
-
|
|
442
|
-
Section: Class 72 - Snapshot Failure
|
|
443
|
-
# (class borrowed from Oracle)
|
|
444
|
-
72000 E ERRCODE_SNAPSHOT_TOO_OLD snapshot_too_old
|
|
448
|
+
58P03 E ERRCODE_FILE_NAME_TOO_LONG file_name_too_long
|
|
445
449
|
|
|
446
450
|
Section: Class F0 - Configuration File Error
|
|
447
451
|
|
data/ext/extconf.rb
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
require 'pp'
|
|
2
2
|
require 'mkmf'
|
|
3
3
|
|
|
4
|
-
|
|
5
4
|
if ENV['MAINTAINER_MODE']
|
|
6
5
|
$stderr.puts "Maintainer mode enabled."
|
|
7
6
|
$CFLAGS <<
|
|
@@ -9,6 +8,8 @@ if ENV['MAINTAINER_MODE']
|
|
|
9
8
|
' -ggdb' <<
|
|
10
9
|
' -DDEBUG' <<
|
|
11
10
|
' -pedantic'
|
|
11
|
+
$LDFLAGS <<
|
|
12
|
+
' -ggdb'
|
|
12
13
|
end
|
|
13
14
|
|
|
14
15
|
if pgdir = with_config( 'pg' )
|
|
@@ -22,12 +23,175 @@ else
|
|
|
22
23
|
$stderr.puts "Calling libpq with GVL locked"
|
|
23
24
|
end
|
|
24
25
|
|
|
25
|
-
if
|
|
26
|
+
if gem_platform=with_config("cross-build")
|
|
27
|
+
gem 'mini_portile2', '~>2.1'
|
|
28
|
+
require 'mini_portile2'
|
|
29
|
+
|
|
30
|
+
OPENSSL_VERSION = ENV['OPENSSL_VERSION'] || '3.6.0'
|
|
31
|
+
OPENSSL_SOURCE_URI = "http://www.openssl.org/source/openssl-#{OPENSSL_VERSION}.tar.gz"
|
|
32
|
+
|
|
33
|
+
KRB5_VERSION = ENV['KRB5_VERSION'] || '1.22.1'
|
|
34
|
+
KRB5_SOURCE_URI = "http://kerberos.org/dist/krb5/#{KRB5_VERSION[/^(\d+\.\d+)/]}/krb5-#{KRB5_VERSION}.tar.gz"
|
|
35
|
+
|
|
36
|
+
POSTGRESQL_VERSION = ENV['POSTGRESQL_VERSION'] || '18.1'
|
|
37
|
+
POSTGRESQL_SOURCE_URI = "http://ftp.postgresql.org/pub/source/v#{POSTGRESQL_VERSION}/postgresql-#{POSTGRESQL_VERSION}.tar.bz2"
|
|
38
|
+
|
|
39
|
+
class BuildRecipe < MiniPortile
|
|
40
|
+
def initialize(name, version, files)
|
|
41
|
+
super(name, version)
|
|
42
|
+
self.files = files
|
|
43
|
+
rootdir = File.expand_path('../..', __FILE__)
|
|
44
|
+
self.target = File.join(rootdir, "ports")
|
|
45
|
+
self.patch_files = Dir[File.join(target, "patches", self.name, self.version, "*.patch")].sort
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def port_path
|
|
49
|
+
"#{target}/#{RUBY_PLATFORM}"
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
# Add "--prefix=/", to avoid our actual build install path compiled into the binary.
|
|
53
|
+
# Instead use DESTDIR variable of make to set our install path.
|
|
54
|
+
def configure_prefix
|
|
55
|
+
"--prefix="
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def cook_and_activate
|
|
59
|
+
checkpoint = File.join(self.target, "#{self.name}-#{self.version}-#{RUBY_PLATFORM}.installed")
|
|
60
|
+
unless File.exist?(checkpoint)
|
|
61
|
+
self.cook
|
|
62
|
+
FileUtils.touch checkpoint
|
|
63
|
+
end
|
|
64
|
+
self.activate
|
|
65
|
+
self
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
openssl_platform = with_config("openssl-platform")
|
|
70
|
+
toolchain = with_config("toolchain")
|
|
71
|
+
|
|
72
|
+
openssl_recipe = BuildRecipe.new("openssl", OPENSSL_VERSION, [OPENSSL_SOURCE_URI]).tap do |recipe|
|
|
73
|
+
class << recipe
|
|
74
|
+
attr_accessor :openssl_platform
|
|
75
|
+
def configure
|
|
76
|
+
envs = []
|
|
77
|
+
envs << "CFLAGS=-DDSO_WIN32 -DOPENSSL_THREADS" if RUBY_PLATFORM =~ /mingw|mswin/
|
|
78
|
+
envs << "CFLAGS=-fPIC -DOPENSSL_THREADS" if RUBY_PLATFORM =~ /linux|darwin/
|
|
79
|
+
execute('configure', ['env', *envs, "./Configure", openssl_platform, "threads", "-static", "CROSS_COMPILE=#{host}-", "--prefix=/"], altlog: "config.log")
|
|
80
|
+
end
|
|
81
|
+
def compile
|
|
82
|
+
execute('compile', "#{make_cmd} build_libs")
|
|
83
|
+
end
|
|
84
|
+
def install
|
|
85
|
+
execute('install', "#{make_cmd} install_dev DESTDIR=#{path}")
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
recipe.openssl_platform = openssl_platform
|
|
90
|
+
recipe.host = toolchain
|
|
91
|
+
recipe.cook_and_activate
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
if RUBY_PLATFORM =~ /linux|darwin/
|
|
95
|
+
krb5_recipe = BuildRecipe.new("krb5", KRB5_VERSION, [KRB5_SOURCE_URI]).tap do |recipe|
|
|
96
|
+
class << recipe
|
|
97
|
+
def work_path
|
|
98
|
+
File.join(super, "src")
|
|
99
|
+
end
|
|
100
|
+
def configure
|
|
101
|
+
if RUBY_PLATFORM=~/darwin/
|
|
102
|
+
ENV["CC"] = host[/^.*[^\.\d]/] + "-clang"
|
|
103
|
+
ENV["CXX"] = host[/^.*[^\.\d]/] + "-c++"
|
|
104
|
+
|
|
105
|
+
# Manually set the correct values for configure checks that libkrb5 won't be
|
|
106
|
+
# able to perform because we're cross-compiling.
|
|
107
|
+
ENV["krb5_cv_attr_constructor_destructor"] = "yes"
|
|
108
|
+
ENV["ac_cv_func_regcomp"] = "yes"
|
|
109
|
+
ENV["ac_cv_printf_positional"] = "yes"
|
|
110
|
+
end
|
|
111
|
+
super
|
|
112
|
+
end
|
|
113
|
+
def install
|
|
114
|
+
execute('install', "#{make_cmd} install DESTDIR=#{path}")
|
|
115
|
+
end
|
|
116
|
+
end
|
|
117
|
+
# We specify -fcommon to get around duplicate definition errors in recent gcc.
|
|
118
|
+
# See https://github.com/cockroachdb/cockroach/issues/49734
|
|
119
|
+
recipe.configure_options << "CFLAGS=-fcommon#{" -fPIC" if RUBY_PLATFORM =~ /linux/}"
|
|
120
|
+
recipe.configure_options << "LDFLAGS=-framework Kerberos" if RUBY_PLATFORM =~ /darwin/
|
|
121
|
+
recipe.configure_options << "--without-keyutils"
|
|
122
|
+
recipe.configure_options << "--disable-nls"
|
|
123
|
+
recipe.configure_options << "--disable-silent-rules"
|
|
124
|
+
recipe.configure_options << "--disable-rpath"
|
|
125
|
+
recipe.configure_options << "--without-system-verto"
|
|
126
|
+
recipe.configure_options << "krb5_cv_attr_constructor_destructor=yes"
|
|
127
|
+
recipe.configure_options << "ac_cv_func_regcomp=yes"
|
|
128
|
+
recipe.configure_options << "ac_cv_printf_positional=yes"
|
|
129
|
+
recipe.host = toolchain
|
|
130
|
+
recipe.cook_and_activate
|
|
131
|
+
end
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
# We build a libpq library file which static links OpenSSL and krb5.
|
|
135
|
+
# Our builtin libpq is referenced in different ways depending on the OS:
|
|
136
|
+
# - Window: Add the ports directory at runtime per RubyInstaller::Runtime.add_dll_directory
|
|
137
|
+
# The file is called "libpq.dll"
|
|
138
|
+
# - Linux: Add a rpath to pg_ext.so which references the ports directory.
|
|
139
|
+
# The file is called "libpq-ruby-pg.so.1" to avoid loading of system libpq by accident.
|
|
140
|
+
# - Macos: Add a reference with relative path in pg_ext.so to the ports directory.
|
|
141
|
+
# The file is called "libpq-ruby-pg.1.dylib" to avoid loading of other libpq by accident.
|
|
142
|
+
libpq_orig, libpq_rubypg = case RUBY_PLATFORM
|
|
143
|
+
when /linux/ then ["libpq.so.5", "libpq-ruby-pg.so.1"]
|
|
144
|
+
when /darwin/ then ["libpq.5.dylib", "libpq-ruby-pg.1.dylib"]
|
|
145
|
+
# when /mingw/ then ["libpq.dll", "libpq.dll"] # renaming not needed
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
postgresql_recipe = BuildRecipe.new("postgresql", POSTGRESQL_VERSION, [POSTGRESQL_SOURCE_URI]).tap do |recipe|
|
|
149
|
+
class << recipe
|
|
150
|
+
def configure_defaults
|
|
151
|
+
[
|
|
152
|
+
"--target=#{host}",
|
|
153
|
+
"--host=#{host}",
|
|
154
|
+
'--with-openssl',
|
|
155
|
+
*(RUBY_PLATFORM=~/linux|darwin/ ? ['--with-gssapi'] : []),
|
|
156
|
+
'--without-zlib',
|
|
157
|
+
'--without-icu',
|
|
158
|
+
'--without-readline',
|
|
159
|
+
'--disable-rpath',
|
|
160
|
+
'ac_cv_search_gss_store_cred_into=',
|
|
161
|
+
]
|
|
162
|
+
end
|
|
163
|
+
def compile
|
|
164
|
+
execute 'compile include', "#{make_cmd} -C src/include install DESTDIR=#{path}"
|
|
165
|
+
execute 'compile interfaces', "#{make_cmd} -C src/interfaces install DESTDIR=#{path}"
|
|
166
|
+
end
|
|
167
|
+
def install
|
|
168
|
+
end
|
|
169
|
+
end
|
|
170
|
+
|
|
171
|
+
recipe.host = toolchain
|
|
172
|
+
recipe.configure_options << "CFLAGS=#{" -fPIC" if RUBY_PLATFORM =~ /linux|darwin/}"
|
|
173
|
+
recipe.configure_options << "LDFLAGS=-L#{openssl_recipe.path}/lib -L#{openssl_recipe.path}/lib64 -L#{openssl_recipe.path}/lib-arm64 #{"-Wl,-soname,#{libpq_rubypg} -lgssapi_krb5 -lkrb5 -lk5crypto -lkrb5support -ldl" if RUBY_PLATFORM =~ /linux/} #{"-Wl,-install_name,@loader_path/../../ports/#{gem_platform}/lib/#{libpq_rubypg} -lgssapi_krb5 -lkrb5 -lk5crypto -lkrb5support -lresolv -framework Kerberos" if RUBY_PLATFORM =~ /darwin/}"
|
|
174
|
+
recipe.configure_options << "LIBS=-lkrb5 -lcom_err -lk5crypto -lkrb5support -lresolv" if RUBY_PLATFORM =~ /linux/
|
|
175
|
+
recipe.configure_options << "LIBS=-lssl -lwsock32 -lgdi32 -lws2_32 -lcrypt32" if RUBY_PLATFORM =~ /mingw|mswin/
|
|
176
|
+
recipe.configure_options << "CPPFLAGS=-I#{openssl_recipe.path}/include"
|
|
177
|
+
recipe.cook_and_activate
|
|
178
|
+
end
|
|
179
|
+
|
|
180
|
+
# Use our own library name for libpq to avoid loading of system libpq by accident.
|
|
181
|
+
FileUtils.ln_sf File.join(postgresql_recipe.port_path, "lib/#{libpq_orig}"),
|
|
182
|
+
File.join(postgresql_recipe.port_path, "lib/#{libpq_rubypg}")
|
|
183
|
+
# Link to libpq_rubypg in our ports directory without adding it as rpath (like dir_config does)
|
|
184
|
+
$CFLAGS << " -I#{postgresql_recipe.path}/include"
|
|
185
|
+
$LDFLAGS << " -L#{postgresql_recipe.path}/lib"
|
|
26
186
|
# Avoid dependency to external libgcc.dll on x86-mingw32
|
|
27
|
-
$LDFLAGS << " -static-libgcc"
|
|
28
|
-
#
|
|
29
|
-
|
|
187
|
+
$LDFLAGS << " -static-libgcc" if RUBY_PLATFORM =~ /mingw|mswin/
|
|
188
|
+
# Avoid: "libpq.so: undefined reference to `dlopen'" in cross-ruby-2.7.8
|
|
189
|
+
$LDFLAGS << " -Wl,--no-as-needed" if RUBY_PLATFORM !~ /aarch64|arm64|darwin/
|
|
190
|
+
# Find libpq in the ports directory coming from lib/3.x
|
|
191
|
+
# It is shared between all compiled ruby versions.
|
|
192
|
+
$LDFLAGS << " '-Wl,-rpath=$$ORIGIN/../../ports/#{gem_platform}/lib'" if RUBY_PLATFORM =~ /linux/
|
|
30
193
|
|
|
194
|
+
$defs.push( "-DPG_IS_BINARY_GEM")
|
|
31
195
|
else
|
|
32
196
|
# Native build
|
|
33
197
|
|
|
@@ -77,7 +241,7 @@ $INSTALLFILES = {
|
|
|
77
241
|
"./postgresql_lib_path.rb" => "$(RUBYLIBDIR)/pg/"
|
|
78
242
|
}
|
|
79
243
|
|
|
80
|
-
if
|
|
244
|
+
if /solaris/ =~ RUBY_PLATFORM
|
|
81
245
|
append_cppflags( '-D__EXTENSIONS__' )
|
|
82
246
|
end
|
|
83
247
|
|
|
@@ -142,25 +306,21 @@ if /mingw/ =~ RUBY_PLATFORM && RbConfig::MAKEFILE_CONFIG['CC'] =~ /gcc/
|
|
|
142
306
|
end
|
|
143
307
|
end
|
|
144
308
|
|
|
145
|
-
have_func '
|
|
309
|
+
have_func 'PQencryptPasswordConn', 'libpq-fe.h' or # since PostgreSQL-10
|
|
146
310
|
abort "Your PostgreSQL is too old. Either install an older version " +
|
|
147
|
-
"of this gem or upgrade your database to at least PostgreSQL-
|
|
311
|
+
"of this gem or upgrade your database to at least PostgreSQL-10."
|
|
148
312
|
# optional headers/functions
|
|
149
|
-
have_func 'PQsslAttribute', 'libpq-fe.h' # since PostgreSQL-9.5
|
|
150
|
-
have_func 'PQresultVerboseErrorMessage', 'libpq-fe.h' # since PostgreSQL-9.6
|
|
151
|
-
have_func 'PQencryptPasswordConn', 'libpq-fe.h' # since PostgreSQL-10
|
|
152
313
|
have_func 'PQresultMemorySize', 'libpq-fe.h' # since PostgreSQL-12
|
|
153
314
|
have_func 'PQenterPipelineMode', 'libpq-fe.h' do |src| # since PostgreSQL-14
|
|
154
315
|
# Ensure header files fit as well
|
|
155
316
|
src + " int con(){ return PGRES_PIPELINE_SYNC; }"
|
|
156
317
|
end
|
|
318
|
+
have_func 'PQsetChunkedRowsMode', 'libpq-fe.h' # since PostgreSQL-17
|
|
157
319
|
have_func 'timegm'
|
|
158
|
-
have_func 'rb_gc_adjust_memory_usage' # since ruby-2.4
|
|
159
|
-
have_func 'rb_gc_mark_movable' # since ruby-2.7
|
|
160
320
|
have_func 'rb_io_wait' # since ruby-3.0
|
|
321
|
+
have_func 'rb_io_descriptor' # since ruby-3.1
|
|
322
|
+
have_func 'rb_hash_new_capa' # since ruby-3.2
|
|
161
323
|
|
|
162
|
-
# unistd.h confilicts with ruby/win32.h when cross compiling for win32 and ruby 1.9.1
|
|
163
|
-
have_header 'unistd.h'
|
|
164
324
|
have_header 'inttypes.h'
|
|
165
325
|
have_header('ruby/fiber/scheduler.h') if RUBY_PLATFORM=~/mingw|mswin/
|
|
166
326
|
|
|
@@ -171,3 +331,20 @@ end
|
|
|
171
331
|
create_header()
|
|
172
332
|
create_makefile( "pg_ext" )
|
|
173
333
|
|
|
334
|
+
if gem_platform
|
|
335
|
+
# exercise the strip command on native binary gems
|
|
336
|
+
# This approach borrowed from
|
|
337
|
+
# https://github.com/rake-compiler/rake-compiler-dock/blob/38066d479050f4fdb3956469255b35a05e5949ef/test/rcd_test/ext/mri/extconf.rb#L97C1-L110C42
|
|
338
|
+
strip_tool = RbConfig::CONFIG['STRIP']
|
|
339
|
+
strip_tool += ' -x' if RUBY_PLATFORM =~ /darwin/
|
|
340
|
+
File.open('Makefile.new', 'w') do |o|
|
|
341
|
+
o.puts 'hijack: all strip'
|
|
342
|
+
o.puts
|
|
343
|
+
o.write(File.read('Makefile'))
|
|
344
|
+
o.puts
|
|
345
|
+
o.puts 'strip: $(DLLIB)'
|
|
346
|
+
o.puts "\t$(ECHO) Stripping $(DLLIB)"
|
|
347
|
+
o.puts "\t$(Q) #{strip_tool} $(DLLIB)"
|
|
348
|
+
end
|
|
349
|
+
File.rename('Makefile.new', 'Makefile')
|
|
350
|
+
end
|
data/ext/gvl_wrappers.c
CHANGED
|
@@ -5,8 +5,19 @@
|
|
|
5
5
|
|
|
6
6
|
#include "pg.h"
|
|
7
7
|
|
|
8
|
-
|
|
9
|
-
|
|
8
|
+
|
|
9
|
+
#ifndef HAVE_PQSETCHUNKEDROWSMODE
|
|
10
|
+
PGresult *PQclosePrepared(PGconn *conn, const char *stmtName){return NULL;}
|
|
11
|
+
PGresult *PQclosePortal(PGconn *conn, const char *portalName){return NULL;}
|
|
12
|
+
int PQsendClosePrepared(PGconn *conn, const char *stmtName){return 0;}
|
|
13
|
+
int PQsendClosePortal(PGconn *conn, const char *portalName){return 0;}
|
|
14
|
+
int PQsendPipelineSync(PGconn *conn){return 0;}
|
|
15
|
+
int PQcancelBlocking(PGcancelConn *cancelConn){return 0;}
|
|
16
|
+
int PQcancelStart(PGcancelConn *cancelConn){return 0;}
|
|
17
|
+
PostgresPollingStatusType PQcancelPoll(PGcancelConn *cancelConn){return PGRES_POLLING_FAILED;}
|
|
18
|
+
#endif
|
|
19
|
+
#ifndef HAVE_PQENTERPIPELINEMODE
|
|
20
|
+
int PQpipelineSync(PGconn *conn){return 0;}
|
|
10
21
|
#endif
|
|
11
22
|
|
|
12
23
|
#ifdef ENABLE_GVL_UNLOCK
|
data/ext/gvl_wrappers.h
CHANGED
|
@@ -21,6 +21,10 @@
|
|
|
21
21
|
# include RUBY_EXTCONF_H
|
|
22
22
|
#endif
|
|
23
23
|
|
|
24
|
+
#ifndef HAVE_PQSETCHUNKEDROWSMODE
|
|
25
|
+
typedef struct pg_cancel_conn PGcancelConn;
|
|
26
|
+
#endif
|
|
27
|
+
|
|
24
28
|
#define DEFINE_PARAM_LIST1(type, name) \
|
|
25
29
|
name,
|
|
26
30
|
|
|
@@ -149,6 +153,12 @@
|
|
|
149
153
|
#define FOR_EACH_PARAM_OF_PQdescribePortal(param) \
|
|
150
154
|
param(PGconn *, conn)
|
|
151
155
|
|
|
156
|
+
#define FOR_EACH_PARAM_OF_PQclosePrepared(param) \
|
|
157
|
+
param(PGconn *, conn)
|
|
158
|
+
|
|
159
|
+
#define FOR_EACH_PARAM_OF_PQclosePortal(param) \
|
|
160
|
+
param(PGconn *, conn)
|
|
161
|
+
|
|
152
162
|
#define FOR_EACH_PARAM_OF_PQgetResult(param)
|
|
153
163
|
|
|
154
164
|
#define FOR_EACH_PARAM_OF_PQputCopyData(param) \
|
|
@@ -196,11 +206,25 @@
|
|
|
196
206
|
#define FOR_EACH_PARAM_OF_PQsendDescribePortal(param) \
|
|
197
207
|
param(PGconn *, conn)
|
|
198
208
|
|
|
209
|
+
#define FOR_EACH_PARAM_OF_PQsendClosePrepared(param) \
|
|
210
|
+
param(PGconn *, conn)
|
|
211
|
+
|
|
212
|
+
#define FOR_EACH_PARAM_OF_PQsendClosePortal(param) \
|
|
213
|
+
param(PGconn *, conn)
|
|
214
|
+
|
|
215
|
+
#define FOR_EACH_PARAM_OF_PQpipelineSync(param)
|
|
216
|
+
|
|
217
|
+
#define FOR_EACH_PARAM_OF_PQsendPipelineSync(param)
|
|
218
|
+
|
|
199
219
|
#define FOR_EACH_PARAM_OF_PQsetClientEncoding(param) \
|
|
200
220
|
param(PGconn *, conn)
|
|
201
221
|
|
|
202
222
|
#define FOR_EACH_PARAM_OF_PQisBusy(param)
|
|
203
223
|
|
|
224
|
+
#define FOR_EACH_PARAM_OF_PQcancelBlocking(param)
|
|
225
|
+
#define FOR_EACH_PARAM_OF_PQcancelStart(param)
|
|
226
|
+
#define FOR_EACH_PARAM_OF_PQcancelPoll(param)
|
|
227
|
+
|
|
204
228
|
#define FOR_EACH_PARAM_OF_PQencryptPasswordConn(param) \
|
|
205
229
|
param(PGconn *, conn) \
|
|
206
230
|
param(const char *, passwd) \
|
|
@@ -225,6 +249,8 @@
|
|
|
225
249
|
function(PQprepare, GVL_TYPE_NONVOID, PGresult *, const Oid *, paramTypes) \
|
|
226
250
|
function(PQdescribePrepared, GVL_TYPE_NONVOID, PGresult *, const char *, stmtName) \
|
|
227
251
|
function(PQdescribePortal, GVL_TYPE_NONVOID, PGresult *, const char *, portalName) \
|
|
252
|
+
function(PQclosePrepared, GVL_TYPE_NONVOID, PGresult *, const char *, stmtName) \
|
|
253
|
+
function(PQclosePortal, GVL_TYPE_NONVOID, PGresult *, const char *, portalName) \
|
|
228
254
|
function(PQgetResult, GVL_TYPE_NONVOID, PGresult *, PGconn *, conn) \
|
|
229
255
|
function(PQputCopyData, GVL_TYPE_NONVOID, int, int, nbytes) \
|
|
230
256
|
function(PQputCopyEnd, GVL_TYPE_NONVOID, int, const char *, errormsg) \
|
|
@@ -236,8 +262,15 @@
|
|
|
236
262
|
function(PQsendQueryPrepared, GVL_TYPE_NONVOID, int, int, resultFormat) \
|
|
237
263
|
function(PQsendDescribePrepared, GVL_TYPE_NONVOID, int, const char *, stmt) \
|
|
238
264
|
function(PQsendDescribePortal, GVL_TYPE_NONVOID, int, const char *, portal) \
|
|
265
|
+
function(PQsendClosePrepared, GVL_TYPE_NONVOID, int, const char *, stmt) \
|
|
266
|
+
function(PQsendClosePortal, GVL_TYPE_NONVOID, int, const char *, portal) \
|
|
267
|
+
function(PQpipelineSync, GVL_TYPE_NONVOID, int, PGconn *, conn) \
|
|
268
|
+
function(PQsendPipelineSync, GVL_TYPE_NONVOID, int, PGconn *, conn) \
|
|
239
269
|
function(PQsetClientEncoding, GVL_TYPE_NONVOID, int, const char *, encoding) \
|
|
240
270
|
function(PQisBusy, GVL_TYPE_NONVOID, int, PGconn *, conn) \
|
|
271
|
+
function(PQcancelBlocking, GVL_TYPE_NONVOID, int, PGcancelConn *, conn) \
|
|
272
|
+
function(PQcancelStart, GVL_TYPE_NONVOID, int, PGcancelConn *, conn) \
|
|
273
|
+
function(PQcancelPoll, GVL_TYPE_NONVOID, PostgresPollingStatusType, PGcancelConn *, conn) \
|
|
241
274
|
function(PQencryptPasswordConn, GVL_TYPE_NONVOID, char *, const char *, algorithm) \
|
|
242
275
|
function(PQcancel, GVL_TYPE_NONVOID, int, int, errbufsize);
|
|
243
276
|
|
data/ext/pg.c
CHANGED
|
@@ -404,6 +404,10 @@ Init_pg_ext(void)
|
|
|
404
404
|
/* Checking if server is in standby mode. Available since PostgreSQL-14. */
|
|
405
405
|
rb_define_const(rb_mPGconstants, "CONNECTION_CHECK_STANDBY", INT2FIX(CONNECTION_CHECK_STANDBY));
|
|
406
406
|
#endif
|
|
407
|
+
#if PG_MAJORVERSION_NUM >= 17
|
|
408
|
+
/* Waiting for connection attempt to be started. Available since PostgreSQL-17. */
|
|
409
|
+
rb_define_const(rb_mPGconstants, "CONNECTION_ALLOCATED", INT2FIX(CONNECTION_ALLOCATED));
|
|
410
|
+
#endif
|
|
407
411
|
|
|
408
412
|
/****** PG::Connection CLASS CONSTANTS: Nonblocking connection polling status ******/
|
|
409
413
|
|
|
@@ -451,14 +455,12 @@ Init_pg_ext(void)
|
|
|
451
455
|
rb_define_const(rb_mPGconstants, "PQERRORS_SQLSTATE", INT2FIX(PQERRORS_SQLSTATE));
|
|
452
456
|
#endif
|
|
453
457
|
|
|
454
|
-
#ifdef HAVE_PQRESULTVERBOSEERRORMESSAGE
|
|
455
458
|
/* See Connection#set_error_context_visibility */
|
|
456
459
|
rb_define_const(rb_mPGconstants, "PQSHOW_CONTEXT_NEVER", INT2FIX(PQSHOW_CONTEXT_NEVER));
|
|
457
460
|
/* See Connection#set_error_context_visibility */
|
|
458
461
|
rb_define_const(rb_mPGconstants, "PQSHOW_CONTEXT_ERRORS", INT2FIX(PQSHOW_CONTEXT_ERRORS));
|
|
459
462
|
/* See Connection#set_error_context_visibility */
|
|
460
463
|
rb_define_const(rb_mPGconstants, "PQSHOW_CONTEXT_ALWAYS", INT2FIX(PQSHOW_CONTEXT_ALWAYS));
|
|
461
|
-
#endif
|
|
462
464
|
|
|
463
465
|
/****** PG::Connection CLASS CONSTANTS: Check Server Status ******/
|
|
464
466
|
|
|
@@ -506,6 +508,10 @@ Init_pg_ext(void)
|
|
|
506
508
|
rb_define_const(rb_mPGconstants, "PGRES_COPY_BOTH", INT2FIX(PGRES_COPY_BOTH));
|
|
507
509
|
/* Result#result_status constant - Single tuple from larger resultset. */
|
|
508
510
|
rb_define_const(rb_mPGconstants, "PGRES_SINGLE_TUPLE", INT2FIX(PGRES_SINGLE_TUPLE));
|
|
511
|
+
#ifdef HAVE_PQSETCHUNKEDROWSMODE
|
|
512
|
+
/* Result#result_status constant - tuple chunk from larger resultset. */
|
|
513
|
+
rb_define_const(rb_mPGconstants, "PGRES_TUPLES_CHUNK", INT2FIX(PGRES_TUPLES_CHUNK));
|
|
514
|
+
#endif
|
|
509
515
|
|
|
510
516
|
#ifdef HAVE_PQENTERPIPELINEMODE
|
|
511
517
|
/* Result#result_status constant - The PG::Result represents a synchronization point in pipeline mode, requested by Connection#pipeline_sync.
|
|
@@ -530,20 +536,18 @@ Init_pg_ext(void)
|
|
|
530
536
|
*/
|
|
531
537
|
rb_define_const(rb_mPGconstants, "PG_DIAG_SEVERITY", INT2FIX(PG_DIAG_SEVERITY));
|
|
532
538
|
|
|
533
|
-
#ifdef PG_DIAG_SEVERITY_NONLOCALIZED
|
|
534
539
|
/* Result#result_error_field argument constant
|
|
535
540
|
*
|
|
536
541
|
* The severity; the field contents are ERROR, FATAL, or PANIC (in an error message), or WARNING, NOTICE, DEBUG, INFO, or LOG (in a notice message).
|
|
537
542
|
* This is identical to the PG_DIAG_SEVERITY field except that the contents are never localized.
|
|
538
543
|
*
|
|
539
|
-
* Available since PostgreSQL-9.6
|
|
540
544
|
*/
|
|
541
545
|
rb_define_const(rb_mPGconstants, "PG_DIAG_SEVERITY_NONLOCALIZED", INT2FIX(PG_DIAG_SEVERITY_NONLOCALIZED));
|
|
542
|
-
|
|
546
|
+
|
|
543
547
|
/* Result#result_error_field argument constant
|
|
544
548
|
*
|
|
545
549
|
* The SQLSTATE code for the error.
|
|
546
|
-
* The SQLSTATE code
|
|
550
|
+
* The SQLSTATE code identifies the type of error that has occurred; it can be used by front-end applications to perform specific operations (such as error handling) in response to a particular database error.
|
|
547
551
|
* For a list of the possible SQLSTATE codes, see Appendix A.
|
|
548
552
|
* This field is not localizable, and is always present.
|
|
549
553
|
*/
|
|
@@ -667,6 +671,12 @@ Init_pg_ext(void)
|
|
|
667
671
|
/* PostgreSQL compiled in default port */
|
|
668
672
|
rb_define_const(rb_mPGconstants, "DEF_PGPORT", INT2FIX(DEF_PGPORT));
|
|
669
673
|
|
|
674
|
+
#ifdef PG_IS_BINARY_GEM
|
|
675
|
+
rb_define_const(rb_mPG, "IS_BINARY_GEM", Qtrue);
|
|
676
|
+
#else
|
|
677
|
+
rb_define_const(rb_mPG, "IS_BINARY_GEM", Qfalse);
|
|
678
|
+
#endif
|
|
679
|
+
|
|
670
680
|
/* Add the constants to the toplevel namespace */
|
|
671
681
|
rb_include_module( rb_mPG, rb_mPGconstants );
|
|
672
682
|
|
|
@@ -689,4 +699,5 @@ Init_pg_ext(void)
|
|
|
689
699
|
init_pg_copycoder();
|
|
690
700
|
init_pg_recordcoder();
|
|
691
701
|
init_pg_tuple();
|
|
702
|
+
init_pg_cancon();
|
|
692
703
|
}
|
data/ext/pg.h
CHANGED
|
@@ -76,15 +76,12 @@ typedef long suseconds_t;
|
|
|
76
76
|
#define PG_MAX_COLUMNS 4000
|
|
77
77
|
#endif
|
|
78
78
|
|
|
79
|
-
#
|
|
80
|
-
#define
|
|
81
|
-
#define pg_gc_location(x) x = rb_gc_location(x)
|
|
82
|
-
#else
|
|
83
|
-
#define rb_gc_mark_movable(x) rb_gc_mark(x)
|
|
84
|
-
#define pg_compact_callback(x) {(x)}
|
|
85
|
-
#define pg_gc_location(x) UNUSED(x)
|
|
79
|
+
#ifndef HAVE_RB_HASH_NEW_CAPA
|
|
80
|
+
#define rb_hash_new_capa(x) rb_hash_new()
|
|
86
81
|
#endif
|
|
87
82
|
|
|
83
|
+
#define pg_gc_location(x) x = rb_gc_location(x)
|
|
84
|
+
|
|
88
85
|
/* For compatibility with ruby < 3.0 */
|
|
89
86
|
#ifndef RUBY_TYPED_FROZEN_SHAREABLE
|
|
90
87
|
#define PG_RUBY_TYPED_FROZEN_SHAREABLE 0
|
|
@@ -123,10 +120,8 @@ typedef struct {
|
|
|
123
120
|
/* enable automatic flushing of send data at the end of send_query calls */
|
|
124
121
|
unsigned int flush_data : 1;
|
|
125
122
|
|
|
126
|
-
#if defined(_WIN32)
|
|
127
123
|
/* File descriptor to be used for rb_w32_unwrap_io_handle() */
|
|
128
124
|
int ruby_sd;
|
|
129
|
-
#endif
|
|
130
125
|
} t_pg_connection;
|
|
131
126
|
|
|
132
127
|
typedef struct pg_coder t_pg_coder;
|
|
@@ -166,10 +161,8 @@ typedef struct {
|
|
|
166
161
|
/* Size of PGresult as published to ruby memory management. */
|
|
167
162
|
ssize_t result_size;
|
|
168
163
|
|
|
169
|
-
/*
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
/* Hash with fnames[] to field number mapping. */
|
|
164
|
+
/* Hash with fnames[] to field number mapping.
|
|
165
|
+
* Init on-demand to create PG::Tuple objects, otherwise Qnil. */
|
|
173
166
|
VALUE field_map;
|
|
174
167
|
|
|
175
168
|
/* List of field names as frozen String or Symbol objects.
|
|
@@ -215,6 +208,7 @@ typedef struct {
|
|
|
215
208
|
t_pg_coder comp;
|
|
216
209
|
t_pg_coder *elem;
|
|
217
210
|
int needs_quotation;
|
|
211
|
+
int dimensions;
|
|
218
212
|
char delimiter;
|
|
219
213
|
} t_pg_composite_coder;
|
|
220
214
|
|
|
@@ -312,6 +306,7 @@ void init_pg_text_decoder _(( void ));
|
|
|
312
306
|
void init_pg_binary_encoder _(( void ));
|
|
313
307
|
void init_pg_binary_decoder _(( void ));
|
|
314
308
|
void init_pg_tuple _(( void ));
|
|
309
|
+
void init_pg_cancon _(( void ));
|
|
315
310
|
VALUE lookup_error_class _(( const char * ));
|
|
316
311
|
VALUE pg_bin_dec_bytea _(( t_pg_coder*, const char *, int, int, int, int ));
|
|
317
312
|
VALUE pg_text_dec_string _(( t_pg_coder*, const char *, int, int, int, int ));
|
|
@@ -351,6 +346,13 @@ void pg_typemap_compact _(( void * ));
|
|
|
351
346
|
PGconn *pg_get_pgconn _(( VALUE ));
|
|
352
347
|
t_pg_connection *pg_get_connection _(( VALUE ));
|
|
353
348
|
VALUE pgconn_block _(( int, VALUE *, VALUE ));
|
|
349
|
+
#ifdef __GNUC__
|
|
350
|
+
__attribute__((format(printf, 3, 4)))
|
|
351
|
+
#endif
|
|
352
|
+
NORETURN(void pg_raise_conn_error _(( VALUE klass, VALUE self, const char *format, ...)));
|
|
353
|
+
VALUE pg_wrap_socket_io _(( int sd, VALUE self, VALUE *p_socket_io, int *p_ruby_sd ));
|
|
354
|
+
void pg_unwrap_socket_io _(( VALUE self, VALUE *p_socket_io, int ruby_sd ));
|
|
355
|
+
|
|
354
356
|
|
|
355
357
|
VALUE pg_new_result _(( PGresult *, VALUE ));
|
|
356
358
|
VALUE pg_new_result_autoclear _(( PGresult *, VALUE ));
|