pg 0.8.0 → 0.9.0.pre156
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/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
|
}
|