pg 0.9.0-x86-mswin32 → 0.11.0pre229-x86-mswin32

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.
@@ -8,8 +8,8 @@
8
8
  Author: ematsu
9
9
  modified at: Wed Jan 20 16:41:51 1999
10
10
 
11
- $Author: jdavis $
12
- $Date: 2007-12-04 14:25:44 -0800 (Tue, 04 Dec 2007) $
11
+ $Author: ged $
12
+ $Date: 2010/10/31 23:29:59 $
13
13
  ************************************************/
14
14
 
15
15
  #include <ctype.h>
@@ -4,6 +4,10 @@
4
4
 
5
5
  #include <stdlib.h>
6
6
 
7
+ #ifdef RUBY_EXTCONF_H
8
+ #include RUBY_EXTCONF_H
9
+ #endif
10
+
7
11
  #include "libpq-fe.h"
8
12
  #include "libpq/libpq-fs.h" /* large-object interface */
9
13
 
@@ -1,109 +1,40 @@
1
+ require 'pp'
1
2
  require 'mkmf'
2
3
 
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
4
 
19
-
20
- if vvec(RUBY_VERSION) < vvec('1.8')
21
- puts 'This library is for ruby-1.8 or higher.'
22
- exit 1
23
- end
24
-
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') ]
5
+ if pgdir = with_config( 'pg' )
6
+ ENV['PATH'] = "#{pgdir}/bin" + File::PATH_SEPARATOR + ENV['PATH']
29
7
  end
30
8
 
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}")
48
- end
49
-
50
- commonflags = archflags.join(' ')
51
- puts " common arch flags: %s" % [ commonflags ]
52
- else
53
- $stderr.puts %{
54
- =========== WARNING ===========
55
-
56
- You are building this extension on OS X without setting the
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.
9
+ if ENV['CROSS_COMPILING']
10
+ $LDFLAGS << " -L#{CONFIG['libdir']}"
60
11
 
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.
64
-
65
- For example:
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'
70
-
71
- Then try building again.
72
-
73
- ===================================
74
- }.gsub( /^\t+/, ' ' )
75
- end
76
-
77
- if commonflags
78
- $CFLAGS.gsub!( /-arch\s+\S+ /, '' )
79
- $LDFLAGS.gsub!( /-arch\s+\S+ /, '' )
80
- CONFIG['LDSHARED'].gsub!( /-arch\s+\S+ /, '' )
81
-
82
- $CFLAGS << ' ' << commonflags
83
- $LDFLAGS << ' ' << commonflags
84
- CONFIG['LDSHARED'] << ' ' << commonflags
85
- end
12
+ # Link against all required libraries for static build, if they are available
13
+ have_library( 'gdi32', 'CreateDC' ) && append_library( $libs, 'gdi32' )
14
+ have_library( 'secur32' ) && append_library( $libs, 'secur32' )
15
+ have_library( 'ws2_32', 'WSASocket') && append_library( $libs, 'ws2_32' )
16
+ have_library( 'crypto', 'BIO_new' ) && append_library( $libs, 'crypto' )
17
+ have_library( 'ssl', 'SSL_new' ) && append_library( $libs, 'ssl' )
86
18
  end
87
19
 
88
-
89
20
  dir_config 'pg'
90
21
 
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')
22
+ if pgconfig = ( with_config('pg-config') || with_config('pg_config') || find_executable('pg_config') )
23
+ $stderr.puts "Using config values from %s" % [ pgconfig ]
24
+ $CPPFLAGS << " -I%s" % [ `#{pgconfig} --includedir`.chomp ]
25
+ $LDFLAGS << " -L%s" % [ `#{pgconfig} --libdir`.chomp ]
26
+ else
27
+ $stderr.puts "No pg_config... trying anyway. If building fails, please try again with",
28
+ " --with-pg-config=/path/to/pg_config"
97
29
  end
98
30
 
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')
31
+ find_header( 'libpq-fe.h' ) or abort "Can't find the 'libpq-fe.h header"
32
+ find_header( 'libpq/libpq-fs.h' ) or abort "Can't find the 'libpq/libpq-fs.h header"
102
33
 
103
34
  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' )
35
+ have_library( 'pq', 'PQconnectdb', ['libpq-fe.h'] ) ||
36
+ have_library( 'libpq', 'PQconnectdb', ['libpq-fe.h'] ) ||
37
+ have_library( 'ms/libpq', 'PQconnectdb', ['libpq-fe.h'] )
107
38
 
108
39
  # optional headers/functions
109
40
  have_func 'PQconnectionUsedPassword'
@@ -112,15 +43,17 @@ have_func 'PQprepare'
112
43
  have_func 'PQexecParams'
113
44
  have_func 'PQescapeString'
114
45
  have_func 'PQescapeStringConn'
46
+ have_func 'PQgetCancel'
115
47
  have_func 'lo_create'
116
48
  have_func 'pg_encoding_to_char'
117
49
  have_func 'PQsetClientEncoding'
118
50
 
51
+ $defs.push( "-DHAVE_ST_NOTIFY_EXTRA" ) if
52
+ have_struct_member 'struct pgNotify', 'extra', 'libpq-fe.h'
53
+
119
54
  # unistd.h confilicts with ruby/win32.h when cross compiling for win32 and ruby 1.9.1
120
55
  have_header 'unistd.h' unless enable_config("static-build")
121
56
 
122
- $CFLAGS << ' -Wall'
123
-
124
57
  create_header()
125
58
  create_makefile( "pg_ext" )
126
59
 
data/ext/pg.c CHANGED
@@ -8,8 +8,8 @@
8
8
  Author: ematsu
9
9
  modified at: Wed Jan 20 16:41:51 1999
10
10
 
11
- $Author$
12
- $Date$
11
+ $Author: ged $
12
+ $Date: 2011/03/30 13:13:47 $
13
13
  ************************************************/
14
14
 
15
15
  #include "pg.h"
@@ -17,13 +17,18 @@
17
17
  # define M17N_SUPPORTED
18
18
  #endif
19
19
 
20
+ #ifdef _WIN32
21
+ // for O_RDWR and O_BINARY
22
+ #include <fcntl.h>
23
+ #endif
24
+
20
25
  #define rb_define_singleton_alias(klass,new,old) rb_define_alias(rb_singleton_class(klass),new,old)
21
26
 
22
27
  static VALUE rb_cPGconn;
23
28
  static VALUE rb_cPGresult;
24
29
  static VALUE rb_ePGError;
25
30
 
26
- static const char *VERSION = "0.9.0";
31
+ static const char *VERSION = "0.11.0";
27
32
 
28
33
 
29
34
  /* The following functions are part of libpq, but not
@@ -50,21 +55,22 @@ static const char *VERSION = "0.9.0";
50
55
  * UTILITY FUNCTIONS
51
56
  **************************************************************************/
52
57
 
53
- static void free_pgconn(PGconn *);
54
- static void pgresult_check(VALUE, VALUE);
58
+ static void free_pgconn( PGconn * );
59
+ static void pgresult_check( VALUE, VALUE );
55
60
 
56
- static PGconn *get_pgconn(VALUE self);
57
- static VALUE pgconn_finish(VALUE self);
58
- static VALUE pgresult_clear(VALUE self);
59
- static VALUE pgresult_aref(VALUE self, VALUE index);
60
- static VALUE make_column_result_array( VALUE self, int col );
61
+ static PGconn *get_pgconn( VALUE );
62
+ static VALUE pgconn_finish( VALUE );
63
+ static VALUE pgresult_clear( VALUE );
64
+ static VALUE pgresult_aref( VALUE, VALUE );
65
+ static VALUE make_column_result_array( VALUE, int );
61
66
 
62
67
  #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);
68
+ # define ASSOCIATE_INDEX( obj, index_holder ) rb_enc_associate_index((obj), enc_get_index((index_holder)))
69
+ static rb_encoding * pgconn_get_client_encoding_as_rb_encoding( PGconn * );
70
+ static const char * pgconn_get_rb_encoding_as_pg_encname( rb_encoding * );
71
+ static int enc_get_index( VALUE );
66
72
  #else
67
- # define ASSOCIATE_INDEX(obj, index_holder) /* nothing */
73
+ # define ASSOCIATE_INDEX( obj, index_holder ) /* nothing */
68
74
  #endif
69
75
 
70
76
  static PQnoticeReceiver default_notice_receiver = NULL;
@@ -240,7 +246,7 @@ parse_connect_args(int argc, VALUE *argv, VALUE self)
240
246
  VALUE args,arg;
241
247
  VALUE conninfo_rstr = rb_str_new("",0);
242
248
  char *host, *port, *opt, *tty, *dbname, *login, *pwd;
243
- host=port=opt=tty=dbname=login=pwd=NULL;
249
+ host = port = opt = tty = dbname = login = pwd = NULL;
244
250
 
245
251
  rb_scan_args(argc, argv, "0*", &args);
246
252
  if (RARRAY_LEN(args) == 1) {
@@ -291,8 +297,9 @@ parse_connect_args(int argc, VALUE *argv, VALUE self)
291
297
  build_key_value_string(conninfo_rstr, "password", rb_ary_entry(args,6));
292
298
  }
293
299
  else {
294
- rb_raise(rb_eArgError,
295
- "Expected connection info string, hash, or 7 separate arguments.");
300
+ rb_raise( rb_eArgError,
301
+ "Expected connection info string, hash, or 7 separate arguments, got a %s.",
302
+ RSTRING_PTR(rb_obj_classname( args )) );
296
303
  }
297
304
 
298
305
  return conninfo_rstr;
@@ -388,7 +395,10 @@ pgconn_alloc(VALUE klass)
388
395
  * # As an Array
389
396
  * PGconn.connect( nil, 5432, nil, nil, 'test', nil, nil )
390
397
  *
391
- * On failure, it raises a PGError.
398
+ * If the Ruby default internal encoding is set (i.e., Encoding.default_internal != nil), the
399
+ * connection will have its +client_encoding+ set accordingly.
400
+ *
401
+ * @raises [PGError] if the connection fails.
392
402
  */
393
403
  static VALUE
394
404
  pgconn_init(int argc, VALUE *argv, VALUE self)
@@ -396,6 +406,10 @@ pgconn_init(int argc, VALUE *argv, VALUE self)
396
406
  PGconn *conn = NULL;
397
407
  VALUE conninfo;
398
408
  VALUE error;
409
+ #ifdef M17N_SUPPORTED
410
+ rb_encoding *enc;
411
+ const char *encname;
412
+ #endif
399
413
 
400
414
  conninfo = parse_connect_args(argc, argv, self);
401
415
  conn = PQconnectdb(StringValuePtr(conninfo));
@@ -412,6 +426,17 @@ pgconn_init(int argc, VALUE *argv, VALUE self)
412
426
  rb_exc_raise(error);
413
427
  }
414
428
 
429
+ #ifdef M17N_SUPPORTED
430
+ /* If Ruby has its Encoding.default_internal set, set PostgreSQL's client_encoding
431
+ * to match */
432
+ if (( enc = rb_default_internal_encoding() )) {
433
+ encname = pgconn_get_rb_encoding_as_pg_encname( enc );
434
+ if ( PQsetClientEncoding(conn, encname) != 0 )
435
+ rb_warn( "Failed to set the default_internal encoding to %s: '%s'",
436
+ encname, PQerrorMessage(conn) );
437
+ }
438
+ #endif
439
+
415
440
  if (rb_block_given_p()) {
416
441
  return rb_ensure(rb_yield, self, pgconn_finish, self);
417
442
  }
@@ -427,6 +452,12 @@ pgconn_init(int argc, VALUE *argv, VALUE self)
427
452
  * This is an asynchronous version of PGconn.connect().
428
453
  *
429
454
  * Use PGconn#connect_poll to poll the status of the connection.
455
+ *
456
+ * NOTE: this does *not* set the connection's +client_encoding+ for you if
457
+ * Encoding.default_internal is set. To set it after the connection is established,
458
+ * call PGconn#internal_encoding=. You can also set it automatically by setting
459
+ * ENV['PGCLIENTENCODING'], or include the 'options' connection parameter.
460
+ *
430
461
  */
431
462
  static VALUE
432
463
  pgconn_s_connect_start(int argc, VALUE *argv, VALUE self)
@@ -489,7 +520,7 @@ pgconn_s_conndefaults(VALUE self)
489
520
  VALUE ary = rb_ary_new();
490
521
  VALUE hash;
491
522
  int i = 0;
492
-
523
+
493
524
  for(i = 0; options[i].keyword != NULL; i++) {
494
525
  hash = rb_hash_new();
495
526
  if(options[i].keyword)
@@ -535,7 +566,7 @@ pgconn_s_encrypt_password(VALUE self, VALUE password, VALUE username)
535
566
  {
536
567
  char *encrypted = NULL;
537
568
  VALUE rval = Qnil;
538
-
569
+
539
570
  Check_Type(password, T_STRING);
540
571
  Check_Type(username, T_STRING);
541
572
 
@@ -1065,7 +1096,7 @@ pgconn_exec(int argc, VALUE *argv, VALUE self)
1065
1096
  else
1066
1097
  paramFormats[i] = NUM2INT(param_format);
1067
1098
  }
1068
-
1099
+
1069
1100
  result = PQexecParams(conn, StringValuePtr(command), nParams, paramTypes,
1070
1101
  (const char * const *)paramValues, paramLengths, paramFormats, resultFormat);
1071
1102
 
@@ -1252,7 +1283,7 @@ pgconn_exec_prepared(int argc, VALUE *argv, VALUE self)
1252
1283
  else
1253
1284
  paramFormats[i] = NUM2INT(param_format);
1254
1285
  }
1255
-
1286
+
1256
1287
  result = PQexecPrepared(conn, StringValuePtr(name), nParams,
1257
1288
  (const char * const *)paramValues, paramLengths, paramFormats,
1258
1289
  resultFormat);
@@ -1617,7 +1648,7 @@ pgconn_send_query(int argc, VALUE *argv, VALUE self)
1617
1648
  else
1618
1649
  paramFormats[i] = NUM2INT(param_format);
1619
1650
  }
1620
-
1651
+
1621
1652
  result = PQsendQueryParams(conn, StringValuePtr(command), nParams, paramTypes,
1622
1653
  (const char * const *)paramValues, paramLengths, paramFormats, resultFormat);
1623
1654
 
@@ -1802,7 +1833,7 @@ pgconn_send_query_prepared(int argc, VALUE *argv, VALUE self)
1802
1833
  else
1803
1834
  paramFormats[i] = NUM2INT(param_format);
1804
1835
  }
1805
-
1836
+
1806
1837
  result = PQsendQueryPrepared(conn, StringValuePtr(name), nParams,
1807
1838
  (const char * const *)paramValues, paramLengths, paramFormats,
1808
1839
  resultFormat);
@@ -2020,7 +2051,7 @@ pgconn_flush(self)
2020
2051
  * conn.cancel() -> String
2021
2052
  *
2022
2053
  * Requests cancellation of the command currently being
2023
- * processed.
2054
+ * processed. (Only implemented in PostgreSQL >= 8.0)
2024
2055
  *
2025
2056
  * Returns +nil+ on success, or a string containing the
2026
2057
  * error message if a failure occurs.
@@ -2028,6 +2059,7 @@ pgconn_flush(self)
2028
2059
  static VALUE
2029
2060
  pgconn_cancel(VALUE self)
2030
2061
  {
2062
+ #ifdef HAVE_PQGETCANCEL
2031
2063
  char errbuf[256];
2032
2064
  PGcancel *cancel;
2033
2065
  VALUE retval;
@@ -2038,13 +2070,16 @@ pgconn_cancel(VALUE self)
2038
2070
  rb_raise(rb_ePGError,"Invalid connection!");
2039
2071
 
2040
2072
  ret = PQcancel(cancel, errbuf, 256);
2041
- if(ret == 1)
2073
+ if(ret == 1)
2042
2074
  retval = Qnil;
2043
2075
  else
2044
2076
  retval = rb_str_new2(errbuf);
2045
2077
 
2046
2078
  PQfreeCancel(cancel);
2047
2079
  return retval;
2080
+ #else
2081
+ rb_notimplement();
2082
+ #endif
2048
2083
  }
2049
2084
 
2050
2085
 
@@ -2052,14 +2087,14 @@ pgconn_cancel(VALUE self)
2052
2087
  * call-seq:
2053
2088
  * conn.notifies()
2054
2089
  *
2055
- * Returns a hash of the unprocessed notifiers.
2090
+ * Returns a hash of the unprocessed notifications.
2056
2091
  * If there is no unprocessed notifier, it returns +nil+.
2057
2092
  */
2058
2093
  static VALUE
2059
2094
  pgconn_notifies(VALUE self)
2060
2095
  {
2061
2096
  PGconn* conn = get_pgconn(self);
2062
- PGnotify *notify;
2097
+ PGnotify *notification;
2063
2098
  VALUE hash;
2064
2099
  VALUE sym_relname, sym_be_pid, sym_extra;
2065
2100
  VALUE relname, be_pid, extra;
@@ -2068,25 +2103,60 @@ pgconn_notifies(VALUE self)
2068
2103
  sym_be_pid = ID2SYM(rb_intern("be_pid"));
2069
2104
  sym_extra = ID2SYM(rb_intern("extra"));
2070
2105
 
2071
- notify = PQnotifies(conn);
2072
- if (notify == NULL) {
2106
+ notification = PQnotifies(conn);
2107
+ if (notification == NULL) {
2073
2108
  return Qnil;
2074
2109
  }
2075
-
2110
+
2076
2111
  hash = rb_hash_new();
2077
- relname = rb_tainted_str_new2(notify->relname);
2078
- be_pid = INT2NUM(notify->be_pid);
2079
- extra = rb_tainted_str_new2(PGNOTIFY_EXTRA(notify));
2080
-
2112
+ relname = rb_tainted_str_new2(notification->relname);
2113
+ be_pid = INT2NUM(notification->be_pid);
2114
+ extra = rb_tainted_str_new2(PGNOTIFY_EXTRA(notification));
2115
+
2081
2116
  rb_hash_aset(hash, sym_relname, relname);
2082
2117
  rb_hash_aset(hash, sym_be_pid, be_pid);
2083
2118
  rb_hash_aset(hash, sym_extra, extra);
2084
2119
 
2085
- PQfreemem(notify);
2120
+ PQfreemem(notification);
2086
2121
  return hash;
2087
2122
  }
2088
2123
 
2089
2124
 
2125
+ #ifdef _WIN32
2126
+ /*
2127
+ * Duplicate the sockets from libpq and create temporary CRT FDs
2128
+ */
2129
+ void create_crt_fd(fd_set *os_set, fd_set *crt_set)
2130
+ {
2131
+ int i;
2132
+ crt_set->fd_count = os_set->fd_count;
2133
+ for (i = 0; i < os_set->fd_count; i++) {
2134
+ WSAPROTOCOL_INFO wsa_pi;
2135
+ /* dupicate the SOCKET */
2136
+ int r = WSADuplicateSocket(os_set->fd_array[i], GetCurrentProcessId(), &wsa_pi);
2137
+ SOCKET s = WSASocket(wsa_pi.iAddressFamily, wsa_pi.iSocketType, wsa_pi.iProtocol, &wsa_pi, 0, 0);
2138
+ /* create the CRT fd so ruby can get back to the SOCKET */
2139
+ int fd = _open_osfhandle(s, O_RDWR|O_BINARY);
2140
+ os_set->fd_array[i] = s;
2141
+ crt_set->fd_array[i] = fd;
2142
+ }
2143
+ }
2144
+
2145
+ /*
2146
+ * Clean up the CRT FDs from create_crt_fd()
2147
+ */
2148
+ void cleanup_crt_fd(fd_set *os_set, fd_set *crt_set)
2149
+ {
2150
+ int i;
2151
+ for (i = 0; i < os_set->fd_count; i++) {
2152
+ /* cleanup the CRT fd */
2153
+ _close(crt_set->fd_array[i]);
2154
+ /* cleanup the duplicated SOCKET */
2155
+ closesocket(os_set->fd_array[i]);
2156
+ }
2157
+ }
2158
+ #endif
2159
+
2090
2160
  /*
2091
2161
  * call-seq:
2092
2162
  * conn.wait_for_notify( [ timeout ] ) -> String
@@ -2104,48 +2174,67 @@ pgconn_notifies(VALUE self)
2104
2174
  static VALUE
2105
2175
  pgconn_wait_for_notify(int argc, VALUE *argv, VALUE self)
2106
2176
  {
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);
2177
+ PGconn *conn = get_pgconn( self );
2178
+ PGnotify *notification;
2179
+ int sd = PQsocket( conn );
2180
+ int ret;
2181
+ struct timeval timeout;
2182
+ struct timeval *ptimeout = NULL;
2183
+ VALUE timeout_in, relname = Qnil, be_pid = Qnil, extra = Qnil;
2184
+ double timeout_sec;
2185
+ fd_set sd_rset;
2186
+ #ifdef _WIN32
2187
+ fd_set crt_sd_rset;
2188
+ #endif
2189
+
2190
+ if ( sd < 0 )
2191
+ rb_bug( "PQsocket(conn): couldn't fetch the connection's socket!" );
2192
+
2193
+ if ( rb_scan_args(argc, argv, "01", &timeout_in) == 1 ) {
2194
+ timeout_sec = NUM2DBL( timeout_in );
2195
+ timeout.tv_sec = (long)timeout_sec;
2196
+ timeout.tv_usec = (long)( (timeout_sec - (long)timeout_sec) * 1e6 );
2197
+ ptimeout = &timeout;
2134
2198
  }
2135
-
2136
- if ( (ret = PQconsumeInput(conn)) != 1 ) {
2137
- rb_raise(rb_ePGError, "PQconsumeInput == %d: %s", ret, PQerrorMessage(conn));
2199
+
2200
+ /* Check for notifications */
2201
+ while ( (notification = PQnotifies(conn)) == NULL ) {
2202
+ FD_ZERO( &sd_rset );
2203
+ FD_SET( sd, &sd_rset );
2204
+
2205
+ #ifdef _WIN32
2206
+ create_crt_fd(&sd_rset, &crt_sd_rset);
2207
+ #endif
2208
+
2209
+ /* Wait for the socket to become readable before checking again */
2210
+ ret = rb_thread_select( sd+1, &sd_rset, NULL, NULL, ptimeout );
2211
+
2212
+ #ifdef _WIN32
2213
+ cleanup_crt_fd(&sd_rset, &crt_sd_rset);
2214
+ #endif
2215
+
2216
+ if ( ret < 0 )
2217
+ rb_sys_fail( 0 );
2218
+
2219
+ /* Return nil if the select timed out */
2220
+ if ( ret == 0 ) return Qnil;
2221
+
2222
+ /* Read the socket */
2223
+ if ( (ret = PQconsumeInput(conn)) != 1 )
2224
+ rb_raise( rb_ePGError, "PQconsumeInput == %d: %s", ret, PQerrorMessage(conn) );
2138
2225
  }
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
2226
 
2146
- if (rb_block_given_p()) rb_yield( rb_ary_new3(2, relname, be_pid) );
2227
+ relname = rb_tainted_str_new2( notification->relname );
2228
+ be_pid = INT2NUM( notification->be_pid );
2229
+ #ifdef HAVE_ST_NOTIFY_EXTRA
2230
+ extra = rb_str_new2( notification->extra );
2231
+ #endif
2232
+ PQfreemem( notification );
2233
+
2234
+ if ( rb_block_given_p() )
2235
+ rb_yield_values( 3, relname, be_pid, extra );
2147
2236
 
2148
- return relname;
2237
+ return relname;
2149
2238
  }
2150
2239
 
2151
2240
 
@@ -2472,7 +2561,7 @@ pgconn_transaction(VALUE self)
2472
2561
  PGresult *result;
2473
2562
  VALUE rb_pgresult;
2474
2563
  int status;
2475
-
2564
+
2476
2565
  if (rb_block_given_p()) {
2477
2566
  result = PQexec(conn, "BEGIN");
2478
2567
  rb_pgresult = new_pgresult(result, conn);
@@ -2490,7 +2579,7 @@ pgconn_transaction(VALUE self)
2490
2579
  pgresult_check(self, rb_pgresult);
2491
2580
  rb_jump_tag(status);
2492
2581
  }
2493
-
2582
+
2494
2583
  }
2495
2584
  else {
2496
2585
  /* no block supplied? */
@@ -2529,7 +2618,7 @@ pgconn_s_quote_ident(VALUE self, VALUE in_str)
2529
2618
  * double-quotes. */
2530
2619
  char buffer[NAMEDATALEN*2+2];
2531
2620
  unsigned int i=0,j=0;
2532
-
2621
+
2533
2622
  if(strlen(str) >= NAMEDATALEN) {
2534
2623
  rb_raise(rb_eArgError,
2535
2624
  "Input string is longer than NAMEDATALEN-1 (%d)",
@@ -2571,6 +2660,9 @@ pgconn_block( int argc, VALUE *argv, VALUE self ) {
2571
2660
  VALUE timeout_in;
2572
2661
  double timeout_sec;
2573
2662
  fd_set sd_rset;
2663
+ #ifdef _WIN32
2664
+ fd_set crt_sd_rset;
2665
+ #endif
2574
2666
 
2575
2667
  /* Always set a timeout in WIN32, as rb_thread_select() sometimes
2576
2668
  * doesn't return when a second ruby thread is running although data
@@ -2594,7 +2686,16 @@ pgconn_block( int argc, VALUE *argv, VALUE self ) {
2594
2686
  while ( PQisBusy(conn) ) {
2595
2687
  FD_ZERO( &sd_rset );
2596
2688
  FD_SET( sd, &sd_rset );
2597
- ret = rb_thread_select( sd+1, &sd_rset, NULL, NULL, ptimeout );
2689
+
2690
+ #ifdef _WIN32
2691
+ create_crt_fd(&sd_rset, &crt_sd_rset);
2692
+ #endif
2693
+
2694
+ ret = rb_thread_select (sd+1, &sd_rset, NULL, NULL, ptimeout );
2695
+
2696
+ #ifdef _WIN32
2697
+ cleanup_crt_fd(&sd_rset, &crt_sd_rset);
2698
+ #endif
2598
2699
 
2599
2700
  /* Return false if there was a timeout argument and the select() timed out */
2600
2701
  if ( ret == 0 && argc )
@@ -3206,7 +3307,7 @@ pgresult_ftablecol(VALUE self, VALUE column_number)
3206
3307
 
3207
3308
  if( col_number < 0 || col_number >= PQnfields(pgresult))
3208
3309
  rb_raise(rb_eArgError,"Invalid column index: %d", col_number);
3209
-
3310
+
3210
3311
  n = PQftablecol(pgresult, col_number);
3211
3312
  return INT2FIX(n);
3212
3313
  }
@@ -3488,34 +3589,84 @@ pgresult_aref(VALUE self, VALUE index)
3488
3589
  VALUE fname,val;
3489
3590
  VALUE tuple;
3490
3591
 
3491
- if(tuple_num < 0 || tuple_num >= PQntuples(result))
3492
- rb_raise(rb_eIndexError, "Index %d is out of range", tuple_num);
3592
+ if ( tuple_num < 0 || tuple_num >= PQntuples(result) )
3593
+ rb_raise( rb_eIndexError, "Index %d is out of range", tuple_num );
3594
+
3493
3595
  tuple = rb_hash_new();
3494
- for(field_num = 0; field_num < PQnfields(result); field_num++) {
3495
- fname = rb_tainted_str_new2(PQfname(result,field_num));
3596
+ for ( field_num = 0; field_num < PQnfields(result); field_num++ ) {
3597
+ fname = rb_tainted_str_new2( PQfname(result,field_num) );
3496
3598
  ASSOCIATE_INDEX(fname, self);
3497
- if(PQgetisnull(result, tuple_num, field_num)) {
3498
- rb_hash_aset(tuple, fname, Qnil);
3599
+ if ( PQgetisnull(result, tuple_num, field_num) ) {
3600
+ rb_hash_aset( tuple, fname, Qnil );
3499
3601
  }
3500
3602
  else {
3501
- val = rb_tainted_str_new(PQgetvalue(result, tuple_num, field_num),
3502
- PQgetlength(result, tuple_num, field_num));
3603
+ val = rb_tainted_str_new( PQgetvalue(result, tuple_num, field_num ),
3604
+ PQgetlength(result, tuple_num, field_num) );
3503
3605
 
3504
3606
  /* associate client encoding for text format only */
3505
- if(0 == PQfformat(result, field_num)) {
3506
- ASSOCIATE_INDEX(val, self);
3607
+ if ( 0 == PQfformat(result, field_num) ) {
3608
+ ASSOCIATE_INDEX( val, self );
3507
3609
  } else {
3508
3610
  #ifdef M17N_SUPPORTED
3509
- rb_enc_associate(val, rb_ascii8bit_encoding());
3611
+ rb_enc_associate( val, rb_ascii8bit_encoding() );
3510
3612
  #endif
3511
3613
  }
3512
- rb_hash_aset(tuple, fname, val);
3614
+ rb_hash_aset( tuple, fname, val );
3513
3615
  }
3514
3616
  }
3515
3617
  return tuple;
3516
3618
  }
3517
3619
 
3518
3620
 
3621
+ /*
3622
+ * call-seq:
3623
+ * res.values -> Array
3624
+ *
3625
+ * Returns all tuples as an array of arrays.
3626
+ */
3627
+ static VALUE
3628
+ pgresult_values(VALUE self, VALUE index)
3629
+ {
3630
+ PGresult* result = (PGresult*) get_pgresult(self);
3631
+ int row;
3632
+ int field;
3633
+ int num_rows = PQntuples(result);
3634
+ int num_fields = PQnfields(result);
3635
+ VALUE ary = rb_ary_new2(num_rows);
3636
+
3637
+ for ( row = 0; row < num_rows; row++ ) {
3638
+ /* create new row */
3639
+ VALUE new_row = rb_ary_new2(num_fields);
3640
+
3641
+ /* add to return array */
3642
+ rb_ary_store( ary, row, new_row );
3643
+
3644
+ /* populate it */
3645
+ for ( field = 0; field < num_fields; field++ ) {
3646
+ if ( PQgetisnull(result, row, field) ) {
3647
+ rb_ary_store( new_row, field, Qnil );
3648
+ }
3649
+ else {
3650
+ VALUE val = rb_tainted_str_new( PQgetvalue(result, row, field),
3651
+ PQgetlength(result, row, field) );
3652
+
3653
+ /* associate client encoding for text format only */
3654
+ if ( 0 == PQfformat(result, field) ) {
3655
+ ASSOCIATE_INDEX( val, self );
3656
+ } else {
3657
+ #ifdef M17N_SUPPORTED
3658
+ rb_enc_associate( val, rb_ascii8bit_encoding() );
3659
+ #endif
3660
+ }
3661
+
3662
+ rb_ary_store( new_row, field, val );
3663
+ }
3664
+ }
3665
+ }
3666
+ return ary;
3667
+ }
3668
+
3669
+
3519
3670
  /*
3520
3671
  * call-seq:
3521
3672
  * res.column_values( n ) -> array
@@ -3548,7 +3699,7 @@ pgresult_field_values( VALUE self, VALUE field )
3548
3699
 
3549
3700
  if ( fnum < 0 )
3550
3701
  rb_raise( rb_eIndexError, "no such field '%s' in result", fieldname );
3551
-
3702
+
3552
3703
  return make_column_result_array( self, fnum );
3553
3704
  }
3554
3705
 
@@ -3564,7 +3715,7 @@ make_column_result_array( VALUE self, int col )
3564
3715
  int row = PQntuples( result );
3565
3716
  VALUE ary = rb_ary_new2( row );
3566
3717
  VALUE val = Qnil;
3567
-
3718
+
3568
3719
  if ( col >= PQnfields(result) )
3569
3720
  rb_raise( rb_eIndexError, "no column %d in result", col );
3570
3721
 
@@ -3583,7 +3734,7 @@ make_column_result_array( VALUE self, int col )
3583
3734
 
3584
3735
  rb_ary_store( ary, row, val );
3585
3736
  }
3586
-
3737
+
3587
3738
  return ary;
3588
3739
  }
3589
3740
 
@@ -3630,39 +3781,42 @@ pgresult_fields(VALUE self)
3630
3781
  return ary;
3631
3782
  }
3632
3783
 
3784
+
3633
3785
  #ifdef M17N_SUPPORTED
3634
3786
  /**
3635
3787
  * The mapping from canonical encoding names in PostgreSQL to ones in Ruby.
3636
3788
  */
3637
3789
  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" },
3790
+ {"BIG5", "Big5" },
3791
+ {"EUC_CN", "GB2312" },
3792
+ {"EUC_JP", "EUC-JP" },
3793
+ {"EUC_JIS_2004", "EUC-JP" },
3794
+ {"EUC_KR", "EUC-KR" },
3795
+ {"EUC_TW", "EUC-TW" },
3796
+ {"GB18030", "GB18030" },
3797
+ {"GBK", "GBK" },
3798
+ {"ISO_8859_5", "ISO-8859-5" },
3799
+ {"ISO_8859_6", "ISO-8859-6" },
3800
+ {"ISO_8859_7", "ISO-8859-7" },
3801
+ {"ISO_8859_8", "ISO-8859-8" },
3802
+ /* {"JOHAB", "JOHAB" }, dummy */
3803
+ {"KOI8", "KOI8-R" },
3804
+ {"KOI8R", "KOI8-R" },
3805
+ {"KOI8U", "KOI8-U" },
3806
+ {"LATIN1", "ISO-8859-1" },
3807
+ {"LATIN2", "ISO-8859-2" },
3808
+ {"LATIN3", "ISO-8859-3" },
3809
+ {"LATIN4", "ISO-8859-4" },
3810
+ {"LATIN5", "ISO-8859-5" },
3811
+ {"LATIN6", "ISO-8859-6" },
3812
+ {"LATIN7", "ISO-8859-7" },
3813
+ {"LATIN8", "ISO-8859-8" },
3814
+ {"LATIN9", "ISO-8859-9" },
3661
3815
  {"LATIN10", "ISO-8859-10" },
3662
- {"MULE_INTERNAL", "Emacs-Mule" },
3816
+ {"MULE_INTERNAL", "Emacs-Mule" },
3663
3817
  {"SJIS", "Windows-31J" },
3664
3818
  {"SHIFT_JIS_2004","Windows-31J" },
3665
- /*{"SQL_ASCII", NULL }, special case*/
3819
+ /* {"SQL_ASCII", NULL }, special case*/
3666
3820
  {"UHC", "CP949" },
3667
3821
  {"UTF8", "UTF-8" },
3668
3822
  {"WIN866", "IBM866" },
@@ -3756,6 +3910,30 @@ cache:
3756
3910
  return enc;
3757
3911
  }
3758
3912
 
3913
+
3914
+ /*
3915
+ * Returns the given rb_encoding as the equivalent PostgreSQL encoding string.
3916
+ *
3917
+ */
3918
+ static const char *
3919
+ pgconn_get_rb_encoding_as_pg_encname( rb_encoding *enc )
3920
+ {
3921
+ const char *rb_encname = rb_enc_name( enc );
3922
+ const char *encname = NULL;
3923
+ int i;
3924
+
3925
+ for (i = 0; i < sizeof(enc_pg2ruby_mapping)/sizeof(enc_pg2ruby_mapping[0]); ++i) {
3926
+ if (strcmp(rb_encname, enc_pg2ruby_mapping[i][1]) == 0) {
3927
+ encname = enc_pg2ruby_mapping[i][0];
3928
+ }
3929
+ }
3930
+
3931
+ if ( !encname ) encname = "SQL_ASCII";
3932
+
3933
+ return encname;
3934
+ }
3935
+
3936
+
3759
3937
  /*
3760
3938
  * call-seq:
3761
3939
  * conn.internal_encoding() -> Encoding
@@ -3933,7 +4111,7 @@ Init_pg_ext()
3933
4111
  rb_define_singleton_method(rb_cPGconn, "conndefaults", pgconn_s_conndefaults, 0);
3934
4112
 
3935
4113
  /****** PGconn CLASS CONSTANTS: Connection Status ******/
3936
-
4114
+
3937
4115
  /* Connection succeeded */
3938
4116
  rb_define_const(rb_cPGconn, "CONNECTION_OK", INT2FIX(CONNECTION_OK));
3939
4117
  /* Connection failed */
@@ -3966,7 +4144,7 @@ Init_pg_ext()
3966
4144
  rb_define_const(rb_cPGconn, "PGRES_POLLING_OK", INT2FIX(PGRES_POLLING_OK));
3967
4145
 
3968
4146
  /****** PGconn CLASS CONSTANTS: Transaction Status ******/
3969
-
4147
+
3970
4148
  /* Transaction is currently idle (#transaction_status) */
3971
4149
  rb_define_const(rb_cPGconn, "PQTRANS_IDLE", INT2FIX(PQTRANS_IDLE));
3972
4150
  /* Transaction is currently active; query has been sent to the server, but not yet completed. (#transaction_status) */
@@ -4241,6 +4419,7 @@ Init_pg_ext()
4241
4419
  rb_define_method(rb_cPGresult, "[]", pgresult_aref, 1);
4242
4420
  rb_define_method(rb_cPGresult, "each", pgresult_each, 0);
4243
4421
  rb_define_method(rb_cPGresult, "fields", pgresult_fields, 0);
4422
+ rb_define_method(rb_cPGresult, "values", pgresult_values, 0);
4244
4423
  rb_define_method(rb_cPGresult, "column_values", pgresult_column_values, 1);
4245
4424
  rb_define_method(rb_cPGresult, "field_values", pgresult_field_values, 1);
4246
4425