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.
@@ -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
@@ -1,87 +1,126 @@
1
1
  require 'mkmf'
2
2
 
3
- begin
4
- IO.popen("pg_config --version").readline.chomp
5
- rescue
6
- $stderr.write("ERROR: can't find pg_config.\n")
7
- $stderr.write("HINT: Make sure pg_config is in your PATH\n")
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
- # OS X compatibility
12
- if(RUBY_PLATFORM =~ /darwin/) then
13
- # test if postgresql is probably universal
14
- bindir = (IO.popen("pg_config --bindir").readline.chomp rescue nil)
15
- filetype = (IO.popen("file #{bindir}/pg_config").
16
- readline.chomp rescue nil)
17
- # if it's not universal, ARCHFLAGS should be set
18
- if((filetype !~ /universal binary/) && ENV['ARCHFLAGS'].nil?) then
19
- arch_tmp = (IO.popen("uname -p").readline.chomp rescue nil)
20
- if(arch_tmp == 'powerpc')
21
- arch = 'ppc'
22
- else
23
- arch = 'i386'
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
- $stderr.write %{
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 PostgreSQL does not appear
30
- to have been built as a universal binary. If you are seeing this
31
- message, that means that the build will probably fail.
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
- Try setting the environment variable ARCHFLAGS
34
- to '-arch #{arch}' before building.
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 ARCHFLAGS='-arch #{arch}'
38
- (in tcsh) % setenv ARCHFLAGS '-arch #{arch}'
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 RUBY_VERSION < '1.8'
49
- puts 'This library is for ruby-1.8 or higher.'
50
- exit 1
51
- end
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
- def config_value(type)
54
- ENV["POSTGRES_#{type.upcase}"] || pg_config(type)
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
- def have_build_env
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
- dir_config('pg', config_value('include'), config_value('lib'))
67
-
68
- desired_functions = %w(
69
- PQconnectionUsedPassword
70
- PQisthreadsafe
71
- PQprepare
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: jdavis $
12
- $Date: 2009-03-28 09:49:43 -0700 (Sat, 28 Mar 2009) $
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
- * * +host+ - server hostname
335
- * * +hostaddr+ - server address (avoids hostname lookup, overrides +host+)
336
- * * +port+ - server port number
337
- * * +dbname+ - connecting database name
338
- * * +user+ - login user name
339
- * * +password+ - login password
340
- * * +connect_timeout+ - maximum time to wait for connection to succeed
341
- * * +options+ - backend options
342
- * * +tty+ - (ignored in newer versions of PostgreSQL)
343
- * * +sslmode+ - (disable|allow|prefer|require)
344
- * * +krbsrvname+ - kerberos service name
345
- * * +gsslib+ - GSS library to use for GSSAPI authentication
346
- * * +service+ - service name to use for additional parameters
347
- *
348
- * _connection_hash_ example: +PGconn.connect(:dbname=>'test', :port=>5432)
349
- * _connection_string_ example: +PGconn.connect("dbname=test port=5432")
350
- * _connection_hash_ example: +PGconn.connect(nil,5432,nil,nil,'test',nil,nil)
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
- * On failure, it raises a PGError exception.
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) -> PGconn
385
- * PGconn.connect_start(connection_string) -> PGconn
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 = PQconnectdb(StringValuePtr(conninfo));
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
- * * +:keyword+ - the name of the option
432
- * * +:envvar+ - the environment variable to fall back to
433
- * * +:compiled+ - the compiled in option as a secondary fallback
434
- * * +:val+ - the option's current value, or +nil+ if not known
435
- * * +:label+ - the label for the field
436
- * * +:dispchar+ - "" for normal, "D" for debug, and "*" for password
437
- * * +:dispsize+ - field size
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 *ret;
536
+ char *encrypted = NULL;
537
+ VALUE rval = Qnil;
538
+
491
539
  Check_Type(password, T_STRING);
492
540
  Check_Type(username, T_STRING);
493
- ret = PQencryptPassword(StringValuePtr(password),
494
- StringValuePtr(username));
495
- return rb_tainted_str_new2(ret);
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
- * * +PGRES_POLLING_READING+ - wait until the socket is ready to read
520
- * * +PGRES_POLLING_WRITING+ - wait until the socket is ready to write
521
- * * +PGRES_POLLING_FAILED+ - the asynchronous connection has failed
522
- * * +PGRES_POLLING_OK+ - the asynchronous connection is ready
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
- * conn.protocol_version -> Integer
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 numbers into two-decimal-digit numbers and appending them together. For example, version 7.4.2 will be returned as 70402, and version 8.1 will be returned as 80100 (leading zeroes are not shown). Zero is returned if the connection is bad.
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(yield_pgresult, rb_pgresult,
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(yield_pgresult, rb_pgresult,
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(yield_pgresult, rb_pgresult,
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(CLASS_OF(self) == rb_cPGconn) {
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
- rb_raise(rb_ePGError, PQerrorMessage(get_pgconn(self)));
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(CLASS_OF(self) == rb_cPGconn) {
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(yield_pgresult, rb_pgresult,
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 an array of the unprocessed notifiers.
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
- * as an identifier. Note: this is not a quote function for values,
2351
- * but for identifiers.
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
- if (rb_scan_args(argc, argv, "01", &timeout_in) == 1) {
2418
- timeout_sec = NUM2DBL(timeout_in);
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
- while(PQisBusy(conn)) {
2426
- FD_ZERO(&sd_rset);
2427
- FD_SET(sd, &sd_rset);
2428
- ret = rb_thread_select(sd+1, &sd_rset, NULL, NULL, ptimeout);
2429
- /* if select() times out, return false */
2430
- if(ret == 0)
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
- PQconsumeInput(conn);
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
- VALUE ret, result;
2456
- ret = Qnil;
2457
- while((result = pgconn_get_result(self)) != Qnil) {
2458
- ret = result;
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
- pgresult_check(self, ret);
2461
- return ret;
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
- pgconn_send_query(argc, argv, self);
2479
- pgconn_block(0, NULL, self);
2480
- return pgconn_get_last_result(self);
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, len);
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
- return rb_tainted_str_new2(PQresStatus(NUM2INT(status)));
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
- return rb_tainted_str_new2(PQresultErrorMessage(get_pgresult(self)));
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
- return rb_tainted_str_new2(PQresultErrorField(result,fieldcode));
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
- return rb_tainted_str_new2(PQfname(result, i));
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 = PQftable(get_pgresult(self), NUM2INT(column_number));
2970
- if (n == InvalidOid) {
2971
- rb_raise(rb_eArgError,"Oid is undefined for column: %d",
2972
- NUM2INT(column_number));
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 n = PQftablecol(get_pgresult(self), NUM2INT(column_number));
2991
- if (n == 0) {
2992
- rb_raise(rb_eArgError,
2993
- "Column number from table is undefined for column: %d",
2994
- NUM2INT(column_number));
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) of the type.
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
- if((modifier = PQfmod(result,fnumber)) == -1)
3058
- rb_raise(rb_eArgError,
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
- return rb_tainted_str_new(PQgetvalue(result, i, j),
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
- return rb_tainted_str_new2(PQcmdStatus(get_pgresult(self)));
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
- rb_ary_push(ary, rb_tainted_str_new2(PQfname(result, i)));
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
- Init_pg()
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, 0);
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, 0);
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
  }