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

Sign up to get free protection for your applications and to get access to all the features.
@@ -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