pg 1.2.3 → 1.4.3

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.
Files changed (107) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data/.appveyor.yml +36 -0
  4. data/.gems +6 -0
  5. data/.github/workflows/binary-gems.yml +86 -0
  6. data/.github/workflows/source-gem.yml +129 -0
  7. data/.gitignore +13 -0
  8. data/.hgsigs +34 -0
  9. data/.hgtags +41 -0
  10. data/.irbrc +23 -0
  11. data/.pryrc +23 -0
  12. data/.tm_properties +21 -0
  13. data/.travis.yml +49 -0
  14. data/Gemfile +14 -0
  15. data/History.rdoc +199 -7
  16. data/Manifest.txt +0 -1
  17. data/README.rdoc +7 -6
  18. data/Rakefile +27 -138
  19. data/Rakefile.cross +8 -5
  20. data/certs/ged.pem +24 -0
  21. data/certs/larskanis-2022.pem +26 -0
  22. data/ext/errorcodes.def +8 -0
  23. data/ext/errorcodes.rb +0 -0
  24. data/ext/errorcodes.txt +3 -1
  25. data/ext/extconf.rb +100 -25
  26. data/ext/gvl_wrappers.c +4 -0
  27. data/ext/gvl_wrappers.h +23 -0
  28. data/ext/pg.c +59 -28
  29. data/ext/pg.h +19 -1
  30. data/ext/pg_coder.c +82 -28
  31. data/ext/pg_connection.c +855 -654
  32. data/ext/pg_copy_coder.c +45 -16
  33. data/ext/pg_record_coder.c +45 -15
  34. data/ext/pg_result.c +79 -42
  35. data/ext/pg_text_decoder.c +1 -1
  36. data/ext/pg_text_encoder.c +6 -6
  37. data/ext/pg_tuple.c +49 -29
  38. data/ext/pg_type_map.c +41 -8
  39. data/ext/pg_type_map_all_strings.c +15 -1
  40. data/ext/pg_type_map_by_class.c +49 -24
  41. data/ext/pg_type_map_by_column.c +66 -28
  42. data/ext/pg_type_map_by_mri_type.c +47 -18
  43. data/ext/pg_type_map_by_oid.c +52 -23
  44. data/ext/pg_type_map_in_ruby.c +50 -19
  45. data/ext/pg_util.c +2 -2
  46. data/lib/pg/basic_type_map_based_on_result.rb +47 -0
  47. data/lib/pg/basic_type_map_for_queries.rb +193 -0
  48. data/lib/pg/basic_type_map_for_results.rb +81 -0
  49. data/lib/pg/basic_type_registry.rb +301 -0
  50. data/lib/pg/coder.rb +1 -1
  51. data/lib/pg/connection.rb +668 -70
  52. data/lib/pg/exceptions.rb +7 -1
  53. data/lib/pg/version.rb +4 -0
  54. data/lib/pg.rb +47 -32
  55. data/misc/openssl-pg-segfault.rb +31 -0
  56. data/misc/postgres/History.txt +9 -0
  57. data/misc/postgres/Manifest.txt +5 -0
  58. data/misc/postgres/README.txt +21 -0
  59. data/misc/postgres/Rakefile +21 -0
  60. data/misc/postgres/lib/postgres.rb +16 -0
  61. data/misc/ruby-pg/History.txt +9 -0
  62. data/misc/ruby-pg/Manifest.txt +5 -0
  63. data/misc/ruby-pg/README.txt +21 -0
  64. data/misc/ruby-pg/Rakefile +21 -0
  65. data/misc/ruby-pg/lib/ruby/pg.rb +16 -0
  66. data/pg.gemspec +32 -0
  67. data/rakelib/task_extension.rb +46 -0
  68. data/sample/array_insert.rb +20 -0
  69. data/sample/async_api.rb +102 -0
  70. data/sample/async_copyto.rb +39 -0
  71. data/sample/async_mixed.rb +56 -0
  72. data/sample/check_conn.rb +21 -0
  73. data/sample/copydata.rb +71 -0
  74. data/sample/copyfrom.rb +81 -0
  75. data/sample/copyto.rb +19 -0
  76. data/sample/cursor.rb +21 -0
  77. data/sample/disk_usage_report.rb +177 -0
  78. data/sample/issue-119.rb +94 -0
  79. data/sample/losample.rb +69 -0
  80. data/sample/minimal-testcase.rb +17 -0
  81. data/sample/notify_wait.rb +72 -0
  82. data/sample/pg_statistics.rb +285 -0
  83. data/sample/replication_monitor.rb +222 -0
  84. data/sample/test_binary_values.rb +33 -0
  85. data/sample/wal_shipper.rb +434 -0
  86. data/sample/warehouse_partitions.rb +311 -0
  87. data.tar.gz.sig +0 -0
  88. metadata +87 -224
  89. metadata.gz.sig +0 -0
  90. data/ChangeLog +0 -0
  91. data/lib/pg/basic_type_mapping.rb +0 -522
  92. data/spec/data/expected_trace.out +0 -26
  93. data/spec/data/random_binary_data +0 -0
  94. data/spec/helpers.rb +0 -380
  95. data/spec/pg/basic_type_mapping_spec.rb +0 -630
  96. data/spec/pg/connection_spec.rb +0 -1949
  97. data/spec/pg/connection_sync_spec.rb +0 -41
  98. data/spec/pg/result_spec.rb +0 -681
  99. data/spec/pg/tuple_spec.rb +0 -333
  100. data/spec/pg/type_map_by_class_spec.rb +0 -138
  101. data/spec/pg/type_map_by_column_spec.rb +0 -226
  102. data/spec/pg/type_map_by_mri_type_spec.rb +0 -136
  103. data/spec/pg/type_map_by_oid_spec.rb +0 -149
  104. data/spec/pg/type_map_in_ruby_spec.rb +0 -164
  105. data/spec/pg/type_map_spec.rb +0 -22
  106. data/spec/pg/type_spec.rb +0 -1123
  107. data/spec/pg_spec.rb +0 -50
data/ext/pg_connection.c CHANGED
@@ -12,6 +12,7 @@
12
12
 
13
13
  VALUE rb_cPGconn;
14
14
  static ID s_id_encode;
15
+ static ID s_id_autoclose_set;
15
16
  static VALUE sym_type, sym_format, sym_value;
16
17
  static VALUE sym_symbol, sym_string, sym_static_symbol;
17
18
 
@@ -20,12 +21,35 @@ static PQnoticeProcessor default_notice_processor = NULL;
20
21
 
21
22
  static VALUE pgconn_finish( VALUE );
22
23
  static VALUE pgconn_set_default_encoding( VALUE self );
24
+ static VALUE pgconn_wait_for_flush( VALUE self );
23
25
  static void pgconn_set_internal_encoding_index( VALUE );
26
+ static const rb_data_type_t pg_connection_type;
27
+ static VALUE pgconn_async_flush(VALUE self);
24
28
 
25
29
  /*
26
30
  * Global functions
27
31
  */
28
32
 
33
+ /*
34
+ * Convenience function to raise connection errors
35
+ */
36
+ #ifdef __GNUC__
37
+ __attribute__((format(printf, 3, 4)))
38
+ #endif
39
+ static void
40
+ pg_raise_conn_error( VALUE klass, VALUE self, const char *format, ...)
41
+ {
42
+ VALUE msg, error;
43
+ va_list ap;
44
+
45
+ va_start(ap, format);
46
+ msg = rb_vsprintf(format, ap);
47
+ va_end(ap);
48
+ error = rb_exc_new_str(klass, msg);
49
+ rb_iv_set(error, "@connection", self);
50
+ rb_exc_raise(error);
51
+ }
52
+
29
53
  /*
30
54
  * Fetch the PG::Connection object data pointer.
31
55
  */
@@ -33,7 +57,7 @@ t_pg_connection *
33
57
  pg_get_connection( VALUE self )
34
58
  {
35
59
  t_pg_connection *this;
36
- Data_Get_Struct( self, t_pg_connection, this);
60
+ TypedData_Get_Struct( self, t_pg_connection, &pg_connection_type, this);
37
61
 
38
62
  return this;
39
63
  }
@@ -46,10 +70,10 @@ static t_pg_connection *
46
70
  pg_get_connection_safe( VALUE self )
47
71
  {
48
72
  t_pg_connection *this;
49
- Data_Get_Struct( self, t_pg_connection, this);
73
+ TypedData_Get_Struct( self, t_pg_connection, &pg_connection_type, this);
50
74
 
51
75
  if ( !this->pgconn )
52
- rb_raise( rb_eConnectionBad, "connection is closed" );
76
+ pg_raise_conn_error( rb_eConnectionBad, self, "connection is closed");
53
77
 
54
78
  return this;
55
79
  }
@@ -65,10 +89,11 @@ PGconn *
65
89
  pg_get_pgconn( VALUE self )
66
90
  {
67
91
  t_pg_connection *this;
68
- Data_Get_Struct( self, t_pg_connection, this);
92
+ TypedData_Get_Struct( self, t_pg_connection, &pg_connection_type, this);
69
93
 
70
- if ( !this->pgconn )
71
- rb_raise( rb_eConnectionBad, "connection is closed" );
94
+ if ( !this->pgconn ){
95
+ pg_raise_conn_error( rb_eConnectionBad, self, "connection is closed");
96
+ }
72
97
 
73
98
  return this->pgconn;
74
99
  }
@@ -86,9 +111,8 @@ pgconn_close_socket_io( VALUE self )
86
111
 
87
112
  if ( RTEST(socket_io) ) {
88
113
  #if defined(_WIN32)
89
- if( rb_w32_unwrap_io_handle(this->ruby_sd) ){
90
- rb_raise(rb_eConnectionBad, "Could not unwrap win32 socket handle");
91
- }
114
+ if( rb_w32_unwrap_io_handle(this->ruby_sd) )
115
+ pg_raise_conn_error( rb_eConnectionBad, self, "Could not unwrap win32 socket handle");
92
116
  #endif
93
117
  rb_funcall( socket_io, rb_intern("close"), 0 );
94
118
  }
@@ -145,16 +169,31 @@ static const char *pg_cstr_enc(VALUE str, int enc_idx){
145
169
  * GC Mark function
146
170
  */
147
171
  static void
148
- pgconn_gc_mark( t_pg_connection *this )
172
+ pgconn_gc_mark( void *_this )
173
+ {
174
+ t_pg_connection *this = (t_pg_connection *)_this;
175
+ rb_gc_mark_movable( this->socket_io );
176
+ rb_gc_mark_movable( this->notice_receiver );
177
+ rb_gc_mark_movable( this->notice_processor );
178
+ rb_gc_mark_movable( this->type_map_for_queries );
179
+ rb_gc_mark_movable( this->type_map_for_results );
180
+ rb_gc_mark_movable( this->trace_stream );
181
+ rb_gc_mark_movable( this->encoder_for_put_copy_data );
182
+ rb_gc_mark_movable( this->decoder_for_get_copy_data );
183
+ }
184
+
185
+ static void
186
+ pgconn_gc_compact( void *_this )
149
187
  {
150
- rb_gc_mark( this->socket_io );
151
- rb_gc_mark( this->notice_receiver );
152
- rb_gc_mark( this->notice_processor );
153
- rb_gc_mark( this->type_map_for_queries );
154
- rb_gc_mark( this->type_map_for_results );
155
- rb_gc_mark( this->trace_stream );
156
- rb_gc_mark( this->encoder_for_put_copy_data );
157
- rb_gc_mark( this->decoder_for_get_copy_data );
188
+ t_pg_connection *this = (t_pg_connection *)_this;
189
+ pg_gc_location( this->socket_io );
190
+ pg_gc_location( this->notice_receiver );
191
+ pg_gc_location( this->notice_processor );
192
+ pg_gc_location( this->type_map_for_queries );
193
+ pg_gc_location( this->type_map_for_results );
194
+ pg_gc_location( this->trace_stream );
195
+ pg_gc_location( this->encoder_for_put_copy_data );
196
+ pg_gc_location( this->decoder_for_get_copy_data );
158
197
  }
159
198
 
160
199
 
@@ -162,11 +201,15 @@ pgconn_gc_mark( t_pg_connection *this )
162
201
  * GC Free function
163
202
  */
164
203
  static void
165
- pgconn_gc_free( t_pg_connection *this )
204
+ pgconn_gc_free( void *_this )
166
205
  {
206
+ t_pg_connection *this = (t_pg_connection *)_this;
167
207
  #if defined(_WIN32)
168
- if ( RTEST(this->socket_io) )
169
- rb_w32_unwrap_io_handle( this->ruby_sd );
208
+ if ( RTEST(this->socket_io) ) {
209
+ if( rb_w32_unwrap_io_handle(this->ruby_sd) ){
210
+ rb_warn("pg: Could not unwrap win32 socket handle by garbage collector");
211
+ }
212
+ }
170
213
  #endif
171
214
  if (this->pgconn != NULL)
172
215
  PQfinish( this->pgconn );
@@ -174,6 +217,29 @@ pgconn_gc_free( t_pg_connection *this )
174
217
  xfree(this);
175
218
  }
176
219
 
220
+ /*
221
+ * Object Size function
222
+ */
223
+ static size_t
224
+ pgconn_memsize( const void *_this )
225
+ {
226
+ const t_pg_connection *this = (const t_pg_connection *)_this;
227
+ return sizeof(*this);
228
+ }
229
+
230
+ static const rb_data_type_t pg_connection_type = {
231
+ "PG::Connection",
232
+ {
233
+ pgconn_gc_mark,
234
+ pgconn_gc_free,
235
+ pgconn_memsize,
236
+ pg_compact_callback(pgconn_gc_compact),
237
+ },
238
+ 0,
239
+ 0,
240
+ 0,
241
+ };
242
+
177
243
 
178
244
  /**************************************************************************
179
245
  * Class Methods
@@ -189,7 +255,7 @@ static VALUE
189
255
  pgconn_s_allocate( VALUE klass )
190
256
  {
191
257
  t_pg_connection *this;
192
- VALUE self = Data_Make_Struct( klass, t_pg_connection, pgconn_gc_mark, pgconn_gc_free, this );
258
+ VALUE self = TypedData_Make_Struct( klass, t_pg_connection, &pg_connection_type, this );
193
259
 
194
260
  this->pgconn = NULL;
195
261
  this->socket_io = Qnil;
@@ -200,82 +266,27 @@ pgconn_s_allocate( VALUE klass )
200
266
  this->encoder_for_put_copy_data = Qnil;
201
267
  this->decoder_for_get_copy_data = Qnil;
202
268
  this->trace_stream = Qnil;
269
+ rb_ivar_set(self, rb_intern("@calls_to_put_copy_data"), INT2FIX(0));
203
270
 
204
271
  return self;
205
272
  }
206
273
 
207
-
208
- /*
209
- * Document-method: new
210
- *
211
- * call-seq:
212
- * PG::Connection.new -> conn
213
- * PG::Connection.new(connection_hash) -> conn
214
- * PG::Connection.new(connection_string) -> conn
215
- * PG::Connection.new(host, port, options, tty, dbname, user, password) -> conn
216
- *
217
- * Create a connection to the specified server.
218
- *
219
- * +connection_hash+ must be a ruby Hash with connection parameters.
220
- * See the {list of valid parameters}[https://www.postgresql.org/docs/current/libpq-connect.html#LIBPQ-PARAMKEYWORDS] in the PostgreSQL documentation.
221
- *
222
- * There are two accepted formats for +connection_string+: plain <code>keyword = value</code> strings and URIs.
223
- * See the documentation of {connection strings}[https://www.postgresql.org/docs/current/libpq-connect.html#LIBPQ-CONNSTRING].
224
- *
225
- * The positional parameter form has the same functionality except that the missing parameters will always take on default values. The parameters are:
226
- * [+host+]
227
- * server hostname
228
- * [+port+]
229
- * server port number
230
- * [+options+]
231
- * backend options
232
- * [+tty+]
233
- * (ignored in newer versions of PostgreSQL)
234
- * [+dbname+]
235
- * connecting database name
236
- * [+user+]
237
- * login user name
238
- * [+password+]
239
- * login password
240
- *
241
- * Examples:
242
- *
243
- * # Connect using all defaults
244
- * PG::Connection.new
245
- *
246
- * # As a Hash
247
- * PG::Connection.new( :dbname => 'test', :port => 5432 )
248
- *
249
- * # As a String
250
- * PG::Connection.new( "dbname=test port=5432" )
251
- *
252
- * # As an Array
253
- * PG::Connection.new( nil, 5432, nil, nil, 'test', nil, nil )
254
- *
255
- * If the Ruby default internal encoding is set (i.e., <code>Encoding.default_internal != nil</code>), the
256
- * connection will have its +client_encoding+ set accordingly.
257
- *
258
- * Raises a PG::Error if the connection fails.
259
- */
260
274
  static VALUE
261
- pgconn_init(int argc, VALUE *argv, VALUE self)
275
+ pgconn_s_sync_connect(int argc, VALUE *argv, VALUE klass)
262
276
  {
263
277
  t_pg_connection *this;
264
278
  VALUE conninfo;
265
- VALUE error;
279
+ VALUE self = pgconn_s_allocate( klass );
266
280
 
267
281
  this = pg_get_connection( self );
268
282
  conninfo = rb_funcall2( rb_cPGconn, rb_intern("parse_connect_args"), argc, argv );
269
283
  this->pgconn = gvl_PQconnectdb(StringValueCStr(conninfo));
270
284
 
271
285
  if(this->pgconn == NULL)
272
- rb_raise(rb_ePGerror, "PQconnectdb() unable to allocate structure");
286
+ rb_raise(rb_ePGerror, "PQconnectdb() unable to allocate PGconn structure");
273
287
 
274
- if (PQstatus(this->pgconn) == CONNECTION_BAD) {
275
- error = rb_exc_new2(rb_eConnectionBad, PQerrorMessage(this->pgconn));
276
- rb_iv_set(error, "@connection", self);
277
- rb_exc_raise(error);
278
- }
288
+ if (PQstatus(this->pgconn) == CONNECTION_BAD)
289
+ pg_raise_conn_error( rb_eConnectionBad, self, "%s", PQerrorMessage(this->pgconn));
279
290
 
280
291
  pgconn_set_default_encoding( self );
281
292
 
@@ -308,7 +319,6 @@ pgconn_s_connect_start( int argc, VALUE *argv, VALUE klass )
308
319
  {
309
320
  VALUE rb_conn;
310
321
  VALUE conninfo;
311
- VALUE error;
312
322
  t_pg_connection *this;
313
323
 
314
324
  /*
@@ -321,13 +331,10 @@ pgconn_s_connect_start( int argc, VALUE *argv, VALUE klass )
321
331
  this->pgconn = gvl_PQconnectStart( StringValueCStr(conninfo) );
322
332
 
323
333
  if( this->pgconn == NULL )
324
- rb_raise(rb_ePGerror, "PQconnectStart() unable to allocate structure");
334
+ rb_raise(rb_ePGerror, "PQconnectStart() unable to allocate PGconn structure");
325
335
 
326
- if ( PQstatus(this->pgconn) == CONNECTION_BAD ) {
327
- error = rb_exc_new2(rb_eConnectionBad, PQerrorMessage(this->pgconn));
328
- rb_iv_set(error, "@connection", rb_conn);
329
- rb_exc_raise(error);
330
- }
336
+ if ( PQstatus(this->pgconn) == CONNECTION_BAD )
337
+ pg_raise_conn_error( rb_eConnectionBad, rb_conn, "%s", PQerrorMessage(this->pgconn));
331
338
 
332
339
  if ( rb_block_given_p() ) {
333
340
  return rb_ensure( rb_yield, rb_conn, pgconn_finish, rb_conn );
@@ -335,34 +342,14 @@ pgconn_s_connect_start( int argc, VALUE *argv, VALUE klass )
335
342
  return rb_conn;
336
343
  }
337
344
 
338
- /*
339
- * call-seq:
340
- * PG::Connection.ping(connection_hash) -> Integer
341
- * PG::Connection.ping(connection_string) -> Integer
342
- * PG::Connection.ping(host, port, options, tty, dbname, login, password) -> Integer
343
- *
344
- * Check server status.
345
- *
346
- * See PG::Connection.new for a description of the parameters.
347
- *
348
- * Returns one of:
349
- * [+PQPING_OK+]
350
- * server is accepting connections
351
- * [+PQPING_REJECT+]
352
- * server is alive but rejecting connections
353
- * [+PQPING_NO_RESPONSE+]
354
- * could not establish connection
355
- * [+PQPING_NO_ATTEMPT+]
356
- * connection not attempted (bad params)
357
- */
358
345
  static VALUE
359
- pgconn_s_ping( int argc, VALUE *argv, VALUE klass )
346
+ pgconn_s_sync_ping( int argc, VALUE *argv, VALUE klass )
360
347
  {
361
348
  PGPing ping;
362
349
  VALUE conninfo;
363
350
 
364
351
  conninfo = rb_funcall2( klass, rb_intern("parse_connect_args"), argc, argv );
365
- ping = PQping( StringValueCStr(conninfo) );
352
+ ping = gvl_PQping( StringValueCStr(conninfo) );
366
353
 
367
354
  return INT2FIX((int)ping);
368
355
  }
@@ -403,32 +390,40 @@ pgconn_s_conndefaults(VALUE self)
403
390
  return array;
404
391
  }
405
392
 
406
-
407
- #ifdef HAVE_PQENCRYPTPASSWORDCONN
408
393
  /*
409
- * call-seq:
410
- * conn.encrypt_password( password, username, algorithm=nil ) -> String
411
- *
412
- * This function is intended to be used by client applications that wish to send commands like <tt>ALTER USER joe PASSWORD 'pwd'</tt>.
413
- * It is good practice not to send the original cleartext password in such a command, because it might be exposed in command logs, activity displays, and so on.
414
- * Instead, use this function to convert the password to encrypted form before it is sent.
415
- *
416
- * The +password+ and +username+ arguments are the cleartext password, and the SQL name of the user it is for.
417
- * +algorithm+ specifies the encryption algorithm to use to encrypt the password.
418
- * Currently supported algorithms are +md5+ and +scram-sha-256+ (+on+ and +off+ are also accepted as aliases for +md5+, for compatibility with older server versions).
419
- * Note that support for +scram-sha-256+ was introduced in PostgreSQL version 10, and will not work correctly with older server versions.
420
- * If algorithm is omitted or +nil+, this function will query the server for the current value of the +password_encryption+ setting.
421
- * That can block, and will fail if the current transaction is aborted, or if the connection is busy executing another query.
422
- * If you wish to use the default algorithm for the server but want to avoid blocking, query +password_encryption+ yourself before calling #encrypt_password, and pass that value as the algorithm.
394
+ * Document-method: PG::Connection.conninfo_parse
423
395
  *
424
- * Return value is the encrypted password.
425
- * The caller can assume the string doesn't contain any special characters that would require escaping.
396
+ * call-seq:
397
+ * PG::Connection.conninfo_parse(conninfo_string) -> Array
426
398
  *
427
- * Available since PostgreSQL-10.
428
- * See also corresponding {libpq function}[https://www.postgresql.org/docs/current/libpq-misc.html#LIBPQ-PQENCRYPTPASSWORDCONN].
399
+ * Returns parsed connection options from the provided connection string as an array of hashes.
400
+ * Each hash has the same keys as PG::Connection.conndefaults() .
401
+ * The values from the +conninfo_string+ are stored in the +:val+ key.
429
402
  */
430
403
  static VALUE
431
- pgconn_encrypt_password(int argc, VALUE *argv, VALUE self)
404
+ pgconn_s_conninfo_parse(VALUE self, VALUE conninfo)
405
+ {
406
+ VALUE array;
407
+ char *errmsg = NULL;
408
+ PQconninfoOption *options = PQconninfoParse(StringValueCStr(conninfo), &errmsg);
409
+ if(errmsg){
410
+ VALUE error = rb_str_new_cstr(errmsg);
411
+ PQfreemem(errmsg);
412
+ rb_raise(rb_ePGerror, "%"PRIsVALUE, error);
413
+ }
414
+ array = pgconn_make_conninfo_array( options );
415
+
416
+ PQconninfoFree(options);
417
+
418
+ UNUSED( self );
419
+
420
+ return array;
421
+ }
422
+
423
+
424
+ #ifdef HAVE_PQENCRYPTPASSWORDCONN
425
+ static VALUE
426
+ pgconn_sync_encrypt_password(int argc, VALUE *argv, VALUE self)
432
427
  {
433
428
  char *encrypted = NULL;
434
429
  VALUE rval = Qnil;
@@ -445,7 +440,7 @@ pgconn_encrypt_password(int argc, VALUE *argv, VALUE self)
445
440
  rval = rb_str_new2( encrypted );
446
441
  PQfreemem( encrypted );
447
442
  } else {
448
- rb_raise(rb_ePGerror, "%s", PQerrorMessage(conn));
443
+ pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(conn));
449
444
  }
450
445
 
451
446
  return rval;
@@ -499,17 +494,18 @@ pgconn_s_encrypt_password(VALUE self, VALUE password, VALUE username)
499
494
  * the asynchronous connection is ready
500
495
  *
501
496
  * Example:
502
- * conn = PG::Connection.connect_start("dbname=mydatabase")
503
- * socket = conn.socket_io
497
+ * require "io/wait"
498
+ *
499
+ * conn = PG::Connection.connect_start(dbname: 'mydatabase')
504
500
  * status = conn.connect_poll
505
501
  * while(status != PG::PGRES_POLLING_OK) do
506
502
  * # do some work while waiting for the connection to complete
507
503
  * if(status == PG::PGRES_POLLING_READING)
508
- * if(not select([socket], [], [], 10.0))
504
+ * unless conn.socket_io.wait_readable(10.0)
509
505
  * raise "Asynchronous connection timed out!"
510
506
  * end
511
507
  * elsif(status == PG::PGRES_POLLING_WRITING)
512
- * if(not select([], [socket], [], 10.0))
508
+ * unless conn.socket_io.wait_writable(10.0)
513
509
  * raise "Asynchronous connection timed out!"
514
510
  * end
515
511
  * end
@@ -523,6 +519,9 @@ pgconn_connect_poll(VALUE self)
523
519
  {
524
520
  PostgresPollingStatusType status;
525
521
  status = gvl_PQconnectPoll(pg_get_pgconn(self));
522
+
523
+ pgconn_close_socket_io(self);
524
+
526
525
  return INT2FIX((int)status);
527
526
  }
528
527
 
@@ -559,15 +558,8 @@ pgconn_finished_p( VALUE self )
559
558
  }
560
559
 
561
560
 
562
- /*
563
- * call-seq:
564
- * conn.reset()
565
- *
566
- * Resets the backend connection. This method closes the
567
- * backend connection and tries to re-connect.
568
- */
569
561
  static VALUE
570
- pgconn_reset( VALUE self )
562
+ pgconn_sync_reset( VALUE self )
571
563
  {
572
564
  pgconn_close_socket_io( self );
573
565
  gvl_PQreset( pg_get_pgconn(self) );
@@ -589,7 +581,7 @@ pgconn_reset_start(VALUE self)
589
581
  {
590
582
  pgconn_close_socket_io( self );
591
583
  if(gvl_PQresetStart(pg_get_pgconn(self)) == 0)
592
- rb_raise(rb_eUnableToSend, "reset has failed");
584
+ pg_raise_conn_error( rb_eUnableToSend, self, "reset has failed");
593
585
  return Qnil;
594
586
  }
595
587
 
@@ -606,6 +598,9 @@ pgconn_reset_poll(VALUE self)
606
598
  {
607
599
  PostgresPollingStatusType status;
608
600
  status = gvl_PQresetPoll(pg_get_pgconn(self));
601
+
602
+ pgconn_close_socket_io(self);
603
+
609
604
  return INT2FIX((int)status);
610
605
  }
611
606
 
@@ -656,7 +651,18 @@ pgconn_pass(VALUE self)
656
651
  * call-seq:
657
652
  * conn.host()
658
653
  *
659
- * Returns the connected server name.
654
+ * Returns the server host name of the active connection.
655
+ * This can be a host name, an IP address, or a directory path if the connection is via Unix socket.
656
+ * (The path case can be distinguished because it will always be an absolute path, beginning with +/+ .)
657
+ *
658
+ * If the connection parameters specified both host and hostaddr, then +host+ will return the host information.
659
+ * If only hostaddr was specified, then that is returned.
660
+ * If multiple hosts were specified in the connection parameters, +host+ returns the host actually connected to.
661
+ *
662
+ * If there is an error producing the host information (perhaps if the connection has not been fully established or there was an error), it returns an empty string.
663
+ *
664
+ * If multiple hosts were specified in the connection parameters, it is not possible to rely on the result of +host+ until the connection is established.
665
+ * The status of the connection can be checked using the function Connection#status .
660
666
  */
661
667
  static VALUE
662
668
  pgconn_host(VALUE self)
@@ -666,6 +672,26 @@ pgconn_host(VALUE self)
666
672
  return rb_str_new2(host);
667
673
  }
668
674
 
675
+ /* PQhostaddr() appeared in PostgreSQL-12 together with PQresultMemorySize() */
676
+ #if defined(HAVE_PQRESULTMEMORYSIZE)
677
+ /*
678
+ * call-seq:
679
+ * conn.hostaddr()
680
+ *
681
+ * Returns the server IP address of the active connection.
682
+ * This can be the address that a host name resolved to, or an IP address provided through the hostaddr parameter.
683
+ * If there is an error producing the host information (perhaps if the connection has not been fully established or there was an error), it returns an empty string.
684
+ *
685
+ */
686
+ static VALUE
687
+ pgconn_hostaddr(VALUE self)
688
+ {
689
+ char *host = PQhostaddr(pg_get_pgconn(self));
690
+ if (!host) return Qnil;
691
+ return rb_str_new2(host);
692
+ }
693
+ #endif
694
+
669
695
  /*
670
696
  * call-seq:
671
697
  * conn.port()
@@ -676,21 +702,19 @@ static VALUE
676
702
  pgconn_port(VALUE self)
677
703
  {
678
704
  char* port = PQport(pg_get_pgconn(self));
679
- return INT2NUM(atol(port));
705
+ return INT2NUM(atoi(port));
680
706
  }
681
707
 
682
708
  /*
683
709
  * call-seq:
684
710
  * conn.tty()
685
711
  *
686
- * Returns the connected pgtty. (Obsolete)
712
+ * Obsolete function.
687
713
  */
688
714
  static VALUE
689
715
  pgconn_tty(VALUE self)
690
716
  {
691
- char *tty = PQtty(pg_get_pgconn(self));
692
- if (!tty) return Qnil;
693
- return rb_str_new2(tty);
717
+ return rb_str_new2("");
694
718
  }
695
719
 
696
720
  /*
@@ -708,7 +732,6 @@ pgconn_options(VALUE self)
708
732
  }
709
733
 
710
734
 
711
- #ifdef HAVE_PQCONNINFO
712
735
  /*
713
736
  * call-seq:
714
737
  * conn.conninfo -> hash
@@ -728,14 +751,20 @@ pgconn_conninfo( VALUE self )
728
751
 
729
752
  return array;
730
753
  }
731
- #endif
732
754
 
733
755
 
734
756
  /*
735
757
  * call-seq:
736
758
  * conn.status()
737
759
  *
738
- * Returns status of connection : CONNECTION_OK or CONNECTION_BAD
760
+ * Returns the status of the connection, which is one:
761
+ * PG::Constants::CONNECTION_OK
762
+ * PG::Constants::CONNECTION_BAD
763
+ *
764
+ * ... and other constants of kind PG::Constants::CONNECTION_*
765
+ *
766
+ * Example:
767
+ * PG.constants.grep(/CONNECTION_/).find{|c| PG.const_get(c) == conn.status} # => :CONNECTION_OK
739
768
  */
740
769
  static VALUE
741
770
  pgconn_status(VALUE self)
@@ -823,7 +852,10 @@ pgconn_server_version(VALUE self)
823
852
  * call-seq:
824
853
  * conn.error_message -> String
825
854
  *
826
- * Returns the error message about connection.
855
+ * Returns the error message most recently generated by an operation on the connection.
856
+ *
857
+ * Nearly all libpq functions will set a message for conn.error_message if they fail.
858
+ * Note that by libpq convention, a nonempty error_message result can consist of multiple lines, and will include a trailing newline.
827
859
  */
828
860
  static VALUE
829
861
  pgconn_error_message(VALUE self)
@@ -857,7 +889,8 @@ pgconn_socket(VALUE self)
857
889
  pg_deprecated(4, ("conn.socket is deprecated and should be replaced by conn.socket_io"));
858
890
 
859
891
  if( (sd = PQsocket(pg_get_pgconn(self))) < 0)
860
- rb_raise(rb_eConnectionBad, "PQsocket() can't get socket descriptor");
892
+ pg_raise_conn_error( rb_eConnectionBad, self, "PQsocket() can't get socket descriptor");
893
+
861
894
  return INT2NUM(sd);
862
895
  }
863
896
 
@@ -865,38 +898,45 @@ pgconn_socket(VALUE self)
865
898
  * call-seq:
866
899
  * conn.socket_io() -> IO
867
900
  *
868
- * Fetch a memorized IO object created from the Connection's underlying socket.
869
- * This object can be used for IO.select to wait for events while running
870
- * asynchronous API calls.
901
+ * Fetch an IO object created from the Connection's underlying socket.
902
+ * This object can be used per <tt>socket_io.wait_readable</tt>, <tt>socket_io.wait_writable</tt> or for <tt>IO.select</tt> to wait for events while running asynchronous API calls.
903
+ * <tt>IO#wait_*able</tt> is is <tt>Fiber.scheduler</tt> compatible in contrast to <tt>IO.select</tt>.
871
904
  *
872
- * Using this instead of #socket avoids the problem of the underlying connection
873
- * being closed by Ruby when an IO created using <tt>IO.for_fd(conn.socket)</tt>
874
- * goes out of scope. In contrast to #socket, it also works on Windows.
905
+ * The IO object can change while the connection is established, but is memorized afterwards.
906
+ * So be sure not to cache the IO object, but repeat calling <tt>conn.socket_io</tt> instead.
907
+ *
908
+ * Using this method also works on Windows in contrast to using #socket .
909
+ * It also avoids the problem of the underlying connection being closed by Ruby when an IO created using <tt>IO.for_fd(conn.socket)</tt> goes out of scope.
875
910
  */
876
911
  static VALUE
877
912
  pgconn_socket_io(VALUE self)
878
913
  {
879
914
  int sd;
880
915
  int ruby_sd;
881
- ID id_autoclose = rb_intern("autoclose=");
882
916
  t_pg_connection *this = pg_get_connection_safe( self );
917
+ VALUE cSocket;
883
918
  VALUE socket_io = this->socket_io;
884
919
 
885
920
  if ( !RTEST(socket_io) ) {
886
- if( (sd = PQsocket(this->pgconn)) < 0)
887
- rb_raise(rb_eConnectionBad, "PQsocket() can't get socket descriptor");
921
+ if( (sd = PQsocket(this->pgconn)) < 0){
922
+ pg_raise_conn_error( rb_eConnectionBad, self, "PQsocket() can't get socket descriptor");
923
+ }
888
924
 
889
925
  #ifdef _WIN32
890
926
  ruby_sd = rb_w32_wrap_io_handle((HANDLE)(intptr_t)sd, O_RDWR|O_BINARY|O_NOINHERIT);
927
+ if( ruby_sd == -1 )
928
+ pg_raise_conn_error( rb_eConnectionBad, self, "Could not wrap win32 socket handle");
929
+
891
930
  this->ruby_sd = ruby_sd;
892
931
  #else
893
932
  ruby_sd = sd;
894
933
  #endif
895
934
 
896
- socket_io = rb_funcall( rb_cIO, rb_intern("for_fd"), 1, INT2NUM(ruby_sd) );
935
+ cSocket = rb_const_get(rb_cObject, rb_intern("BasicSocket"));
936
+ socket_io = rb_funcall( cSocket, rb_intern("for_fd"), 1, INT2NUM(ruby_sd));
897
937
 
898
938
  /* Disable autoclose feature */
899
- rb_funcall( socket_io, id_autoclose, 1, Qfalse );
939
+ rb_funcall( socket_io, s_id_autoclose_set, 1, Qfalse );
900
940
 
901
941
  this->socket_io = socket_io;
902
942
  }
@@ -918,6 +958,51 @@ pgconn_backend_pid(VALUE self)
918
958
  return INT2NUM(PQbackendPID(pg_get_pgconn(self)));
919
959
  }
920
960
 
961
+ typedef struct
962
+ {
963
+ struct sockaddr_storage addr;
964
+ socklen_t salen;
965
+ } SockAddr;
966
+
967
+ /* Copy of struct pg_cancel from libpq-int.h
968
+ *
969
+ * See https://github.com/postgres/postgres/blame/master/src/interfaces/libpq/libpq-int.h#L577-L586
970
+ */
971
+ struct pg_cancel
972
+ {
973
+ SockAddr raddr; /* Remote address */
974
+ int be_pid; /* PID of backend --- needed for cancels */
975
+ int be_key; /* key of backend --- needed for cancels */
976
+ };
977
+
978
+ /*
979
+ * call-seq:
980
+ * conn.backend_key() -> Integer
981
+ *
982
+ * Returns the key of the backend server process for this connection.
983
+ * This key can be used to cancel queries on the server.
984
+ */
985
+ static VALUE
986
+ pgconn_backend_key(VALUE self)
987
+ {
988
+ int be_key;
989
+ struct pg_cancel *cancel;
990
+ PGconn *conn = pg_get_pgconn(self);
991
+
992
+ cancel = (struct pg_cancel*)PQgetCancel(conn);
993
+ if(cancel == NULL)
994
+ pg_raise_conn_error( rb_ePGerror, self, "Invalid connection!");
995
+
996
+ if( cancel->be_pid != PQbackendPID(conn) )
997
+ rb_raise(rb_ePGerror,"Unexpected binary struct layout - please file a bug report at ruby-pg!");
998
+
999
+ be_key = cancel->be_key;
1000
+
1001
+ PQfreeCancel(cancel);
1002
+
1003
+ return INT2NUM(be_key);
1004
+ }
1005
+
921
1006
  /*
922
1007
  * call-seq:
923
1008
  * conn.connection_needs_password() -> Boolean
@@ -948,7 +1033,7 @@ pgconn_connection_used_password(VALUE self)
948
1033
  /* :TODO: get_ssl */
949
1034
 
950
1035
 
951
- static VALUE pgconn_exec_params( int, VALUE *, VALUE );
1036
+ static VALUE pgconn_sync_exec_params( int, VALUE *, VALUE );
952
1037
 
953
1038
  /*
954
1039
  * call-seq:
@@ -962,11 +1047,11 @@ static VALUE pgconn_exec_params( int, VALUE *, VALUE );
962
1047
  * However #async_exec has two advantages:
963
1048
  *
964
1049
  * 1. #async_exec can be aborted by signals (like Ctrl-C), while #exec blocks signal processing until the query is answered.
965
- * 2. Ruby VM gets notified about IO blocked operations.
966
- * It can therefore schedule things like garbage collection, while queries are running like in this proposal: https://bugs.ruby-lang.org/issues/14723
1050
+ * 2. Ruby VM gets notified about IO blocked operations and can pass them through <tt>Fiber.scheduler</tt>.
1051
+ * So only <tt>async_*</tt> methods are compatible to event based schedulers like the async gem.
967
1052
  */
968
1053
  static VALUE
969
- pgconn_exec(int argc, VALUE *argv, VALUE self)
1054
+ pgconn_sync_exec(int argc, VALUE *argv, VALUE self)
970
1055
  {
971
1056
  t_pg_connection *this = pg_get_connection_safe( self );
972
1057
  PGresult *result = NULL;
@@ -987,7 +1072,7 @@ pgconn_exec(int argc, VALUE *argv, VALUE self)
987
1072
  pg_deprecated(0, ("forwarding exec to exec_params is deprecated"));
988
1073
 
989
1074
  /* Otherwise, just call #exec_params instead for backward-compatibility */
990
- return pgconn_exec_params( argc, argv, self );
1075
+ return pgconn_sync_exec_params( argc, argv, self );
991
1076
 
992
1077
  }
993
1078
 
@@ -1019,7 +1104,7 @@ struct query_params_data {
1019
1104
  * Filled by alloc_query_params()
1020
1105
  */
1021
1106
 
1022
- /* Wraps the pointer of allocated memory, if function parameters dont't
1107
+ /* Wraps the pointer of allocated memory, if function parameters don't
1023
1108
  * fit in the memory_pool below.
1024
1109
  */
1025
1110
  VALUE heap_pool;
@@ -1037,7 +1122,7 @@ struct query_params_data {
1037
1122
  Oid *types;
1038
1123
 
1039
1124
  /* This array takes the string values for the timeframe of the query,
1040
- * if param value convertion is required
1125
+ * if param value conversion is required
1041
1126
  */
1042
1127
  VALUE gc_array;
1043
1128
 
@@ -1051,8 +1136,9 @@ struct query_params_data {
1051
1136
  };
1052
1137
 
1053
1138
  static void
1054
- free_typecast_heap_chain(struct linked_typecast_data *chain_entry)
1139
+ free_typecast_heap_chain(void *_chain_entry)
1055
1140
  {
1141
+ struct linked_typecast_data *chain_entry = (struct linked_typecast_data *)_chain_entry;
1056
1142
  while(chain_entry){
1057
1143
  struct linked_typecast_data *next = chain_entry->next;
1058
1144
  xfree(chain_entry);
@@ -1060,6 +1146,18 @@ free_typecast_heap_chain(struct linked_typecast_data *chain_entry)
1060
1146
  }
1061
1147
  }
1062
1148
 
1149
+ static const rb_data_type_t pg_typecast_buffer_type = {
1150
+ "PG::Connection typecast buffer chain",
1151
+ {
1152
+ (RUBY_DATA_FUNC) NULL,
1153
+ free_typecast_heap_chain,
1154
+ (size_t (*)(const void *))NULL,
1155
+ },
1156
+ 0,
1157
+ 0,
1158
+ RUBY_TYPED_FREE_IMMEDIATELY,
1159
+ };
1160
+
1063
1161
  static char *
1064
1162
  alloc_typecast_buf( VALUE *typecast_heap_chain, int len )
1065
1163
  {
@@ -1070,17 +1168,28 @@ alloc_typecast_buf( VALUE *typecast_heap_chain, int len )
1070
1168
  /* Did we already wrap a memory chain per T_DATA object? */
1071
1169
  if( NIL_P( *typecast_heap_chain ) ){
1072
1170
  /* Leave free'ing of the buffer chain to the GC, when paramsData has left the stack */
1073
- *typecast_heap_chain = Data_Wrap_Struct( rb_cObject, NULL, free_typecast_heap_chain, allocated );
1171
+ *typecast_heap_chain = TypedData_Wrap_Struct( rb_cObject, &pg_typecast_buffer_type, allocated );
1074
1172
  allocated->next = NULL;
1075
1173
  } else {
1076
1174
  /* Append to the chain */
1077
- allocated->next = DATA_PTR( *typecast_heap_chain );
1078
- DATA_PTR( *typecast_heap_chain ) = allocated;
1175
+ allocated->next = RTYPEDDATA_DATA( *typecast_heap_chain );
1176
+ RTYPEDDATA_DATA( *typecast_heap_chain ) = allocated;
1079
1177
  }
1080
1178
 
1081
1179
  return &allocated->data[0];
1082
1180
  }
1083
1181
 
1182
+ static const rb_data_type_t pg_query_heap_pool_type = {
1183
+ "PG::Connection query heap pool",
1184
+ {
1185
+ (RUBY_DATA_FUNC) NULL,
1186
+ RUBY_TYPED_DEFAULT_FREE,
1187
+ (size_t (*)(const void *))NULL,
1188
+ },
1189
+ 0,
1190
+ 0,
1191
+ RUBY_TYPED_FREE_IMMEDIATELY,
1192
+ };
1084
1193
 
1085
1194
  static int
1086
1195
  alloc_query_params(struct query_params_data *paramsData)
@@ -1095,7 +1204,7 @@ alloc_query_params(struct query_params_data *paramsData)
1095
1204
 
1096
1205
  Check_Type(paramsData->params, T_ARRAY);
1097
1206
 
1098
- p_typemap = DATA_PTR( paramsData->typemap );
1207
+ p_typemap = RTYPEDDATA_DATA( paramsData->typemap );
1099
1208
  p_typemap->funcs.fit_to_query( paramsData->typemap, paramsData->params );
1100
1209
 
1101
1210
  paramsData->heap_pool = Qnil;
@@ -1114,7 +1223,7 @@ alloc_query_params(struct query_params_data *paramsData)
1114
1223
  /* Allocate one combined memory pool for all possible function parameters */
1115
1224
  memory_pool = (char*)xmalloc( required_pool_size );
1116
1225
  /* Leave free'ing of the buffer to the GC, when paramsData has left the stack */
1117
- paramsData->heap_pool = Data_Wrap_Struct( rb_cObject, NULL, -1, memory_pool );
1226
+ paramsData->heap_pool = TypedData_Wrap_Struct( rb_cObject, &pg_query_heap_pool_type, memory_pool );
1118
1227
  required_pool_size = 0;
1119
1228
  }else{
1120
1229
  /* Use stack memory for function parameters */
@@ -1227,12 +1336,11 @@ pgconn_query_assign_typemap( VALUE self, struct query_params_data *paramsData )
1227
1336
  /* Use default typemap for queries. It's type is checked when assigned. */
1228
1337
  paramsData->typemap = pg_get_connection(self)->type_map_for_queries;
1229
1338
  }else{
1339
+ t_typemap *tm;
1340
+ UNUSED(tm);
1341
+
1230
1342
  /* Check type of method param */
1231
- if ( !rb_obj_is_kind_of(paramsData->typemap, rb_cTypeMap) ) {
1232
- rb_raise( rb_eTypeError, "wrong argument type %s (expected kind of PG::TypeMap)",
1233
- rb_obj_classname( paramsData->typemap ) );
1234
- }
1235
- Check_Type( paramsData->typemap, T_DATA );
1343
+ TypedData_Get_Struct(paramsData->typemap, t_typemap, &pg_typemap_type, tm);
1236
1344
  }
1237
1345
  }
1238
1346
 
@@ -1246,7 +1354,7 @@ pgconn_query_assign_typemap( VALUE self, struct query_params_data *paramsData )
1246
1354
  * It's not recommended to use explicit sync or async variants but #exec_params instead, unless you have a good reason to do so.
1247
1355
  */
1248
1356
  static VALUE
1249
- pgconn_exec_params( int argc, VALUE *argv, VALUE self )
1357
+ pgconn_sync_exec_params( int argc, VALUE *argv, VALUE self )
1250
1358
  {
1251
1359
  t_pg_connection *this = pg_get_connection_safe( self );
1252
1360
  PGresult *result = NULL;
@@ -1266,7 +1374,7 @@ pgconn_exec_params( int argc, VALUE *argv, VALUE self )
1266
1374
  */
1267
1375
  if ( NIL_P(paramsData.params) ) {
1268
1376
  pg_deprecated(1, ("forwarding exec_params to exec is deprecated"));
1269
- return pgconn_exec( 1, argv, self );
1377
+ return pgconn_sync_exec( 1, argv, self );
1270
1378
  }
1271
1379
  pgconn_query_assign_typemap( self, &paramsData );
1272
1380
 
@@ -1297,7 +1405,7 @@ pgconn_exec_params( int argc, VALUE *argv, VALUE self )
1297
1405
  * It's not recommended to use explicit sync or async variants but #prepare instead, unless you have a good reason to do so.
1298
1406
  */
1299
1407
  static VALUE
1300
- pgconn_prepare(int argc, VALUE *argv, VALUE self)
1408
+ pgconn_sync_prepare(int argc, VALUE *argv, VALUE self)
1301
1409
  {
1302
1410
  t_pg_connection *this = pg_get_connection_safe( self );
1303
1411
  PGresult *result = NULL;
@@ -1346,7 +1454,7 @@ pgconn_prepare(int argc, VALUE *argv, VALUE self)
1346
1454
  * It's not recommended to use explicit sync or async variants but #exec_prepared instead, unless you have a good reason to do so.
1347
1455
  */
1348
1456
  static VALUE
1349
- pgconn_exec_prepared(int argc, VALUE *argv, VALUE self)
1457
+ pgconn_sync_exec_prepared(int argc, VALUE *argv, VALUE self)
1350
1458
  {
1351
1459
  t_pg_connection *this = pg_get_connection_safe( self );
1352
1460
  PGresult *result = NULL;
@@ -1391,7 +1499,7 @@ pgconn_exec_prepared(int argc, VALUE *argv, VALUE self)
1391
1499
  * It's not recommended to use explicit sync or async variants but #describe_prepared instead, unless you have a good reason to do so.
1392
1500
  */
1393
1501
  static VALUE
1394
- pgconn_describe_prepared(VALUE self, VALUE stmt_name)
1502
+ pgconn_sync_describe_prepared(VALUE self, VALUE stmt_name)
1395
1503
  {
1396
1504
  PGresult *result;
1397
1505
  VALUE rb_pgresult;
@@ -1419,7 +1527,7 @@ pgconn_describe_prepared(VALUE self, VALUE stmt_name)
1419
1527
  * It's not recommended to use explicit sync or async variants but #describe_portal instead, unless you have a good reason to do so.
1420
1528
  */
1421
1529
  static VALUE
1422
- pgconn_describe_portal(self, stmt_name)
1530
+ pgconn_sync_describe_portal(self, stmt_name)
1423
1531
  VALUE self, stmt_name;
1424
1532
  {
1425
1533
  PGresult *result;
@@ -1454,6 +1562,9 @@ pgconn_describe_portal(self, stmt_name)
1454
1562
  * * +PGRES_NONFATAL_ERROR+
1455
1563
  * * +PGRES_FATAL_ERROR+
1456
1564
  * * +PGRES_COPY_BOTH+
1565
+ * * +PGRES_SINGLE_TUPLE+
1566
+ * * +PGRES_PIPELINE_SYNC+
1567
+ * * +PGRES_PIPELINE_ABORTED+
1457
1568
  */
1458
1569
  static VALUE
1459
1570
  pgconn_make_empty_pgresult(VALUE self, VALUE status)
@@ -1509,9 +1620,9 @@ pgconn_s_escape(VALUE self, VALUE string)
1509
1620
  if( !singleton ) {
1510
1621
  size = PQescapeStringConn(pg_get_pgconn(self), RSTRING_PTR(result),
1511
1622
  RSTRING_PTR(string), RSTRING_LEN(string), &error);
1512
- if(error) {
1513
- rb_raise(rb_ePGerror, "%s", PQerrorMessage(pg_get_pgconn(self)));
1514
- }
1623
+ if(error)
1624
+ pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(pg_get_pgconn(self)));
1625
+
1515
1626
  } else {
1516
1627
  size = PQescapeString(RSTRING_PTR(result), RSTRING_PTR(string), RSTRING_LEN(string));
1517
1628
  }
@@ -1607,7 +1718,6 @@ pgconn_escape_literal(VALUE self, VALUE string)
1607
1718
  {
1608
1719
  t_pg_connection *this = pg_get_connection_safe( self );
1609
1720
  char *escaped = NULL;
1610
- VALUE error;
1611
1721
  VALUE result = Qnil;
1612
1722
  int enc_idx = this->enc_idx;
1613
1723
 
@@ -1618,12 +1728,8 @@ pgconn_escape_literal(VALUE self, VALUE string)
1618
1728
 
1619
1729
  escaped = PQescapeLiteral(this->pgconn, RSTRING_PTR(string), RSTRING_LEN(string));
1620
1730
  if (escaped == NULL)
1621
- {
1622
- error = rb_exc_new2(rb_ePGerror, PQerrorMessage(this->pgconn));
1623
- rb_iv_set(error, "@connection", self);
1624
- rb_exc_raise(error);
1625
- return Qnil;
1626
- }
1731
+ pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(this->pgconn));
1732
+
1627
1733
  result = rb_str_new2(escaped);
1628
1734
  PQfreemem(escaped);
1629
1735
  PG_ENCODING_SET_NOCHECK(result, enc_idx);
@@ -1646,7 +1752,6 @@ pgconn_escape_identifier(VALUE self, VALUE string)
1646
1752
  {
1647
1753
  t_pg_connection *this = pg_get_connection_safe( self );
1648
1754
  char *escaped = NULL;
1649
- VALUE error;
1650
1755
  VALUE result = Qnil;
1651
1756
  int enc_idx = this->enc_idx;
1652
1757
 
@@ -1657,12 +1762,8 @@ pgconn_escape_identifier(VALUE self, VALUE string)
1657
1762
 
1658
1763
  escaped = PQescapeIdentifier(this->pgconn, RSTRING_PTR(string), RSTRING_LEN(string));
1659
1764
  if (escaped == NULL)
1660
- {
1661
- error = rb_exc_new2(rb_ePGerror, PQerrorMessage(this->pgconn));
1662
- rb_iv_set(error, "@connection", self);
1663
- rb_exc_raise(error);
1664
- return Qnil;
1665
- }
1765
+ pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(this->pgconn));
1766
+
1666
1767
  result = rb_str_new2(escaped);
1667
1768
  PQfreemem(escaped);
1668
1769
  PG_ENCODING_SET_NOCHECK(result, enc_idx);
@@ -1710,14 +1811,9 @@ static VALUE
1710
1811
  pgconn_set_single_row_mode(VALUE self)
1711
1812
  {
1712
1813
  PGconn *conn = pg_get_pgconn(self);
1713
- VALUE error;
1714
1814
 
1715
1815
  if( PQsetSingleRowMode(conn) == 0 )
1716
- {
1717
- error = rb_exc_new2(rb_ePGerror, PQerrorMessage(conn));
1718
- rb_iv_set(error, "@connection", self);
1719
- rb_exc_raise(error);
1720
- }
1816
+ pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(conn));
1721
1817
 
1722
1818
  return self;
1723
1819
  }
@@ -1741,15 +1837,13 @@ static VALUE
1741
1837
  pgconn_send_query(int argc, VALUE *argv, VALUE self)
1742
1838
  {
1743
1839
  t_pg_connection *this = pg_get_connection_safe( self );
1744
- VALUE error;
1745
1840
 
1746
1841
  /* If called with no or nil parameters, use PQexec for compatibility */
1747
1842
  if ( argc == 1 || (argc >= 2 && argc <= 4 && NIL_P(argv[1]) )) {
1748
- if(gvl_PQsendQuery(this->pgconn, pg_cstr_enc(argv[0], this->enc_idx)) == 0) {
1749
- error = rb_exc_new2(rb_eUnableToSend, PQerrorMessage(this->pgconn));
1750
- rb_iv_set(error, "@connection", self);
1751
- rb_exc_raise(error);
1752
- }
1843
+ if(gvl_PQsendQuery(this->pgconn, pg_cstr_enc(argv[0], this->enc_idx)) == 0)
1844
+ pg_raise_conn_error( rb_eUnableToSend, self, "%s", PQerrorMessage(this->pgconn));
1845
+
1846
+ pgconn_wait_for_flush( self );
1753
1847
  return Qnil;
1754
1848
  }
1755
1849
 
@@ -1779,7 +1873,7 @@ pgconn_send_query(int argc, VALUE *argv, VALUE self)
1779
1873
  * or, it may be a String. If it is a string, that is equivalent to the hash:
1780
1874
  * { :value => <string value>, :type => 0, :format => 0 }
1781
1875
  *
1782
- * PostgreSQL bind parameters are represented as $1, $1, $2, etc.,
1876
+ * PostgreSQL bind parameters are represented as $1, $2, $3, etc.,
1783
1877
  * inside the SQL query. The 0th element of the +params+ array is bound
1784
1878
  * to $1, the 1st element is bound to $2, etc. +nil+ is treated as +NULL+.
1785
1879
  *
@@ -1805,7 +1899,6 @@ pgconn_send_query_params(int argc, VALUE *argv, VALUE self)
1805
1899
  t_pg_connection *this = pg_get_connection_safe( self );
1806
1900
  int result;
1807
1901
  VALUE command, in_res_fmt;
1808
- VALUE error;
1809
1902
  int nParams;
1810
1903
  int resultFormat;
1811
1904
  struct query_params_data paramsData = { this->enc_idx };
@@ -1822,11 +1915,10 @@ pgconn_send_query_params(int argc, VALUE *argv, VALUE self)
1822
1915
 
1823
1916
  free_query_params( &paramsData );
1824
1917
 
1825
- if(result == 0) {
1826
- error = rb_exc_new2(rb_eUnableToSend, PQerrorMessage(this->pgconn));
1827
- rb_iv_set(error, "@connection", self);
1828
- rb_exc_raise(error);
1829
- }
1918
+ if(result == 0)
1919
+ pg_raise_conn_error( rb_eUnableToSend, self, "%s", PQerrorMessage(this->pgconn));
1920
+
1921
+ pgconn_wait_for_flush( self );
1830
1922
  return Qnil;
1831
1923
  }
1832
1924
 
@@ -1847,7 +1939,7 @@ pgconn_send_query_params(int argc, VALUE *argv, VALUE self)
1847
1939
  *
1848
1940
  * For example: "SELECT $1::int"
1849
1941
  *
1850
- * PostgreSQL bind parameters are represented as $1, $1, $2, etc.,
1942
+ * PostgreSQL bind parameters are represented as $1, $2, $3, etc.,
1851
1943
  * inside the SQL query.
1852
1944
  */
1853
1945
  static VALUE
@@ -1857,7 +1949,6 @@ pgconn_send_prepare(int argc, VALUE *argv, VALUE self)
1857
1949
  int result;
1858
1950
  VALUE name, command, in_paramtypes;
1859
1951
  VALUE param;
1860
- VALUE error;
1861
1952
  int i = 0;
1862
1953
  int nParams = 0;
1863
1954
  Oid *paramTypes = NULL;
@@ -1886,10 +1977,9 @@ pgconn_send_prepare(int argc, VALUE *argv, VALUE self)
1886
1977
  xfree(paramTypes);
1887
1978
 
1888
1979
  if(result == 0) {
1889
- error = rb_exc_new2(rb_eUnableToSend, PQerrorMessage(this->pgconn));
1890
- rb_iv_set(error, "@connection", self);
1891
- rb_exc_raise(error);
1980
+ pg_raise_conn_error( rb_eUnableToSend, self, "%s", PQerrorMessage(this->pgconn));
1892
1981
  }
1982
+ pgconn_wait_for_flush( self );
1893
1983
  return Qnil;
1894
1984
  }
1895
1985
 
@@ -1911,7 +2001,7 @@ pgconn_send_prepare(int argc, VALUE *argv, VALUE self)
1911
2001
  * or, it may be a String. If it is a string, that is equivalent to the hash:
1912
2002
  * { :value => <string value>, :format => 0 }
1913
2003
  *
1914
- * PostgreSQL bind parameters are represented as $1, $1, $2, etc.,
2004
+ * PostgreSQL bind parameters are represented as $1, $2, $3, etc.,
1915
2005
  * inside the SQL query. The 0th element of the +params+ array is bound
1916
2006
  * to $1, the 1st element is bound to $2, etc. +nil+ is treated as +NULL+.
1917
2007
  *
@@ -1931,7 +2021,6 @@ pgconn_send_query_prepared(int argc, VALUE *argv, VALUE self)
1931
2021
  t_pg_connection *this = pg_get_connection_safe( self );
1932
2022
  int result;
1933
2023
  VALUE name, in_res_fmt;
1934
- VALUE error;
1935
2024
  int nParams;
1936
2025
  int resultFormat;
1937
2026
  struct query_params_data paramsData = { this->enc_idx };
@@ -1941,7 +2030,6 @@ pgconn_send_query_prepared(int argc, VALUE *argv, VALUE self)
1941
2030
 
1942
2031
  if(NIL_P(paramsData.params)) {
1943
2032
  paramsData.params = rb_ary_new2(0);
1944
- resultFormat = 0;
1945
2033
  }
1946
2034
  pgconn_query_assign_typemap( self, &paramsData );
1947
2035
 
@@ -1954,11 +2042,10 @@ pgconn_send_query_prepared(int argc, VALUE *argv, VALUE self)
1954
2042
 
1955
2043
  free_query_params( &paramsData );
1956
2044
 
1957
- if(result == 0) {
1958
- error = rb_exc_new2(rb_eUnableToSend, PQerrorMessage(this->pgconn));
1959
- rb_iv_set(error, "@connection", self);
1960
- rb_exc_raise(error);
1961
- }
2045
+ if(result == 0)
2046
+ pg_raise_conn_error( rb_eUnableToSend, self, "%s", PQerrorMessage(this->pgconn));
2047
+
2048
+ pgconn_wait_for_flush( self );
1962
2049
  return Qnil;
1963
2050
  }
1964
2051
 
@@ -1972,14 +2059,12 @@ pgconn_send_query_prepared(int argc, VALUE *argv, VALUE self)
1972
2059
  static VALUE
1973
2060
  pgconn_send_describe_prepared(VALUE self, VALUE stmt_name)
1974
2061
  {
1975
- VALUE error;
1976
2062
  t_pg_connection *this = pg_get_connection_safe( self );
1977
2063
  /* returns 0 on failure */
1978
- if(gvl_PQsendDescribePrepared(this->pgconn, pg_cstr_enc(stmt_name, this->enc_idx)) == 0) {
1979
- error = rb_exc_new2(rb_eUnableToSend, PQerrorMessage(this->pgconn));
1980
- rb_iv_set(error, "@connection", self);
1981
- rb_exc_raise(error);
1982
- }
2064
+ if(gvl_PQsendDescribePrepared(this->pgconn, pg_cstr_enc(stmt_name, this->enc_idx)) == 0)
2065
+ pg_raise_conn_error( rb_eUnableToSend, self, "%s", PQerrorMessage(this->pgconn));
2066
+
2067
+ pgconn_wait_for_flush( self );
1983
2068
  return Qnil;
1984
2069
  }
1985
2070
 
@@ -1994,36 +2079,18 @@ pgconn_send_describe_prepared(VALUE self, VALUE stmt_name)
1994
2079
  static VALUE
1995
2080
  pgconn_send_describe_portal(VALUE self, VALUE portal)
1996
2081
  {
1997
- VALUE error;
1998
2082
  t_pg_connection *this = pg_get_connection_safe( self );
1999
2083
  /* returns 0 on failure */
2000
- if(gvl_PQsendDescribePortal(this->pgconn, pg_cstr_enc(portal, this->enc_idx)) == 0) {
2001
- error = rb_exc_new2(rb_eUnableToSend, PQerrorMessage(this->pgconn));
2002
- rb_iv_set(error, "@connection", self);
2003
- rb_exc_raise(error);
2004
- }
2084
+ if(gvl_PQsendDescribePortal(this->pgconn, pg_cstr_enc(portal, this->enc_idx)) == 0)
2085
+ pg_raise_conn_error( rb_eUnableToSend, self, "%s", PQerrorMessage(this->pgconn));
2086
+
2087
+ pgconn_wait_for_flush( self );
2005
2088
  return Qnil;
2006
2089
  }
2007
2090
 
2008
2091
 
2009
- /*
2010
- * call-seq:
2011
- * conn.get_result() -> PG::Result
2012
- * conn.get_result() {|pg_result| block }
2013
- *
2014
- * Blocks waiting for the next result from a call to
2015
- * #send_query (or another asynchronous command), and returns
2016
- * it. Returns +nil+ if no more results are available.
2017
- *
2018
- * Note: call this function repeatedly until it returns +nil+, or else
2019
- * you will not be able to issue further commands.
2020
- *
2021
- * If the optional code block is given, it will be passed <i>result</i> as an argument,
2022
- * and the PG::Result object will automatically be cleared when the block terminates.
2023
- * In this instance, <code>conn.exec</code> returns the value of the block.
2024
- */
2025
2092
  static VALUE
2026
- pgconn_get_result(VALUE self)
2093
+ pgconn_sync_get_result(VALUE self)
2027
2094
  {
2028
2095
  PGconn *conn = pg_get_pgconn(self);
2029
2096
  PGresult *result;
@@ -2049,17 +2116,15 @@ pgconn_get_result(VALUE self)
2049
2116
  * or *notifies* to see if the state has changed.
2050
2117
  */
2051
2118
  static VALUE
2052
- pgconn_consume_input(self)
2053
- VALUE self;
2119
+ pgconn_consume_input(VALUE self)
2054
2120
  {
2055
- VALUE error;
2056
2121
  PGconn *conn = pg_get_pgconn(self);
2057
2122
  /* returns 0 on error */
2058
2123
  if(PQconsumeInput(conn) == 0) {
2059
- error = rb_exc_new2(rb_eConnectionBad, PQerrorMessage(conn));
2060
- rb_iv_set(error, "@connection", self);
2061
- rb_exc_raise(error);
2124
+ pgconn_close_socket_io(self);
2125
+ pg_raise_conn_error( rb_eConnectionBad, self, "%s", PQerrorMessage(conn));
2062
2126
  }
2127
+
2063
2128
  return Qnil;
2064
2129
  }
2065
2130
 
@@ -2068,37 +2133,18 @@ pgconn_consume_input(self)
2068
2133
  * conn.is_busy() -> Boolean
2069
2134
  *
2070
2135
  * Returns +true+ if a command is busy, that is, if
2071
- * PQgetResult would block. Otherwise returns +false+.
2136
+ * #get_result would block. Otherwise returns +false+.
2072
2137
  */
2073
2138
  static VALUE
2074
- pgconn_is_busy(self)
2075
- VALUE self;
2139
+ pgconn_is_busy(VALUE self)
2076
2140
  {
2077
2141
  return gvl_PQisBusy(pg_get_pgconn(self)) ? Qtrue : Qfalse;
2078
2142
  }
2079
2143
 
2080
- /*
2081
- * call-seq:
2082
- * conn.setnonblocking(Boolean) -> nil
2083
- *
2084
- * Sets the nonblocking status of the connection.
2085
- * In the blocking state, calls to #send_query
2086
- * will block until the message is sent to the server,
2087
- * but will not wait for the query results.
2088
- * In the nonblocking state, calls to #send_query
2089
- * will return an error if the socket is not ready for
2090
- * writing.
2091
- * Note: This function does not affect #exec, because
2092
- * that function doesn't return until the server has
2093
- * processed the query and returned the results.
2094
- * Returns +nil+.
2095
- */
2096
2144
  static VALUE
2097
- pgconn_setnonblocking(self, state)
2098
- VALUE self, state;
2145
+ pgconn_sync_setnonblocking(VALUE self, VALUE state)
2099
2146
  {
2100
2147
  int arg;
2101
- VALUE error;
2102
2148
  PGconn *conn = pg_get_pgconn(self);
2103
2149
  if(state == Qtrue)
2104
2150
  arg = 1;
@@ -2107,67 +2153,32 @@ pgconn_setnonblocking(self, state)
2107
2153
  else
2108
2154
  rb_raise(rb_eArgError, "Boolean value expected");
2109
2155
 
2110
- if(PQsetnonblocking(conn, arg) == -1) {
2111
- error = rb_exc_new2(rb_ePGerror, PQerrorMessage(conn));
2112
- rb_iv_set(error, "@connection", self);
2113
- rb_exc_raise(error);
2114
- }
2156
+ if(PQsetnonblocking(conn, arg) == -1)
2157
+ pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(conn));
2158
+
2115
2159
  return Qnil;
2116
2160
  }
2117
2161
 
2118
2162
 
2119
- /*
2120
- * call-seq:
2121
- * conn.isnonblocking() -> Boolean
2122
- *
2123
- * Returns +true+ if a command is busy, that is, if
2124
- * PQgetResult would block. Otherwise returns +false+.
2125
- */
2126
2163
  static VALUE
2127
- pgconn_isnonblocking(self)
2128
- VALUE self;
2164
+ pgconn_sync_isnonblocking(VALUE self)
2129
2165
  {
2130
2166
  return PQisnonblocking(pg_get_pgconn(self)) ? Qtrue : Qfalse;
2131
2167
  }
2132
2168
 
2133
- /*
2134
- * call-seq:
2135
- * conn.flush() -> Boolean
2136
- *
2137
- * Attempts to flush any queued output data to the server.
2138
- * Returns +true+ if data is successfully flushed, +false+
2139
- * if not (can only return +false+ if connection is
2140
- * nonblocking.
2141
- * Raises PG::Error if some other failure occurred.
2142
- */
2143
2169
  static VALUE
2144
- pgconn_flush(self)
2145
- VALUE self;
2170
+ pgconn_sync_flush(VALUE self)
2146
2171
  {
2147
2172
  PGconn *conn = pg_get_pgconn(self);
2148
- int ret;
2149
- VALUE error;
2150
- ret = PQflush(conn);
2151
- if(ret == -1) {
2152
- error = rb_exc_new2(rb_ePGerror, PQerrorMessage(conn));
2153
- rb_iv_set(error, "@connection", self);
2154
- rb_exc_raise(error);
2155
- }
2173
+ int ret = PQflush(conn);
2174
+ if(ret == -1)
2175
+ pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(conn));
2176
+
2156
2177
  return (ret) ? Qfalse : Qtrue;
2157
2178
  }
2158
2179
 
2159
- /*
2160
- * call-seq:
2161
- * conn.cancel() -> String
2162
- *
2163
- * Requests cancellation of the command currently being
2164
- * processed. (Only implemented in PostgreSQL >= 8.0)
2165
- *
2166
- * Returns +nil+ on success, or a string containing the
2167
- * error message if a failure occurs.
2168
- */
2169
2180
  static VALUE
2170
- pgconn_cancel(VALUE self)
2181
+ pgconn_sync_cancel(VALUE self)
2171
2182
  {
2172
2183
  char errbuf[256];
2173
2184
  PGcancel *cancel;
@@ -2176,9 +2187,9 @@ pgconn_cancel(VALUE self)
2176
2187
 
2177
2188
  cancel = PQgetCancel(pg_get_pgconn(self));
2178
2189
  if(cancel == NULL)
2179
- rb_raise(rb_ePGerror,"Invalid connection!");
2190
+ pg_raise_conn_error( rb_ePGerror, self, "Invalid connection!");
2180
2191
 
2181
- ret = gvl_PQcancel(cancel, errbuf, 256);
2192
+ ret = gvl_PQcancel(cancel, errbuf, sizeof(errbuf));
2182
2193
  if(ret == 1)
2183
2194
  retval = Qnil;
2184
2195
  else
@@ -2229,55 +2240,63 @@ pgconn_notifies(VALUE self)
2229
2240
  return hash;
2230
2241
  }
2231
2242
 
2232
- /* Win32 + Ruby 1.9+ */
2233
- #if defined( _WIN32 )
2234
- /*
2235
- * On Windows, use platform-specific strategies to wait for the socket
2236
- * instead of rb_wait_for_single_fd().
2243
+ #if defined(_WIN32)
2244
+
2245
+ /* We use a specialized implementation of rb_io_wait() on Windows.
2246
+ * This is because rb_io_wait() and rb_wait_for_single_fd() are very slow on Windows.
2237
2247
  */
2238
2248
 
2249
+ #if defined(HAVE_RUBY_FIBER_SCHEDULER_H)
2250
+ #include <ruby/fiber/scheduler.h>
2251
+ #endif
2252
+
2253
+ typedef enum {
2254
+ PG_RUBY_IO_READABLE = RB_WAITFD_IN,
2255
+ PG_RUBY_IO_WRITABLE = RB_WAITFD_OUT,
2256
+ PG_RUBY_IO_PRIORITY = RB_WAITFD_PRI,
2257
+ } pg_rb_io_event_t;
2258
+
2239
2259
  int rb_w32_wait_events( HANDLE *events, int num, DWORD timeout );
2240
2260
 
2241
- static void *
2242
- wait_socket_readable( PGconn *conn, struct timeval *ptimeout, void *(*is_readable)(PGconn *) )
2243
- {
2244
- int sd = PQsocket( conn );
2245
- void *retval;
2261
+ static VALUE
2262
+ pg_rb_thread_io_wait(VALUE io, VALUE events, VALUE timeout) {
2263
+ rb_io_t *fptr;
2264
+ struct timeval ptimeout;
2265
+
2246
2266
  struct timeval aborttime={0,0}, currtime, waittime;
2247
2267
  DWORD timeout_milisec = INFINITE;
2248
- DWORD wait_ret;
2249
- WSAEVENT hEvent;
2250
-
2251
- if ( sd < 0 )
2252
- rb_raise(rb_eConnectionBad, "PQsocket() can't get socket descriptor");
2268
+ HANDLE hEvent = WSACreateEvent();
2253
2269
 
2254
- hEvent = WSACreateEvent();
2270
+ long rb_events = NUM2UINT(events);
2271
+ long w32_events = 0;
2272
+ DWORD wait_ret;
2255
2273
 
2256
- /* Check for connection errors (PQisBusy is true on connection errors) */
2257
- if( PQconsumeInput(conn) == 0 ) {
2258
- WSACloseEvent( hEvent );
2259
- rb_raise( rb_eConnectionBad, "PQconsumeInput() %s", PQerrorMessage(conn) );
2260
- }
2274
+ GetOpenFile((io), fptr);
2275
+ if( !NIL_P(timeout) ){
2276
+ ptimeout.tv_sec = (time_t)(NUM2DBL(timeout));
2277
+ ptimeout.tv_usec = (time_t)((NUM2DBL(timeout) - (double)ptimeout.tv_sec) * 1e6);
2261
2278
 
2262
- if ( ptimeout ) {
2263
2279
  gettimeofday(&currtime, NULL);
2264
- timeradd(&currtime, ptimeout, &aborttime);
2280
+ timeradd(&currtime, &ptimeout, &aborttime);
2265
2281
  }
2266
2282
 
2267
- while ( !(retval=is_readable(conn)) ) {
2268
- if ( WSAEventSelect(sd, hEvent, FD_READ|FD_CLOSE) == SOCKET_ERROR ) {
2283
+ if(rb_events & PG_RUBY_IO_READABLE) w32_events |= FD_READ | FD_ACCEPT | FD_CLOSE;
2284
+ if(rb_events & PG_RUBY_IO_WRITABLE) w32_events |= FD_WRITE | FD_CONNECT;
2285
+ if(rb_events & PG_RUBY_IO_PRIORITY) w32_events |= FD_OOB;
2286
+
2287
+ for(;;) {
2288
+ if ( WSAEventSelect(_get_osfhandle(fptr->fd), hEvent, w32_events) == SOCKET_ERROR ) {
2269
2289
  WSACloseEvent( hEvent );
2270
2290
  rb_raise( rb_eConnectionBad, "WSAEventSelect socket error: %d", WSAGetLastError() );
2271
2291
  }
2272
2292
 
2273
- if ( ptimeout ) {
2293
+ if ( !NIL_P(timeout) ) {
2274
2294
  gettimeofday(&currtime, NULL);
2275
2295
  timersub(&aborttime, &currtime, &waittime);
2276
2296
  timeout_milisec = (DWORD)( waittime.tv_sec * 1e3 + waittime.tv_usec / 1e3 );
2277
2297
  }
2278
2298
 
2279
- /* Is the given timeout valid? */
2280
- if( !ptimeout || (waittime.tv_sec >= 0 && waittime.tv_usec >= 0) ){
2299
+ if( NIL_P(timeout) || (waittime.tv_sec >= 0 && waittime.tv_usec >= 0) ){
2281
2300
  /* Wait for the socket to become readable before checking again */
2282
2301
  wait_ret = rb_w32_wait_events( &hEvent, 1, timeout_milisec );
2283
2302
  } else {
@@ -2286,9 +2305,11 @@ wait_socket_readable( PGconn *conn, struct timeval *ptimeout, void *(*is_readabl
2286
2305
 
2287
2306
  if ( wait_ret == WAIT_TIMEOUT ) {
2288
2307
  WSACloseEvent( hEvent );
2289
- return NULL;
2308
+ return UINT2NUM(0);
2290
2309
  } else if ( wait_ret == WAIT_OBJECT_0 ) {
2310
+ WSACloseEvent( hEvent );
2291
2311
  /* The event we were waiting for. */
2312
+ return UINT2NUM(rb_events);
2292
2313
  } else if ( wait_ret == WAIT_OBJECT_0 + 1) {
2293
2314
  /* This indicates interruption from timer thread, GC, exception
2294
2315
  * from other threads etc... */
@@ -2300,36 +2321,66 @@ wait_socket_readable( PGconn *conn, struct timeval *ptimeout, void *(*is_readabl
2300
2321
  WSACloseEvent( hEvent );
2301
2322
  rb_raise( rb_eConnectionBad, "Wait on socket abandoned (WaitForMultipleObjects)" );
2302
2323
  }
2303
-
2304
- /* Check for connection errors (PQisBusy is true on connection errors) */
2305
- if ( PQconsumeInput(conn) == 0 ) {
2306
- WSACloseEvent( hEvent );
2307
- rb_raise( rb_eConnectionBad, "PQconsumeInput() %s", PQerrorMessage(conn) );
2308
- }
2309
2324
  }
2325
+ }
2310
2326
 
2311
- WSACloseEvent( hEvent );
2312
- return retval;
2327
+ static VALUE
2328
+ pg_rb_io_wait(VALUE io, VALUE events, VALUE timeout) {
2329
+ #if defined(HAVE_RUBY_FIBER_SCHEDULER_H)
2330
+ /* We don't support Fiber.scheduler on Windows ruby-3.0 because there is no fast way to check whether a scheduler is active.
2331
+ * Fortunatelly ruby-3.1 offers a C-API for it.
2332
+ */
2333
+ VALUE scheduler = rb_fiber_scheduler_current();
2334
+
2335
+ if (!NIL_P(scheduler)) {
2336
+ return rb_io_wait(io, events, timeout);
2337
+ }
2338
+ #endif
2339
+ return pg_rb_thread_io_wait(io, events, timeout);
2313
2340
  }
2314
2341
 
2342
+ #elif defined(HAVE_RB_IO_WAIT)
2343
+
2344
+ /* Use our own function and constants names, to avoid conflicts with truffleruby-head on its road to ruby-3.0 compatibility. */
2345
+ #define pg_rb_io_wait rb_io_wait
2346
+ #define PG_RUBY_IO_READABLE RUBY_IO_READABLE
2347
+ #define PG_RUBY_IO_WRITABLE RUBY_IO_WRITABLE
2348
+ #define PG_RUBY_IO_PRIORITY RUBY_IO_PRIORITY
2349
+
2315
2350
  #else
2351
+ /* For compat with ruby < 3.0 */
2352
+
2353
+ typedef enum {
2354
+ PG_RUBY_IO_READABLE = RB_WAITFD_IN,
2355
+ PG_RUBY_IO_WRITABLE = RB_WAITFD_OUT,
2356
+ PG_RUBY_IO_PRIORITY = RB_WAITFD_PRI,
2357
+ } pg_rb_io_event_t;
2316
2358
 
2317
- /* non Win32 */
2359
+ static VALUE
2360
+ pg_rb_io_wait(VALUE io, VALUE events, VALUE timeout) {
2361
+ rb_io_t *fptr;
2362
+ struct timeval waittime;
2363
+ int res;
2364
+
2365
+ GetOpenFile((io), fptr);
2366
+ if( !NIL_P(timeout) ){
2367
+ waittime.tv_sec = (time_t)(NUM2DBL(timeout));
2368
+ waittime.tv_usec = (time_t)((NUM2DBL(timeout) - (double)waittime.tv_sec) * 1e6);
2369
+ }
2370
+ res = rb_wait_for_single_fd(fptr->fd, NUM2UINT(events), NIL_P(timeout) ? NULL : &waittime);
2371
+
2372
+ return UINT2NUM(res);
2373
+ }
2374
+ #endif
2318
2375
 
2319
2376
  static void *
2320
- wait_socket_readable( PGconn *conn, struct timeval *ptimeout, void *(*is_readable)(PGconn *))
2377
+ wait_socket_readable( VALUE self, struct timeval *ptimeout, void *(*is_readable)(PGconn *))
2321
2378
  {
2322
- int sd = PQsocket( conn );
2323
- int ret;
2379
+ VALUE ret;
2324
2380
  void *retval;
2325
2381
  struct timeval aborttime={0,0}, currtime, waittime;
2326
-
2327
- if ( sd < 0 )
2328
- rb_raise(rb_eConnectionBad, "PQsocket() can't get socket descriptor");
2329
-
2330
- /* Check for connection errors (PQisBusy is true on connection errors) */
2331
- if ( PQconsumeInput(conn) == 0 )
2332
- rb_raise( rb_eConnectionBad, "PQconsumeInput() %s", PQerrorMessage(conn) );
2382
+ VALUE wait_timeout = Qnil;
2383
+ PGconn *conn = pg_get_pgconn(self);
2333
2384
 
2334
2385
  if ( ptimeout ) {
2335
2386
  gettimeofday(&currtime, NULL);
@@ -2340,36 +2391,79 @@ wait_socket_readable( PGconn *conn, struct timeval *ptimeout, void *(*is_readabl
2340
2391
  if ( ptimeout ) {
2341
2392
  gettimeofday(&currtime, NULL);
2342
2393
  timersub(&aborttime, &currtime, &waittime);
2394
+ wait_timeout = DBL2NUM((double)(waittime.tv_sec) + (double)(waittime.tv_usec) / 1000000.0);
2343
2395
  }
2344
2396
 
2345
2397
  /* Is the given timeout valid? */
2346
2398
  if( !ptimeout || (waittime.tv_sec >= 0 && waittime.tv_usec >= 0) ){
2399
+ VALUE socket_io;
2400
+
2401
+ /* before we wait for data, make sure everything has been sent */
2402
+ pgconn_async_flush(self);
2403
+ if ((retval=is_readable(conn)))
2404
+ return retval;
2405
+
2406
+ socket_io = pgconn_socket_io(self);
2347
2407
  /* Wait for the socket to become readable before checking again */
2348
- ret = rb_wait_for_single_fd( sd, RB_WAITFD_IN, ptimeout ? &waittime : NULL );
2408
+ ret = pg_rb_io_wait(socket_io, RB_INT2NUM(PG_RUBY_IO_READABLE), wait_timeout);
2349
2409
  } else {
2350
- ret = 0;
2351
- }
2352
-
2353
- if ( ret < 0 ){
2354
- rb_sys_fail( "rb_wait_for_single_fd()" );
2410
+ ret = Qfalse;
2355
2411
  }
2356
2412
 
2357
2413
  /* Return false if the select() timed out */
2358
- if ( ret == 0 ){
2414
+ if ( ret == Qfalse ){
2359
2415
  return NULL;
2360
2416
  }
2361
2417
 
2362
2418
  /* Check for connection errors (PQisBusy is true on connection errors) */
2363
2419
  if ( PQconsumeInput(conn) == 0 ){
2364
- rb_raise( rb_eConnectionBad, "PQconsumeInput() %s", PQerrorMessage(conn) );
2420
+ pgconn_close_socket_io(self);
2421
+ pg_raise_conn_error(rb_eConnectionBad, self, "PQconsumeInput() %s", PQerrorMessage(conn));
2365
2422
  }
2366
2423
  }
2367
2424
 
2368
2425
  return retval;
2369
2426
  }
2370
2427
 
2428
+ /*
2429
+ * call-seq:
2430
+ * conn.flush() -> Boolean
2431
+ *
2432
+ * Attempts to flush any queued output data to the server.
2433
+ * Returns +true+ if data is successfully flushed, +false+
2434
+ * if not. It can only return +false+ if connection is
2435
+ * in nonblocking mode.
2436
+ * Raises PG::Error if some other failure occurred.
2437
+ */
2438
+ static VALUE
2439
+ pgconn_async_flush(VALUE self)
2440
+ {
2441
+ while( pgconn_sync_flush(self) == Qfalse ){
2442
+ /* wait for the socket to become read- or write-ready */
2443
+ int events;
2444
+ VALUE socket_io = pgconn_socket_io(self);
2445
+ events = RB_NUM2INT(pg_rb_io_wait(socket_io, RB_INT2NUM(PG_RUBY_IO_READABLE | PG_RUBY_IO_WRITABLE), Qnil));
2446
+
2447
+ if (events & PG_RUBY_IO_READABLE)
2448
+ pgconn_consume_input(self);
2449
+ }
2450
+ return Qtrue;
2451
+ }
2452
+
2453
+ static VALUE
2454
+ pgconn_wait_for_flush( VALUE self ){
2455
+ if( !pg_get_connection_safe(self)->flush_data )
2456
+ return Qnil;
2371
2457
 
2372
- #endif
2458
+ return pgconn_async_flush(self);
2459
+ }
2460
+
2461
+ static VALUE
2462
+ pgconn_flush_data_set( VALUE self, VALUE enabled ){
2463
+ t_pg_connection *conn = pg_get_connection(self);
2464
+ conn->flush_data = RTEST(enabled);
2465
+ return enabled;
2466
+ }
2373
2467
 
2374
2468
  static void *
2375
2469
  notify_readable(PGconn *conn)
@@ -2408,7 +2502,7 @@ pgconn_wait_for_notify(int argc, VALUE *argv, VALUE self)
2408
2502
  ptimeout = &timeout;
2409
2503
  }
2410
2504
 
2411
- pnotification = (PGnotify*) wait_socket_readable( this->pgconn, ptimeout, notify_readable);
2505
+ pnotification = (PGnotify*) wait_socket_readable( self, ptimeout, notify_readable);
2412
2506
 
2413
2507
  /* Return nil if the select timed out */
2414
2508
  if ( !pnotification ) return Qnil;
@@ -2429,28 +2523,8 @@ pgconn_wait_for_notify(int argc, VALUE *argv, VALUE self)
2429
2523
  }
2430
2524
 
2431
2525
 
2432
- /*
2433
- * call-seq:
2434
- * conn.put_copy_data( buffer [, encoder] ) -> Boolean
2435
- *
2436
- * Transmits _buffer_ as copy data to the server.
2437
- * Returns true if the data was sent, false if it was
2438
- * not sent (false is only possible if the connection
2439
- * is in nonblocking mode, and this command would block).
2440
- *
2441
- * _encoder_ can be a PG::Coder derivation (typically PG::TextEncoder::CopyRow).
2442
- * This encodes the data fields given as _buffer_ from an Array of Strings to
2443
- * PostgreSQL's COPY text format inclusive proper escaping. Optionally
2444
- * the encoder can type cast the fields from various Ruby types in one step,
2445
- * if PG::TextEncoder::CopyRow#type_map is set accordingly.
2446
- *
2447
- * Raises an exception if an error occurs.
2448
- *
2449
- * See also #copy_data.
2450
- *
2451
- */
2452
2526
  static VALUE
2453
- pgconn_put_copy_data(int argc, VALUE *argv, VALUE self)
2527
+ pgconn_sync_put_copy_data(int argc, VALUE *argv, VALUE self)
2454
2528
  {
2455
2529
  int ret;
2456
2530
  int len;
@@ -2467,13 +2541,11 @@ pgconn_put_copy_data(int argc, VALUE *argv, VALUE self)
2467
2541
  if( NIL_P(this->encoder_for_put_copy_data) ){
2468
2542
  buffer = value;
2469
2543
  } else {
2470
- p_coder = DATA_PTR( this->encoder_for_put_copy_data );
2544
+ p_coder = RTYPEDDATA_DATA( this->encoder_for_put_copy_data );
2471
2545
  }
2472
- } else if( rb_obj_is_kind_of(encoder, rb_cPG_Coder) ) {
2473
- Data_Get_Struct( encoder, t_pg_coder, p_coder );
2474
2546
  } else {
2475
- rb_raise( rb_eTypeError, "wrong encoder type %s (expected some kind of PG::Coder)",
2476
- rb_obj_classname( encoder ) );
2547
+ /* Check argument type and use argument encoder */
2548
+ TypedData_Get_Struct(encoder, t_pg_coder, &pg_coder_type, p_coder);
2477
2549
  }
2478
2550
 
2479
2551
  if( p_coder ){
@@ -2496,36 +2568,19 @@ pgconn_put_copy_data(int argc, VALUE *argv, VALUE self)
2496
2568
  Check_Type(buffer, T_STRING);
2497
2569
 
2498
2570
  ret = gvl_PQputCopyData(this->pgconn, RSTRING_PTR(buffer), RSTRING_LENINT(buffer));
2499
- if(ret == -1) {
2500
- VALUE error = rb_exc_new2(rb_ePGerror, PQerrorMessage(this->pgconn));
2501
- rb_iv_set(error, "@connection", self);
2502
- rb_exc_raise(error);
2503
- }
2571
+ if(ret == -1)
2572
+ pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(this->pgconn));
2573
+
2504
2574
  RB_GC_GUARD(intermediate);
2505
2575
  RB_GC_GUARD(buffer);
2506
2576
 
2507
2577
  return (ret) ? Qtrue : Qfalse;
2508
2578
  }
2509
2579
 
2510
- /*
2511
- * call-seq:
2512
- * conn.put_copy_end( [ error_message ] ) -> Boolean
2513
- *
2514
- * Sends end-of-data indication to the server.
2515
- *
2516
- * _error_message_ is an optional parameter, and if set,
2517
- * forces the COPY command to fail with the string
2518
- * _error_message_.
2519
- *
2520
- * Returns true if the end-of-data was sent, false if it was
2521
- * not sent (false is only possible if the connection
2522
- * is in nonblocking mode, and this command would block).
2523
- */
2524
2580
  static VALUE
2525
- pgconn_put_copy_end(int argc, VALUE *argv, VALUE self)
2581
+ pgconn_sync_put_copy_end(int argc, VALUE *argv, VALUE self)
2526
2582
  {
2527
2583
  VALUE str;
2528
- VALUE error;
2529
2584
  int ret;
2530
2585
  const char *error_message = NULL;
2531
2586
  t_pg_connection *this = pg_get_connection_safe( self );
@@ -2536,38 +2591,16 @@ pgconn_put_copy_end(int argc, VALUE *argv, VALUE self)
2536
2591
  error_message = pg_cstr_enc(str, this->enc_idx);
2537
2592
 
2538
2593
  ret = gvl_PQputCopyEnd(this->pgconn, error_message);
2539
- if(ret == -1) {
2540
- error = rb_exc_new2(rb_ePGerror, PQerrorMessage(this->pgconn));
2541
- rb_iv_set(error, "@connection", self);
2542
- rb_exc_raise(error);
2543
- }
2594
+ if(ret == -1)
2595
+ pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(this->pgconn));
2596
+
2544
2597
  return (ret) ? Qtrue : Qfalse;
2545
2598
  }
2546
2599
 
2547
- /*
2548
- * call-seq:
2549
- * conn.get_copy_data( [ async = false [, decoder = nil ]] ) -> Object
2550
- *
2551
- * Return one row of data, +nil+
2552
- * if the copy is done, or +false+ if the call would
2553
- * block (only possible if _async_ is true).
2554
- *
2555
- * If _decoder_ is not set or +nil+, data is returned as binary string.
2556
- *
2557
- * If _decoder_ is set to a PG::Coder derivation, the return type depends on this decoder.
2558
- * PG::TextDecoder::CopyRow decodes the received data fields from one row of PostgreSQL's
2559
- * COPY text format to an Array of Strings.
2560
- * Optionally the decoder can type cast the single fields to various Ruby types in one step,
2561
- * if PG::TextDecoder::CopyRow#type_map is set accordingly.
2562
- *
2563
- * See also #copy_data.
2564
- *
2565
- */
2566
2600
  static VALUE
2567
- pgconn_get_copy_data(int argc, VALUE *argv, VALUE self )
2601
+ pgconn_sync_get_copy_data(int argc, VALUE *argv, VALUE self )
2568
2602
  {
2569
2603
  VALUE async_in;
2570
- VALUE error;
2571
2604
  VALUE result;
2572
2605
  int ret;
2573
2606
  char *buffer;
@@ -2579,20 +2612,16 @@ pgconn_get_copy_data(int argc, VALUE *argv, VALUE self )
2579
2612
 
2580
2613
  if( NIL_P(decoder) ){
2581
2614
  if( !NIL_P(this->decoder_for_get_copy_data) ){
2582
- p_coder = DATA_PTR( this->decoder_for_get_copy_data );
2615
+ p_coder = RTYPEDDATA_DATA( this->decoder_for_get_copy_data );
2583
2616
  }
2584
- } else if( rb_obj_is_kind_of(decoder, rb_cPG_Coder) ) {
2585
- Data_Get_Struct( decoder, t_pg_coder, p_coder );
2586
2617
  } else {
2587
- rb_raise( rb_eTypeError, "wrong decoder type %s (expected some kind of PG::Coder)",
2588
- rb_obj_classname( decoder ) );
2618
+ /* Check argument type and use argument decoder */
2619
+ TypedData_Get_Struct(decoder, t_pg_coder, &pg_coder_type, p_coder);
2589
2620
  }
2590
2621
 
2591
2622
  ret = gvl_PQgetCopyData(this->pgconn, &buffer, RTEST(async_in));
2592
- if(ret == -2) { /* error */
2593
- error = rb_exc_new2(rb_ePGerror, PQerrorMessage(this->pgconn));
2594
- rb_iv_set(error, "@connection", self);
2595
- rb_exc_raise(error);
2623
+ if(ret == -2){ /* error */
2624
+ pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(this->pgconn));
2596
2625
  }
2597
2626
  if(ret == -1) { /* No data left */
2598
2627
  return Qnil;
@@ -2830,7 +2859,7 @@ notice_processor_proxy(void *arg, const char *message)
2830
2859
  * call-seq:
2831
2860
  * conn.set_notice_processor {|message| ... } -> Proc
2832
2861
  *
2833
- * See #set_notice_receiver for the desription of what this and the
2862
+ * See #set_notice_receiver for the description of what this and the
2834
2863
  * notice_processor methods do.
2835
2864
  *
2836
2865
  * This function takes a new block to act as the notice processor and returns
@@ -2884,68 +2913,27 @@ pgconn_get_client_encoding(VALUE self)
2884
2913
 
2885
2914
  /*
2886
2915
  * call-seq:
2887
- * conn.set_client_encoding( encoding )
2916
+ * conn.sync_set_client_encoding( encoding )
2888
2917
  *
2889
- * Sets the client encoding to the _encoding_ String.
2918
+ * This function has the same behavior as #async_set_client_encoding, but is implemented using the synchronous command processing API of libpq.
2919
+ * See #async_exec for the differences between the two API variants.
2920
+ * It's not recommended to use explicit sync or async variants but #set_client_encoding instead, unless you have a good reason to do so.
2890
2921
  */
2891
2922
  static VALUE
2892
- pgconn_set_client_encoding(VALUE self, VALUE str)
2923
+ pgconn_sync_set_client_encoding(VALUE self, VALUE str)
2893
2924
  {
2894
2925
  PGconn *conn = pg_get_pgconn( self );
2895
2926
 
2896
2927
  Check_Type(str, T_STRING);
2897
2928
 
2898
- if ( (gvl_PQsetClientEncoding(conn, StringValueCStr(str))) == -1 ) {
2899
- rb_raise(rb_ePGerror, "%s", PQerrorMessage(conn));
2900
- }
2929
+ if ( (gvl_PQsetClientEncoding(conn, StringValueCStr(str))) == -1 )
2930
+ pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(conn));
2931
+
2901
2932
  pgconn_set_internal_encoding_index( self );
2902
2933
 
2903
2934
  return Qnil;
2904
2935
  }
2905
2936
 
2906
- /*
2907
- * call-seq:
2908
- * conn.transaction { |conn| ... } -> result of the block
2909
- *
2910
- * Executes a +BEGIN+ at the start of the block,
2911
- * and a +COMMIT+ at the end of the block, or
2912
- * +ROLLBACK+ if any exception occurs.
2913
- */
2914
- static VALUE
2915
- pgconn_transaction(VALUE self)
2916
- {
2917
- PGconn *conn = pg_get_pgconn(self);
2918
- PGresult *result;
2919
- VALUE rb_pgresult;
2920
- VALUE block_result = Qnil;
2921
- int status;
2922
-
2923
- if (rb_block_given_p()) {
2924
- result = gvl_PQexec(conn, "BEGIN");
2925
- rb_pgresult = pg_new_result(result, self);
2926
- pg_result_check(rb_pgresult);
2927
- block_result = rb_protect(rb_yield, self, &status);
2928
- if(status == 0) {
2929
- result = gvl_PQexec(conn, "COMMIT");
2930
- rb_pgresult = pg_new_result(result, self);
2931
- pg_result_check(rb_pgresult);
2932
- }
2933
- else {
2934
- /* exception occurred, ROLLBACK and re-raise */
2935
- result = gvl_PQexec(conn, "ROLLBACK");
2936
- rb_pgresult = pg_new_result(result, self);
2937
- pg_result_check(rb_pgresult);
2938
- rb_jump_tag(status);
2939
- }
2940
-
2941
- }
2942
- else {
2943
- /* no block supplied? */
2944
- rb_raise(rb_eArgError, "Must supply block for PG::Connection#transaction");
2945
- }
2946
- return block_result;
2947
- }
2948
-
2949
2937
 
2950
2938
  /*
2951
2939
  * call-seq:
@@ -3020,10 +3008,8 @@ get_result_readable(PGconn *conn)
3020
3008
  * If +true+ is returned, +conn.is_busy+ will return +false+
3021
3009
  * and +conn.get_result+ will not block.
3022
3010
  */
3023
- static VALUE
3011
+ VALUE
3024
3012
  pgconn_block( int argc, VALUE *argv, VALUE self ) {
3025
- PGconn *conn = pg_get_pgconn( self );
3026
-
3027
3013
  struct timeval timeout;
3028
3014
  struct timeval *ptimeout = NULL;
3029
3015
  VALUE timeout_in;
@@ -3037,7 +3023,7 @@ pgconn_block( int argc, VALUE *argv, VALUE self ) {
3037
3023
  ptimeout = &timeout;
3038
3024
  }
3039
3025
 
3040
- ret = wait_socket_readable( conn, ptimeout, get_result_readable);
3026
+ ret = wait_socket_readable( self, ptimeout, get_result_readable);
3041
3027
 
3042
3028
  if( !ret )
3043
3029
  return Qfalse;
@@ -3046,6 +3032,42 @@ pgconn_block( int argc, VALUE *argv, VALUE self ) {
3046
3032
  }
3047
3033
 
3048
3034
 
3035
+ /*
3036
+ * call-seq:
3037
+ * conn.sync_get_last_result( ) -> PG::Result
3038
+ *
3039
+ * This function has the same behavior as #async_get_last_result, but is implemented using the synchronous command processing API of libpq.
3040
+ * See #async_exec for the differences between the two API variants.
3041
+ * It's not recommended to use explicit sync or async variants but #get_last_result instead, unless you have a good reason to do so.
3042
+ */
3043
+ static VALUE
3044
+ pgconn_sync_get_last_result(VALUE self)
3045
+ {
3046
+ PGconn *conn = pg_get_pgconn(self);
3047
+ VALUE rb_pgresult = Qnil;
3048
+ PGresult *cur, *prev;
3049
+
3050
+
3051
+ cur = prev = NULL;
3052
+ while ((cur = gvl_PQgetResult(conn)) != NULL) {
3053
+ int status;
3054
+
3055
+ if (prev) PQclear(prev);
3056
+ prev = cur;
3057
+
3058
+ status = PQresultStatus(cur);
3059
+ if (status == PGRES_COPY_OUT || status == PGRES_COPY_IN || status == PGRES_COPY_BOTH)
3060
+ break;
3061
+ }
3062
+
3063
+ if (prev) {
3064
+ rb_pgresult = pg_new_result( prev, self );
3065
+ pg_result_check(rb_pgresult);
3066
+ }
3067
+
3068
+ return rb_pgresult;
3069
+ }
3070
+
3049
3071
  /*
3050
3072
  * call-seq:
3051
3073
  * conn.get_last_result( ) -> PG::Result
@@ -3056,27 +3078,36 @@ pgconn_block( int argc, VALUE *argv, VALUE self ) {
3056
3078
  * returns the last non-NULL result, or +nil+ if no
3057
3079
  * results are available.
3058
3080
  *
3081
+ * If the last result contains a bad result_status, an
3082
+ * appropriate exception is raised.
3083
+ *
3059
3084
  * This function is similar to #get_result
3060
3085
  * except that it is designed to get one and only
3061
- * one result.
3086
+ * one result and that it checks the result state.
3062
3087
  */
3063
3088
  static VALUE
3064
- pgconn_get_last_result(VALUE self)
3089
+ pgconn_async_get_last_result(VALUE self)
3065
3090
  {
3066
3091
  PGconn *conn = pg_get_pgconn(self);
3067
3092
  VALUE rb_pgresult = Qnil;
3068
3093
  PGresult *cur, *prev;
3069
3094
 
3070
-
3071
- cur = prev = NULL;
3072
- while ((cur = gvl_PQgetResult(conn)) != NULL) {
3095
+ cur = prev = NULL;
3096
+ for(;;) {
3073
3097
  int status;
3074
3098
 
3099
+ /* wait for input (without blocking) before reading each result */
3100
+ wait_socket_readable(self, NULL, get_result_readable);
3101
+
3102
+ cur = gvl_PQgetResult(conn);
3103
+ if (cur == NULL)
3104
+ break;
3105
+
3075
3106
  if (prev) PQclear(prev);
3076
3107
  prev = cur;
3077
3108
 
3078
3109
  status = PQresultStatus(cur);
3079
- if (status == PGRES_COPY_OUT || status == PGRES_COPY_IN)
3110
+ if (status == PGRES_COPY_OUT || status == PGRES_COPY_IN || status == PGRES_COPY_BOTH)
3080
3111
  break;
3081
3112
  }
3082
3113
 
@@ -3100,22 +3131,60 @@ static VALUE
3100
3131
  pgconn_discard_results(VALUE self)
3101
3132
  {
3102
3133
  PGconn *conn = pg_get_pgconn(self);
3134
+ VALUE socket_io;
3103
3135
 
3104
- PGresult *cur;
3105
- while ((cur = gvl_PQgetResult(conn)) != NULL) {
3106
- int status = PQresultStatus(cur);
3136
+ if( PQtransactionStatus(conn) == PQTRANS_IDLE ) {
3137
+ return Qnil;
3138
+ }
3139
+
3140
+ socket_io = pgconn_socket_io(self);
3141
+
3142
+ for(;;) {
3143
+ PGresult *cur;
3144
+ int status;
3145
+
3146
+ /* pgconn_block() raises an exception in case of errors.
3147
+ * To avoid this call pg_rb_io_wait() and PQconsumeInput() without rb_raise().
3148
+ */
3149
+ while( gvl_PQisBusy(conn) ){
3150
+ pg_rb_io_wait(socket_io, RB_INT2NUM(PG_RUBY_IO_READABLE), Qnil);
3151
+ if ( PQconsumeInput(conn) == 0 ) {
3152
+ pgconn_close_socket_io(self);
3153
+ return Qfalse;
3154
+ }
3155
+ }
3156
+
3157
+ cur = gvl_PQgetResult(conn);
3158
+ if( cur == NULL) break;
3159
+
3160
+ status = PQresultStatus(cur);
3107
3161
  PQclear(cur);
3108
3162
  if (status == PGRES_COPY_IN){
3109
3163
  gvl_PQputCopyEnd(conn, "COPY terminated by new PQexec");
3110
3164
  }
3111
3165
  if (status == PGRES_COPY_OUT){
3112
- char *buffer = NULL;
3113
- while( gvl_PQgetCopyData(conn, &buffer, 0) > 0)
3114
- PQfreemem(buffer);
3166
+ for(;;) {
3167
+ char *buffer = NULL;
3168
+ int st = gvl_PQgetCopyData(conn, &buffer, 1);
3169
+ if( st == 0 ) {
3170
+ /* would block -> wait for readable data */
3171
+ pg_rb_io_wait(socket_io, RB_INT2NUM(PG_RUBY_IO_READABLE), Qnil);
3172
+ if ( PQconsumeInput(conn) == 0 ) {
3173
+ pgconn_close_socket_io(self);
3174
+ return Qfalse;
3175
+ }
3176
+ } else if( st > 0 ) {
3177
+ /* some data retrieved -> discard it */
3178
+ PQfreemem(buffer);
3179
+ } else {
3180
+ /* no more data */
3181
+ break;
3182
+ }
3183
+ }
3115
3184
  }
3116
3185
  }
3117
3186
 
3118
- return Qnil;
3187
+ return Qtrue;
3119
3188
  }
3120
3189
 
3121
3190
  /*
@@ -3138,6 +3207,7 @@ pgconn_discard_results(VALUE self)
3138
3207
  * #exec is an alias for #async_exec which is almost identical to #sync_exec .
3139
3208
  * #sync_exec is implemented on the simpler synchronous command processing API of libpq, whereas
3140
3209
  * #async_exec is implemented on the asynchronous API and on ruby's IO mechanisms.
3210
+ * Only #async_exec is compatible to <tt>Fiber.scheduler</tt> based asynchronous IO processing introduced in ruby-3.0.
3141
3211
  * Both methods ensure that other threads can process while waiting for the server to
3142
3212
  * complete the request, but #sync_exec blocks all signals to be processed until the query is finished.
3143
3213
  * This is most notably visible by a delayed reaction to Control+C.
@@ -3152,8 +3222,7 @@ pgconn_async_exec(int argc, VALUE *argv, VALUE self)
3152
3222
 
3153
3223
  pgconn_discard_results( self );
3154
3224
  pgconn_send_query( argc, argv, self );
3155
- pgconn_block( 0, NULL, self ); /* wait for input (without blocking) before reading the last result */
3156
- rb_pgresult = pgconn_get_last_result( self );
3225
+ rb_pgresult = pgconn_async_get_last_result( self );
3157
3226
 
3158
3227
  if ( rb_block_given_p() ) {
3159
3228
  return rb_ensure( rb_yield, rb_pgresult, pg_result_clear, rb_pgresult );
@@ -3182,7 +3251,7 @@ pgconn_async_exec(int argc, VALUE *argv, VALUE self)
3182
3251
  * or, it may be a String. If it is a string, that is equivalent to the hash:
3183
3252
  * { :value => <string value>, :type => 0, :format => 0 }
3184
3253
  *
3185
- * PostgreSQL bind parameters are represented as $1, $1, $2, etc.,
3254
+ * PostgreSQL bind parameters are represented as $1, $2, $3, etc.,
3186
3255
  * inside the SQL query. The 0th element of the +params+ array is bound
3187
3256
  * to $1, the 1st element is bound to $2, etc. +nil+ is treated as +NULL+.
3188
3257
  *
@@ -3225,8 +3294,7 @@ pgconn_async_exec_params(int argc, VALUE *argv, VALUE self)
3225
3294
  } else {
3226
3295
  pgconn_send_query_params( argc, argv, self );
3227
3296
  }
3228
- pgconn_block( 0, NULL, self ); /* wait for input (without blocking) before reading the last result */
3229
- rb_pgresult = pgconn_get_last_result( self );
3297
+ rb_pgresult = pgconn_async_get_last_result( self );
3230
3298
 
3231
3299
  if ( rb_block_given_p() ) {
3232
3300
  return rb_ensure( rb_yield, rb_pgresult, pg_result_clear, rb_pgresult );
@@ -3252,7 +3320,7 @@ pgconn_async_exec_params(int argc, VALUE *argv, VALUE self)
3252
3320
  *
3253
3321
  * For example: "SELECT $1::int"
3254
3322
  *
3255
- * PostgreSQL bind parameters are represented as $1, $1, $2, etc.,
3323
+ * PostgreSQL bind parameters are represented as $1, $2, $3, etc.,
3256
3324
  * inside the SQL query.
3257
3325
  *
3258
3326
  * See also corresponding {libpq function}[https://www.postgresql.org/docs/current/libpq-exec.html#LIBPQ-PQPREPARE].
@@ -3264,8 +3332,7 @@ pgconn_async_prepare(int argc, VALUE *argv, VALUE self)
3264
3332
 
3265
3333
  pgconn_discard_results( self );
3266
3334
  pgconn_send_prepare( argc, argv, self );
3267
- pgconn_block( 0, NULL, self ); /* wait for input (without blocking) before reading the last result */
3268
- rb_pgresult = pgconn_get_last_result( self );
3335
+ rb_pgresult = pgconn_async_get_last_result( self );
3269
3336
 
3270
3337
  if ( rb_block_given_p() ) {
3271
3338
  return rb_ensure( rb_yield, rb_pgresult, pg_result_clear, rb_pgresult );
@@ -3292,7 +3359,7 @@ pgconn_async_prepare(int argc, VALUE *argv, VALUE self)
3292
3359
  * or, it may be a String. If it is a string, that is equivalent to the hash:
3293
3360
  * { :value => <string value>, :format => 0 }
3294
3361
  *
3295
- * PostgreSQL bind parameters are represented as $1, $1, $2, etc.,
3362
+ * PostgreSQL bind parameters are represented as $1, $2, $3, etc.,
3296
3363
  * inside the SQL query. The 0th element of the +params+ array is bound
3297
3364
  * to $1, the 1st element is bound to $2, etc. +nil+ is treated as +NULL+.
3298
3365
  *
@@ -3318,8 +3385,7 @@ pgconn_async_exec_prepared(int argc, VALUE *argv, VALUE self)
3318
3385
 
3319
3386
  pgconn_discard_results( self );
3320
3387
  pgconn_send_query_prepared( argc, argv, self );
3321
- pgconn_block( 0, NULL, self ); /* wait for input (without blocking) before reading the last result */
3322
- rb_pgresult = pgconn_get_last_result( self );
3388
+ rb_pgresult = pgconn_async_get_last_result( self );
3323
3389
 
3324
3390
  if ( rb_block_given_p() ) {
3325
3391
  return rb_ensure( rb_yield, rb_pgresult, pg_result_clear, rb_pgresult );
@@ -3343,8 +3409,7 @@ pgconn_async_describe_portal(VALUE self, VALUE portal)
3343
3409
 
3344
3410
  pgconn_discard_results( self );
3345
3411
  pgconn_send_describe_portal( self, portal );
3346
- pgconn_block( 0, NULL, self ); /* wait for input (without blocking) before reading the last result */
3347
- rb_pgresult = pgconn_get_last_result( self );
3412
+ rb_pgresult = pgconn_async_get_last_result( self );
3348
3413
 
3349
3414
  if ( rb_block_given_p() ) {
3350
3415
  return rb_ensure( rb_yield, rb_pgresult, pg_result_clear, rb_pgresult );
@@ -3368,8 +3433,7 @@ pgconn_async_describe_prepared(VALUE self, VALUE stmt_name)
3368
3433
 
3369
3434
  pgconn_discard_results( self );
3370
3435
  pgconn_send_describe_prepared( self, stmt_name );
3371
- pgconn_block( 0, NULL, self ); /* wait for input (without blocking) before reading the last result */
3372
- rb_pgresult = pgconn_get_last_result( self );
3436
+ rb_pgresult = pgconn_async_get_last_result( self );
3373
3437
 
3374
3438
  if ( rb_block_given_p() ) {
3375
3439
  return rb_ensure( rb_yield, rb_pgresult, pg_result_clear, rb_pgresult );
@@ -3457,6 +3521,122 @@ pgconn_ssl_attribute_names(VALUE self)
3457
3521
  #endif
3458
3522
 
3459
3523
 
3524
+ #ifdef HAVE_PQENTERPIPELINEMODE
3525
+ /*
3526
+ * call-seq:
3527
+ * conn.pipeline_status -> Integer
3528
+ *
3529
+ * Returns the current pipeline mode status of the libpq connection.
3530
+ *
3531
+ * PQpipelineStatus can return one of the following values:
3532
+ *
3533
+ * * PQ_PIPELINE_ON - The libpq connection is in pipeline mode.
3534
+ * * PQ_PIPELINE_OFF - The libpq connection is not in pipeline mode.
3535
+ * * PQ_PIPELINE_ABORTED - The libpq connection is in pipeline mode and an error occurred while processing the current pipeline.
3536
+ * The aborted flag is cleared when PQgetResult returns a result of type PGRES_PIPELINE_SYNC.
3537
+ *
3538
+ * Available since PostgreSQL-14
3539
+ */
3540
+ static VALUE
3541
+ pgconn_pipeline_status(VALUE self)
3542
+ {
3543
+ int res = PQpipelineStatus(pg_get_pgconn(self));
3544
+ return INT2FIX(res);
3545
+ }
3546
+
3547
+
3548
+ /*
3549
+ * call-seq:
3550
+ * conn.enter_pipeline_mode -> nil
3551
+ *
3552
+ * Causes a connection to enter pipeline mode if it is currently idle or already in pipeline mode.
3553
+ *
3554
+ * Raises PG::Error and has no effect if the connection is not currently idle, i.e., it has a result ready, or it is waiting for more input from the server, etc.
3555
+ * This function does not actually send anything to the server, it just changes the libpq connection state.
3556
+ *
3557
+ * Available since PostgreSQL-14
3558
+ */
3559
+ static VALUE
3560
+ pgconn_enter_pipeline_mode(VALUE self)
3561
+ {
3562
+ PGconn *conn = pg_get_pgconn(self);
3563
+ int res = PQenterPipelineMode(conn);
3564
+ if( res != 1 )
3565
+ pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(conn));
3566
+
3567
+ return Qnil;
3568
+ }
3569
+
3570
+ /*
3571
+ * call-seq:
3572
+ * conn.exit_pipeline_mode -> nil
3573
+ *
3574
+ * Causes a connection to exit pipeline mode if it is currently in pipeline mode with an empty queue and no pending results.
3575
+ *
3576
+ * Takes no action if not in pipeline mode.
3577
+ * Raises PG::Error if the current statement isn't finished processing, or PQgetResult has not been called to collect results from all previously sent query.
3578
+ *
3579
+ * Available since PostgreSQL-14
3580
+ */
3581
+ static VALUE
3582
+ pgconn_exit_pipeline_mode(VALUE self)
3583
+ {
3584
+ PGconn *conn = pg_get_pgconn(self);
3585
+ int res = PQexitPipelineMode(conn);
3586
+ if( res != 1 )
3587
+ pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(conn));
3588
+
3589
+ return Qnil;
3590
+ }
3591
+
3592
+
3593
+ /*
3594
+ * call-seq:
3595
+ * conn.pipeline_sync -> nil
3596
+ *
3597
+ * Marks a synchronization point in a pipeline by sending a sync message and flushing the send buffer.
3598
+ * This serves as the delimiter of an implicit transaction and an error recovery point; see Section 34.5.1.3 of the PostgreSQL documentation.
3599
+ *
3600
+ * Raises PG::Error if the connection is not in pipeline mode or sending a sync message failed.
3601
+ *
3602
+ * Available since PostgreSQL-14
3603
+ */
3604
+ static VALUE
3605
+ pgconn_pipeline_sync(VALUE self)
3606
+ {
3607
+ PGconn *conn = pg_get_pgconn(self);
3608
+ int res = PQpipelineSync(conn);
3609
+ if( res != 1 )
3610
+ pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(conn));
3611
+
3612
+ return Qnil;
3613
+ }
3614
+
3615
+ /*
3616
+ * call-seq:
3617
+ * conn.pipeline_sync -> nil
3618
+ *
3619
+ * Sends a request for the server to flush its output buffer.
3620
+ *
3621
+ * The server flushes its output buffer automatically as a result of Connection#pipeline_sync being called, or on any request when not in pipeline mode.
3622
+ * This function is useful to cause the server to flush its output buffer in pipeline mode without establishing a synchronization point.
3623
+ * Note that the request is not itself flushed to the server automatically; use Connection#flush if necessary.
3624
+ *
3625
+ * Available since PostgreSQL-14
3626
+ */
3627
+ static VALUE
3628
+ pgconn_send_flush_request(VALUE self)
3629
+ {
3630
+ PGconn *conn = pg_get_pgconn(self);
3631
+ int res = PQsendFlushRequest(conn);
3632
+ if( res != 1 )
3633
+ pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(conn));
3634
+
3635
+ return Qnil;
3636
+ }
3637
+
3638
+ #endif
3639
+
3460
3640
  /**************************************************************************
3461
3641
  * LARGE OBJECT SUPPORT
3462
3642
  **************************************************************************/
@@ -3483,7 +3663,7 @@ pgconn_locreat(int argc, VALUE *argv, VALUE self)
3483
3663
 
3484
3664
  lo_oid = lo_creat(conn, mode);
3485
3665
  if (lo_oid == 0)
3486
- rb_raise(rb_ePGerror, "lo_creat failed");
3666
+ pg_raise_conn_error( rb_ePGerror, self, "lo_creat failed");
3487
3667
 
3488
3668
  return UINT2NUM(lo_oid);
3489
3669
  }
@@ -3504,7 +3684,7 @@ pgconn_locreate(VALUE self, VALUE in_lo_oid)
3504
3684
 
3505
3685
  ret = lo_create(conn, lo_oid);
3506
3686
  if (ret == InvalidOid)
3507
- rb_raise(rb_ePGerror, "lo_create failed");
3687
+ pg_raise_conn_error( rb_ePGerror, self, "lo_create failed");
3508
3688
 
3509
3689
  return UINT2NUM(ret);
3510
3690
  }
@@ -3528,7 +3708,7 @@ pgconn_loimport(VALUE self, VALUE filename)
3528
3708
 
3529
3709
  lo_oid = lo_import(conn, StringValueCStr(filename));
3530
3710
  if (lo_oid == 0) {
3531
- rb_raise(rb_ePGerror, "%s", PQerrorMessage(conn));
3711
+ pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(conn));
3532
3712
  }
3533
3713
  return UINT2NUM(lo_oid);
3534
3714
  }
@@ -3549,7 +3729,7 @@ pgconn_loexport(VALUE self, VALUE lo_oid, VALUE filename)
3549
3729
  oid = NUM2UINT(lo_oid);
3550
3730
 
3551
3731
  if (lo_export(conn, oid, StringValueCStr(filename)) < 0) {
3552
- rb_raise(rb_ePGerror, "%s", PQerrorMessage(conn));
3732
+ pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(conn));
3553
3733
  }
3554
3734
  return Qnil;
3555
3735
  }
@@ -3580,7 +3760,7 @@ pgconn_loopen(int argc, VALUE *argv, VALUE self)
3580
3760
  mode = NUM2INT(nmode);
3581
3761
 
3582
3762
  if((fd = lo_open(conn, lo_oid, mode)) < 0) {
3583
- rb_raise(rb_ePGerror, "can't open large object: %s", PQerrorMessage(conn));
3763
+ pg_raise_conn_error( rb_ePGerror, self, "can't open large object: %s", PQerrorMessage(conn));
3584
3764
  }
3585
3765
  return INT2FIX(fd);
3586
3766
  }
@@ -3602,11 +3782,11 @@ pgconn_lowrite(VALUE self, VALUE in_lo_desc, VALUE buffer)
3602
3782
  Check_Type(buffer, T_STRING);
3603
3783
 
3604
3784
  if( RSTRING_LEN(buffer) < 0) {
3605
- rb_raise(rb_ePGerror, "write buffer zero string");
3785
+ pg_raise_conn_error( rb_ePGerror, self, "write buffer zero string");
3606
3786
  }
3607
3787
  if((n = lo_write(conn, fd, StringValuePtr(buffer),
3608
3788
  RSTRING_LEN(buffer))) < 0) {
3609
- rb_raise(rb_ePGerror, "lo_write failed: %s", PQerrorMessage(conn));
3789
+ pg_raise_conn_error( rb_ePGerror, self, "lo_write failed: %s", PQerrorMessage(conn));
3610
3790
  }
3611
3791
 
3612
3792
  return INT2FIX(n);
@@ -3629,16 +3809,12 @@ pgconn_loread(VALUE self, VALUE in_lo_desc, VALUE in_len)
3629
3809
  VALUE str;
3630
3810
  char *buffer;
3631
3811
 
3632
- buffer = ALLOC_N(char, len);
3633
- if(buffer == NULL)
3634
- rb_raise(rb_eNoMemError, "ALLOC failed!");
3635
-
3636
- if (len < 0){
3637
- rb_raise(rb_ePGerror,"nagative length %d given", len);
3638
- }
3812
+ if (len < 0)
3813
+ pg_raise_conn_error( rb_ePGerror, self, "negative length %d given", len);
3639
3814
 
3815
+ buffer = ALLOC_N(char, len);
3640
3816
  if((ret = lo_read(conn, lo_desc, buffer, len)) < 0)
3641
- rb_raise(rb_ePGerror, "lo_read failed");
3817
+ pg_raise_conn_error( rb_ePGerror, self, "lo_read failed");
3642
3818
 
3643
3819
  if(ret == 0) {
3644
3820
  xfree(buffer);
@@ -3668,7 +3844,7 @@ pgconn_lolseek(VALUE self, VALUE in_lo_desc, VALUE offset, VALUE whence)
3668
3844
  int ret;
3669
3845
 
3670
3846
  if((ret = lo_lseek(conn, lo_desc, NUM2INT(offset), NUM2INT(whence))) < 0) {
3671
- rb_raise(rb_ePGerror, "lo_lseek failed");
3847
+ pg_raise_conn_error( rb_ePGerror, self, "lo_lseek failed");
3672
3848
  }
3673
3849
 
3674
3850
  return INT2FIX(ret);
@@ -3688,7 +3864,7 @@ pgconn_lotell(VALUE self, VALUE in_lo_desc)
3688
3864
  int lo_desc = NUM2INT(in_lo_desc);
3689
3865
 
3690
3866
  if((position = lo_tell(conn, lo_desc)) < 0)
3691
- rb_raise(rb_ePGerror,"lo_tell failed");
3867
+ pg_raise_conn_error( rb_ePGerror, self, "lo_tell failed");
3692
3868
 
3693
3869
  return INT2FIX(position);
3694
3870
  }
@@ -3707,7 +3883,7 @@ pgconn_lotruncate(VALUE self, VALUE in_lo_desc, VALUE in_len)
3707
3883
  size_t len = NUM2INT(in_len);
3708
3884
 
3709
3885
  if(lo_truncate(conn,lo_desc,len) < 0)
3710
- rb_raise(rb_ePGerror,"lo_truncate failed");
3886
+ pg_raise_conn_error( rb_ePGerror, self, "lo_truncate failed");
3711
3887
 
3712
3888
  return Qnil;
3713
3889
  }
@@ -3725,7 +3901,7 @@ pgconn_loclose(VALUE self, VALUE in_lo_desc)
3725
3901
  int lo_desc = NUM2INT(in_lo_desc);
3726
3902
 
3727
3903
  if(lo_close(conn,lo_desc) < 0)
3728
- rb_raise(rb_ePGerror,"lo_close failed");
3904
+ pg_raise_conn_error( rb_ePGerror, self, "lo_close failed");
3729
3905
 
3730
3906
  return Qnil;
3731
3907
  }
@@ -3743,7 +3919,7 @@ pgconn_lounlink(VALUE self, VALUE in_oid)
3743
3919
  Oid oid = NUM2UINT(in_oid);
3744
3920
 
3745
3921
  if(lo_unlink(conn,oid) < 0)
3746
- rb_raise(rb_ePGerror,"lo_unlink failed");
3922
+ pg_raise_conn_error( rb_ePGerror, self, "lo_unlink failed");
3747
3923
 
3748
3924
  return Qnil;
3749
3925
  }
@@ -3801,11 +3977,11 @@ static VALUE
3801
3977
  pgconn_internal_encoding_set(VALUE self, VALUE enc)
3802
3978
  {
3803
3979
  if (NIL_P(enc)) {
3804
- pgconn_set_client_encoding( self, rb_usascii_str_new_cstr("SQL_ASCII") );
3980
+ pgconn_sync_set_client_encoding( self, rb_usascii_str_new_cstr("SQL_ASCII") );
3805
3981
  return enc;
3806
3982
  }
3807
3983
  else if ( TYPE(enc) == T_STRING && strcasecmp("JOHAB", StringValueCStr(enc)) == 0 ) {
3808
- pgconn_set_client_encoding(self, rb_usascii_str_new_cstr("JOHAB"));
3984
+ pgconn_sync_set_client_encoding(self, rb_usascii_str_new_cstr("JOHAB"));
3809
3985
  return enc;
3810
3986
  }
3811
3987
  else {
@@ -3843,16 +4019,33 @@ pgconn_external_encoding(VALUE self)
3843
4019
  return rb_enc_from_encoding( enc );
3844
4020
  }
3845
4021
 
4022
+ /*
4023
+ * call-seq:
4024
+ * conn.set_client_encoding( encoding )
4025
+ *
4026
+ * Sets the client encoding to the _encoding_ String.
4027
+ */
4028
+ static VALUE
4029
+ pgconn_async_set_client_encoding(VALUE self, VALUE encname)
4030
+ {
4031
+ VALUE query_format, query;
4032
+
4033
+ Check_Type(encname, T_STRING);
4034
+ query_format = rb_str_new_cstr("set client_encoding to '%s'");
4035
+ query = rb_funcall(query_format, rb_intern("%"), 1, encname);
4036
+
4037
+ pgconn_async_exec(1, &query, self);
4038
+ pgconn_set_internal_encoding_index( self );
4039
+
4040
+ return Qnil;
4041
+ }
3846
4042
 
3847
4043
  static VALUE
3848
4044
  pgconn_set_client_encoding_async1( VALUE args )
3849
4045
  {
3850
4046
  VALUE self = ((VALUE*)args)[0];
3851
4047
  VALUE encname = ((VALUE*)args)[1];
3852
- VALUE query_format = rb_str_new_cstr("set client_encoding to '%s'");
3853
- VALUE query = rb_funcall(query_format, rb_intern("%"), 1, encname);
3854
-
3855
- pgconn_async_exec(1, &query, self);
4048
+ pgconn_async_set_client_encoding(self, encname);
3856
4049
  return 0;
3857
4050
  }
3858
4051
 
@@ -3867,9 +4060,9 @@ pgconn_set_client_encoding_async2( VALUE arg, VALUE ex )
3867
4060
 
3868
4061
 
3869
4062
  static VALUE
3870
- pgconn_set_client_encoding_async( VALUE self, const char *encname )
4063
+ pgconn_set_client_encoding_async( VALUE self, VALUE encname )
3871
4064
  {
3872
- VALUE args[] = { self, rb_str_new_cstr(encname) };
4065
+ VALUE args[] = { self, encname };
3873
4066
  return rb_rescue(pgconn_set_client_encoding_async1, (VALUE)&args, pgconn_set_client_encoding_async2, Qnil);
3874
4067
  }
3875
4068
 
@@ -3891,10 +4084,9 @@ pgconn_set_default_encoding( VALUE self )
3891
4084
 
3892
4085
  if (( enc = rb_default_internal_encoding() )) {
3893
4086
  encname = pg_get_rb_encoding_as_pg_encoding( enc );
3894
- if ( pgconn_set_client_encoding_async(self, encname) != 0 )
4087
+ if ( pgconn_set_client_encoding_async(self, rb_str_new_cstr(encname)) != 0 )
3895
4088
  rb_warning( "Failed to set the default_internal encoding to %s: '%s'",
3896
4089
  encname, PQerrorMessage(conn) );
3897
- pgconn_set_internal_encoding_index( self );
3898
4090
  return rb_enc_from_encoding( enc );
3899
4091
  } else {
3900
4092
  pgconn_set_internal_encoding_index( self );
@@ -3916,12 +4108,12 @@ static VALUE
3916
4108
  pgconn_type_map_for_queries_set(VALUE self, VALUE typemap)
3917
4109
  {
3918
4110
  t_pg_connection *this = pg_get_connection( self );
4111
+ t_typemap *tm;
4112
+ UNUSED(tm);
4113
+
4114
+ /* Check type of method param */
4115
+ TypedData_Get_Struct(typemap, t_typemap, &pg_typemap_type, tm);
3919
4116
 
3920
- if ( !rb_obj_is_kind_of(typemap, rb_cTypeMap) ) {
3921
- rb_raise( rb_eTypeError, "wrong argument type %s (expected kind of PG::TypeMap)",
3922
- rb_obj_classname( typemap ) );
3923
- }
3924
- Check_Type(typemap, T_DATA);
3925
4117
  this->type_map_for_queries = typemap;
3926
4118
 
3927
4119
  return typemap;
@@ -3956,12 +4148,10 @@ static VALUE
3956
4148
  pgconn_type_map_for_results_set(VALUE self, VALUE typemap)
3957
4149
  {
3958
4150
  t_pg_connection *this = pg_get_connection( self );
4151
+ t_typemap *tm;
4152
+ UNUSED(tm);
3959
4153
 
3960
- if ( !rb_obj_is_kind_of(typemap, rb_cTypeMap) ) {
3961
- rb_raise( rb_eTypeError, "wrong argument type %s (expected kind of PG::TypeMap)",
3962
- rb_obj_classname( typemap ) );
3963
- }
3964
- Check_Type(typemap, T_DATA);
4154
+ TypedData_Get_Struct(typemap, t_typemap, &pg_typemap_type, tm);
3965
4155
  this->type_map_for_results = typemap;
3966
4156
 
3967
4157
  return typemap;
@@ -3996,20 +4186,19 @@ pgconn_type_map_for_results_get(VALUE self)
3996
4186
  *
3997
4187
  */
3998
4188
  static VALUE
3999
- pgconn_encoder_for_put_copy_data_set(VALUE self, VALUE typemap)
4189
+ pgconn_encoder_for_put_copy_data_set(VALUE self, VALUE encoder)
4000
4190
  {
4001
4191
  t_pg_connection *this = pg_get_connection( self );
4002
4192
 
4003
- if( typemap != Qnil ){
4004
- if ( !rb_obj_is_kind_of(typemap, rb_cPG_Coder) ) {
4005
- rb_raise( rb_eTypeError, "wrong argument type %s (expected kind of PG::Coder)",
4006
- rb_obj_classname( typemap ) );
4007
- }
4008
- Check_Type(typemap, T_DATA);
4193
+ if( encoder != Qnil ){
4194
+ t_pg_coder *co;
4195
+ UNUSED(co);
4196
+ /* Check argument type */
4197
+ TypedData_Get_Struct(encoder, t_pg_coder, &pg_coder_type, co);
4009
4198
  }
4010
- this->encoder_for_put_copy_data = typemap;
4199
+ this->encoder_for_put_copy_data = encoder;
4011
4200
 
4012
- return typemap;
4201
+ return encoder;
4013
4202
  }
4014
4203
 
4015
4204
  /*
@@ -4045,20 +4234,19 @@ pgconn_encoder_for_put_copy_data_get(VALUE self)
4045
4234
  *
4046
4235
  */
4047
4236
  static VALUE
4048
- pgconn_decoder_for_get_copy_data_set(VALUE self, VALUE typemap)
4237
+ pgconn_decoder_for_get_copy_data_set(VALUE self, VALUE decoder)
4049
4238
  {
4050
4239
  t_pg_connection *this = pg_get_connection( self );
4051
4240
 
4052
- if( typemap != Qnil ){
4053
- if ( !rb_obj_is_kind_of(typemap, rb_cPG_Coder) ) {
4054
- rb_raise( rb_eTypeError, "wrong argument type %s (expected kind of PG::Coder)",
4055
- rb_obj_classname( typemap ) );
4056
- }
4057
- Check_Type(typemap, T_DATA);
4241
+ if( decoder != Qnil ){
4242
+ t_pg_coder *co;
4243
+ UNUSED(co);
4244
+ /* Check argument type */
4245
+ TypedData_Get_Struct(decoder, t_pg_coder, &pg_coder_type, co);
4058
4246
  }
4059
- this->decoder_for_get_copy_data = typemap;
4247
+ this->decoder_for_get_copy_data = decoder;
4060
4248
 
4061
- return typemap;
4249
+ return decoder;
4062
4250
  }
4063
4251
 
4064
4252
  /*
@@ -4141,6 +4329,7 @@ void
4141
4329
  init_pg_connection()
4142
4330
  {
4143
4331
  s_id_encode = rb_intern("encode");
4332
+ s_id_autoclose_set = rb_intern("autoclose=");
4144
4333
  sym_type = ID2SYM(rb_intern("type"));
4145
4334
  sym_format = ID2SYM(rb_intern("format"));
4146
4335
  sym_value = ID2SYM(rb_intern("value"));
@@ -4156,10 +4345,6 @@ init_pg_connection()
4156
4345
  /****** PG::Connection CLASS METHODS ******/
4157
4346
  rb_define_alloc_func( rb_cPGconn, pgconn_s_allocate );
4158
4347
 
4159
- SINGLETON_ALIAS(rb_cPGconn, "connect", "new");
4160
- SINGLETON_ALIAS(rb_cPGconn, "open", "new");
4161
- SINGLETON_ALIAS(rb_cPGconn, "setdb", "new");
4162
- SINGLETON_ALIAS(rb_cPGconn, "setdblogin", "new");
4163
4348
  rb_define_singleton_method(rb_cPGconn, "escape_string", pgconn_s_escape, 1);
4164
4349
  SINGLETON_ALIAS(rb_cPGconn, "escape", "escape_string");
4165
4350
  rb_define_singleton_method(rb_cPGconn, "escape_bytea", pgconn_s_escape_bytea, 1);
@@ -4168,14 +4353,15 @@ init_pg_connection()
4168
4353
  rb_define_singleton_method(rb_cPGconn, "quote_ident", pgconn_s_quote_ident, 1);
4169
4354
  rb_define_singleton_method(rb_cPGconn, "connect_start", pgconn_s_connect_start, -1);
4170
4355
  rb_define_singleton_method(rb_cPGconn, "conndefaults", pgconn_s_conndefaults, 0);
4171
- rb_define_singleton_method(rb_cPGconn, "ping", pgconn_s_ping, -1);
4356
+ rb_define_singleton_method(rb_cPGconn, "conninfo_parse", pgconn_s_conninfo_parse, 1);
4357
+ rb_define_singleton_method(rb_cPGconn, "sync_ping", pgconn_s_sync_ping, -1);
4358
+ rb_define_singleton_method(rb_cPGconn, "sync_connect", pgconn_s_sync_connect, -1);
4172
4359
 
4173
4360
  /****** PG::Connection INSTANCE METHODS: Connection Control ******/
4174
- rb_define_method(rb_cPGconn, "initialize", pgconn_init, -1);
4175
4361
  rb_define_method(rb_cPGconn, "connect_poll", pgconn_connect_poll, 0);
4176
4362
  rb_define_method(rb_cPGconn, "finish", pgconn_finish, 0);
4177
4363
  rb_define_method(rb_cPGconn, "finished?", pgconn_finished_p, 0);
4178
- rb_define_method(rb_cPGconn, "reset", pgconn_reset, 0);
4364
+ rb_define_method(rb_cPGconn, "sync_reset", pgconn_sync_reset, 0);
4179
4365
  rb_define_method(rb_cPGconn, "reset_start", pgconn_reset_start, 0);
4180
4366
  rb_define_method(rb_cPGconn, "reset_poll", pgconn_reset_poll, 0);
4181
4367
  rb_define_alias(rb_cPGconn, "close", "finish");
@@ -4185,11 +4371,12 @@ init_pg_connection()
4185
4371
  rb_define_method(rb_cPGconn, "user", pgconn_user, 0);
4186
4372
  rb_define_method(rb_cPGconn, "pass", pgconn_pass, 0);
4187
4373
  rb_define_method(rb_cPGconn, "host", pgconn_host, 0);
4374
+ #if defined(HAVE_PQRESULTMEMORYSIZE)
4375
+ rb_define_method(rb_cPGconn, "hostaddr", pgconn_hostaddr, 0);
4376
+ #endif
4188
4377
  rb_define_method(rb_cPGconn, "port", pgconn_port, 0);
4189
4378
  rb_define_method(rb_cPGconn, "tty", pgconn_tty, 0);
4190
- #ifdef HAVE_PQCONNINFO
4191
4379
  rb_define_method(rb_cPGconn, "conninfo", pgconn_conninfo, 0);
4192
- #endif
4193
4380
  rb_define_method(rb_cPGconn, "options", pgconn_options, 0);
4194
4381
  rb_define_method(rb_cPGconn, "status", pgconn_status, 0);
4195
4382
  rb_define_method(rb_cPGconn, "transaction_status", pgconn_transaction_status, 0);
@@ -4200,17 +4387,18 @@ init_pg_connection()
4200
4387
  rb_define_method(rb_cPGconn, "socket", pgconn_socket, 0);
4201
4388
  rb_define_method(rb_cPGconn, "socket_io", pgconn_socket_io, 0);
4202
4389
  rb_define_method(rb_cPGconn, "backend_pid", pgconn_backend_pid, 0);
4390
+ rb_define_method(rb_cPGconn, "backend_key", pgconn_backend_key, 0);
4203
4391
  rb_define_method(rb_cPGconn, "connection_needs_password", pgconn_connection_needs_password, 0);
4204
4392
  rb_define_method(rb_cPGconn, "connection_used_password", pgconn_connection_used_password, 0);
4205
4393
  /* rb_define_method(rb_cPGconn, "getssl", pgconn_getssl, 0); */
4206
4394
 
4207
4395
  /****** PG::Connection INSTANCE METHODS: Command Execution ******/
4208
- rb_define_method(rb_cPGconn, "sync_exec", pgconn_exec, -1);
4209
- rb_define_method(rb_cPGconn, "sync_exec_params", pgconn_exec_params, -1);
4210
- rb_define_method(rb_cPGconn, "sync_prepare", pgconn_prepare, -1);
4211
- rb_define_method(rb_cPGconn, "sync_exec_prepared", pgconn_exec_prepared, -1);
4212
- rb_define_method(rb_cPGconn, "sync_describe_prepared", pgconn_describe_prepared, 1);
4213
- rb_define_method(rb_cPGconn, "sync_describe_portal", pgconn_describe_portal, 1);
4396
+ rb_define_method(rb_cPGconn, "sync_exec", pgconn_sync_exec, -1);
4397
+ rb_define_method(rb_cPGconn, "sync_exec_params", pgconn_sync_exec_params, -1);
4398
+ rb_define_method(rb_cPGconn, "sync_prepare", pgconn_sync_prepare, -1);
4399
+ rb_define_method(rb_cPGconn, "sync_exec_prepared", pgconn_sync_exec_prepared, -1);
4400
+ rb_define_method(rb_cPGconn, "sync_describe_prepared", pgconn_sync_describe_prepared, 1);
4401
+ rb_define_method(rb_cPGconn, "sync_describe_portal", pgconn_sync_describe_portal, 1);
4214
4402
 
4215
4403
  rb_define_method(rb_cPGconn, "exec", pgconn_async_exec, -1);
4216
4404
  rb_define_method(rb_cPGconn, "exec_params", pgconn_async_exec_params, -1);
@@ -4243,25 +4431,26 @@ init_pg_connection()
4243
4431
  rb_define_method(rb_cPGconn, "send_query_prepared", pgconn_send_query_prepared, -1);
4244
4432
  rb_define_method(rb_cPGconn, "send_describe_prepared", pgconn_send_describe_prepared, 1);
4245
4433
  rb_define_method(rb_cPGconn, "send_describe_portal", pgconn_send_describe_portal, 1);
4246
- rb_define_method(rb_cPGconn, "get_result", pgconn_get_result, 0);
4434
+ rb_define_method(rb_cPGconn, "sync_get_result", pgconn_sync_get_result, 0);
4247
4435
  rb_define_method(rb_cPGconn, "consume_input", pgconn_consume_input, 0);
4248
4436
  rb_define_method(rb_cPGconn, "is_busy", pgconn_is_busy, 0);
4249
- rb_define_method(rb_cPGconn, "setnonblocking", pgconn_setnonblocking, 1);
4250
- rb_define_method(rb_cPGconn, "isnonblocking", pgconn_isnonblocking, 0);
4251
- rb_define_alias(rb_cPGconn, "nonblocking?", "isnonblocking");
4252
- rb_define_method(rb_cPGconn, "flush", pgconn_flush, 0);
4437
+ rb_define_method(rb_cPGconn, "sync_setnonblocking", pgconn_sync_setnonblocking, 1);
4438
+ rb_define_method(rb_cPGconn, "sync_isnonblocking", pgconn_sync_isnonblocking, 0);
4439
+ rb_define_method(rb_cPGconn, "sync_flush", pgconn_sync_flush, 0);
4440
+ rb_define_method(rb_cPGconn, "flush", pgconn_async_flush, 0);
4441
+ rb_define_alias(rb_cPGconn, "async_flush", "flush");
4253
4442
  rb_define_method(rb_cPGconn, "discard_results", pgconn_discard_results, 0);
4254
4443
 
4255
4444
  /****** PG::Connection INSTANCE METHODS: Cancelling Queries in Progress ******/
4256
- rb_define_method(rb_cPGconn, "cancel", pgconn_cancel, 0);
4445
+ rb_define_method(rb_cPGconn, "sync_cancel", pgconn_sync_cancel, 0);
4257
4446
 
4258
4447
  /****** PG::Connection INSTANCE METHODS: NOTIFY ******/
4259
4448
  rb_define_method(rb_cPGconn, "notifies", pgconn_notifies, 0);
4260
4449
 
4261
4450
  /****** PG::Connection INSTANCE METHODS: COPY ******/
4262
- rb_define_method(rb_cPGconn, "put_copy_data", pgconn_put_copy_data, -1);
4263
- rb_define_method(rb_cPGconn, "put_copy_end", pgconn_put_copy_end, -1);
4264
- rb_define_method(rb_cPGconn, "get_copy_data", pgconn_get_copy_data, -1);
4451
+ rb_define_method(rb_cPGconn, "sync_put_copy_data", pgconn_sync_put_copy_data, -1);
4452
+ rb_define_method(rb_cPGconn, "sync_put_copy_end", pgconn_sync_put_copy_end, -1);
4453
+ rb_define_method(rb_cPGconn, "sync_get_copy_data", pgconn_sync_get_copy_data, -1);
4265
4454
 
4266
4455
  /****** PG::Connection INSTANCE METHODS: Control Functions ******/
4267
4456
  rb_define_method(rb_cPGconn, "set_error_verbosity", pgconn_set_error_verbosity, 1);
@@ -4277,16 +4466,20 @@ init_pg_connection()
4277
4466
 
4278
4467
  /****** PG::Connection INSTANCE METHODS: Other ******/
4279
4468
  rb_define_method(rb_cPGconn, "get_client_encoding", pgconn_get_client_encoding, 0);
4280
- rb_define_method(rb_cPGconn, "set_client_encoding", pgconn_set_client_encoding, 1);
4469
+ rb_define_method(rb_cPGconn, "sync_set_client_encoding", pgconn_sync_set_client_encoding, 1);
4470
+ rb_define_method(rb_cPGconn, "set_client_encoding", pgconn_async_set_client_encoding, 1);
4471
+ rb_define_alias(rb_cPGconn, "async_set_client_encoding", "set_client_encoding");
4281
4472
  rb_define_alias(rb_cPGconn, "client_encoding=", "set_client_encoding");
4282
- rb_define_method(rb_cPGconn, "transaction", pgconn_transaction, 0);
4283
4473
  rb_define_method(rb_cPGconn, "block", pgconn_block, -1);
4474
+ rb_define_private_method(rb_cPGconn, "flush_data=", pgconn_flush_data_set, 1);
4284
4475
  rb_define_method(rb_cPGconn, "wait_for_notify", pgconn_wait_for_notify, -1);
4285
4476
  rb_define_alias(rb_cPGconn, "notifies_wait", "wait_for_notify");
4286
4477
  rb_define_method(rb_cPGconn, "quote_ident", pgconn_s_quote_ident, 1);
4287
- rb_define_method(rb_cPGconn, "get_last_result", pgconn_get_last_result, 0);
4478
+ rb_define_method(rb_cPGconn, "sync_get_last_result", pgconn_sync_get_last_result, 0);
4479
+ rb_define_method(rb_cPGconn, "get_last_result", pgconn_async_get_last_result, 0);
4480
+ rb_define_alias(rb_cPGconn, "async_get_last_result", "get_last_result");
4288
4481
  #ifdef HAVE_PQENCRYPTPASSWORDCONN
4289
- rb_define_method(rb_cPGconn, "encrypt_password", pgconn_encrypt_password, -1);
4482
+ rb_define_method(rb_cPGconn, "sync_encrypt_password", pgconn_sync_encrypt_password, -1);
4290
4483
  #endif
4291
4484
 
4292
4485
  #ifdef HAVE_PQSSLATTRIBUTE
@@ -4295,6 +4488,14 @@ init_pg_connection()
4295
4488
  rb_define_method(rb_cPGconn, "ssl_attribute_names", pgconn_ssl_attribute_names, 0);
4296
4489
  #endif
4297
4490
 
4491
+ #ifdef HAVE_PQENTERPIPELINEMODE
4492
+ rb_define_method(rb_cPGconn, "pipeline_status", pgconn_pipeline_status, 0);
4493
+ rb_define_method(rb_cPGconn, "enter_pipeline_mode", pgconn_enter_pipeline_mode, 0);
4494
+ rb_define_method(rb_cPGconn, "exit_pipeline_mode", pgconn_exit_pipeline_mode, 0);
4495
+ rb_define_method(rb_cPGconn, "pipeline_sync", pgconn_pipeline_sync, 0);
4496
+ rb_define_method(rb_cPGconn, "send_flush_request", pgconn_send_flush_request, 0);
4497
+ #endif
4498
+
4298
4499
  /****** PG::Connection INSTANCE METHODS: Large Object Support ******/
4299
4500
  rb_define_method(rb_cPGconn, "lo_creat", pgconn_locreat, -1);
4300
4501
  rb_define_alias(rb_cPGconn, "locreat", "lo_creat");