pg 0.8.0 → 0.9.0.pre156
Sign up to get free protection for your applications and to get access to all the features.
- data/ChangeLog +440 -230
- data/Contributors +2 -0
- data/README +41 -98
- data/README.OS_X +19 -0
- data/README.ja +183 -0
- data/README.windows +72 -0
- data/Rakefile.local +239 -0
- data/ext/extconf.rb +101 -62
- data/ext/pg.c +823 -142
- data/ext/pg.h +9 -2
- data/lib/pg.rb +11 -0
- data/rake/191_compat.rb +26 -0
- data/rake/dependencies.rb +76 -0
- data/rake/helpers.rb +435 -0
- data/rake/hg.rb +273 -0
- data/rake/manual.rb +782 -0
- data/rake/packaging.rb +123 -0
- data/rake/publishing.rb +274 -0
- data/rake/rdoc.rb +30 -0
- data/rake/style.rb +62 -0
- data/rake/svn.rb +668 -0
- data/rake/testing.rb +187 -0
- data/rake/verifytask.rb +64 -0
- data/spec/lib/helpers.rb +216 -0
- data/spec/m17n_spec.rb +139 -0
- data/spec/pgconn_spec.rb +199 -38
- data/spec/pgresult_spec.rb +157 -51
- metadata +71 -48
- data/COPYING.txt +0 -340
- data/Rakefile +0 -103
- data/doc/postgres.html +0 -278
- data/doc/postgres.jp.html +0 -256
- data/ext/mingw/Rakefile +0 -24
- data/ext/mingw/build.rake +0 -40
- data/ext/mkrf_config.rb +0 -138
- data/ext/vc/pg.sln +0 -26
- data/sample/losample.rb +0 -47
- data/sample/psql.rb +0 -1181
- data/sample/psqlHelp.rb +0 -158
- data/sample/test1.rb +0 -63
- data/sample/test2.rb +0 -44
- data/sample/test4.rb +0 -71
- data/spec/data/expected_trace.out +0 -26
- data/spec/data/random_binary_data +0 -0
data/Rakefile.local
ADDED
@@ -0,0 +1,239 @@
|
|
1
|
+
#!rake
|
2
|
+
|
3
|
+
require 'rake/extensiontask'
|
4
|
+
require 'rake/extensioncompiler'
|
5
|
+
require 'rbconfig'
|
6
|
+
|
7
|
+
# C extension constants
|
8
|
+
EXT_MAKEFILE = EXTDIR + 'Makefile'
|
9
|
+
EXT_SOURCES = FileList[ EXTDIR + '*.c' ]
|
10
|
+
EXT_SO = EXTDIR + "pg.#{CONFIG['DLEXT']}"
|
11
|
+
|
12
|
+
SITEARCH_DIR = LIBDIR + Config::CONFIG['sitearch']
|
13
|
+
|
14
|
+
NUM_CPUS = if File.exist?('/proc/cpuinfo')
|
15
|
+
File.read('/proc/cpuinfo').scan('processor').length
|
16
|
+
else
|
17
|
+
1
|
18
|
+
end
|
19
|
+
|
20
|
+
# Cross-compilation constants
|
21
|
+
COMPILE_HOME = File.expand_path("~/.rake-compiler")
|
22
|
+
OPENSSL_VERSION = ENV['OPENSSL_VERSION'] || '0.9.8l'
|
23
|
+
POSTGRESQL_VERSION = ENV['POSTGRESQL_VERSION'] || '8.4.2'
|
24
|
+
|
25
|
+
CROSS_PREFIX = if RUBY_PLATFORM.include?( 'darwin' )
|
26
|
+
'i386-mingw32'
|
27
|
+
else
|
28
|
+
'i586-mingw32msvc'
|
29
|
+
end
|
30
|
+
|
31
|
+
|
32
|
+
#####################################################################
|
33
|
+
### T A S K S
|
34
|
+
#####################################################################
|
35
|
+
|
36
|
+
# Make both the default task and the spec task depend on building the extension
|
37
|
+
task :local => :compile
|
38
|
+
task :spec => :compile
|
39
|
+
namespace :spec do
|
40
|
+
task :doc => [ :compile ]
|
41
|
+
task :quiet => [ :compile ]
|
42
|
+
task :html => [ :compile ]
|
43
|
+
task :text => [ :compile ]
|
44
|
+
end
|
45
|
+
|
46
|
+
ENV['RUBY_CC_VERSION'] = '1.8.6:1.9.1'
|
47
|
+
|
48
|
+
Rake::ExtensionTask.new do |ext|
|
49
|
+
ext.name = 'pg_ext'
|
50
|
+
ext.gem_spec = GEMSPEC
|
51
|
+
ext.ext_dir = 'ext'
|
52
|
+
ext.lib_dir = 'lib'
|
53
|
+
ext.source_pattern = "*.{c,h}"
|
54
|
+
|
55
|
+
# If there's an explicit 'compile' argument, use everything after it as options.
|
56
|
+
if offset = ARGV.index( 'compile' )
|
57
|
+
trace "config options = %p" % [ ARGV[(offset + 1)..-1] ]
|
58
|
+
ext.config_options = ARGV[ (offset + 1)..-1 ]
|
59
|
+
# Otherwise, just grab everything from the first option onward
|
60
|
+
elsif offset = ARGV.index( ARGV.find {|arg| arg =~ /^--/ } )
|
61
|
+
trace "config options = %p" % [ ARGV[offset..-1] ]
|
62
|
+
ext.config_options = ARGV[ offset..-1 ]
|
63
|
+
else
|
64
|
+
trace "No config options (ARGV = %p)" % [ ARGV ]
|
65
|
+
end
|
66
|
+
|
67
|
+
ext.cross_compile = true # enable cross compilation (requires cross compile toolchain)
|
68
|
+
ext.cross_platform = %w[i386-mswin32 i386-mingw32] # forces the Windows platform instead of the default one
|
69
|
+
|
70
|
+
# configure options only for cross compile
|
71
|
+
ext.cross_config_options += [
|
72
|
+
"--with-pg-include=#{COMPILE_HOME}/builds/postgresql-#{POSTGRESQL_VERSION}/src/interfaces/libpq",
|
73
|
+
"--with-opt-include=#{COMPILE_HOME}/builds/postgresql-#{POSTGRESQL_VERSION}/src/include",
|
74
|
+
"--with-pg-lib=#{COMPILE_HOME}/builds/postgresql-#{POSTGRESQL_VERSION}/src/interfaces/libpq",
|
75
|
+
"--with-opt-lib=#{COMPILE_HOME}/builds/openssl-#{OPENSSL_VERSION}",
|
76
|
+
"--enable-static-build",
|
77
|
+
]
|
78
|
+
|
79
|
+
end
|
80
|
+
|
81
|
+
|
82
|
+
desc "Stop any Postmaster instances that remain after testing."
|
83
|
+
task :cleanup_testing_dbs do
|
84
|
+
require 'spec/lib/helpers'
|
85
|
+
PgTestingHelpers.stop_existing_postmasters()
|
86
|
+
Rake::Task[:clean].invoke
|
87
|
+
end
|
88
|
+
|
89
|
+
|
90
|
+
#####################################################################
|
91
|
+
### C R O S S - C O M P I L A T I O N - T A S K S
|
92
|
+
#####################################################################
|
93
|
+
|
94
|
+
|
95
|
+
# define a location where sources will be stored
|
96
|
+
directory "#{COMPILE_HOME}/sources"
|
97
|
+
directory "#{COMPILE_HOME}/builds/openssl-#{OPENSSL_VERSION}"
|
98
|
+
|
99
|
+
# clean intermediate files and folders
|
100
|
+
CLEAN.include("#{COMPILE_HOME}/builds/openssl-#{OPENSSL_VERSION}")
|
101
|
+
|
102
|
+
# openssl source file should be stored there
|
103
|
+
file "#{COMPILE_HOME}/sources/openssl-#{OPENSSL_VERSION}.tar.gz" => ["#{COMPILE_HOME}/sources"] do |t|
|
104
|
+
# download the source file using wget or curl
|
105
|
+
chdir File.dirname(t.name) do
|
106
|
+
#http://www.openssl.org/source/openssl-0.9.8k.tar.gz
|
107
|
+
url = "http://www.openssl.org/source/#{File.basename(t.name)}"
|
108
|
+
sh "wget #{url} || curl -O #{url}"
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
# Extract the openssl builds
|
113
|
+
file "#{COMPILE_HOME}/builds/openssl-#{OPENSSL_VERSION}" => ["#{COMPILE_HOME}/sources/openssl-#{OPENSSL_VERSION}.tar.gz"] do |t|
|
114
|
+
chdir File.dirname(t.name) do
|
115
|
+
t.prerequisites.each { |f| sh "tar xfz ../sources/#{File.basename(f)}" }
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
# generate the makefile in a clean build location
|
120
|
+
file "#{COMPILE_HOME}/builds/openssl-#{OPENSSL_VERSION}/Makefile" =>
|
121
|
+
["#{COMPILE_HOME}/builds/openssl-#{OPENSSL_VERSION}"] do |t|
|
122
|
+
|
123
|
+
chdir File.dirname(t.name) do
|
124
|
+
sh File.expand_path("Configure"), 'mingw'
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
# make
|
129
|
+
file "#{COMPILE_HOME}/builds/openssl-#{OPENSSL_VERSION}/libssleay32.a" => ["#{COMPILE_HOME}/builds/openssl-#{OPENSSL_VERSION}/Makefile"] do |t|
|
130
|
+
chdir File.dirname(t.prerequisites.first) do
|
131
|
+
sh <<-EOT
|
132
|
+
export cross=#{CROSS_PREFIX}- &&
|
133
|
+
make -j#{NUM_CPUS} CC="${cross}gcc -DDSO_WIN32" AR="${cross}ar r" RANLIB="${cross}ranlib" build_libs &&
|
134
|
+
cp libcrypto.a libeay32.a &&
|
135
|
+
cp libssl.a libssleay32.a
|
136
|
+
EOT
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
#desc 'compile static libssl.a'
|
141
|
+
task 'openssl-make' => ["#{COMPILE_HOME}/builds/openssl-#{OPENSSL_VERSION}/libssleay32.a"]
|
142
|
+
|
143
|
+
|
144
|
+
# define a location where sources will be stored
|
145
|
+
directory "#{COMPILE_HOME}/builds/postgresql-#{POSTGRESQL_VERSION}"
|
146
|
+
|
147
|
+
# clean intermediate files and folders
|
148
|
+
CLEAN.include("#{COMPILE_HOME}/builds/postgresql-#{POSTGRESQL_VERSION}")
|
149
|
+
|
150
|
+
|
151
|
+
# postgresql source file should be stored there
|
152
|
+
file "#{COMPILE_HOME}/sources/postgresql-#{POSTGRESQL_VERSION}.tar.bz2" => ["#{COMPILE_HOME}/sources"] do |t|
|
153
|
+
# download the source file using wget or curl
|
154
|
+
chdir File.dirname(t.name) do
|
155
|
+
#http://wwwmaster.postgresql.org/redir/53/h/source/v8.4.0/postgresql-8.4.0.tar.bz2
|
156
|
+
url = "http://wwwmaster.postgresql.org/redir/53/h/source/v#{POSTGRESQL_VERSION}/#{File.basename(t.name)}"
|
157
|
+
sh "wget #{url} || curl -O #{url}"
|
158
|
+
end
|
159
|
+
end
|
160
|
+
|
161
|
+
# Extract the postgresql sources
|
162
|
+
file "#{COMPILE_HOME}/builds/postgresql-#{POSTGRESQL_VERSION}" => ["#{COMPILE_HOME}/sources/postgresql-#{POSTGRESQL_VERSION}.tar.bz2"] do |t|
|
163
|
+
chdir File.dirname(t.name) do
|
164
|
+
t.prerequisites.each { |f| sh "tar xfj ../sources/#{File.basename(f)}" }
|
165
|
+
end
|
166
|
+
end
|
167
|
+
|
168
|
+
# generate the makefile in a clean build location
|
169
|
+
file "#{COMPILE_HOME}/builds/postgresql-#{POSTGRESQL_VERSION}/src/Makefile.global" =>
|
170
|
+
["#{COMPILE_HOME}/builds/postgresql-#{POSTGRESQL_VERSION}",
|
171
|
+
"#{COMPILE_HOME}/builds/openssl-#{OPENSSL_VERSION}/libssleay32.a"] do |t|
|
172
|
+
|
173
|
+
options = [
|
174
|
+
'--target=i386-mingw32',
|
175
|
+
"--host=#{Rake::ExtensionCompiler.mingw_host}",
|
176
|
+
'--with-openssl',
|
177
|
+
'--without-zlib',
|
178
|
+
'--disable-shared',
|
179
|
+
]
|
180
|
+
|
181
|
+
chdir "#{COMPILE_HOME}/builds/postgresql-#{POSTGRESQL_VERSION}" do
|
182
|
+
configure_path = File.expand_path("#{COMPILE_HOME}/builds/postgresql-#{POSTGRESQL_VERSION}/configure")
|
183
|
+
sh <<-EOT
|
184
|
+
export CFLAGS=-L#{COMPILE_HOME}/builds/openssl-#{OPENSSL_VERSION} &&
|
185
|
+
export LDFLAGS=-L#{COMPILE_HOME}/builds/openssl-#{OPENSSL_VERSION} &&
|
186
|
+
export LDFLAGS_SL=-L#{COMPILE_HOME}/builds/openssl-#{OPENSSL_VERSION} &&
|
187
|
+
export "LIBS=-lwsock32 -lgdi32" &&
|
188
|
+
export CPPFLAGS=-I#{COMPILE_HOME}/builds/openssl-#{OPENSSL_VERSION}/include &&
|
189
|
+
#{configure_path} #{options.join(" ")}
|
190
|
+
EOT
|
191
|
+
end
|
192
|
+
end
|
193
|
+
|
194
|
+
# backup Makefile.shlib
|
195
|
+
file "#{COMPILE_HOME}/builds/postgresql-#{POSTGRESQL_VERSION}/src/Makefile.shlib.bak" => ["#{COMPILE_HOME}/builds/postgresql-#{POSTGRESQL_VERSION}/src/Makefile.global"] do |t|
|
196
|
+
cp "#{COMPILE_HOME}/builds/postgresql-#{POSTGRESQL_VERSION}/src/Makefile.shlib", t.name
|
197
|
+
end
|
198
|
+
|
199
|
+
# patch the Makefile.shlib
|
200
|
+
file "#{COMPILE_HOME}/builds/postgresql-#{POSTGRESQL_VERSION}/src/Makefile.shlib" => ["#{COMPILE_HOME}/builds/postgresql-#{POSTGRESQL_VERSION}/src/Makefile.shlib.bak"] do |t|
|
201
|
+
content = File.open(t.name, 'rb') { |f| f.read }
|
202
|
+
|
203
|
+
out = ""
|
204
|
+
|
205
|
+
content.each_line do |line|
|
206
|
+
if line =~ /^(\s*haslibarule\s*=\s*yes)/
|
207
|
+
out << "##{$1}\n"
|
208
|
+
else
|
209
|
+
out << line
|
210
|
+
end
|
211
|
+
end
|
212
|
+
|
213
|
+
when_writing("Patching Makefile.shlib") {
|
214
|
+
File.open(t.name, 'wb') { |f| f.write(out) }
|
215
|
+
}
|
216
|
+
end
|
217
|
+
|
218
|
+
|
219
|
+
# make libpq.a
|
220
|
+
file "#{COMPILE_HOME}/builds/postgresql-#{POSTGRESQL_VERSION}/src/interfaces/libpq/libpq.a" => ["#{COMPILE_HOME}/builds/postgresql-#{POSTGRESQL_VERSION}/src/Makefile.global", "#{COMPILE_HOME}/builds/postgresql-#{POSTGRESQL_VERSION}/src/Makefile.shlib"] do |t|
|
221
|
+
chdir File.dirname(t.name) do
|
222
|
+
sh "make -j#{NUM_CPUS} libpq.a PORTNAME=win32"
|
223
|
+
end
|
224
|
+
end
|
225
|
+
|
226
|
+
#desc 'compile static libpg.a'
|
227
|
+
task 'postgresql-make' => ['openssl-make', "#{COMPILE_HOME}/builds/postgresql-#{POSTGRESQL_VERSION}/src/interfaces/libpq/libpq.a"]
|
228
|
+
|
229
|
+
desc 'cross compile pg for win32'
|
230
|
+
task 'cross' => [:mingw32, 'postgresql-make']
|
231
|
+
|
232
|
+
task :mingw32 do
|
233
|
+
# Use Rake::ExtensionCompiler helpers to find the proper host
|
234
|
+
unless Rake::ExtensionCompiler.mingw_host then
|
235
|
+
warn "You need to install mingw32 cross compile functionality to be able to continue."
|
236
|
+
warn "Please refer to your distribution/package manager documentation about installation."
|
237
|
+
fail
|
238
|
+
end
|
239
|
+
end
|
data/ext/extconf.rb
CHANGED
@@ -1,87 +1,126 @@
|
|
1
1
|
require 'mkmf'
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
3
|
+
if pgdir = with_config( 'pg' )
|
4
|
+
ENV['PATH'] = "#{pgdir}/bin" + File::PATH_SEPERATOR + ENV['PATH']
|
5
|
+
end
|
6
|
+
|
7
|
+
### Read the output of a command using the fork+pipe syntax so execution errors
|
8
|
+
### propagate to Ruby.
|
9
|
+
def read_cmd_output( *cmd )
|
10
|
+
output = IO.read( '|-' ) or exec( *cmd )
|
11
|
+
return output.chomp
|
12
|
+
end
|
13
|
+
|
14
|
+
### Turn a version string into a Comparable binary datastructure
|
15
|
+
def vvec( version )
|
16
|
+
version.split( '.' ).collect {|i| Integer(i) }.pack( 'N*' )
|
17
|
+
end
|
18
|
+
|
19
|
+
|
20
|
+
if vvec(RUBY_VERSION) < vvec('1.8')
|
21
|
+
puts 'This library is for ruby-1.8 or higher.'
|
8
22
|
exit 1
|
9
23
|
end
|
10
24
|
|
11
|
-
|
12
|
-
if(
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
25
|
+
pgconfig = with_config( 'pg-config' ) || 'pg_config'
|
26
|
+
if pgconfig = find_executable( pgconfig )
|
27
|
+
$CPPFLAGS << " -I%s" % [ read_cmd_output(pgconfig, '--includedir') ]
|
28
|
+
$LDFLAGS << " -L%s" % [ read_cmd_output(pgconfig, '--libdir') ]
|
29
|
+
end
|
30
|
+
|
31
|
+
# Sort out the universal vs. single-archicture build problems on MacOS X
|
32
|
+
if RUBY_PLATFORM.include?( 'darwin' )
|
33
|
+
puts "MacOS X build: fixing architecture flags:"
|
34
|
+
|
35
|
+
# Only keep the '-arch <a>' flags present in both the cflags reported
|
36
|
+
# by pg_config and those that Ruby specifies.
|
37
|
+
commonflags = nil
|
38
|
+
if ENV['ARCHFLAGS']
|
39
|
+
puts " using the value in ARCHFLAGS environment variable (%p)." % [ ENV['ARCHFLAGS'] ]
|
40
|
+
commonflags = ENV['ARCHFLAGS']
|
41
|
+
elsif pgconfig
|
42
|
+
puts " finding flags common to both Ruby and PostgreSQL..."
|
43
|
+
archflags = []
|
44
|
+
pgcflags = read_cmd_output( pgconfig, '--cflags' )
|
45
|
+
pgcflags.scan( /-arch\s+(\S+)/ ).each do |arch|
|
46
|
+
puts " testing for architecture: %p" % [ arch ]
|
47
|
+
archflags << "-arch #{arch}" if Config::CONFIG['CFLAGS'].index("-arch #{arch}")
|
24
48
|
end
|
25
|
-
|
49
|
+
|
50
|
+
commonflags = archflags.join(' ')
|
51
|
+
puts " common arch flags: %s" % [ commonflags ]
|
52
|
+
else
|
53
|
+
$stderr.puts %{
|
26
54
|
=========== WARNING ===========
|
27
55
|
|
28
56
|
You are building this extension on OS X without setting the
|
29
|
-
ARCHFLAGS environment variable, and
|
30
|
-
|
31
|
-
|
57
|
+
ARCHFLAGS environment variable, and pg_config wasn't found in
|
58
|
+
your PATH. If you are seeing this message, that means that the
|
59
|
+
build will probably fail.
|
32
60
|
|
33
|
-
|
34
|
-
to '
|
61
|
+
If it does, you can correct this by either including the path
|
62
|
+
to 'pg_config' in your PATH or setting the environment variable
|
63
|
+
ARCHFLAGS to '-arch <arch>' before building.
|
35
64
|
|
36
65
|
For example:
|
37
|
-
(in bash) $ export
|
38
|
-
|
66
|
+
(in bash) $ export PATH=/opt/local/lib/postgresql84/bin:$PATH
|
67
|
+
$ export ARCHFLAGS='-arch x86_64'
|
68
|
+
(in tcsh) % set path = ( /opt/local/lib/postgresql84/bin $PATH )
|
69
|
+
% setenv ARCHFLAGS '-arch x86_64'
|
39
70
|
|
40
71
|
Then try building again.
|
41
72
|
|
42
73
|
===================================
|
43
|
-
}
|
44
|
-
# We don't exit here. Who knows? It might build.
|
74
|
+
}.gsub( /^\t+/, ' ' )
|
45
75
|
end
|
46
|
-
end
|
47
76
|
|
48
|
-
if
|
49
|
-
|
50
|
-
|
51
|
-
|
77
|
+
if commonflags
|
78
|
+
$CFLAGS.gsub!( /-arch\s+\S+ /, '' )
|
79
|
+
$LDFLAGS.gsub!( /-arch\s+\S+ /, '' )
|
80
|
+
CONFIG['LDSHARED'].gsub!( /-arch\s+\S+ /, '' )
|
52
81
|
|
53
|
-
|
54
|
-
|
82
|
+
$CFLAGS << ' ' << commonflags
|
83
|
+
$LDFLAGS << ' ' << commonflags
|
84
|
+
CONFIG['LDSHARED'] << ' ' << commonflags
|
85
|
+
end
|
55
86
|
end
|
56
87
|
|
57
|
-
def pg_config(type)
|
58
|
-
IO.popen("pg_config --#{type}dir").readline.chomp rescue nil
|
59
|
-
end
|
60
88
|
|
61
|
-
|
62
|
-
(have_library('pq') || have_library('libpq') || have_library('ms/libpq')) &&
|
63
|
-
have_header('libpq-fe.h') && have_header('libpq/libpq-fs.h')
|
64
|
-
end
|
89
|
+
dir_config 'pg'
|
65
90
|
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
PQexecParams
|
73
|
-
PQescapeString
|
74
|
-
PQescapeStringConn
|
75
|
-
lo_create
|
76
|
-
pg_encoding_to_char
|
77
|
-
PQsetClientEncoding
|
78
|
-
)
|
79
|
-
|
80
|
-
if have_build_env
|
81
|
-
desired_functions.each(&method(:have_func))
|
82
|
-
$OBJS = ['pg.o','compat.o']
|
83
|
-
create_makefile("pg")
|
84
|
-
else
|
85
|
-
puts 'Could not find PostgreSQL build environment (libraries & headers): Makefile not created'
|
91
|
+
if enable_config("static-build")
|
92
|
+
# Link against all required libraries for static build, if they are available
|
93
|
+
have_library('gdi32', 'CreateDC') && append_library($libs, 'gdi32')
|
94
|
+
have_library('secur32') && append_library($libs, 'secur32')
|
95
|
+
have_library('crypto', 'BIO_new') && append_library($libs, 'crypto')
|
96
|
+
have_library('ssl', 'SSL_new') && append_library($libs, 'ssl')
|
86
97
|
end
|
87
98
|
|
99
|
+
|
100
|
+
abort "Can't find the 'libpq-fe.h header" unless have_header( 'libpq-fe.h' )
|
101
|
+
abort "Can't find the 'libpq/libpq-fs.h header" unless have_header('libpq/libpq-fs.h')
|
102
|
+
|
103
|
+
abort "Can't find the PostgreSQL client library (libpq)" unless
|
104
|
+
have_library( 'pq', 'PQconnectdb' ) ||
|
105
|
+
have_library( 'libpq', 'PQconnectdb' ) ||
|
106
|
+
have_library( 'ms/libpq', 'PQconnectdb' )
|
107
|
+
|
108
|
+
# optional headers/functions
|
109
|
+
have_func 'PQconnectionUsedPassword'
|
110
|
+
have_func 'PQisthreadsafe'
|
111
|
+
have_func 'PQprepare'
|
112
|
+
have_func 'PQexecParams'
|
113
|
+
have_func 'PQescapeString'
|
114
|
+
have_func 'PQescapeStringConn'
|
115
|
+
have_func 'lo_create'
|
116
|
+
have_func 'pg_encoding_to_char'
|
117
|
+
have_func 'PQsetClientEncoding'
|
118
|
+
|
119
|
+
# unistd.h confilicts with ruby/win32.h when cross compiling for win32 and ruby 1.9.1
|
120
|
+
have_header 'unistd.h' unless enable_config("static-build")
|
121
|
+
|
122
|
+
$CFLAGS << ' -Wall'
|
123
|
+
|
124
|
+
create_header()
|
125
|
+
create_makefile( "pg_ext" )
|
126
|
+
|
data/ext/pg.c
CHANGED
@@ -8,11 +8,14 @@
|
|
8
8
|
Author: ematsu
|
9
9
|
modified at: Wed Jan 20 16:41:51 1999
|
10
10
|
|
11
|
-
$Author
|
12
|
-
$Date
|
11
|
+
$Author$
|
12
|
+
$Date$
|
13
13
|
************************************************/
|
14
14
|
|
15
15
|
#include "pg.h"
|
16
|
+
#if defined(HAVE_RUBY_ENCODING_H) && HAVE_RUBY_ENCODING_H
|
17
|
+
# define M17N_SUPPORTED
|
18
|
+
#endif
|
16
19
|
|
17
20
|
#define rb_define_singleton_alias(klass,new,old) rb_define_alias(rb_singleton_class(klass),new,old)
|
18
21
|
|
@@ -20,6 +23,9 @@ static VALUE rb_cPGconn;
|
|
20
23
|
static VALUE rb_cPGresult;
|
21
24
|
static VALUE rb_ePGError;
|
22
25
|
|
26
|
+
static const char *VERSION = "0.9.0";
|
27
|
+
|
28
|
+
|
23
29
|
/* The following functions are part of libpq, but not
|
24
30
|
* available from ruby-pg, because they are deprecated,
|
25
31
|
* obsolete, or generally not useful:
|
@@ -51,10 +57,20 @@ static PGconn *get_pgconn(VALUE self);
|
|
51
57
|
static VALUE pgconn_finish(VALUE self);
|
52
58
|
static VALUE pgresult_clear(VALUE self);
|
53
59
|
static VALUE pgresult_aref(VALUE self, VALUE index);
|
60
|
+
static VALUE make_column_result_array( VALUE self, int col );
|
61
|
+
|
62
|
+
#ifdef M17N_SUPPORTED
|
63
|
+
# define ASSOCIATE_INDEX(obj, index_holder) rb_enc_associate_index((obj), enc_get_index((index_holder)))
|
64
|
+
static rb_encoding * pgconn_get_client_encoding_as_rb_encoding(PGconn* conn);
|
65
|
+
static int enc_get_index(VALUE val);
|
66
|
+
#else
|
67
|
+
# define ASSOCIATE_INDEX(obj, index_holder) /* nothing */
|
68
|
+
#endif
|
54
69
|
|
55
70
|
static PQnoticeReceiver default_notice_receiver = NULL;
|
56
71
|
static PQnoticeProcessor default_notice_processor = NULL;
|
57
72
|
|
73
|
+
|
58
74
|
/*
|
59
75
|
* Used to quote the values passed in a Hash to PGconn.init
|
60
76
|
* when building the connection string.
|
@@ -115,11 +131,23 @@ get_pgresult(VALUE self)
|
|
115
131
|
return result;
|
116
132
|
}
|
117
133
|
|
134
|
+
#ifdef M17N_SUPPORTED
|
135
|
+
static VALUE
|
136
|
+
new_pgresult(PGresult *result, PGconn *conn)
|
137
|
+
{
|
138
|
+
VALUE val = Data_Wrap_Struct(rb_cPGresult, NULL, free_pgresult, result);
|
139
|
+
rb_encoding *enc = pgconn_get_client_encoding_as_rb_encoding(conn);
|
140
|
+
rb_enc_set_index(val, rb_enc_to_index(enc));
|
141
|
+
return val;
|
142
|
+
}
|
143
|
+
#else
|
118
144
|
static VALUE
|
119
145
|
new_pgresult(PGresult *result)
|
120
146
|
{
|
121
147
|
return Data_Wrap_Struct(rb_cPGresult, NULL, free_pgresult, result);
|
122
148
|
}
|
149
|
+
# define new_pgresult(result, conn) new_pgresult((result))
|
150
|
+
#endif
|
123
151
|
|
124
152
|
/*
|
125
153
|
* Raises appropriate exception if PGresult is
|
@@ -164,17 +192,6 @@ pgresult_check(VALUE rb_pgconn, VALUE rb_pgresult)
|
|
164
192
|
return;
|
165
193
|
}
|
166
194
|
|
167
|
-
static VALUE
|
168
|
-
yield_pgresult(VALUE rb_pgresult)
|
169
|
-
{
|
170
|
-
int i;
|
171
|
-
PGresult *result = get_pgresult(rb_pgresult);
|
172
|
-
for(i = 0; i < PQntuples(result); i++) {
|
173
|
-
return rb_yield(pgresult_aref(rb_pgresult, INT2NUM(i)));
|
174
|
-
}
|
175
|
-
return Qnil;
|
176
|
-
}
|
177
|
-
|
178
195
|
static void
|
179
196
|
notice_receiver_proxy(void *arg, const PGresult *result)
|
180
197
|
{
|
@@ -330,26 +347,48 @@ pgconn_alloc(VALUE klass)
|
|
330
347
|
* PGconn.new(connection_hash) -> PGconn
|
331
348
|
* PGconn.new(connection_string) -> PGconn
|
332
349
|
* PGconn.new(host, port, options, tty, dbname, login, password) -> PGconn
|
333
|
-
*
|
334
|
-
*
|
335
|
-
*
|
336
|
-
*
|
337
|
-
*
|
338
|
-
*
|
339
|
-
*
|
340
|
-
*
|
341
|
-
*
|
342
|
-
*
|
343
|
-
*
|
344
|
-
*
|
345
|
-
*
|
346
|
-
*
|
347
|
-
*
|
348
|
-
*
|
349
|
-
*
|
350
|
-
*
|
350
|
+
*
|
351
|
+
* Create a connection to the specified server.
|
352
|
+
*
|
353
|
+
* [+host+]
|
354
|
+
* server hostname
|
355
|
+
* [+hostaddr+]
|
356
|
+
* server address (avoids hostname lookup, overrides +host+)
|
357
|
+
* [+port+]
|
358
|
+
* server port number
|
359
|
+
* [+dbname+]
|
360
|
+
* connecting database name
|
361
|
+
* [+user+]
|
362
|
+
* login user name
|
363
|
+
* [+password+]
|
364
|
+
* login password
|
365
|
+
* [+connect_timeout+]
|
366
|
+
* maximum time to wait for connection to succeed
|
367
|
+
* [+options+]
|
368
|
+
* backend options
|
369
|
+
* [+tty+]
|
370
|
+
* (ignored in newer versions of PostgreSQL)
|
371
|
+
* [+sslmode+]
|
372
|
+
* (disable|allow|prefer|require)
|
373
|
+
* [+krbsrvname+]
|
374
|
+
* kerberos service name
|
375
|
+
* [+gsslib+]
|
376
|
+
* GSS library to use for GSSAPI authentication
|
377
|
+
* [+service+]
|
378
|
+
* service name to use for additional parameters
|
379
|
+
*
|
380
|
+
* Examples:
|
381
|
+
*
|
382
|
+
* # As a Hash
|
383
|
+
* PGconn.connect( :dbname => 'test', :port => 5432 )
|
384
|
+
*
|
385
|
+
* # As a String
|
386
|
+
* PGconn.connect( "dbname=test port=5432" )
|
387
|
+
*
|
388
|
+
* # As an Array
|
389
|
+
* PGconn.connect( nil, 5432, nil, nil, 'test', nil, nil )
|
351
390
|
*
|
352
|
-
*
|
391
|
+
* On failure, it raises a PGError.
|
353
392
|
*/
|
354
393
|
static VALUE
|
355
394
|
pgconn_init(int argc, VALUE *argv, VALUE self)
|
@@ -381,8 +420,8 @@ pgconn_init(int argc, VALUE *argv, VALUE self)
|
|
381
420
|
|
382
421
|
/*
|
383
422
|
* call-seq:
|
384
|
-
* PGconn.connect_start(connection_hash)
|
385
|
-
* PGconn.connect_start(connection_string)
|
423
|
+
* PGconn.connect_start(connection_hash) -> PGconn
|
424
|
+
* PGconn.connect_start(connection_string) -> PGconn
|
386
425
|
* PGconn.connect_start(host, port, options, tty, dbname, login, password) -> PGconn
|
387
426
|
*
|
388
427
|
* This is an asynchronous version of PGconn.connect().
|
@@ -404,7 +443,7 @@ pgconn_s_connect_start(int argc, VALUE *argv, VALUE self)
|
|
404
443
|
rb_conn = pgconn_alloc(rb_cPGconn);
|
405
444
|
|
406
445
|
conninfo = parse_connect_args(argc, argv, self);
|
407
|
-
conn =
|
446
|
+
conn = PQconnectStart(StringValuePtr(conninfo));
|
408
447
|
|
409
448
|
if(conn == NULL)
|
410
449
|
rb_raise(rb_ePGError, "PQconnectStart() unable to allocate structure");
|
@@ -428,13 +467,20 @@ pgconn_s_connect_start(int argc, VALUE *argv, VALUE self)
|
|
428
467
|
* PGconn.conndefaults() -> Array
|
429
468
|
*
|
430
469
|
* Returns an array of hashes. Each hash has the keys:
|
431
|
-
*
|
432
|
-
*
|
433
|
-
*
|
434
|
-
*
|
435
|
-
*
|
436
|
-
*
|
437
|
-
*
|
470
|
+
* [+:keyword+]
|
471
|
+
* the name of the option
|
472
|
+
* [+:envvar+]
|
473
|
+
* the environment variable to fall back to
|
474
|
+
* [+:compiled+]
|
475
|
+
* the compiled in option as a secondary fallback
|
476
|
+
* [+:val+]
|
477
|
+
* the option's current value, or +nil+ if not known
|
478
|
+
* [+:label+]
|
479
|
+
* the label for the field
|
480
|
+
* [+:dispchar+]
|
481
|
+
* "" for normal, "D" for debug, and "*" for password
|
482
|
+
* [+:dispsize+]
|
483
|
+
* field size
|
438
484
|
*/
|
439
485
|
static VALUE
|
440
486
|
pgconn_s_conndefaults(VALUE self)
|
@@ -487,14 +533,23 @@ pgconn_s_conndefaults(VALUE self)
|
|
487
533
|
static VALUE
|
488
534
|
pgconn_s_encrypt_password(VALUE self, VALUE password, VALUE username)
|
489
535
|
{
|
490
|
-
char *
|
536
|
+
char *encrypted = NULL;
|
537
|
+
VALUE rval = Qnil;
|
538
|
+
|
491
539
|
Check_Type(password, T_STRING);
|
492
540
|
Check_Type(username, T_STRING);
|
493
|
-
|
494
|
-
|
495
|
-
|
541
|
+
|
542
|
+
encrypted = PQencryptPassword(StringValuePtr(password), StringValuePtr(username));
|
543
|
+
rval = rb_str_new2( encrypted );
|
544
|
+
PQfreemem( encrypted );
|
545
|
+
|
546
|
+
OBJ_INFECT( rval, password );
|
547
|
+
OBJ_INFECT( rval, username );
|
548
|
+
|
549
|
+
return rval;
|
496
550
|
}
|
497
551
|
|
552
|
+
|
498
553
|
/*
|
499
554
|
* call-seq:
|
500
555
|
* PGconn.isthreadsafe() -> Boolean
|
@@ -516,10 +571,14 @@ pgconn_s_isthreadsafe(VALUE self)
|
|
516
571
|
* conn.connect_poll() -> Fixnum
|
517
572
|
*
|
518
573
|
* Returns one of:
|
519
|
-
*
|
520
|
-
*
|
521
|
-
*
|
522
|
-
*
|
574
|
+
* [+PGRES_POLLING_READING+]
|
575
|
+
* wait until the socket is ready to read
|
576
|
+
* [+PGRES_POLLING_WRITING+]
|
577
|
+
* wait until the socket is ready to write
|
578
|
+
* [+PGRES_POLLING_FAILED+]
|
579
|
+
* the asynchronous connection has failed
|
580
|
+
* [+PGRES_POLLING_OK+]
|
581
|
+
* the asynchronous connection is ready
|
523
582
|
*
|
524
583
|
* Example:
|
525
584
|
* conn = PGconn.connect_start("dbname=mydatabase")
|
@@ -768,7 +827,7 @@ pgconn_parameter_status(VALUE self, VALUE param_name)
|
|
768
827
|
|
769
828
|
/*
|
770
829
|
* call-seq:
|
771
|
-
*
|
830
|
+
* conn.protocol_version -> Integer
|
772
831
|
*
|
773
832
|
* The 3.0 protocol will normally be used when communicating with PostgreSQL 7.4
|
774
833
|
* or later servers; pre-7.4 servers support only protocol 2.0. (Protocol 1.0 is
|
@@ -780,11 +839,16 @@ pgconn_protocol_version(VALUE self)
|
|
780
839
|
return INT2NUM(PQprotocolVersion(get_pgconn(self)));
|
781
840
|
}
|
782
841
|
|
783
|
-
/*
|
784
|
-
* call-seq:
|
842
|
+
/*
|
843
|
+
* call-seq:
|
785
844
|
* conn.server_version -> Integer
|
786
|
-
*
|
787
|
-
* The number is formed by converting the major, minor, and revision
|
845
|
+
*
|
846
|
+
* The number is formed by converting the major, minor, and revision
|
847
|
+
* numbers into two-decimal-digit numbers and appending them together.
|
848
|
+
* For example, version 7.4.2 will be returned as 70402, and version
|
849
|
+
* 8.1 will be returned as 80100 (leading zeroes are not shown). Zero
|
850
|
+
* is returned if the connection is bad.
|
851
|
+
*
|
788
852
|
*/
|
789
853
|
static VALUE
|
790
854
|
pgconn_server_version(VALUE self)
|
@@ -869,6 +933,7 @@ pgconn_connection_used_password(VALUE self)
|
|
869
933
|
/*
|
870
934
|
* call-seq:
|
871
935
|
* conn.exec(sql [, params, result_format ] ) -> PGresult
|
936
|
+
* conn.exec(sql [, params, result_format ] ) {|pg_result| block }
|
872
937
|
*
|
873
938
|
* Sends SQL query request specified by _sql_ to PostgreSQL.
|
874
939
|
* Returns a PGresult instance on success.
|
@@ -896,6 +961,10 @@ pgconn_connection_used_password(VALUE self)
|
|
896
961
|
*
|
897
962
|
* The optional +result_format+ should be 0 for text results, 1
|
898
963
|
* for binary.
|
964
|
+
*
|
965
|
+
* If the optional code block is given, it will be passed <i>result</i> as an argument,
|
966
|
+
* and the PGresult object will automatically be cleared when the block terminates.
|
967
|
+
* In this instance, <code>conn.exec</code> returns the value of the block.
|
899
968
|
*/
|
900
969
|
static VALUE
|
901
970
|
pgconn_exec(int argc, VALUE *argv, VALUE self)
|
@@ -923,10 +992,10 @@ pgconn_exec(int argc, VALUE *argv, VALUE self)
|
|
923
992
|
/* If called with no parameters, use PQexec */
|
924
993
|
if(NIL_P(params)) {
|
925
994
|
result = PQexec(conn, StringValuePtr(command));
|
926
|
-
rb_pgresult = new_pgresult(result);
|
995
|
+
rb_pgresult = new_pgresult(result, conn);
|
927
996
|
pgresult_check(self, rb_pgresult);
|
928
997
|
if (rb_block_given_p()) {
|
929
|
-
return rb_ensure(
|
998
|
+
return rb_ensure(rb_yield, rb_pgresult,
|
930
999
|
pgresult_clear, rb_pgresult);
|
931
1000
|
}
|
932
1001
|
return rb_pgresult;
|
@@ -1007,10 +1076,10 @@ pgconn_exec(int argc, VALUE *argv, VALUE self)
|
|
1007
1076
|
xfree(paramLengths);
|
1008
1077
|
xfree(paramFormats);
|
1009
1078
|
|
1010
|
-
rb_pgresult = new_pgresult(result);
|
1079
|
+
rb_pgresult = new_pgresult(result, conn);
|
1011
1080
|
pgresult_check(self, rb_pgresult);
|
1012
1081
|
if (rb_block_given_p()) {
|
1013
|
-
return rb_ensure(
|
1082
|
+
return rb_ensure(rb_yield, rb_pgresult,
|
1014
1083
|
pgresult_clear, rb_pgresult);
|
1015
1084
|
}
|
1016
1085
|
return rb_pgresult;
|
@@ -1070,7 +1139,7 @@ pgconn_prepare(int argc, VALUE *argv, VALUE self)
|
|
1070
1139
|
|
1071
1140
|
xfree(paramTypes);
|
1072
1141
|
|
1073
|
-
rb_pgresult = new_pgresult(result);
|
1142
|
+
rb_pgresult = new_pgresult(result, conn);
|
1074
1143
|
pgresult_check(self, rb_pgresult);
|
1075
1144
|
return rb_pgresult;
|
1076
1145
|
}
|
@@ -1078,6 +1147,7 @@ pgconn_prepare(int argc, VALUE *argv, VALUE self)
|
|
1078
1147
|
/*
|
1079
1148
|
* call-seq:
|
1080
1149
|
* conn.exec_prepared(statement_name [, params, result_format ] ) -> PGresult
|
1150
|
+
* conn.exec_prepared(statement_name [, params, result_format ] ) {|pg_result| block }
|
1081
1151
|
*
|
1082
1152
|
* Execute prepared named statement specified by _statement_name_.
|
1083
1153
|
* Returns a PGresult instance on success.
|
@@ -1098,6 +1168,10 @@ pgconn_prepare(int argc, VALUE *argv, VALUE self)
|
|
1098
1168
|
*
|
1099
1169
|
* The optional +result_format+ should be 0 for text results, 1
|
1100
1170
|
* for binary.
|
1171
|
+
*
|
1172
|
+
* If the optional code block is given, it will be passed <i>result</i> as an argument,
|
1173
|
+
* and the PGresult object will automatically be cleared when the block terminates.
|
1174
|
+
* In this instance, <code>conn.exec_prepared</code> returns the value of the block.
|
1101
1175
|
*/
|
1102
1176
|
static VALUE
|
1103
1177
|
pgconn_exec_prepared(int argc, VALUE *argv, VALUE self)
|
@@ -1189,10 +1263,10 @@ pgconn_exec_prepared(int argc, VALUE *argv, VALUE self)
|
|
1189
1263
|
xfree(paramLengths);
|
1190
1264
|
xfree(paramFormats);
|
1191
1265
|
|
1192
|
-
rb_pgresult = new_pgresult(result);
|
1266
|
+
rb_pgresult = new_pgresult(result, conn);
|
1193
1267
|
pgresult_check(self, rb_pgresult);
|
1194
1268
|
if (rb_block_given_p()) {
|
1195
|
-
return rb_ensure(
|
1269
|
+
return rb_ensure(rb_yield, rb_pgresult,
|
1196
1270
|
pgresult_clear, rb_pgresult);
|
1197
1271
|
}
|
1198
1272
|
return rb_pgresult;
|
@@ -1220,7 +1294,7 @@ pgconn_describe_prepared(VALUE self, VALUE stmt_name)
|
|
1220
1294
|
stmt = StringValuePtr(stmt_name);
|
1221
1295
|
}
|
1222
1296
|
result = PQdescribePrepared(conn, stmt);
|
1223
|
-
rb_pgresult = new_pgresult(result);
|
1297
|
+
rb_pgresult = new_pgresult(result, conn);
|
1224
1298
|
pgresult_check(self, rb_pgresult);
|
1225
1299
|
return rb_pgresult;
|
1226
1300
|
}
|
@@ -1248,7 +1322,7 @@ pgconn_describe_portal(self, stmt_name)
|
|
1248
1322
|
stmt = StringValuePtr(stmt_name);
|
1249
1323
|
}
|
1250
1324
|
result = PQdescribePortal(conn, stmt);
|
1251
|
-
rb_pgresult = new_pgresult(result);
|
1325
|
+
rb_pgresult = new_pgresult(result, conn);
|
1252
1326
|
pgresult_check(self, rb_pgresult);
|
1253
1327
|
return rb_pgresult;
|
1254
1328
|
}
|
@@ -1276,7 +1350,7 @@ pgconn_make_empty_pgresult(VALUE self, VALUE status)
|
|
1276
1350
|
VALUE rb_pgresult;
|
1277
1351
|
PGconn *conn = get_pgconn(self);
|
1278
1352
|
result = PQmakeEmptyPGresult(conn, NUM2INT(status));
|
1279
|
-
rb_pgresult = new_pgresult(result);
|
1353
|
+
rb_pgresult = new_pgresult(result, conn);
|
1280
1354
|
pgresult_check(self, rb_pgresult);
|
1281
1355
|
return rb_pgresult;
|
1282
1356
|
}
|
@@ -1297,6 +1371,8 @@ pgconn_make_empty_pgresult(VALUE self, VALUE status)
|
|
1297
1371
|
*
|
1298
1372
|
* Consider using exec_params, which avoids the need for passing values
|
1299
1373
|
* inside of SQL commands.
|
1374
|
+
*
|
1375
|
+
* Encoding of escaped string will be equal to client encoding of connection.
|
1300
1376
|
*/
|
1301
1377
|
static VALUE
|
1302
1378
|
pgconn_s_escape(VALUE self, VALUE string)
|
@@ -1304,15 +1380,19 @@ pgconn_s_escape(VALUE self, VALUE string)
|
|
1304
1380
|
char *escaped;
|
1305
1381
|
int size,error;
|
1306
1382
|
VALUE result;
|
1383
|
+
#ifdef M17N_SUPPORTED
|
1384
|
+
rb_encoding* enc;
|
1385
|
+
#endif
|
1307
1386
|
|
1308
1387
|
Check_Type(string, T_STRING);
|
1309
1388
|
|
1310
1389
|
escaped = ALLOC_N(char, RSTRING_LEN(string) * 2 + 1);
|
1311
|
-
if(
|
1390
|
+
if(rb_obj_class(self) == rb_cPGconn) {
|
1312
1391
|
size = PQescapeStringConn(get_pgconn(self), escaped,
|
1313
1392
|
RSTRING_PTR(string), RSTRING_LEN(string), &error);
|
1314
1393
|
if(error) {
|
1315
|
-
|
1394
|
+
xfree(escaped);
|
1395
|
+
rb_raise(rb_ePGError, "%s", PQerrorMessage(get_pgconn(self)));
|
1316
1396
|
}
|
1317
1397
|
} else {
|
1318
1398
|
size = PQescapeString(escaped, RSTRING_PTR(string),
|
@@ -1321,6 +1401,16 @@ pgconn_s_escape(VALUE self, VALUE string)
|
|
1321
1401
|
result = rb_str_new(escaped, size);
|
1322
1402
|
xfree(escaped);
|
1323
1403
|
OBJ_INFECT(result, string);
|
1404
|
+
|
1405
|
+
#ifdef M17N_SUPPORTED
|
1406
|
+
if(rb_obj_class(self) == rb_cPGconn) {
|
1407
|
+
enc = pgconn_get_client_encoding_as_rb_encoding(get_pgconn(self));
|
1408
|
+
} else {
|
1409
|
+
enc = rb_enc_get(string);
|
1410
|
+
}
|
1411
|
+
rb_enc_associate(result, enc);
|
1412
|
+
#endif
|
1413
|
+
|
1324
1414
|
return result;
|
1325
1415
|
}
|
1326
1416
|
|
@@ -1360,7 +1450,7 @@ pgconn_s_escape_bytea(VALUE self, VALUE str)
|
|
1360
1450
|
from = (unsigned char*)RSTRING_PTR(str);
|
1361
1451
|
from_len = RSTRING_LEN(str);
|
1362
1452
|
|
1363
|
-
if(
|
1453
|
+
if(rb_obj_class(self) == rb_cPGconn) {
|
1364
1454
|
to = PQescapeByteaConn(get_pgconn(self), from, from_len, &to_len);
|
1365
1455
|
} else {
|
1366
1456
|
to = PQescapeBytea( from, from_len, &to_len);
|
@@ -1778,6 +1868,7 @@ pgconn_send_describe_portal(VALUE self, VALUE portal)
|
|
1778
1868
|
/*
|
1779
1869
|
* call-seq:
|
1780
1870
|
* conn.get_result() -> PGresult
|
1871
|
+
* conn.get_result() {|pg_result| block }
|
1781
1872
|
*
|
1782
1873
|
* Blocks waiting for the next result from a call to
|
1783
1874
|
* +PGconn#send_query+ (or another asynchronous command), and returns
|
@@ -1785,6 +1876,10 @@ pgconn_send_describe_portal(VALUE self, VALUE portal)
|
|
1785
1876
|
*
|
1786
1877
|
* Note: call this function repeatedly until it returns +nil+, or else
|
1787
1878
|
* you will not be able to issue further commands.
|
1879
|
+
*
|
1880
|
+
* If the optional code block is given, it will be passed <i>result</i> as an argument,
|
1881
|
+
* and the PGresult object will automatically be cleared when the block terminates.
|
1882
|
+
* In this instance, <code>conn.exec</code> returns the value of the block.
|
1788
1883
|
*/
|
1789
1884
|
static VALUE
|
1790
1885
|
pgconn_get_result(VALUE self)
|
@@ -1796,9 +1891,9 @@ pgconn_get_result(VALUE self)
|
|
1796
1891
|
result = PQgetResult(conn);
|
1797
1892
|
if(result == NULL)
|
1798
1893
|
return Qnil;
|
1799
|
-
rb_pgresult = new_pgresult(result);
|
1894
|
+
rb_pgresult = new_pgresult(result, conn);
|
1800
1895
|
if (rb_block_given_p()) {
|
1801
|
-
return rb_ensure(
|
1896
|
+
return rb_ensure(rb_yield, rb_pgresult,
|
1802
1897
|
pgresult_clear, rb_pgresult);
|
1803
1898
|
}
|
1804
1899
|
return rb_pgresult;
|
@@ -1952,11 +2047,12 @@ pgconn_cancel(VALUE self)
|
|
1952
2047
|
return retval;
|
1953
2048
|
}
|
1954
2049
|
|
2050
|
+
|
1955
2051
|
/*
|
1956
2052
|
* call-seq:
|
1957
2053
|
* conn.notifies()
|
1958
2054
|
*
|
1959
|
-
* Returns
|
2055
|
+
* Returns a hash of the unprocessed notifiers.
|
1960
2056
|
* If there is no unprocessed notifier, it returns +nil+.
|
1961
2057
|
*/
|
1962
2058
|
static VALUE
|
@@ -1991,6 +2087,68 @@ pgconn_notifies(VALUE self)
|
|
1991
2087
|
}
|
1992
2088
|
|
1993
2089
|
|
2090
|
+
/*
|
2091
|
+
* call-seq:
|
2092
|
+
* conn.wait_for_notify( [ timeout ] ) -> String
|
2093
|
+
* conn.wait_for_notify( [ timeout ] ) { |event, pid| block }
|
2094
|
+
*
|
2095
|
+
* Blocks while waiting for notification(s), or until the optional
|
2096
|
+
* _timeout_ is reached, whichever comes first. _timeout_ is
|
2097
|
+
* measured in seconds and can be fractional.
|
2098
|
+
*
|
2099
|
+
* Returns +nil+ if _timeout_ is reached, the name of the NOTIFY
|
2100
|
+
* event otherwise. If used in block form, passes the name of the
|
2101
|
+
* NOTIFY +event+ and the generating +pid+ into the block.
|
2102
|
+
*
|
2103
|
+
*/
|
2104
|
+
static VALUE
|
2105
|
+
pgconn_wait_for_notify(int argc, VALUE *argv, VALUE self)
|
2106
|
+
{
|
2107
|
+
PGconn *conn = get_pgconn(self);
|
2108
|
+
PGnotify *notify;
|
2109
|
+
int sd = PQsocket(conn);
|
2110
|
+
int ret;
|
2111
|
+
struct timeval timeout;
|
2112
|
+
struct timeval *ptimeout = NULL;
|
2113
|
+
VALUE timeout_in, relname = Qnil, be_pid = Qnil;
|
2114
|
+
double timeout_sec;
|
2115
|
+
fd_set sd_rset;
|
2116
|
+
|
2117
|
+
if (sd < 0)
|
2118
|
+
rb_bug("PQsocket(conn): couldn't fetch the connection's socket!");
|
2119
|
+
|
2120
|
+
if (rb_scan_args(argc, argv, "01", &timeout_in) == 1) {
|
2121
|
+
timeout_sec = NUM2DBL(timeout_in);
|
2122
|
+
timeout.tv_sec = (long)timeout_sec;
|
2123
|
+
timeout.tv_usec = (long)((timeout_sec - (long)timeout_sec) * 1e6);
|
2124
|
+
ptimeout = &timeout;
|
2125
|
+
}
|
2126
|
+
|
2127
|
+
FD_ZERO(&sd_rset);
|
2128
|
+
FD_SET(sd, &sd_rset);
|
2129
|
+
ret = rb_thread_select(sd+1, &sd_rset, NULL, NULL, ptimeout);
|
2130
|
+
if (ret == 0) {
|
2131
|
+
return Qnil;
|
2132
|
+
} else if (ret < 0) {
|
2133
|
+
rb_sys_fail(0);
|
2134
|
+
}
|
2135
|
+
|
2136
|
+
if ( (ret = PQconsumeInput(conn)) != 1 ) {
|
2137
|
+
rb_raise(rb_ePGError, "PQconsumeInput == %d: %s", ret, PQerrorMessage(conn));
|
2138
|
+
}
|
2139
|
+
|
2140
|
+
while ((notify = PQnotifies(conn)) != NULL) {
|
2141
|
+
relname = rb_tainted_str_new2(notify->relname);
|
2142
|
+
be_pid = INT2NUM(notify->be_pid);
|
2143
|
+
PQfreemem(notify);
|
2144
|
+
}
|
2145
|
+
|
2146
|
+
if (rb_block_given_p()) rb_yield( rb_ary_new3(2, relname, be_pid) );
|
2147
|
+
|
2148
|
+
return relname;
|
2149
|
+
}
|
2150
|
+
|
2151
|
+
|
1994
2152
|
/*
|
1995
2153
|
* call-seq:
|
1996
2154
|
* conn.put_copy_data( buffer ) -> Boolean
|
@@ -2317,18 +2475,18 @@ pgconn_transaction(VALUE self)
|
|
2317
2475
|
|
2318
2476
|
if (rb_block_given_p()) {
|
2319
2477
|
result = PQexec(conn, "BEGIN");
|
2320
|
-
rb_pgresult = new_pgresult(result);
|
2478
|
+
rb_pgresult = new_pgresult(result, conn);
|
2321
2479
|
pgresult_check(self, rb_pgresult);
|
2322
2480
|
rb_protect(rb_yield, self, &status);
|
2323
2481
|
if(status == 0) {
|
2324
2482
|
result = PQexec(conn, "COMMIT");
|
2325
|
-
rb_pgresult = new_pgresult(result);
|
2483
|
+
rb_pgresult = new_pgresult(result, conn);
|
2326
2484
|
pgresult_check(self, rb_pgresult);
|
2327
2485
|
}
|
2328
2486
|
else {
|
2329
2487
|
/* exception occurred, ROLLBACK and re-raise */
|
2330
2488
|
result = PQexec(conn, "ROLLBACK");
|
2331
|
-
rb_pgresult = new_pgresult(result);
|
2489
|
+
rb_pgresult = new_pgresult(result, conn);
|
2332
2490
|
pgresult_check(self, rb_pgresult);
|
2333
2491
|
rb_jump_tag(status);
|
2334
2492
|
}
|
@@ -2346,17 +2504,18 @@ pgconn_transaction(VALUE self)
|
|
2346
2504
|
* PGconn.quote_ident( str ) -> String
|
2347
2505
|
* conn.quote_ident( str ) -> String
|
2348
2506
|
*
|
2349
|
-
* Returns a string that is safe for inclusion in a SQL query
|
2350
|
-
*
|
2351
|
-
*
|
2507
|
+
* Returns a string that is safe for inclusion in a SQL query as an
|
2508
|
+
* identifier. Note: this is not a quote function for values, but for
|
2509
|
+
* identifiers.
|
2510
|
+
*
|
2511
|
+
* For example, in a typical SQL query: <tt>SELECT FOO FROM MYTABLE</tt>
|
2512
|
+
* The identifier <tt>FOO</tt> is folded to lower case, so it actually
|
2513
|
+
* means <tt>foo</tt>. If you really want to access the case-sensitive
|
2514
|
+
* field name <tt>FOO</tt>, use this function like
|
2515
|
+
* <tt>PGconn.quote_ident('FOO')</tt>, which will return <tt>"FOO"</tt>
|
2516
|
+
* (with double-quotes). PostgreSQL will see the double-quotes, and
|
2517
|
+
* it will not fold to lower case.
|
2352
2518
|
*
|
2353
|
-
* For example, in a typical SQL query: +SELECT FOO FROM MYTABLE+
|
2354
|
-
* The identifier +FOO+ is folded to lower case, so it actually means
|
2355
|
-
* +foo+. If you really want to access the case-sensitive field name
|
2356
|
-
* +FOO+, use this function like +PGconn.quote_ident('FOO')+, which
|
2357
|
-
* will return +"FOO"+ (with double-quotes). PostgreSQL will see the
|
2358
|
-
* double-quotes, and it will not fold to lower case.
|
2359
|
-
*
|
2360
2519
|
* Similarly, this function also protects against special characters,
|
2361
2520
|
* and other things that might allow SQL injection if the identifier
|
2362
2521
|
* comes from an untrusted source.
|
@@ -2403,8 +2562,7 @@ pgconn_s_quote_ident(VALUE self, VALUE in_str)
|
|
2403
2562
|
* and +conn.get_result+ will not block.
|
2404
2563
|
*/
|
2405
2564
|
static VALUE
|
2406
|
-
pgconn_block(int argc, VALUE *argv, VALUE self)
|
2407
|
-
{
|
2565
|
+
pgconn_block( int argc, VALUE *argv, VALUE self ) {
|
2408
2566
|
PGconn *conn = get_pgconn(self);
|
2409
2567
|
int sd = PQsocket(conn);
|
2410
2568
|
int ret;
|
@@ -2414,27 +2572,41 @@ pgconn_block(int argc, VALUE *argv, VALUE self)
|
|
2414
2572
|
double timeout_sec;
|
2415
2573
|
fd_set sd_rset;
|
2416
2574
|
|
2417
|
-
|
2418
|
-
|
2575
|
+
/* Always set a timeout in WIN32, as rb_thread_select() sometimes
|
2576
|
+
* doesn't return when a second ruby thread is running although data
|
2577
|
+
* could be read. So we use timeout-based polling instead.
|
2578
|
+
*/
|
2579
|
+
#if defined(_WIN32)
|
2580
|
+
timeout.tv_sec = 0;
|
2581
|
+
timeout.tv_usec = 10000;
|
2582
|
+
ptimeout = &timeout;
|
2583
|
+
#endif
|
2584
|
+
|
2585
|
+
if ( rb_scan_args(argc, argv, "01", &timeout_in) == 1 ) {
|
2586
|
+
timeout_sec = NUM2DBL( timeout_in );
|
2419
2587
|
timeout.tv_sec = (long)timeout_sec;
|
2420
2588
|
timeout.tv_usec = (long)((timeout_sec - (long)timeout_sec) * 1e6);
|
2421
2589
|
ptimeout = &timeout;
|
2422
2590
|
}
|
2423
2591
|
|
2424
|
-
PQconsumeInput(conn);
|
2425
|
-
|
2426
|
-
|
2427
|
-
|
2428
|
-
|
2429
|
-
|
2430
|
-
|
2592
|
+
PQconsumeInput( conn );
|
2593
|
+
|
2594
|
+
while ( PQisBusy(conn) ) {
|
2595
|
+
FD_ZERO( &sd_rset );
|
2596
|
+
FD_SET( sd, &sd_rset );
|
2597
|
+
ret = rb_thread_select( sd+1, &sd_rset, NULL, NULL, ptimeout );
|
2598
|
+
|
2599
|
+
/* Return false if there was a timeout argument and the select() timed out */
|
2600
|
+
if ( ret == 0 && argc )
|
2431
2601
|
return Qfalse;
|
2432
|
-
|
2602
|
+
|
2603
|
+
PQconsumeInput( conn );
|
2433
2604
|
}
|
2434
2605
|
|
2435
2606
|
return Qtrue;
|
2436
2607
|
}
|
2437
2608
|
|
2609
|
+
|
2438
2610
|
/*
|
2439
2611
|
* call-seq:
|
2440
2612
|
* conn.get_last_result( ) -> PGresult
|
@@ -2452,19 +2624,36 @@ pgconn_block(int argc, VALUE *argv, VALUE self)
|
|
2452
2624
|
static VALUE
|
2453
2625
|
pgconn_get_last_result(VALUE self)
|
2454
2626
|
{
|
2455
|
-
|
2456
|
-
|
2457
|
-
|
2458
|
-
|
2627
|
+
PGconn *conn = get_pgconn(self);
|
2628
|
+
VALUE rb_pgresult = Qnil;
|
2629
|
+
PGresult *cur, *prev;
|
2630
|
+
|
2631
|
+
|
2632
|
+
cur = prev = NULL;
|
2633
|
+
while ((cur = PQgetResult(conn)) != NULL) {
|
2634
|
+
int status;
|
2635
|
+
|
2636
|
+
if (prev) PQclear(prev);
|
2637
|
+
prev = cur;
|
2638
|
+
|
2639
|
+
status = PQresultStatus(cur);
|
2640
|
+
if (status == PGRES_COPY_OUT || status == PGRES_COPY_IN)
|
2641
|
+
break;
|
2459
2642
|
}
|
2460
|
-
|
2461
|
-
|
2643
|
+
|
2644
|
+
if (prev) {
|
2645
|
+
rb_pgresult = new_pgresult(prev, conn);
|
2646
|
+
pgresult_check(self, rb_pgresult);
|
2647
|
+
}
|
2648
|
+
|
2649
|
+
return rb_pgresult;
|
2462
2650
|
}
|
2463
2651
|
|
2464
2652
|
|
2465
2653
|
/*
|
2466
2654
|
* call-seq:
|
2467
2655
|
* conn.async_exec(sql [, params, result_format ] ) -> PGresult
|
2656
|
+
* conn.async_exec(sql [, params, result_format ] ) {|pg_result| block }
|
2468
2657
|
*
|
2469
2658
|
* This function has the same behavior as +PGconn#exec+,
|
2470
2659
|
* except that it's implemented using asynchronous command
|
@@ -2475,11 +2664,22 @@ pgconn_get_last_result(VALUE self)
|
|
2475
2664
|
static VALUE
|
2476
2665
|
pgconn_async_exec(int argc, VALUE *argv, VALUE self)
|
2477
2666
|
{
|
2478
|
-
|
2479
|
-
|
2480
|
-
|
2667
|
+
VALUE rb_pgresult = Qnil;
|
2668
|
+
|
2669
|
+
/* remove any remaining results from the queue */
|
2670
|
+
pgconn_get_last_result( self );
|
2671
|
+
|
2672
|
+
pgconn_send_query( argc, argv, self );
|
2673
|
+
pgconn_block( 0, NULL, self );
|
2674
|
+
rb_pgresult = pgconn_get_last_result( self );
|
2675
|
+
|
2676
|
+
if ( rb_block_given_p() ) {
|
2677
|
+
return rb_ensure( rb_yield, rb_pgresult, pgresult_clear, rb_pgresult );
|
2678
|
+
}
|
2679
|
+
return rb_pgresult;
|
2481
2680
|
}
|
2482
2681
|
|
2682
|
+
|
2483
2683
|
/**************************************************************************
|
2484
2684
|
* LARGE OBJECT SUPPORT
|
2485
2685
|
**************************************************************************/
|
@@ -2551,7 +2751,7 @@ pgconn_loimport(VALUE self, VALUE filename)
|
|
2551
2751
|
|
2552
2752
|
lo_oid = lo_import(conn, StringValuePtr(filename));
|
2553
2753
|
if (lo_oid == 0) {
|
2554
|
-
rb_raise(rb_ePGError, PQerrorMessage(conn));
|
2754
|
+
rb_raise(rb_ePGError, "%s", PQerrorMessage(conn));
|
2555
2755
|
}
|
2556
2756
|
return INT2FIX(lo_oid);
|
2557
2757
|
}
|
@@ -2575,7 +2775,7 @@ pgconn_loexport(VALUE self, VALUE lo_oid, VALUE filename)
|
|
2575
2775
|
}
|
2576
2776
|
|
2577
2777
|
if (lo_export(conn, oid, StringValuePtr(filename)) < 0) {
|
2578
|
-
rb_raise(rb_ePGError, PQerrorMessage(conn));
|
2778
|
+
rb_raise(rb_ePGError, "%s", PQerrorMessage(conn));
|
2579
2779
|
}
|
2580
2780
|
return Qnil;
|
2581
2781
|
}
|
@@ -2606,7 +2806,7 @@ pgconn_loopen(int argc, VALUE *argv, VALUE self)
|
|
2606
2806
|
mode = NUM2INT(nmode);
|
2607
2807
|
|
2608
2808
|
if((fd = lo_open(conn, lo_oid, mode)) < 0) {
|
2609
|
-
rb_raise(rb_ePGError, "can't open large object");
|
2809
|
+
rb_raise(rb_ePGError, "can't open large object: %s", PQerrorMessage(conn));
|
2610
2810
|
}
|
2611
2811
|
return INT2FIX(fd);
|
2612
2812
|
}
|
@@ -2632,7 +2832,7 @@ pgconn_lowrite(VALUE self, VALUE in_lo_desc, VALUE buffer)
|
|
2632
2832
|
}
|
2633
2833
|
if((n = lo_write(conn, fd, StringValuePtr(buffer),
|
2634
2834
|
RSTRING_LEN(buffer))) < 0) {
|
2635
|
-
rb_raise(rb_ePGError, "lo_write failed");
|
2835
|
+
rb_raise(rb_ePGError, "lo_write failed: %s", PQerrorMessage(conn));
|
2636
2836
|
}
|
2637
2837
|
|
2638
2838
|
return INT2FIX(n);
|
@@ -2671,7 +2871,7 @@ pgconn_loread(VALUE self, VALUE in_lo_desc, VALUE in_len)
|
|
2671
2871
|
return Qnil;
|
2672
2872
|
}
|
2673
2873
|
|
2674
|
-
str = rb_tainted_str_new(buffer,
|
2874
|
+
str = rb_tainted_str_new(buffer, ret);
|
2675
2875
|
xfree(buffer);
|
2676
2876
|
|
2677
2877
|
return str;
|
@@ -2679,7 +2879,7 @@ pgconn_loread(VALUE self, VALUE in_lo_desc, VALUE in_len)
|
|
2679
2879
|
|
2680
2880
|
|
2681
2881
|
/*
|
2682
|
-
* call-seq
|
2882
|
+
* call-seq:
|
2683
2883
|
* conn.lo_lseek( lo_desc, offset, whence ) -> Fixnum
|
2684
2884
|
*
|
2685
2885
|
* Move the large object pointer _lo_desc_ to offset _offset_.
|
@@ -2830,7 +3030,9 @@ pgresult_result_status(VALUE self)
|
|
2830
3030
|
static VALUE
|
2831
3031
|
pgresult_res_status(VALUE self, VALUE status)
|
2832
3032
|
{
|
2833
|
-
|
3033
|
+
VALUE ret = rb_tainted_str_new2(PQresStatus(NUM2INT(status)));
|
3034
|
+
ASSOCIATE_INDEX(ret, self);
|
3035
|
+
return ret;
|
2834
3036
|
}
|
2835
3037
|
|
2836
3038
|
/*
|
@@ -2842,7 +3044,9 @@ pgresult_res_status(VALUE self, VALUE status)
|
|
2842
3044
|
static VALUE
|
2843
3045
|
pgresult_result_error_message(VALUE self)
|
2844
3046
|
{
|
2845
|
-
|
3047
|
+
VALUE ret = rb_tainted_str_new2(PQresultErrorMessage(get_pgresult(self)));
|
3048
|
+
ASSOCIATE_INDEX(ret, self);
|
3049
|
+
return ret;
|
2846
3050
|
}
|
2847
3051
|
|
2848
3052
|
/*
|
@@ -2870,7 +3074,9 @@ pgresult_result_error_field(VALUE self, VALUE field)
|
|
2870
3074
|
{
|
2871
3075
|
PGresult *result = get_pgresult(self);
|
2872
3076
|
int fieldcode = NUM2INT(field);
|
2873
|
-
|
3077
|
+
VALUE ret = rb_tainted_str_new2(PQresultErrorField(result,fieldcode));
|
3078
|
+
ASSOCIATE_INDEX(ret, self);
|
3079
|
+
return ret;
|
2874
3080
|
}
|
2875
3081
|
|
2876
3082
|
/*
|
@@ -2920,6 +3126,7 @@ pgresult_nfields(VALUE self)
|
|
2920
3126
|
static VALUE
|
2921
3127
|
pgresult_fname(VALUE self, VALUE index)
|
2922
3128
|
{
|
3129
|
+
VALUE fname;
|
2923
3130
|
PGresult *result;
|
2924
3131
|
int i = NUM2INT(index);
|
2925
3132
|
|
@@ -2927,7 +3134,9 @@ pgresult_fname(VALUE self, VALUE index)
|
|
2927
3134
|
if (i < 0 || i >= PQnfields(result)) {
|
2928
3135
|
rb_raise(rb_eArgError,"invalid field number %d", i);
|
2929
3136
|
}
|
2930
|
-
|
3137
|
+
fname = rb_tainted_str_new2(PQfname(result, i));
|
3138
|
+
ASSOCIATE_INDEX(fname, self);
|
3139
|
+
return fname;
|
2931
3140
|
}
|
2932
3141
|
|
2933
3142
|
/*
|
@@ -2966,11 +3175,14 @@ pgresult_fnumber(VALUE self, VALUE name)
|
|
2966
3175
|
static VALUE
|
2967
3176
|
pgresult_ftable(VALUE self, VALUE column_number)
|
2968
3177
|
{
|
2969
|
-
Oid n
|
2970
|
-
|
2971
|
-
|
2972
|
-
|
2973
|
-
|
3178
|
+
Oid n ;
|
3179
|
+
int col_number = NUM2INT(column_number);
|
3180
|
+
PGresult *pgresult = get_pgresult(self);
|
3181
|
+
|
3182
|
+
if( col_number < 0 || col_number >= PQnfields(pgresult))
|
3183
|
+
rb_raise(rb_eArgError,"Invalid column index: %d", col_number);
|
3184
|
+
|
3185
|
+
n = PQftable(pgresult, col_number);
|
2974
3186
|
return INT2FIX(n);
|
2975
3187
|
}
|
2976
3188
|
|
@@ -2987,12 +3199,15 @@ pgresult_ftable(VALUE self, VALUE column_number)
|
|
2987
3199
|
static VALUE
|
2988
3200
|
pgresult_ftablecol(VALUE self, VALUE column_number)
|
2989
3201
|
{
|
2990
|
-
int
|
2991
|
-
|
2992
|
-
|
2993
|
-
|
2994
|
-
|
2995
|
-
|
3202
|
+
int col_number = NUM2INT(column_number);
|
3203
|
+
PGresult *pgresult = get_pgresult(self);
|
3204
|
+
|
3205
|
+
int n;
|
3206
|
+
|
3207
|
+
if( col_number < 0 || col_number >= PQnfields(pgresult))
|
3208
|
+
rb_raise(rb_eArgError,"Invalid column index: %d", col_number);
|
3209
|
+
|
3210
|
+
n = PQftablecol(pgresult, col_number);
|
2996
3211
|
return INT2FIX(n);
|
2997
3212
|
}
|
2998
3213
|
|
@@ -3010,7 +3225,7 @@ pgresult_fformat(VALUE self, VALUE column_number)
|
|
3010
3225
|
{
|
3011
3226
|
PGresult *result = get_pgresult(self);
|
3012
3227
|
int fnumber = NUM2INT(column_number);
|
3013
|
-
if (fnumber >= PQnfields(result)) {
|
3228
|
+
if (fnumber < 0 || fnumber >= PQnfields(result)) {
|
3014
3229
|
rb_raise(rb_eArgError, "Column number is out of range: %d",
|
3015
3230
|
fnumber);
|
3016
3231
|
}
|
@@ -3023,7 +3238,17 @@ pgresult_fformat(VALUE self, VALUE column_number)
|
|
3023
3238
|
*
|
3024
3239
|
* Returns the data type associated with _column_number_.
|
3025
3240
|
*
|
3026
|
-
* The integer returned is the internal +OID+ number (in PostgreSQL)
|
3241
|
+
* The integer returned is the internal +OID+ number (in PostgreSQL)
|
3242
|
+
* of the type. To get a human-readable value for the type, use the
|
3243
|
+
* returned OID and the field's #fmod value with the format_type() SQL
|
3244
|
+
* function:
|
3245
|
+
*
|
3246
|
+
* # Get the type of the second column of the result 'res'
|
3247
|
+
* typename = conn.
|
3248
|
+
* exec( "SELECT format_type($1,$2)", [res.ftype(1), res.fmod(1)] ).
|
3249
|
+
* getvalue( 0, 0 )
|
3250
|
+
*
|
3251
|
+
* Raises an ArgumentError if _column_number_ is out of range.
|
3027
3252
|
*/
|
3028
3253
|
static VALUE
|
3029
3254
|
pgresult_ftype(VALUE self, VALUE index)
|
@@ -3040,9 +3265,10 @@ pgresult_ftype(VALUE self, VALUE index)
|
|
3040
3265
|
* call-seq:
|
3041
3266
|
* res.fmod( column_number )
|
3042
3267
|
*
|
3043
|
-
* Returns the type modifier associated with column _column_number_.
|
3268
|
+
* Returns the type modifier associated with column _column_number_. See
|
3269
|
+
* the #ftype method for an example of how to use this.
|
3044
3270
|
*
|
3045
|
-
* Raises ArgumentError if _column_number_ is out of range.
|
3271
|
+
* Raises an ArgumentError if _column_number_ is out of range.
|
3046
3272
|
*/
|
3047
3273
|
static VALUE
|
3048
3274
|
pgresult_fmod(VALUE self, VALUE column_number)
|
@@ -3050,14 +3276,12 @@ pgresult_fmod(VALUE self, VALUE column_number)
|
|
3050
3276
|
PGresult *result = get_pgresult(self);
|
3051
3277
|
int fnumber = NUM2INT(column_number);
|
3052
3278
|
int modifier;
|
3053
|
-
if (fnumber >= PQnfields(result)) {
|
3279
|
+
if (fnumber < 0 || fnumber >= PQnfields(result)) {
|
3054
3280
|
rb_raise(rb_eArgError, "Column number is out of range: %d",
|
3055
3281
|
fnumber);
|
3056
3282
|
}
|
3057
|
-
|
3058
|
-
|
3059
|
-
"No modifier information available for column: %d",
|
3060
|
-
fnumber);
|
3283
|
+
modifier = PQfmod(result,fnumber);
|
3284
|
+
|
3061
3285
|
return INT2NUM(modifier);
|
3062
3286
|
}
|
3063
3287
|
|
@@ -3094,6 +3318,7 @@ pgresult_fsize(VALUE self, VALUE index)
|
|
3094
3318
|
static VALUE
|
3095
3319
|
pgresult_getvalue(VALUE self, VALUE tup_num, VALUE field_num)
|
3096
3320
|
{
|
3321
|
+
VALUE ret;
|
3097
3322
|
PGresult *result;
|
3098
3323
|
int i = NUM2INT(tup_num);
|
3099
3324
|
int j = NUM2INT(field_num);
|
@@ -3107,8 +3332,10 @@ pgresult_getvalue(VALUE self, VALUE tup_num, VALUE field_num)
|
|
3107
3332
|
}
|
3108
3333
|
if(PQgetisnull(result, i, j))
|
3109
3334
|
return Qnil;
|
3110
|
-
|
3335
|
+
ret = rb_tainted_str_new(PQgetvalue(result, i, j),
|
3111
3336
|
PQgetlength(result, i, j));
|
3337
|
+
ASSOCIATE_INDEX(ret, self);
|
3338
|
+
return ret;
|
3112
3339
|
}
|
3113
3340
|
|
3114
3341
|
/*
|
@@ -3200,7 +3427,9 @@ pgresult_paramtype(VALUE self, VALUE param_number)
|
|
3200
3427
|
static VALUE
|
3201
3428
|
pgresult_cmd_status(VALUE self)
|
3202
3429
|
{
|
3203
|
-
|
3430
|
+
VALUE ret = rb_tainted_str_new2(PQcmdStatus(get_pgresult(self)));
|
3431
|
+
ASSOCIATE_INDEX(ret, self);
|
3432
|
+
return ret;
|
3204
3433
|
}
|
3205
3434
|
|
3206
3435
|
/*
|
@@ -3259,23 +3488,106 @@ pgresult_aref(VALUE self, VALUE index)
|
|
3259
3488
|
VALUE fname,val;
|
3260
3489
|
VALUE tuple;
|
3261
3490
|
|
3262
|
-
if(tuple_num >= PQntuples(result))
|
3491
|
+
if(tuple_num < 0 || tuple_num >= PQntuples(result))
|
3263
3492
|
rb_raise(rb_eIndexError, "Index %d is out of range", tuple_num);
|
3264
3493
|
tuple = rb_hash_new();
|
3265
3494
|
for(field_num = 0; field_num < PQnfields(result); field_num++) {
|
3266
3495
|
fname = rb_tainted_str_new2(PQfname(result,field_num));
|
3496
|
+
ASSOCIATE_INDEX(fname, self);
|
3267
3497
|
if(PQgetisnull(result, tuple_num, field_num)) {
|
3268
3498
|
rb_hash_aset(tuple, fname, Qnil);
|
3269
3499
|
}
|
3270
3500
|
else {
|
3271
3501
|
val = rb_tainted_str_new(PQgetvalue(result, tuple_num, field_num),
|
3272
3502
|
PQgetlength(result, tuple_num, field_num));
|
3503
|
+
|
3504
|
+
/* associate client encoding for text format only */
|
3505
|
+
if(0 == PQfformat(result, field_num)) {
|
3506
|
+
ASSOCIATE_INDEX(val, self);
|
3507
|
+
} else {
|
3508
|
+
#ifdef M17N_SUPPORTED
|
3509
|
+
rb_enc_associate(val, rb_ascii8bit_encoding());
|
3510
|
+
#endif
|
3511
|
+
}
|
3273
3512
|
rb_hash_aset(tuple, fname, val);
|
3274
3513
|
}
|
3275
3514
|
}
|
3276
3515
|
return tuple;
|
3277
3516
|
}
|
3278
3517
|
|
3518
|
+
|
3519
|
+
/*
|
3520
|
+
* call-seq:
|
3521
|
+
* res.column_values( n ) -> array
|
3522
|
+
*
|
3523
|
+
* Returns an Array of the values from the nth column of each
|
3524
|
+
* tuple in the result.
|
3525
|
+
*
|
3526
|
+
*/
|
3527
|
+
static VALUE
|
3528
|
+
pgresult_column_values(VALUE self, VALUE index)
|
3529
|
+
{
|
3530
|
+
int col = NUM2INT( index );
|
3531
|
+
return make_column_result_array( self, col );
|
3532
|
+
}
|
3533
|
+
|
3534
|
+
|
3535
|
+
/*
|
3536
|
+
* call-seq:
|
3537
|
+
* res.field_values( field ) -> array
|
3538
|
+
*
|
3539
|
+
* Returns an Array of the values from the given _field_ of each tuple in the result.
|
3540
|
+
*
|
3541
|
+
*/
|
3542
|
+
static VALUE
|
3543
|
+
pgresult_field_values( VALUE self, VALUE field )
|
3544
|
+
{
|
3545
|
+
PGresult *result = get_pgresult( self );
|
3546
|
+
const char *fieldname = RSTRING_PTR( field );
|
3547
|
+
int fnum = PQfnumber( result, fieldname );
|
3548
|
+
|
3549
|
+
if ( fnum < 0 )
|
3550
|
+
rb_raise( rb_eIndexError, "no such field '%s' in result", fieldname );
|
3551
|
+
|
3552
|
+
return make_column_result_array( self, fnum );
|
3553
|
+
}
|
3554
|
+
|
3555
|
+
|
3556
|
+
/*
|
3557
|
+
* Make a Ruby array out of the encoded values from the specified
|
3558
|
+
* column in the given result.
|
3559
|
+
*/
|
3560
|
+
static VALUE
|
3561
|
+
make_column_result_array( VALUE self, int col )
|
3562
|
+
{
|
3563
|
+
PGresult *result = get_pgresult( self );
|
3564
|
+
int row = PQntuples( result );
|
3565
|
+
VALUE ary = rb_ary_new2( row );
|
3566
|
+
VALUE val = Qnil;
|
3567
|
+
|
3568
|
+
if ( col >= PQnfields(result) )
|
3569
|
+
rb_raise( rb_eIndexError, "no column %d in result", col );
|
3570
|
+
|
3571
|
+
while ( row-- ) {
|
3572
|
+
val = rb_tainted_str_new( PQgetvalue(result, row, col),
|
3573
|
+
PQgetlength(result, row, col) );
|
3574
|
+
|
3575
|
+
/* associate client encoding for text format only */
|
3576
|
+
if ( 0 == PQfformat(result, col) ) {
|
3577
|
+
ASSOCIATE_INDEX( val, self );
|
3578
|
+
} else {
|
3579
|
+
#ifdef M17N_SUPPORTED
|
3580
|
+
rb_enc_associate( val, rb_ascii8bit_encoding() );
|
3581
|
+
#endif
|
3582
|
+
}
|
3583
|
+
|
3584
|
+
rb_ary_store( ary, row, val );
|
3585
|
+
}
|
3586
|
+
|
3587
|
+
return ary;
|
3588
|
+
}
|
3589
|
+
|
3590
|
+
|
3279
3591
|
/*
|
3280
3592
|
* call-seq:
|
3281
3593
|
* res.each{ |tuple| ... }
|
@@ -3311,20 +3623,287 @@ pgresult_fields(VALUE self)
|
|
3311
3623
|
n = PQnfields(result);
|
3312
3624
|
ary = rb_ary_new2(n);
|
3313
3625
|
for (i=0;i<n;i++) {
|
3314
|
-
|
3626
|
+
VALUE val = rb_tainted_str_new2(PQfname(result, i));
|
3627
|
+
ASSOCIATE_INDEX(val, self);
|
3628
|
+
rb_ary_push(ary, val);
|
3315
3629
|
}
|
3316
3630
|
return ary;
|
3317
3631
|
}
|
3318
3632
|
|
3633
|
+
#ifdef M17N_SUPPORTED
|
3634
|
+
/**
|
3635
|
+
* The mapping from canonical encoding names in PostgreSQL to ones in Ruby.
|
3636
|
+
*/
|
3637
|
+
static const char * const (enc_pg2ruby_mapping[][2]) = {
|
3638
|
+
{"BIG5", "Big5" },
|
3639
|
+
{"EUC_CN", "GB2312" },
|
3640
|
+
{"EUC_JP", "EUC-JP" },
|
3641
|
+
{"EUC_JIS_2004", "EUC-JP" },
|
3642
|
+
{"EUC_KR", "EUC-KR" },
|
3643
|
+
{"EUC_TW", "EUC-TW" },
|
3644
|
+
{"GB18030", "GB18030" },
|
3645
|
+
{"GBK", "GBK" },
|
3646
|
+
{"ISO_8859_5", "ISO-8859-5" },
|
3647
|
+
{"ISO_8859_6", "ISO-8859-6" },
|
3648
|
+
{"ISO_8859_7", "ISO-8859-7" },
|
3649
|
+
{"ISO_8859_8", "ISO-8859-8" },
|
3650
|
+
/* {"JOHAB", "JOHAB" }, dummy */
|
3651
|
+
{"KOI8", "KOI8-U" },
|
3652
|
+
{"LATIN1", "ISO-8859-1" },
|
3653
|
+
{"LATIN2", "ISO-8859-2" },
|
3654
|
+
{"LATIN3", "ISO-8859-3" },
|
3655
|
+
{"LATIN4", "ISO-8859-4" },
|
3656
|
+
{"LATIN5", "ISO-8859-5" },
|
3657
|
+
{"LATIN6", "ISO-8859-6" },
|
3658
|
+
{"LATIN7", "ISO-8859-7" },
|
3659
|
+
{"LATIN8", "ISO-8859-8" },
|
3660
|
+
{"LATIN9", "ISO-8859-9" },
|
3661
|
+
{"LATIN10", "ISO-8859-10" },
|
3662
|
+
{"MULE_INTERNAL", "Emacs-Mule" },
|
3663
|
+
{"SJIS", "Windows-31J" },
|
3664
|
+
{"SHIFT_JIS_2004","Windows-31J" },
|
3665
|
+
/*{"SQL_ASCII", NULL }, special case*/
|
3666
|
+
{"UHC", "CP949" },
|
3667
|
+
{"UTF8", "UTF-8" },
|
3668
|
+
{"WIN866", "IBM866" },
|
3669
|
+
{"WIN874", "Windows-874" },
|
3670
|
+
{"WIN1250", "Windows-1250"},
|
3671
|
+
{"WIN1251", "Windows-1251"},
|
3672
|
+
{"WIN1252", "Windows-1252"},
|
3673
|
+
{"WIN1253", "Windows-1253"},
|
3674
|
+
{"WIN1254", "Windows-1254"},
|
3675
|
+
{"WIN1255", "Windows-1255"},
|
3676
|
+
{"WIN1256", "Windows-1256"},
|
3677
|
+
{"WIN1257", "Windows-1257"},
|
3678
|
+
{"WIN1258", "Windows-1258"}
|
3679
|
+
};
|
3680
|
+
|
3681
|
+
|
3682
|
+
/*
|
3683
|
+
* A cache of mapping from PostgreSQL's encoding indices to Ruby's rb_encoding*s.
|
3684
|
+
*/
|
3685
|
+
static struct st_table *enc_pg2ruby;
|
3686
|
+
static ID s_id_index;
|
3687
|
+
|
3688
|
+
static int enc_get_index(VALUE val)
|
3689
|
+
{
|
3690
|
+
int i = ENCODING_GET_INLINED(val);
|
3691
|
+
if (i == ENCODING_INLINE_MAX) {
|
3692
|
+
VALUE iv = rb_ivar_get(val, s_id_index);
|
3693
|
+
i = NUM2INT(iv);
|
3694
|
+
}
|
3695
|
+
return i;
|
3696
|
+
}
|
3697
|
+
|
3698
|
+
extern int rb_enc_alias(const char *alias, const char *orig); /* declaration missing in Ruby 1.9.1 */
|
3699
|
+
static rb_encoding *
|
3700
|
+
find_or_create_johab(void)
|
3701
|
+
{
|
3702
|
+
static const char * const aliases[] = { "JOHAB", "Windows-1361", "CP1361" };
|
3703
|
+
int enc_index;
|
3704
|
+
int i;
|
3705
|
+
for (i = 0; i < sizeof(aliases)/sizeof(aliases[0]); ++i) {
|
3706
|
+
enc_index = rb_enc_find_index(aliases[i]);
|
3707
|
+
if (enc_index > 0) return rb_enc_from_index(enc_index);
|
3708
|
+
}
|
3709
|
+
|
3710
|
+
enc_index = rb_define_dummy_encoding(aliases[0]);
|
3711
|
+
for (i = 1; i < sizeof(aliases)/sizeof(aliases[0]); ++i) {
|
3712
|
+
rb_enc_alias(aliases[i], aliases[0]);
|
3713
|
+
}
|
3714
|
+
return rb_enc_from_index(enc_index);
|
3715
|
+
}
|
3716
|
+
|
3717
|
+
/*
|
3718
|
+
* Returns the client_encoding of the given connection as a rb_encoding*
|
3719
|
+
*
|
3720
|
+
* * returns NULL if the client encoding is 'SQL_ASCII'.
|
3721
|
+
* * returns ASCII-8BIT if the client encoding is unknown.
|
3722
|
+
*/
|
3723
|
+
static rb_encoding *
|
3724
|
+
pgconn_get_client_encoding_as_rb_encoding(PGconn* conn)
|
3725
|
+
{
|
3726
|
+
rb_encoding *enc;
|
3727
|
+
int enc_id = PQclientEncoding(conn);
|
3728
|
+
|
3729
|
+
if (st_lookup(enc_pg2ruby, (st_data_t)enc_id, (st_data_t*)&enc)) {
|
3730
|
+
return enc;
|
3731
|
+
}
|
3732
|
+
else {
|
3733
|
+
int i;
|
3734
|
+
const char *name = pg_encoding_to_char(enc_id);
|
3735
|
+
if (strcmp("SQL_ASCII", name) == 0) {
|
3736
|
+
enc = NULL;
|
3737
|
+
goto cache;
|
3738
|
+
}
|
3739
|
+
for (i = 0; i < sizeof(enc_pg2ruby_mapping)/sizeof(enc_pg2ruby_mapping[0]); ++i) {
|
3740
|
+
if (strcmp(name, enc_pg2ruby_mapping[i][0]) == 0) {
|
3741
|
+
enc = rb_enc_find(enc_pg2ruby_mapping[i][1]);
|
3742
|
+
goto cache;
|
3743
|
+
}
|
3744
|
+
}
|
3745
|
+
|
3746
|
+
/* Ruby 1.9.1 does not supoort JOHAB */
|
3747
|
+
if (strcmp(name, "JOHAB") == 0) {
|
3748
|
+
enc = find_or_create_johab();
|
3749
|
+
goto cache;
|
3750
|
+
}
|
3751
|
+
|
3752
|
+
enc = rb_ascii8bit_encoding();
|
3753
|
+
}
|
3754
|
+
cache:
|
3755
|
+
st_insert(enc_pg2ruby, (st_data_t)enc_id, (st_data_t)enc);
|
3756
|
+
return enc;
|
3757
|
+
}
|
3758
|
+
|
3759
|
+
/*
|
3760
|
+
* call-seq:
|
3761
|
+
* conn.internal_encoding() -> Encoding
|
3762
|
+
*
|
3763
|
+
* defined in Ruby 1.9 or later.
|
3764
|
+
*
|
3765
|
+
* Returns:
|
3766
|
+
* * an Encoding - client_encoding of the connection as a Ruby Encoding object.
|
3767
|
+
* * nil - the client_encoding is 'SQL_ASCII'
|
3768
|
+
*/
|
3769
|
+
static VALUE
|
3770
|
+
pgconn_internal_encoding(VALUE self)
|
3771
|
+
{
|
3772
|
+
return rb_enc_from_encoding(pgconn_get_client_encoding_as_rb_encoding(get_pgconn(self)));
|
3773
|
+
}
|
3774
|
+
|
3775
|
+
static VALUE pgconn_external_encoding(VALUE self);
|
3776
|
+
|
3777
|
+
/*
|
3778
|
+
* call-seq:
|
3779
|
+
* conn.internal_encoding = value
|
3780
|
+
*
|
3781
|
+
* A wrapper of +PGconn#set_client_encoding+.
|
3782
|
+
* defined in Ruby 1.9 or later.
|
3783
|
+
*
|
3784
|
+
* +value+ can be one of:
|
3785
|
+
* * an Encoding
|
3786
|
+
* * a String - a name of Encoding
|
3787
|
+
* * +nil+ - sets 'SQL_ASCII' to the client_encoding.
|
3788
|
+
*/
|
3789
|
+
static VALUE
|
3790
|
+
pgconn_internal_encoding_set(VALUE self, VALUE enc)
|
3791
|
+
{
|
3792
|
+
if (NIL_P(enc)) {
|
3793
|
+
pgconn_set_client_encoding(self, rb_usascii_str_new_cstr("SQL_ASCII"));
|
3794
|
+
return enc;
|
3795
|
+
}
|
3796
|
+
else if (TYPE(enc) == T_STRING && strcasecmp("JOHAB", RSTRING_PTR(enc)) == 0) {
|
3797
|
+
pgconn_set_client_encoding(self, rb_usascii_str_new_cstr("JOHAB"));
|
3798
|
+
return enc;
|
3799
|
+
}
|
3800
|
+
else {
|
3801
|
+
int i;
|
3802
|
+
const char *name;
|
3803
|
+
name = rb_enc_name(rb_to_encoding(enc));
|
3804
|
+
|
3805
|
+
/* sequential search becuase rarely called */
|
3806
|
+
for (i = 0; i < sizeof(enc_pg2ruby_mapping)/sizeof(enc_pg2ruby_mapping[0]); ++i) {
|
3807
|
+
if (strcmp(name, enc_pg2ruby_mapping[i][1]) == 0) {
|
3808
|
+
if (PQsetClientEncoding(get_pgconn(self), enc_pg2ruby_mapping[i][0]) == -1) {
|
3809
|
+
VALUE server_encoding = pgconn_external_encoding(self);
|
3810
|
+
rb_raise(rb_eEncCompatError, "imcompatible character encodings: %s and %s",
|
3811
|
+
rb_enc_name(rb_to_encoding(server_encoding)),
|
3812
|
+
enc_pg2ruby_mapping[i][0]);
|
3813
|
+
}
|
3814
|
+
return enc;
|
3815
|
+
}
|
3816
|
+
}
|
3817
|
+
|
3818
|
+
/* Ruby 1.9.1 does not support JOHAB */
|
3819
|
+
if (strcasecmp(name, "JOHAB") == 0) {
|
3820
|
+
pgconn_set_client_encoding(self, rb_usascii_str_new_cstr("JOHAB"));
|
3821
|
+
return enc;
|
3822
|
+
}
|
3823
|
+
}
|
3824
|
+
|
3825
|
+
enc = rb_inspect(enc);
|
3826
|
+
rb_raise(rb_ePGError, "unknown encoding: %s", StringValuePtr(enc));
|
3827
|
+
}
|
3828
|
+
|
3829
|
+
|
3830
|
+
|
3831
|
+
static VALUE enc_server_encoding_getvalue(VALUE pgresult)
|
3832
|
+
{
|
3833
|
+
return pgresult_getvalue(pgresult, INT2FIX(0), INT2FIX(0));
|
3834
|
+
}
|
3835
|
+
|
3836
|
+
/*
|
3837
|
+
* call-seq:
|
3838
|
+
* conn.external_encoding() -> Encoding
|
3839
|
+
*
|
3840
|
+
* defined in Ruby 1.9 or later.
|
3841
|
+
* * Returns the server_encoding of the connected database as a Ruby Encoding object.
|
3842
|
+
* * Maps 'SQL_ASCII' to ASCII-8BIT.
|
3843
|
+
*/
|
3844
|
+
static VALUE
|
3845
|
+
pgconn_external_encoding(VALUE self)
|
3846
|
+
{
|
3847
|
+
VALUE enc;
|
3848
|
+
enc = rb_iv_get(self, "@external_encoding");
|
3849
|
+
if (RTEST(enc)) {
|
3850
|
+
return enc;
|
3851
|
+
}
|
3852
|
+
else {
|
3853
|
+
int i;
|
3854
|
+
VALUE query = rb_usascii_str_new_cstr("SHOW server_encoding");
|
3855
|
+
VALUE pgresult = pgconn_exec(1, &query, self);
|
3856
|
+
VALUE enc_name = rb_ensure(enc_server_encoding_getvalue, pgresult, pgresult_clear, pgresult);
|
3857
|
+
|
3858
|
+
if (strcmp("SQL_ASCII", StringValuePtr(enc_name)) == 0) {
|
3859
|
+
enc = rb_enc_from_encoding(rb_ascii8bit_encoding());
|
3860
|
+
goto cache;
|
3861
|
+
}
|
3862
|
+
for (i = 0; i < sizeof(enc_pg2ruby_mapping)/sizeof(enc_pg2ruby_mapping[0]); ++i) {
|
3863
|
+
if (strcmp(StringValuePtr(enc_name), enc_pg2ruby_mapping[i][0]) == 0) {
|
3864
|
+
enc = rb_enc_from_encoding(rb_enc_find(enc_pg2ruby_mapping[i][1]));
|
3865
|
+
goto cache;
|
3866
|
+
}
|
3867
|
+
}
|
3868
|
+
|
3869
|
+
/* Ruby 1.9.1 does not supoort JOHAB */
|
3870
|
+
if (strcmp(StringValuePtr(enc_name), "JOHAB") == 0) {
|
3871
|
+
enc = rb_enc_from_encoding(find_or_create_johab());
|
3872
|
+
goto cache;
|
3873
|
+
}
|
3874
|
+
|
3875
|
+
/* fallback */
|
3876
|
+
enc = rb_enc_from_encoding(rb_enc_find(StringValuePtr(enc_name)));
|
3877
|
+
}
|
3878
|
+
|
3879
|
+
cache:
|
3880
|
+
rb_iv_set(self, "@external_encoding", enc);
|
3881
|
+
return enc;
|
3882
|
+
}
|
3883
|
+
|
3884
|
+
static void
|
3885
|
+
init_m17n(void)
|
3886
|
+
{
|
3887
|
+
enc_pg2ruby = st_init_numtable();
|
3888
|
+
s_id_index = rb_intern("@encoding");
|
3889
|
+
rb_define_method(rb_cPGconn, "internal_encoding", pgconn_internal_encoding, 0);
|
3890
|
+
rb_define_method(rb_cPGconn, "internal_encoding=", pgconn_internal_encoding_set, 1);
|
3891
|
+
rb_define_method(rb_cPGconn, "external_encoding", pgconn_external_encoding, 0);
|
3892
|
+
}
|
3893
|
+
|
3894
|
+
|
3895
|
+
#endif
|
3319
3896
|
/**************************************************************************/
|
3320
3897
|
|
3321
3898
|
void
|
3322
|
-
|
3899
|
+
Init_pg_ext()
|
3323
3900
|
{
|
3324
3901
|
rb_ePGError = rb_define_class("PGError", rb_eStandardError);
|
3325
3902
|
rb_cPGconn = rb_define_class("PGconn", rb_cObject);
|
3326
3903
|
rb_cPGresult = rb_define_class("PGresult", rb_cObject);
|
3327
3904
|
|
3905
|
+
/* Library version */
|
3906
|
+
rb_define_const( rb_cPGconn, "VERSION", rb_str_new2(VERSION) );
|
3328
3907
|
|
3329
3908
|
/*************************
|
3330
3909
|
* PGError
|
@@ -3348,46 +3927,77 @@ Init_pg()
|
|
3348
3927
|
rb_define_singleton_method(rb_cPGconn, "escape_bytea", pgconn_s_escape_bytea, 1);
|
3349
3928
|
rb_define_singleton_method(rb_cPGconn, "unescape_bytea", pgconn_s_unescape_bytea, 1);
|
3350
3929
|
rb_define_singleton_method(rb_cPGconn, "isthreadsafe", pgconn_s_isthreadsafe, 0);
|
3351
|
-
rb_define_singleton_method(rb_cPGconn, "encrypt_password", pgconn_s_encrypt_password,
|
3930
|
+
rb_define_singleton_method(rb_cPGconn, "encrypt_password", pgconn_s_encrypt_password, 2);
|
3352
3931
|
rb_define_singleton_method(rb_cPGconn, "quote_ident", pgconn_s_quote_ident, 1);
|
3353
3932
|
rb_define_singleton_method(rb_cPGconn, "connect_start", pgconn_s_connect_start, -1);
|
3354
3933
|
rb_define_singleton_method(rb_cPGconn, "conndefaults", pgconn_s_conndefaults, 0);
|
3355
3934
|
|
3356
3935
|
/****** PGconn CLASS CONSTANTS: Connection Status ******/
|
3936
|
+
|
3937
|
+
/* Connection succeeded */
|
3357
3938
|
rb_define_const(rb_cPGconn, "CONNECTION_OK", INT2FIX(CONNECTION_OK));
|
3939
|
+
/* Connection failed */
|
3358
3940
|
rb_define_const(rb_cPGconn, "CONNECTION_BAD", INT2FIX(CONNECTION_BAD));
|
3359
3941
|
|
3360
3942
|
/****** PGconn CLASS CONSTANTS: Nonblocking connection status ******/
|
3943
|
+
|
3944
|
+
/* Waiting for connection to be made. */
|
3361
3945
|
rb_define_const(rb_cPGconn, "CONNECTION_STARTED", INT2FIX(CONNECTION_STARTED));
|
3946
|
+
/* Connection OK; waiting to send. */
|
3362
3947
|
rb_define_const(rb_cPGconn, "CONNECTION_MADE", INT2FIX(CONNECTION_MADE));
|
3948
|
+
/* Waiting for a response from the server. */
|
3363
3949
|
rb_define_const(rb_cPGconn, "CONNECTION_AWAITING_RESPONSE", INT2FIX(CONNECTION_AWAITING_RESPONSE));
|
3950
|
+
/* Received authentication; waiting for backend start-up to finish. */
|
3364
3951
|
rb_define_const(rb_cPGconn, "CONNECTION_AUTH_OK", INT2FIX(CONNECTION_AUTH_OK));
|
3952
|
+
/* Negotiating SSL encryption. */
|
3365
3953
|
rb_define_const(rb_cPGconn, "CONNECTION_SSL_STARTUP", INT2FIX(CONNECTION_SSL_STARTUP));
|
3954
|
+
/* Negotiating environment-driven parameter settings. */
|
3366
3955
|
rb_define_const(rb_cPGconn, "CONNECTION_SETENV", INT2FIX(CONNECTION_SETENV));
|
3367
3956
|
|
3368
3957
|
/****** PGconn CLASS CONSTANTS: Nonblocking connection polling status ******/
|
3958
|
+
|
3959
|
+
/* Async connection is waiting to read */
|
3369
3960
|
rb_define_const(rb_cPGconn, "PGRES_POLLING_READING", INT2FIX(PGRES_POLLING_READING));
|
3961
|
+
/* Async connection is waiting to write */
|
3370
3962
|
rb_define_const(rb_cPGconn, "PGRES_POLLING_WRITING", INT2FIX(PGRES_POLLING_WRITING));
|
3963
|
+
/* Async connection failed or was reset */
|
3371
3964
|
rb_define_const(rb_cPGconn, "PGRES_POLLING_FAILED", INT2FIX(PGRES_POLLING_FAILED));
|
3965
|
+
/* Async connection succeeded */
|
3372
3966
|
rb_define_const(rb_cPGconn, "PGRES_POLLING_OK", INT2FIX(PGRES_POLLING_OK));
|
3373
3967
|
|
3374
3968
|
/****** PGconn CLASS CONSTANTS: Transaction Status ******/
|
3969
|
+
|
3970
|
+
/* Transaction is currently idle (#transaction_status) */
|
3375
3971
|
rb_define_const(rb_cPGconn, "PQTRANS_IDLE", INT2FIX(PQTRANS_IDLE));
|
3972
|
+
/* Transaction is currently active; query has been sent to the server, but not yet completed. (#transaction_status) */
|
3376
3973
|
rb_define_const(rb_cPGconn, "PQTRANS_ACTIVE", INT2FIX(PQTRANS_ACTIVE));
|
3974
|
+
/* Transaction is currently idle, in a valid transaction block (#transaction_status) */
|
3377
3975
|
rb_define_const(rb_cPGconn, "PQTRANS_INTRANS", INT2FIX(PQTRANS_INTRANS));
|
3976
|
+
/* Transaction is currently idle, in a failed transaction block (#transaction_status) */
|
3378
3977
|
rb_define_const(rb_cPGconn, "PQTRANS_INERROR", INT2FIX(PQTRANS_INERROR));
|
3978
|
+
/* Transaction's connection is bad (#transaction_status) */
|
3379
3979
|
rb_define_const(rb_cPGconn, "PQTRANS_UNKNOWN", INT2FIX(PQTRANS_UNKNOWN));
|
3380
3980
|
|
3381
3981
|
/****** PGconn CLASS CONSTANTS: Error Verbosity ******/
|
3982
|
+
|
3983
|
+
/* Terse error verbosity level (#set_error_verbosity) */
|
3382
3984
|
rb_define_const(rb_cPGconn, "PQERRORS_TERSE", INT2FIX(PQERRORS_TERSE));
|
3985
|
+
/* Default error verbosity level (#set_error_verbosity) */
|
3383
3986
|
rb_define_const(rb_cPGconn, "PQERRORS_DEFAULT", INT2FIX(PQERRORS_DEFAULT));
|
3987
|
+
/* Verbose error verbosity level (#set_error_verbosity) */
|
3384
3988
|
rb_define_const(rb_cPGconn, "PQERRORS_VERBOSE", INT2FIX(PQERRORS_VERBOSE));
|
3385
3989
|
|
3386
3990
|
/****** PGconn CLASS CONSTANTS: Large Objects ******/
|
3991
|
+
|
3992
|
+
/* Flag for #lo_creat, #lo_open -- open for writing */
|
3387
3993
|
rb_define_const(rb_cPGconn, "INV_WRITE", INT2FIX(INV_WRITE));
|
3994
|
+
/* Flag for #lo_creat, #lo_open -- open for reading */
|
3388
3995
|
rb_define_const(rb_cPGconn, "INV_READ", INT2FIX(INV_READ));
|
3996
|
+
/* Flag for #lo_lseek -- seek from object start */
|
3389
3997
|
rb_define_const(rb_cPGconn, "SEEK_SET", INT2FIX(SEEK_SET));
|
3998
|
+
/* Flag for #lo_lseek -- seek from current position */
|
3390
3999
|
rb_define_const(rb_cPGconn, "SEEK_CUR", INT2FIX(SEEK_CUR));
|
4000
|
+
/* Flag for #lo_lseek -- seek from object end */
|
3391
4001
|
rb_define_const(rb_cPGconn, "SEEK_END", INT2FIX(SEEK_END));
|
3392
4002
|
|
3393
4003
|
/****** PGconn INSTANCE METHODS: Connection Control ******/
|
@@ -3444,6 +4054,7 @@ Init_pg()
|
|
3444
4054
|
rb_define_method(rb_cPGconn, "is_busy", pgconn_is_busy, 0);
|
3445
4055
|
rb_define_method(rb_cPGconn, "setnonblocking", pgconn_setnonblocking, 1);
|
3446
4056
|
rb_define_method(rb_cPGconn, "isnonblocking", pgconn_isnonblocking, 0);
|
4057
|
+
rb_define_alias(rb_cPGconn, "nonblocking?", "isnonblocking");
|
3447
4058
|
rb_define_method(rb_cPGconn, "flush", pgconn_flush, 0);
|
3448
4059
|
|
3449
4060
|
/****** PGconn INSTANCE METHODS: Cancelling Queries in Progress ******/
|
@@ -3471,6 +4082,8 @@ Init_pg()
|
|
3471
4082
|
rb_define_method(rb_cPGconn, "set_client_encoding", pgconn_set_client_encoding, 1);
|
3472
4083
|
rb_define_method(rb_cPGconn, "transaction", pgconn_transaction, 0);
|
3473
4084
|
rb_define_method(rb_cPGconn, "block", pgconn_block, -1);
|
4085
|
+
rb_define_method(rb_cPGconn, "wait_for_notify", pgconn_wait_for_notify, -1);
|
4086
|
+
rb_define_alias(rb_cPGconn, "notifies_wait", "wait_for_notify");
|
3474
4087
|
rb_define_method(rb_cPGconn, "quote_ident", pgconn_s_quote_ident, 1);
|
3475
4088
|
rb_define_method(rb_cPGconn, "async_exec", pgconn_async_exec, -1);
|
3476
4089
|
rb_define_alias(rb_cPGconn, "async_query", "async_exec");
|
@@ -3510,29 +4123,92 @@ Init_pg()
|
|
3510
4123
|
rb_include_module(rb_cPGresult, rb_mEnumerable);
|
3511
4124
|
|
3512
4125
|
/****** PGresult CONSTANTS: result status ******/
|
4126
|
+
|
4127
|
+
/* #result_status constant: The string sent to the server was empty. */
|
3513
4128
|
rb_define_const(rb_cPGresult, "PGRES_EMPTY_QUERY", INT2FIX(PGRES_EMPTY_QUERY));
|
4129
|
+
/* #result_status constant: Successful completion of a command returning no data. */
|
3514
4130
|
rb_define_const(rb_cPGresult, "PGRES_COMMAND_OK", INT2FIX(PGRES_COMMAND_OK));
|
4131
|
+
/* #result_status constant: Successful completion of a command returning data
|
4132
|
+
(such as a SELECT or SHOW). */
|
3515
4133
|
rb_define_const(rb_cPGresult, "PGRES_TUPLES_OK", INT2FIX(PGRES_TUPLES_OK));
|
4134
|
+
/* #result_status constant: Copy Out (from server) data transfer started. */
|
3516
4135
|
rb_define_const(rb_cPGresult, "PGRES_COPY_OUT", INT2FIX(PGRES_COPY_OUT));
|
4136
|
+
/* #result_status constant: Copy In (to server) data transfer started. */
|
3517
4137
|
rb_define_const(rb_cPGresult, "PGRES_COPY_IN", INT2FIX(PGRES_COPY_IN));
|
4138
|
+
/* #result_status constant: The server’s response was not understood. */
|
3518
4139
|
rb_define_const(rb_cPGresult, "PGRES_BAD_RESPONSE", INT2FIX(PGRES_BAD_RESPONSE));
|
4140
|
+
/* #result_status constant: A nonfatal error (a notice or warning) occurred. */
|
3519
4141
|
rb_define_const(rb_cPGresult, "PGRES_NONFATAL_ERROR",INT2FIX(PGRES_NONFATAL_ERROR));
|
4142
|
+
/* #result_status constant: A fatal error occurred. */
|
3520
4143
|
rb_define_const(rb_cPGresult, "PGRES_FATAL_ERROR", INT2FIX(PGRES_FATAL_ERROR));
|
3521
4144
|
|
3522
4145
|
/****** PGresult CONSTANTS: result error field codes ******/
|
4146
|
+
|
4147
|
+
/* #result_error_field argument constant: The severity; the field contents
|
4148
|
+
* are ERROR, FATAL, or PANIC (in an error message), or WARNING, NOTICE,
|
4149
|
+
* DEBUG, INFO, or LOG (in a notice message), or a localized translation
|
4150
|
+
* of one of these. Always present.
|
4151
|
+
*/
|
3523
4152
|
rb_define_const(rb_cPGresult, "PG_DIAG_SEVERITY", INT2FIX(PG_DIAG_SEVERITY));
|
4153
|
+
/* #result_error_field argument constant: The SQLSTATE code for the
|
4154
|
+
* error. The SQLSTATE code identies the type of error that has occurred;
|
4155
|
+
* it can be used by front-end applications to perform specic operations
|
4156
|
+
* (such as er- ror handling) in response to a particular database
|
4157
|
+
* error. For a list of the possible SQLSTATE codes, see Appendix A.
|
4158
|
+
* This eld is not localizable, and is always present.
|
4159
|
+
*/
|
3524
4160
|
rb_define_const(rb_cPGresult, "PG_DIAG_SQLSTATE", INT2FIX(PG_DIAG_SQLSTATE));
|
4161
|
+
/* #result_error_field argument constant: The primary human-readable
|
4162
|
+
* error message (typically one line). Always present. */
|
3525
4163
|
rb_define_const(rb_cPGresult, "PG_DIAG_MESSAGE_PRIMARY", INT2FIX(PG_DIAG_MESSAGE_PRIMARY));
|
4164
|
+
/* #result_error_field argument constant: Detail: an optional secondary
|
4165
|
+
* error message carrying more detail about the problem. Might run to
|
4166
|
+
* multiple lines.
|
4167
|
+
*/
|
3526
4168
|
rb_define_const(rb_cPGresult, "PG_DIAG_MESSAGE_DETAIL", INT2FIX(PG_DIAG_MESSAGE_DETAIL));
|
4169
|
+
/* #result_error_field argument constant: Hint: an optional suggestion
|
4170
|
+
* what to do about the problem. This is intended to differ from detail
|
4171
|
+
* in that it offers advice (potentially inappropriate) rather than
|
4172
|
+
* hard facts. Might run to multiple lines.
|
4173
|
+
*/
|
3527
4174
|
rb_define_const(rb_cPGresult, "PG_DIAG_MESSAGE_HINT", INT2FIX(PG_DIAG_MESSAGE_HINT));
|
4175
|
+
/* #result_error_field argument constant: A string containing a decimal
|
4176
|
+
* integer indicating an error cursor position as an index into the
|
4177
|
+
* original statement string. The rst character has index 1, and
|
4178
|
+
* positions are measured in characters not bytes.
|
4179
|
+
*/
|
3528
4180
|
rb_define_const(rb_cPGresult, "PG_DIAG_STATEMENT_POSITION", INT2FIX(PG_DIAG_STATEMENT_POSITION));
|
4181
|
+
/* #result_error_field argument constant: This is dened the same as
|
4182
|
+
* the PG_DIAG_STATEMENT_POSITION eld, but it is used when the cursor
|
4183
|
+
* position refers to an internally generated command rather than the
|
4184
|
+
* one submitted by the client. The PG_DIAG_INTERNAL_QUERY eld will
|
4185
|
+
* always appear when this eld appears.
|
4186
|
+
*/
|
3529
4187
|
rb_define_const(rb_cPGresult, "PG_DIAG_INTERNAL_POSITION", INT2FIX(PG_DIAG_INTERNAL_POSITION));
|
4188
|
+
/* #result_error_field argument constant: The text of a failed
|
4189
|
+
* internally-generated command. This could be, for example, a SQL
|
4190
|
+
* query issued by a PL/pgSQL function.
|
4191
|
+
*/
|
3530
4192
|
rb_define_const(rb_cPGresult, "PG_DIAG_INTERNAL_QUERY", INT2FIX(PG_DIAG_INTERNAL_QUERY));
|
4193
|
+
/* #result_error_field argument constant: An indication of the context
|
4194
|
+
* in which the error occurred. Presently this includes a call stack
|
4195
|
+
* traceback of active procedural language functions and internally-generated
|
4196
|
+
* queries. The trace is one entry per line, most recent rst.
|
4197
|
+
*/
|
3531
4198
|
rb_define_const(rb_cPGresult, "PG_DIAG_CONTEXT", INT2FIX(PG_DIAG_CONTEXT));
|
4199
|
+
/* #result_error_field argument constant: The le name of the source-code
|
4200
|
+
* location where the error was reported. */
|
3532
4201
|
rb_define_const(rb_cPGresult, "PG_DIAG_SOURCE_FILE", INT2FIX(PG_DIAG_SOURCE_FILE));
|
4202
|
+
/* #result_error_field argument constant: The line number of the
|
4203
|
+
* source-code location where the error was reported. */
|
3533
4204
|
rb_define_const(rb_cPGresult, "PG_DIAG_SOURCE_LINE", INT2FIX(PG_DIAG_SOURCE_LINE));
|
4205
|
+
/* #result_error_field argument constant: The name of the source-code
|
4206
|
+
* function reporting the error. */
|
3534
4207
|
rb_define_const(rb_cPGresult, "PG_DIAG_SOURCE_FUNCTION", INT2FIX(PG_DIAG_SOURCE_FUNCTION));
|
3535
4208
|
|
4209
|
+
/* Invalid OID constant */
|
4210
|
+
rb_define_const(rb_cPGresult, "InvalidOid", INT2FIX(InvalidOid));
|
4211
|
+
|
3536
4212
|
/****** PGresult INSTANCE METHODS: libpq ******/
|
3537
4213
|
rb_define_method(rb_cPGresult, "result_status", pgresult_result_status, 0);
|
3538
4214
|
rb_define_method(rb_cPGresult, "res_status", pgresult_res_status, 1);
|
@@ -3555,7 +4231,7 @@ Init_pg()
|
|
3555
4231
|
rb_define_method(rb_cPGresult, "getisnull", pgresult_getisnull, 2);
|
3556
4232
|
rb_define_method(rb_cPGresult, "getlength", pgresult_getlength, 2);
|
3557
4233
|
rb_define_method(rb_cPGresult, "nparams", pgresult_nparams, 0);
|
3558
|
-
rb_define_method(rb_cPGresult, "paramtype", pgresult_paramtype,
|
4234
|
+
rb_define_method(rb_cPGresult, "paramtype", pgresult_paramtype, 1);
|
3559
4235
|
rb_define_method(rb_cPGresult, "cmd_status", pgresult_cmd_status, 0);
|
3560
4236
|
rb_define_method(rb_cPGresult, "cmd_tuples", pgresult_cmd_tuples, 0);
|
3561
4237
|
rb_define_alias(rb_cPGresult, "cmdtuples", "cmd_tuples");
|
@@ -3565,5 +4241,10 @@ Init_pg()
|
|
3565
4241
|
rb_define_method(rb_cPGresult, "[]", pgresult_aref, 1);
|
3566
4242
|
rb_define_method(rb_cPGresult, "each", pgresult_each, 0);
|
3567
4243
|
rb_define_method(rb_cPGresult, "fields", pgresult_fields, 0);
|
4244
|
+
rb_define_method(rb_cPGresult, "column_values", pgresult_column_values, 1);
|
4245
|
+
rb_define_method(rb_cPGresult, "field_values", pgresult_field_values, 1);
|
3568
4246
|
|
4247
|
+
#ifdef M17N_SUPPORTED
|
4248
|
+
init_m17n();
|
4249
|
+
#endif
|
3569
4250
|
}
|