pg-ct 0.10.0
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.
- data/BSD +23 -0
- data/ChangeLog +585 -0
- data/Contributors +30 -0
- data/GPL +340 -0
- data/LICENSE +58 -0
- data/README +68 -0
- data/README.OS_X +19 -0
- data/README.ja +183 -0
- data/README.windows +72 -0
- data/Rakefile +359 -0
- data/Rakefile.local +298 -0
- data/ext/compat.c +541 -0
- data/ext/compat.h +180 -0
- data/ext/extconf.rb +147 -0
- data/ext/pg.c +4307 -0
- data/ext/pg.h +49 -0
- data/lib/pg.rb +14 -0
- data/rake/191_compat.rb +26 -0
- data/rake/dependencies.rb +76 -0
- data/rake/documentation.rb +123 -0
- data/rake/helpers.rb +502 -0
- data/rake/hg.rb +287 -0
- data/rake/manual.rb +787 -0
- data/rake/packaging.rb +129 -0
- data/rake/publishing.rb +341 -0
- data/rake/style.rb +62 -0
- data/rake/svn.rb +668 -0
- data/rake/testing.rb +151 -0
- data/rake/verifytask.rb +64 -0
- data/spec/data/expected_trace.out +26 -0
- data/spec/data/random_binary_data +0 -0
- data/spec/lib/helpers.rb +236 -0
- data/spec/m17n_spec.rb +151 -0
- data/spec/pgconn_spec.rb +437 -0
- data/spec/pgresult_spec.rb +215 -0
- metadata +126 -0
data/Rakefile.local
ADDED
@@ -0,0 +1,298 @@
|
|
1
|
+
#!rake
|
2
|
+
|
3
|
+
require 'uri'
|
4
|
+
require 'tempfile'
|
5
|
+
require 'rbconfig'
|
6
|
+
|
7
|
+
require 'rake/clean'
|
8
|
+
require 'rake/extensiontask'
|
9
|
+
require 'rake/extensioncompiler'
|
10
|
+
|
11
|
+
MISCDIR = BASEDIR + 'misc'
|
12
|
+
|
13
|
+
EXT_MAKEFILE = EXTDIR + 'Makefile'
|
14
|
+
EXT_SOURCES = FileList[ EXTDIR + '*.c' ]
|
15
|
+
EXT_SO = EXTDIR + "pg_ext.#{CONFIG['DLEXT']}"
|
16
|
+
|
17
|
+
NUM_CPUS = if File.exist?('/proc/cpuinfo')
|
18
|
+
File.read('/proc/cpuinfo').scan('processor').length
|
19
|
+
elsif RUBY_PLATFORM.include?( 'darwin' )
|
20
|
+
`system_profiler SPHardwareDataType | grep 'Cores' | awk '{print $5}'`.chomp
|
21
|
+
else
|
22
|
+
1
|
23
|
+
end
|
24
|
+
|
25
|
+
# Cross-compilation constants
|
26
|
+
OPENSSL_VERSION = ENV['OPENSSL_VERSION'] || '1.0.0a'
|
27
|
+
POSTGRESQL_VERSION = ENV['POSTGRESQL_VERSION'] || '9.0.1'
|
28
|
+
|
29
|
+
COMPILE_HOME = Pathname( "~/.rake-compiler" ).expand_path
|
30
|
+
STATIC_SOURCESDIR = COMPILE_HOME + 'sources'
|
31
|
+
STATIC_BUILDDIR = COMPILE_HOME + 'builds'
|
32
|
+
|
33
|
+
# Static OpenSSL build vars
|
34
|
+
STATIC_OPENSSL_BUILDDIR = STATIC_BUILDDIR + "openssl-#{OPENSSL_VERSION}"
|
35
|
+
|
36
|
+
OPENSSL_SOURCE_URI =
|
37
|
+
URI( "http://www.openssl.org/source/openssl-#{OPENSSL_VERSION}.tar.gz" )
|
38
|
+
OPENSSL_TARBALL = STATIC_SOURCESDIR + File.basename( OPENSSL_SOURCE_URI.path )
|
39
|
+
OPENSSL_MAKEFILE = STATIC_OPENSSL_BUILDDIR + 'Makefile'
|
40
|
+
|
41
|
+
LIBSSLEAY32 = STATIC_OPENSSL_BUILDDIR + 'libssleay32.a'
|
42
|
+
LIBEAY32 = STATIC_OPENSSL_BUILDDIR + 'libeay32.a'
|
43
|
+
|
44
|
+
OPENSSL_PATCHES = Rake::FileList[ MISCDIR + "openssl-#{OPENSSL_VERSION}.*.patch" ]
|
45
|
+
|
46
|
+
# Static PostgreSQL build vars
|
47
|
+
STATIC_POSTGRESQL_BUILDDIR = STATIC_BUILDDIR + "postgresql-#{POSTGRESQL_VERSION}"
|
48
|
+
POSTGRESQL_SOURCE_URI = begin
|
49
|
+
uristring = "http://ftp9.us.postgresql.org/pub/mirrors/postgresql/source/" +
|
50
|
+
"v%s/postgresql-%s.tar.gz" % [ POSTGRESQL_VERSION, POSTGRESQL_VERSION ]
|
51
|
+
URI( uristring )
|
52
|
+
end
|
53
|
+
POSTGRESQL_TARBALL = STATIC_SOURCESDIR + File.basename( POSTGRESQL_SOURCE_URI.path )
|
54
|
+
|
55
|
+
STATIC_POSTGRESQL_SRCDIR = STATIC_POSTGRESQL_BUILDDIR + 'src'
|
56
|
+
STATIC_POSTGRESQL_LIBDIR = STATIC_POSTGRESQL_SRCDIR + 'interfaces/libpq'
|
57
|
+
STATIC_POSTGRESQL_INCDIR = STATIC_POSTGRESQL_SRCDIR + 'include'
|
58
|
+
|
59
|
+
POSTGRESQL_GLOBAL_MAKEFILE = STATIC_POSTGRESQL_SRCDIR + 'Makefile.global'
|
60
|
+
POSTGRESQL_SHLIB_MAKEFILE = STATIC_POSTGRESQL_SRCDIR + 'Makefile.shlib'
|
61
|
+
POSTGRESQL_SHLIB_MF_ORIG = STATIC_POSTGRESQL_SRCDIR + 'Makefile.shlib.orig'
|
62
|
+
POSTGRESQL_LIB = STATIC_POSTGRESQL_LIBDIR + 'libpq.a'
|
63
|
+
|
64
|
+
CROSS_PREFIX = if RUBY_PLATFORM.include?( 'darwin' )
|
65
|
+
'i386-mingw32'
|
66
|
+
else
|
67
|
+
'i586-mingw32msvc'
|
68
|
+
end
|
69
|
+
|
70
|
+
# Make sure the spec data is packaged up with the gem
|
71
|
+
SPEC_DATA = Rake::FileList[ SPECDIR + 'data/*' ]
|
72
|
+
GEMSPEC.test_files += SPEC_DATA.to_a
|
73
|
+
|
74
|
+
# Clean up any testing database directories
|
75
|
+
TESTING_TMPDIRS = Rake::FileList[ "#{BASEDIR}/tmp_test_*" ]
|
76
|
+
CLOBBER.include( STATIC_SOURCESDIR.to_s, *TESTING_TMPDIRS )
|
77
|
+
|
78
|
+
# clean intermediate files and folders
|
79
|
+
CLEAN.include( STATIC_BUILDDIR.to_s )
|
80
|
+
|
81
|
+
|
82
|
+
#####################################################################
|
83
|
+
### T A S K S
|
84
|
+
#####################################################################
|
85
|
+
|
86
|
+
# Make both the default task and the spec task depend on building the extension
|
87
|
+
task :local => :compile
|
88
|
+
task :spec => :compile
|
89
|
+
namespace :spec do
|
90
|
+
task :doc => [ :compile ]
|
91
|
+
task :quiet => [ :compile ]
|
92
|
+
task :html => [ :compile ]
|
93
|
+
task :text => [ :compile ]
|
94
|
+
end
|
95
|
+
|
96
|
+
ENV['RUBY_CC_VERSION'] = '1.8.6:1.9.2'
|
97
|
+
|
98
|
+
Rake::ExtensionTask.new do |ext|
|
99
|
+
ext.name = 'pg_ext'
|
100
|
+
ext.gem_spec = GEMSPEC
|
101
|
+
ext.ext_dir = EXTDIR.to_s
|
102
|
+
ext.lib_dir = LIBDIR.to_s
|
103
|
+
ext.source_pattern = "*.{c,h}"
|
104
|
+
|
105
|
+
# If there's an explicit 'compile' argument, use everything after it as options.
|
106
|
+
if offset = ARGV.index( 'compile' )
|
107
|
+
trace "config options = %p" % [ ARGV[(offset + 1)..-1] ]
|
108
|
+
ext.config_options = ARGV[ (offset + 1)..-1 ]
|
109
|
+
# Otherwise, just grab everything from the first option onward
|
110
|
+
elsif offset = ARGV.index( ARGV.find {|arg| arg =~ /^--/ } )
|
111
|
+
trace "config options = %p" % [ ARGV[offset..-1] ]
|
112
|
+
ext.config_options = ARGV[ offset..-1 ]
|
113
|
+
else
|
114
|
+
trace "No config options (ARGV = %p)" % [ ARGV ]
|
115
|
+
end
|
116
|
+
|
117
|
+
ext.cross_compile = true
|
118
|
+
ext.cross_platform = %w[i386-mswin32 i386-mingw32]
|
119
|
+
|
120
|
+
# configure options only for cross compile
|
121
|
+
ext.cross_config_options += [
|
122
|
+
"--with-pg-include=#{STATIC_POSTGRESQL_LIBDIR}",
|
123
|
+
"--with-opt-include=#{STATIC_POSTGRESQL_INCDIR}",
|
124
|
+
"--with-pg-lib=#{STATIC_POSTGRESQL_LIBDIR}",
|
125
|
+
"--with-opt-lib=#{STATIC_OPENSSL_BUILDDIR}",
|
126
|
+
"--enable-static-build",
|
127
|
+
]
|
128
|
+
|
129
|
+
end
|
130
|
+
|
131
|
+
task :cross do
|
132
|
+
ENV['CROSS_COMPILING'] = 'yes'
|
133
|
+
end
|
134
|
+
|
135
|
+
|
136
|
+
desc "Stop any Postmaster instances that remain after testing."
|
137
|
+
task :cleanup_testing_dbs do
|
138
|
+
require 'spec/lib/helpers'
|
139
|
+
PgTestingHelpers.stop_existing_postmasters()
|
140
|
+
Rake::Task[:clean].invoke
|
141
|
+
end
|
142
|
+
|
143
|
+
|
144
|
+
#####################################################################
|
145
|
+
### C R O S S - C O M P I L A T I O N - T A S K S
|
146
|
+
#####################################################################
|
147
|
+
|
148
|
+
|
149
|
+
directory STATIC_SOURCESDIR.to_s
|
150
|
+
|
151
|
+
#
|
152
|
+
# Static OpenSSL build tasks
|
153
|
+
#
|
154
|
+
directory STATIC_OPENSSL_BUILDDIR.to_s
|
155
|
+
|
156
|
+
# openssl source file should be stored there
|
157
|
+
file OPENSSL_TARBALL => STATIC_SOURCESDIR do |t|
|
158
|
+
download( OPENSSL_SOURCE_URI, t.name )
|
159
|
+
end
|
160
|
+
|
161
|
+
# Extract the openssl builds
|
162
|
+
file STATIC_OPENSSL_BUILDDIR => OPENSSL_TARBALL do |t|
|
163
|
+
trace "extracting %s to %s" % [ OPENSSL_TARBALL, STATIC_OPENSSL_BUILDDIR.parent ]
|
164
|
+
STATIC_OPENSSL_BUILDDIR.mkpath
|
165
|
+
run 'tar', '-xzf', OPENSSL_TARBALL.to_s, '-C', STATIC_OPENSSL_BUILDDIR.parent.to_s
|
166
|
+
OPENSSL_MAKEFILE.unlink if OPENSSL_MAKEFILE.exist?
|
167
|
+
|
168
|
+
OPENSSL_PATCHES.each do |patchfile|
|
169
|
+
trace " applying patch #{patchfile}..."
|
170
|
+
run 'patch', '-Np1', '-d', STATIC_OPENSSL_BUILDDIR.to_s,
|
171
|
+
'-i', File.expand_path( patchfile, BASEDIR )
|
172
|
+
end
|
173
|
+
end
|
174
|
+
|
175
|
+
CMD_PRELUDE = [
|
176
|
+
'env',
|
177
|
+
"CC=#{CROSS_PREFIX}-gcc",
|
178
|
+
"CFLAGS=-DDSO_WIN32",
|
179
|
+
"AR=#{CROSS_PREFIX}-ar",
|
180
|
+
"RANLIB=#{CROSS_PREFIX}-ranlib"
|
181
|
+
]
|
182
|
+
|
183
|
+
|
184
|
+
# generate the makefile in a clean build location
|
185
|
+
file OPENSSL_MAKEFILE => STATIC_OPENSSL_BUILDDIR do |t|
|
186
|
+
Dir.chdir( STATIC_OPENSSL_BUILDDIR ) do
|
187
|
+
cmd = CMD_PRELUDE.dup
|
188
|
+
cmd << "./Configure" << 'mingw'
|
189
|
+
|
190
|
+
run( *cmd )
|
191
|
+
end
|
192
|
+
end
|
193
|
+
|
194
|
+
desc "compile static openssl libraries"
|
195
|
+
task :openssl_libs => [ LIBSSLEAY32, LIBEAY32 ]
|
196
|
+
|
197
|
+
task :compile_static_openssl => OPENSSL_MAKEFILE do |t|
|
198
|
+
Dir.chdir( STATIC_OPENSSL_BUILDDIR ) do
|
199
|
+
cmd = CMD_PRELUDE.dup
|
200
|
+
cmd << 'make' << "-j#{NUM_CPUS}" << 'build_libs'
|
201
|
+
|
202
|
+
run( *cmd )
|
203
|
+
end
|
204
|
+
end
|
205
|
+
|
206
|
+
desc "compile static #{LIBEAY32}"
|
207
|
+
file LIBEAY32 => :compile_static_openssl do |t|
|
208
|
+
FileUtils.cp( STATIC_OPENSSL_BUILDDIR + 'libcrypto.a', LIBEAY32.to_s )
|
209
|
+
end
|
210
|
+
|
211
|
+
desc "compile static #{LIBSSLEAY32}"
|
212
|
+
file LIBSSLEAY32 => :compile_static_openssl do |t|
|
213
|
+
FileUtils.cp( STATIC_OPENSSL_BUILDDIR + 'libssl.a', LIBSSLEAY32.to_s )
|
214
|
+
end
|
215
|
+
|
216
|
+
|
217
|
+
|
218
|
+
#
|
219
|
+
# Static PostgreSQL build tasks
|
220
|
+
#
|
221
|
+
directory STATIC_POSTGRESQL_BUILDDIR.to_s
|
222
|
+
|
223
|
+
|
224
|
+
# postgresql source file should be stored there
|
225
|
+
file POSTGRESQL_TARBALL => STATIC_SOURCESDIR do |t|
|
226
|
+
download( POSTGRESQL_SOURCE_URI, t.name )
|
227
|
+
end
|
228
|
+
|
229
|
+
# Extract the postgresql sources
|
230
|
+
file STATIC_POSTGRESQL_BUILDDIR => POSTGRESQL_TARBALL do |t|
|
231
|
+
trace "extracting %s to %s" % [ POSTGRESQL_TARBALL, STATIC_POSTGRESQL_BUILDDIR.parent ]
|
232
|
+
STATIC_POSTGRESQL_BUILDDIR.mkpath
|
233
|
+
run 'tar', '-xzf', POSTGRESQL_TARBALL.to_s, '-C', STATIC_POSTGRESQL_BUILDDIR.parent.to_s
|
234
|
+
mv POSTGRESQL_SHLIB_MAKEFILE, POSTGRESQL_SHLIB_MF_ORIG
|
235
|
+
end
|
236
|
+
|
237
|
+
# generate the makefile in a clean build location
|
238
|
+
file POSTGRESQL_GLOBAL_MAKEFILE => [ STATIC_POSTGRESQL_BUILDDIR, :openssl_libs ] do |t|
|
239
|
+
options = [
|
240
|
+
'--target=i386-mingw32',
|
241
|
+
"--host=#{Rake::ExtensionCompiler.mingw_host}",
|
242
|
+
'--with-openssl',
|
243
|
+
'--without-zlib',
|
244
|
+
'--disable-shared',
|
245
|
+
]
|
246
|
+
|
247
|
+
Dir.chdir( STATIC_POSTGRESQL_BUILDDIR ) do
|
248
|
+
configure_path = STATIC_POSTGRESQL_BUILDDIR + 'configure'
|
249
|
+
cmd = [ configure_path.to_s, *options ]
|
250
|
+
cmd << "CFLAGS=-L#{STATIC_OPENSSL_BUILDDIR}"
|
251
|
+
cmd << "LDFLAGS=-L#{STATIC_OPENSSL_BUILDDIR}"
|
252
|
+
cmd << "LDFLAGS_SL=-L#{STATIC_OPENSSL_BUILDDIR}"
|
253
|
+
cmd << "LIBS=-lwsock32 -lgdi32"
|
254
|
+
cmd << "CPPFLAGS=-I#{STATIC_OPENSSL_BUILDDIR}/include"
|
255
|
+
|
256
|
+
run( *cmd )
|
257
|
+
end
|
258
|
+
end
|
259
|
+
|
260
|
+
|
261
|
+
# patch the Makefile.shlib -- depend on the build dir so it's only
|
262
|
+
# rewritten if the tarball is re-extracted.
|
263
|
+
file POSTGRESQL_SHLIB_MAKEFILE => POSTGRESQL_SHLIB_MF_ORIG do |t|
|
264
|
+
tf = Tempfile.new( POSTGRESQL_SHLIB_MAKEFILE.basename )
|
265
|
+
POSTGRESQL_SHLIB_MF_ORIG.open( File::RDONLY ) do |ifh|
|
266
|
+
ifh.each_line do |line|
|
267
|
+
tf.print( line.sub(/^(\s*haslibarule\s*=\s*yes)/, "# \\1 ") )
|
268
|
+
end
|
269
|
+
end
|
270
|
+
tf.close
|
271
|
+
|
272
|
+
FileUtils.mv( tf.path, t.name, :verbose => $trace )
|
273
|
+
end
|
274
|
+
|
275
|
+
|
276
|
+
# make libpq.a
|
277
|
+
file POSTGRESQL_LIB => [ POSTGRESQL_GLOBAL_MAKEFILE, POSTGRESQL_SHLIB_MAKEFILE ] do |t|
|
278
|
+
Dir.chdir( POSTGRESQL_LIB.dirname ) do
|
279
|
+
sh 'make', "-j#{NUM_CPUS}", POSTGRESQL_LIB.basename.to_s, 'PORTNAME=win32'
|
280
|
+
end
|
281
|
+
end
|
282
|
+
|
283
|
+
|
284
|
+
#desc 'compile static libpg.a'
|
285
|
+
task :static_libpq => POSTGRESQL_LIB
|
286
|
+
|
287
|
+
desc 'cross compile pg for win32'
|
288
|
+
task :cross => [ :mingw32, :static_libpq ]
|
289
|
+
|
290
|
+
task :mingw32 do
|
291
|
+
# Use Rake::ExtensionCompiler helpers to find the proper host
|
292
|
+
unless Rake::ExtensionCompiler.mingw_host then
|
293
|
+
warn "You need to install mingw32 cross compile functionality to be able to continue."
|
294
|
+
warn "Please refer to your distribution/package manager documentation about installation."
|
295
|
+
fail
|
296
|
+
end
|
297
|
+
end
|
298
|
+
|
data/ext/compat.c
ADDED
@@ -0,0 +1,541 @@
|
|
1
|
+
/************************************************
|
2
|
+
|
3
|
+
compat.c -
|
4
|
+
|
5
|
+
Author: matz
|
6
|
+
created at: Tue May 13 20:07:35 JST 1997
|
7
|
+
|
8
|
+
Author: ematsu
|
9
|
+
modified at: Wed Jan 20 16:41:51 1999
|
10
|
+
|
11
|
+
$Author$
|
12
|
+
$Date$
|
13
|
+
************************************************/
|
14
|
+
|
15
|
+
#include <ctype.h>
|
16
|
+
#include "compat.h"
|
17
|
+
|
18
|
+
#ifdef PG_BEFORE_080300
|
19
|
+
int
|
20
|
+
PQconnectionNeedsPassword(PGconn *conn)
|
21
|
+
{
|
22
|
+
rb_raise(rb_eStandardError,
|
23
|
+
"PQconnectionNeedsPassword not supported by this client version.");
|
24
|
+
}
|
25
|
+
|
26
|
+
int
|
27
|
+
PQconnectionUsedPassword(PGconn *conn)
|
28
|
+
{
|
29
|
+
rb_raise(rb_eStandardError,
|
30
|
+
"PQconnectionUsedPassword not supported by this client version.");
|
31
|
+
}
|
32
|
+
|
33
|
+
int
|
34
|
+
lo_truncate(PGconn *conn, int fd, size_t len)
|
35
|
+
{
|
36
|
+
rb_raise(rb_eStandardError, "lo_truncate not supported by this client version.");
|
37
|
+
}
|
38
|
+
#endif /* PG_BEFORE_080300 */
|
39
|
+
|
40
|
+
#ifdef PG_BEFORE_080200
|
41
|
+
int
|
42
|
+
PQisthreadsafe()
|
43
|
+
{
|
44
|
+
return Qfalse;
|
45
|
+
}
|
46
|
+
|
47
|
+
int
|
48
|
+
PQnparams(const PGresult *res)
|
49
|
+
{
|
50
|
+
rb_raise(rb_eStandardError, "PQnparams not supported by this client version.");
|
51
|
+
}
|
52
|
+
|
53
|
+
Oid
|
54
|
+
PQparamtype(const PGresult *res, int param_number)
|
55
|
+
{
|
56
|
+
rb_raise(rb_eStandardError, "PQparamtype not supported by this client version.");
|
57
|
+
}
|
58
|
+
|
59
|
+
PGresult *
|
60
|
+
PQdescribePrepared(PGconn *conn, const char *stmtName)
|
61
|
+
{
|
62
|
+
rb_raise(rb_eStandardError, "PQdescribePrepared not supported by this client version.");
|
63
|
+
}
|
64
|
+
|
65
|
+
PGresult *
|
66
|
+
PQdescribePortal(PGconn *conn, const char *portalName)
|
67
|
+
{
|
68
|
+
rb_raise(rb_eStandardError, "PQdescribePortal not supported by this client version.");
|
69
|
+
}
|
70
|
+
|
71
|
+
int
|
72
|
+
PQsendDescribePrepared(PGconn *conn, const char *stmtName)
|
73
|
+
{
|
74
|
+
rb_raise(rb_eStandardError, "PQsendDescribePrepared not supported by this client version.");
|
75
|
+
}
|
76
|
+
|
77
|
+
int
|
78
|
+
PQsendDescribePortal(PGconn *conn, const char *portalName)
|
79
|
+
{
|
80
|
+
rb_raise(rb_eStandardError, "PQsendDescribePortal not supported by this client version.");
|
81
|
+
}
|
82
|
+
|
83
|
+
char *
|
84
|
+
PQencryptPassword(const char *passwd, const char *user)
|
85
|
+
{
|
86
|
+
rb_raise(rb_eStandardError, "PQencryptPassword not supported by this client version.");
|
87
|
+
}
|
88
|
+
#endif /* PG_BEFORE_080200 */
|
89
|
+
|
90
|
+
#ifdef PG_BEFORE_080100
|
91
|
+
Oid
|
92
|
+
lo_create(PGconn *conn, Oid lobjId)
|
93
|
+
{
|
94
|
+
rb_raise(rb_eStandardError, "lo_create not supported by this client version.");
|
95
|
+
}
|
96
|
+
#endif /* PG_BEFORE_080100 */
|
97
|
+
|
98
|
+
#ifdef PG_BEFORE_080000
|
99
|
+
PGresult *
|
100
|
+
PQprepare(PGconn *conn, const char *stmtName, const char *query,
|
101
|
+
int nParams, const Oid *paramTypes)
|
102
|
+
{
|
103
|
+
rb_raise(rb_eStandardError, "PQprepare not supported by this client version.");
|
104
|
+
}
|
105
|
+
|
106
|
+
int
|
107
|
+
PQsendPrepare(PGconn *conn, const char *stmtName, const char *query,
|
108
|
+
int nParams, const Oid *paramTypes)
|
109
|
+
{
|
110
|
+
rb_raise(rb_eStandardError, "PQsendPrepare not supported by this client version.");
|
111
|
+
}
|
112
|
+
|
113
|
+
int
|
114
|
+
PQserverVersion(const PGconn* conn)
|
115
|
+
{
|
116
|
+
rb_raise(rb_eStandardError, "PQserverVersion not supported by this client version.");
|
117
|
+
}
|
118
|
+
#endif /* PG_BEFORE_080000 */
|
119
|
+
|
120
|
+
#ifdef PG_BEFORE_070400
|
121
|
+
PGresult *
|
122
|
+
PQexecParams(PGconn *conn, const char *command, int nParams,
|
123
|
+
const Oid *paramTypes, const char * const * paramValues, const int *paramLengths,
|
124
|
+
const int *paramFormats, int resultFormat)
|
125
|
+
{
|
126
|
+
rb_raise(rb_eStandardError, "PQexecParams not supported by this client version.");
|
127
|
+
}
|
128
|
+
|
129
|
+
PGTransactionStatusType
|
130
|
+
PQtransactionStatus(const PGconn *conn)
|
131
|
+
{
|
132
|
+
rb_raise(rb_eStandardError, "PQtransactionStatus not supported by this client version.");
|
133
|
+
}
|
134
|
+
|
135
|
+
char *
|
136
|
+
PQparameterStatus(const PGconn *conn, const char *paramName)
|
137
|
+
{
|
138
|
+
rb_raise(rb_eStandardError, "PQparameterStatus not supported by this client version.");
|
139
|
+
}
|
140
|
+
|
141
|
+
int
|
142
|
+
PQprotocolVersion(const PGconn *conn)
|
143
|
+
{
|
144
|
+
rb_raise(rb_eStandardError, "PQprotocolVersion not supported by this client version.");
|
145
|
+
}
|
146
|
+
|
147
|
+
PGresult
|
148
|
+
*PQexecPrepared(PGconn *conn, const char *stmtName, int nParams,
|
149
|
+
const char * const *ParamValues, const int *paramLengths, const int *paramFormats,
|
150
|
+
int resultFormat)
|
151
|
+
{
|
152
|
+
rb_raise(rb_eStandardError, "PQexecPrepared not supported by this client version.");
|
153
|
+
}
|
154
|
+
|
155
|
+
int
|
156
|
+
PQsendQueryParams(PGconn *conn, const char *command, int nParams,
|
157
|
+
const Oid *paramTypes, const char * const * paramValues, const int *paramLengths,
|
158
|
+
const int *paramFormats, int resultFormat)
|
159
|
+
{
|
160
|
+
rb_raise(rb_eStandardError, "PQsendQueryParams not supported by this client version.");
|
161
|
+
}
|
162
|
+
|
163
|
+
int
|
164
|
+
PQsendQueryPrepared(PGconn *conn, const char *stmtName, int nParams,
|
165
|
+
const char * const *ParamValues, const int *paramLengths, const int *paramFormats,
|
166
|
+
int resultFormat)
|
167
|
+
{
|
168
|
+
rb_raise(rb_eStandardError, "PQsendQueryPrepared not supported by this client version.");
|
169
|
+
}
|
170
|
+
|
171
|
+
int
|
172
|
+
PQputCopyData(PGconn *conn, const char *buffer, int nbytes)
|
173
|
+
{
|
174
|
+
rb_raise(rb_eStandardError, "PQputCopyData not supported by this client version.");
|
175
|
+
}
|
176
|
+
|
177
|
+
int
|
178
|
+
PQputCopyEnd(PGconn *conn, const char *errormsg)
|
179
|
+
{
|
180
|
+
rb_raise(rb_eStandardError, "PQputCopyEnd not supported by this client version.");
|
181
|
+
}
|
182
|
+
|
183
|
+
int
|
184
|
+
PQgetCopyData(PGconn *conn, char **buffer, int async)
|
185
|
+
{
|
186
|
+
rb_raise(rb_eStandardError, "PQgetCopyData not supported by this client version.");
|
187
|
+
}
|
188
|
+
|
189
|
+
PGVerbosity
|
190
|
+
PQsetErrorVerbosity(PGconn *conn, PGVerbosity verbosity)
|
191
|
+
{
|
192
|
+
rb_raise(rb_eStandardError, "PQsetErrorVerbosity not supported by this client version.");
|
193
|
+
}
|
194
|
+
|
195
|
+
Oid
|
196
|
+
PQftable(const PGresult *res, int column_number)
|
197
|
+
{
|
198
|
+
rb_raise(rb_eStandardError, "PQftable not supported by this client version.");
|
199
|
+
}
|
200
|
+
|
201
|
+
int
|
202
|
+
PQftablecol(const PGresult *res, int column_number)
|
203
|
+
{
|
204
|
+
rb_raise(rb_eStandardError, "PQftablecol not supported by this client version.");
|
205
|
+
}
|
206
|
+
|
207
|
+
int
|
208
|
+
PQfformat(const PGresult *res, int column_number)
|
209
|
+
{
|
210
|
+
rb_raise(rb_eStandardError, "PQfformat not supported by this client version.");
|
211
|
+
}
|
212
|
+
|
213
|
+
PQnoticeReceiver
|
214
|
+
PQsetNoticeReceiver(PGconn *conn, PQnoticeReceiver proc, void *arg)
|
215
|
+
{
|
216
|
+
rb_raise(rb_eStandardError, "PQsetNoticeReceiver not supported by this client version.");
|
217
|
+
}
|
218
|
+
|
219
|
+
char *
|
220
|
+
PQresultErrorField(const PGresult *res, int fieldcode)
|
221
|
+
{
|
222
|
+
rb_raise(rb_eStandardError, "PQresultErrorField not supported by this client version.");
|
223
|
+
}
|
224
|
+
#endif /* PG_BEFORE_070400 */
|
225
|
+
|
226
|
+
#ifdef PG_BEFORE_070300
|
227
|
+
size_t
|
228
|
+
PQescapeStringConn(PGconn *conn, char *to, const char *from,
|
229
|
+
size_t length, int *error)
|
230
|
+
{
|
231
|
+
return PQescapeString(to,from,length);
|
232
|
+
}
|
233
|
+
|
234
|
+
unsigned char *
|
235
|
+
PQescapeByteaConn(PGconn *conn, const unsigned char *from,
|
236
|
+
size_t from_length, size_t *to_length)
|
237
|
+
{
|
238
|
+
return PQescapeBytea(from, from_length, to_length);
|
239
|
+
}
|
240
|
+
#endif /* PG_BEFORE_070300 */
|
241
|
+
|
242
|
+
|
243
|
+
/**************************************************************************
|
244
|
+
|
245
|
+
IF ANY CODE IS COPIED FROM POSTGRESQL, PLACE IT AFTER THIS COMMENT.
|
246
|
+
|
247
|
+
***************************************************************************
|
248
|
+
|
249
|
+
Portions of code after this point were copied from the PostgreSQL source
|
250
|
+
distribution, available at http://www.postgresql.org
|
251
|
+
|
252
|
+
***************************************************************************
|
253
|
+
|
254
|
+
Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
|
255
|
+
|
256
|
+
Portions Copyright (c) 1994, The Regents of the University of California
|
257
|
+
|
258
|
+
Permission to use, copy, modify, and distribute this software and its
|
259
|
+
documentation for any purpose, without fee, and without a written agreement
|
260
|
+
is hereby granted, provided that the above copyright notice and this
|
261
|
+
paragraph and the following two paragraphs appear in all copies.
|
262
|
+
|
263
|
+
IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
|
264
|
+
DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING
|
265
|
+
LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS
|
266
|
+
DOCUMENTATION, EVEN IF THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE
|
267
|
+
POSSIBILITY OF SUCH DAMAGE.
|
268
|
+
|
269
|
+
THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
|
270
|
+
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
|
271
|
+
AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
|
272
|
+
ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATIONS TO
|
273
|
+
PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
|
274
|
+
|
275
|
+
**************************************************************************/
|
276
|
+
|
277
|
+
#ifndef HAVE_PQSETCLIENTENCODING
|
278
|
+
int
|
279
|
+
PQsetClientEncoding(PGconn *conn, const char *encoding)
|
280
|
+
{
|
281
|
+
char qbuf[128];
|
282
|
+
static const char query[] = "set client_encoding to '%s'";
|
283
|
+
PGresult *res;
|
284
|
+
int status;
|
285
|
+
|
286
|
+
if (!conn || PQstatus(conn) != CONNECTION_OK)
|
287
|
+
return -1;
|
288
|
+
|
289
|
+
if (!encoding)
|
290
|
+
return -1;
|
291
|
+
|
292
|
+
/* check query buffer overflow */
|
293
|
+
if (sizeof(qbuf) < (sizeof(query) + strlen(encoding)))
|
294
|
+
return -1;
|
295
|
+
|
296
|
+
/* ok, now send a query */
|
297
|
+
sprintf(qbuf, query, encoding);
|
298
|
+
res = PQexec(conn, qbuf);
|
299
|
+
|
300
|
+
if (res == NULL)
|
301
|
+
return -1;
|
302
|
+
if (PQresultStatus(res) != PGRES_COMMAND_OK)
|
303
|
+
status = -1;
|
304
|
+
else
|
305
|
+
{
|
306
|
+
/*
|
307
|
+
* In protocol 2 we have to assume the setting will stick, and adjust
|
308
|
+
* our state immediately. In protocol 3 and up we can rely on the
|
309
|
+
* backend to report the parameter value, and we'll change state at
|
310
|
+
* that time.
|
311
|
+
*/
|
312
|
+
if (PQprotocolVersion(conn) < 3)
|
313
|
+
pqSaveParameterStatus(conn, "client_encoding", encoding);
|
314
|
+
status = 0; /* everything is ok */
|
315
|
+
}
|
316
|
+
PQclear(res);
|
317
|
+
return status;
|
318
|
+
}
|
319
|
+
#endif /* HAVE_PQSETCLIENTENCODING */
|
320
|
+
|
321
|
+
#ifndef HAVE_PQESCAPESTRING
|
322
|
+
/*
|
323
|
+
* Escaping arbitrary strings to get valid SQL literal strings.
|
324
|
+
*
|
325
|
+
* Replaces "\\" with "\\\\" and "'" with "''".
|
326
|
+
*
|
327
|
+
* length is the length of the source string. (Note: if a terminating NUL
|
328
|
+
* is encountered sooner, PQescapeString stops short of "length"; the behavior
|
329
|
+
* is thus rather like strncpy.)
|
330
|
+
*
|
331
|
+
* For safety the buffer at "to" must be at least 2*length + 1 bytes long.
|
332
|
+
* A terminating NUL character is added to the output string, whether the
|
333
|
+
* input is NUL-terminated or not.
|
334
|
+
*
|
335
|
+
* Returns the actual length of the output (not counting the terminating NUL).
|
336
|
+
*/
|
337
|
+
size_t
|
338
|
+
PQescapeString(char *to, const char *from, size_t length)
|
339
|
+
{
|
340
|
+
const char *source = from;
|
341
|
+
char *target = to;
|
342
|
+
size_t remaining = length;
|
343
|
+
|
344
|
+
while (remaining > 0 && *source != '\0')
|
345
|
+
{
|
346
|
+
switch (*source)
|
347
|
+
{
|
348
|
+
case '\\':
|
349
|
+
*target++ = '\\';
|
350
|
+
*target++ = '\\';
|
351
|
+
break;
|
352
|
+
|
353
|
+
case '\'':
|
354
|
+
*target++ = '\'';
|
355
|
+
*target++ = '\'';
|
356
|
+
break;
|
357
|
+
|
358
|
+
default:
|
359
|
+
*target++ = *source;
|
360
|
+
break;
|
361
|
+
}
|
362
|
+
source++;
|
363
|
+
remaining--;
|
364
|
+
}
|
365
|
+
|
366
|
+
/* Write the terminating NUL character. */
|
367
|
+
*target = '\0';
|
368
|
+
|
369
|
+
return target - to;
|
370
|
+
}
|
371
|
+
|
372
|
+
/*
|
373
|
+
* PQescapeBytea - converts from binary string to the
|
374
|
+
* minimal encoding necessary to include the string in an SQL
|
375
|
+
* INSERT statement with a bytea type column as the target.
|
376
|
+
*
|
377
|
+
* The following transformations are applied
|
378
|
+
* '\0' == ASCII 0 == \\000
|
379
|
+
* '\'' == ASCII 39 == \'
|
380
|
+
* '\\' == ASCII 92 == \\\\
|
381
|
+
* anything < 0x20, or > 0x7e ---> \\ooo
|
382
|
+
* (where ooo is an octal expression)
|
383
|
+
*/
|
384
|
+
unsigned char *
|
385
|
+
PQescapeBytea(const unsigned char *bintext, size_t binlen, size_t *bytealen)
|
386
|
+
{
|
387
|
+
const unsigned char *vp;
|
388
|
+
unsigned char *rp;
|
389
|
+
unsigned char *result;
|
390
|
+
size_t i;
|
391
|
+
size_t len;
|
392
|
+
|
393
|
+
/*
|
394
|
+
* empty string has 1 char ('\0')
|
395
|
+
*/
|
396
|
+
len = 1;
|
397
|
+
|
398
|
+
vp = bintext;
|
399
|
+
for (i = binlen; i > 0; i--, vp++)
|
400
|
+
{
|
401
|
+
if (*vp < 0x20 || *vp > 0x7e)
|
402
|
+
len += 5; /* '5' is for '\\ooo' */
|
403
|
+
else if (*vp == '\'')
|
404
|
+
len += 2;
|
405
|
+
else if (*vp == '\\')
|
406
|
+
len += 4;
|
407
|
+
else
|
408
|
+
len++;
|
409
|
+
}
|
410
|
+
|
411
|
+
rp = result = (unsigned char *) malloc(len);
|
412
|
+
if (rp == NULL)
|
413
|
+
return NULL;
|
414
|
+
|
415
|
+
vp = bintext;
|
416
|
+
*bytealen = len;
|
417
|
+
|
418
|
+
for (i = binlen; i > 0; i--, vp++)
|
419
|
+
{
|
420
|
+
if (*vp < 0x20 || *vp > 0x7e)
|
421
|
+
{
|
422
|
+
(void) sprintf(rp, "\\\\%03o", *vp);
|
423
|
+
rp += 5;
|
424
|
+
}
|
425
|
+
else if (*vp == '\'')
|
426
|
+
{
|
427
|
+
rp[0] = '\\';
|
428
|
+
rp[1] = '\'';
|
429
|
+
rp += 2;
|
430
|
+
}
|
431
|
+
else if (*vp == '\\')
|
432
|
+
{
|
433
|
+
rp[0] = '\\';
|
434
|
+
rp[1] = '\\';
|
435
|
+
rp[2] = '\\';
|
436
|
+
rp[3] = '\\';
|
437
|
+
rp += 4;
|
438
|
+
}
|
439
|
+
else
|
440
|
+
*rp++ = *vp;
|
441
|
+
}
|
442
|
+
*rp = '\0';
|
443
|
+
|
444
|
+
return result;
|
445
|
+
}
|
446
|
+
|
447
|
+
#define ISFIRSTOCTDIGIT(CH) ((CH) >= '0' && (CH) <= '3')
|
448
|
+
#define ISOCTDIGIT(CH) ((CH) >= '0' && (CH) <= '7')
|
449
|
+
#define OCTVAL(CH) ((CH) - '0')
|
450
|
+
|
451
|
+
/*
|
452
|
+
* PQunescapeBytea - converts the null terminated string representation
|
453
|
+
* of a bytea, strtext, into binary, filling a buffer. It returns a
|
454
|
+
* pointer to the buffer (or NULL on error), and the size of the
|
455
|
+
* buffer in retbuflen. The pointer may subsequently be used as an
|
456
|
+
* argument to the function free(3). It is the reverse of PQescapeBytea.
|
457
|
+
*
|
458
|
+
* The following transformations are made:
|
459
|
+
* \\ == ASCII 92 == \
|
460
|
+
* \ooo == a byte whose value = ooo (ooo is an octal number)
|
461
|
+
* \x == x (x is any character not matched by the above transformations)
|
462
|
+
*/
|
463
|
+
unsigned char *
|
464
|
+
PQunescapeBytea(const unsigned char *strtext, size_t *retbuflen)
|
465
|
+
{
|
466
|
+
size_t strtextlen,
|
467
|
+
buflen;
|
468
|
+
unsigned char *buffer,
|
469
|
+
*tmpbuf;
|
470
|
+
size_t i,
|
471
|
+
j;
|
472
|
+
|
473
|
+
if (strtext == NULL)
|
474
|
+
return NULL;
|
475
|
+
|
476
|
+
strtextlen = strlen(strtext);
|
477
|
+
|
478
|
+
/*
|
479
|
+
* Length of input is max length of output, but add one to avoid
|
480
|
+
* unportable malloc(0) if input is zero-length.
|
481
|
+
*/
|
482
|
+
buffer = (unsigned char *) malloc(strtextlen + 1);
|
483
|
+
if (buffer == NULL)
|
484
|
+
return NULL;
|
485
|
+
|
486
|
+
for (i = j = 0; i < strtextlen;)
|
487
|
+
{
|
488
|
+
switch (strtext[i])
|
489
|
+
{
|
490
|
+
case '\\':
|
491
|
+
i++;
|
492
|
+
if (strtext[i] == '\\')
|
493
|
+
buffer[j++] = strtext[i++];
|
494
|
+
else
|
495
|
+
{
|
496
|
+
if ((ISFIRSTOCTDIGIT(strtext[i])) &&
|
497
|
+
(ISOCTDIGIT(strtext[i + 1])) &&
|
498
|
+
(ISOCTDIGIT(strtext[i + 2])))
|
499
|
+
{
|
500
|
+
int byte;
|
501
|
+
|
502
|
+
byte = OCTVAL(strtext[i++]);
|
503
|
+
byte = (byte << 3) + OCTVAL(strtext[i++]);
|
504
|
+
byte = (byte << 3) + OCTVAL(strtext[i++]);
|
505
|
+
buffer[j++] = byte;
|
506
|
+
}
|
507
|
+
}
|
508
|
+
|
509
|
+
/*
|
510
|
+
* Note: if we see '\' followed by something that isn't a
|
511
|
+
* recognized escape sequence, we loop around having done
|
512
|
+
* nothing except advance i. Therefore the something will
|
513
|
+
* be emitted as ordinary data on the next cycle. Corner
|
514
|
+
* case: '\' at end of string will just be discarded.
|
515
|
+
*/
|
516
|
+
break;
|
517
|
+
|
518
|
+
default:
|
519
|
+
buffer[j++] = strtext[i++];
|
520
|
+
break;
|
521
|
+
}
|
522
|
+
}
|
523
|
+
buflen = j; /* buflen is the length of the dequoted
|
524
|
+
* data */
|
525
|
+
|
526
|
+
/* Shrink the buffer to be no larger than necessary */
|
527
|
+
/* +1 avoids unportable behavior when buflen==0 */
|
528
|
+
tmpbuf = realloc(buffer, buflen + 1);
|
529
|
+
|
530
|
+
/* It would only be a very brain-dead realloc that could fail, but... */
|
531
|
+
if (!tmpbuf)
|
532
|
+
{
|
533
|
+
free(buffer);
|
534
|
+
return NULL;
|
535
|
+
}
|
536
|
+
|
537
|
+
*retbuflen = buflen;
|
538
|
+
return tmpbuf;
|
539
|
+
}
|
540
|
+
#endif
|
541
|
+
|