pg 1.2.3 → 1.4.6

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 (119) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data/.appveyor.yml +42 -0
  4. data/.gems +6 -0
  5. data/.github/workflows/binary-gems.yml +117 -0
  6. data/.github/workflows/source-gem.yml +137 -0
  7. data/.gitignore +19 -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.md +804 -0
  16. data/Manifest.txt +0 -1
  17. data/README.ja.md +266 -0
  18. data/README.md +272 -0
  19. data/Rakefile +33 -135
  20. data/Rakefile.cross +12 -13
  21. data/certs/ged.pem +24 -0
  22. data/certs/larskanis-2022.pem +26 -0
  23. data/certs/larskanis-2023.pem +24 -0
  24. data/ext/errorcodes.def +12 -0
  25. data/ext/errorcodes.rb +0 -0
  26. data/ext/errorcodes.txt +4 -1
  27. data/ext/extconf.rb +100 -25
  28. data/ext/gvl_wrappers.c +4 -0
  29. data/ext/gvl_wrappers.h +23 -0
  30. data/ext/pg.c +62 -29
  31. data/ext/pg.h +20 -1
  32. data/ext/pg_binary_decoder.c +1 -1
  33. data/ext/pg_binary_encoder.c +1 -1
  34. data/ext/pg_coder.c +83 -29
  35. data/ext/pg_connection.c +953 -670
  36. data/ext/pg_copy_coder.c +46 -17
  37. data/ext/pg_errors.c +1 -1
  38. data/ext/pg_record_coder.c +46 -16
  39. data/ext/pg_result.c +88 -49
  40. data/ext/pg_text_decoder.c +2 -2
  41. data/ext/pg_text_encoder.c +7 -7
  42. data/ext/pg_tuple.c +50 -30
  43. data/ext/pg_type_map.c +42 -9
  44. data/ext/pg_type_map_all_strings.c +16 -2
  45. data/ext/pg_type_map_by_class.c +50 -25
  46. data/ext/pg_type_map_by_column.c +68 -30
  47. data/ext/pg_type_map_by_mri_type.c +48 -19
  48. data/ext/pg_type_map_by_oid.c +53 -24
  49. data/ext/pg_type_map_in_ruby.c +51 -20
  50. data/ext/pg_util.c +2 -2
  51. data/lib/pg/basic_type_map_based_on_result.rb +47 -0
  52. data/lib/pg/basic_type_map_for_queries.rb +193 -0
  53. data/lib/pg/basic_type_map_for_results.rb +81 -0
  54. data/lib/pg/basic_type_registry.rb +301 -0
  55. data/lib/pg/coder.rb +1 -1
  56. data/lib/pg/connection.rb +669 -81
  57. data/lib/pg/exceptions.rb +14 -1
  58. data/lib/pg/version.rb +4 -0
  59. data/lib/pg.rb +45 -36
  60. data/misc/openssl-pg-segfault.rb +31 -0
  61. data/misc/postgres/History.txt +9 -0
  62. data/misc/postgres/Manifest.txt +5 -0
  63. data/misc/postgres/README.txt +21 -0
  64. data/misc/postgres/Rakefile +21 -0
  65. data/misc/postgres/lib/postgres.rb +16 -0
  66. data/misc/ruby-pg/History.txt +9 -0
  67. data/misc/ruby-pg/Manifest.txt +5 -0
  68. data/misc/ruby-pg/README.txt +21 -0
  69. data/misc/ruby-pg/Rakefile +21 -0
  70. data/misc/ruby-pg/lib/ruby/pg.rb +16 -0
  71. data/pg.gemspec +34 -0
  72. data/rakelib/task_extension.rb +46 -0
  73. data/sample/array_insert.rb +20 -0
  74. data/sample/async_api.rb +102 -0
  75. data/sample/async_copyto.rb +39 -0
  76. data/sample/async_mixed.rb +56 -0
  77. data/sample/check_conn.rb +21 -0
  78. data/sample/copydata.rb +71 -0
  79. data/sample/copyfrom.rb +81 -0
  80. data/sample/copyto.rb +19 -0
  81. data/sample/cursor.rb +21 -0
  82. data/sample/disk_usage_report.rb +177 -0
  83. data/sample/issue-119.rb +94 -0
  84. data/sample/losample.rb +69 -0
  85. data/sample/minimal-testcase.rb +17 -0
  86. data/sample/notify_wait.rb +72 -0
  87. data/sample/pg_statistics.rb +285 -0
  88. data/sample/replication_monitor.rb +222 -0
  89. data/sample/test_binary_values.rb +33 -0
  90. data/sample/wal_shipper.rb +434 -0
  91. data/sample/warehouse_partitions.rb +311 -0
  92. data/translation/.po4a-version +7 -0
  93. data/translation/po/all.pot +875 -0
  94. data/translation/po/ja.po +868 -0
  95. data/translation/po4a.cfg +9 -0
  96. data.tar.gz.sig +0 -0
  97. metadata +120 -206
  98. metadata.gz.sig +0 -0
  99. data/ChangeLog +0 -0
  100. data/History.rdoc +0 -578
  101. data/README.ja.rdoc +0 -13
  102. data/README.rdoc +0 -213
  103. data/lib/pg/basic_type_mapping.rb +0 -522
  104. data/spec/data/expected_trace.out +0 -26
  105. data/spec/data/random_binary_data +0 -0
  106. data/spec/helpers.rb +0 -380
  107. data/spec/pg/basic_type_mapping_spec.rb +0 -630
  108. data/spec/pg/connection_spec.rb +0 -1949
  109. data/spec/pg/connection_sync_spec.rb +0 -41
  110. data/spec/pg/result_spec.rb +0 -681
  111. data/spec/pg/tuple_spec.rb +0 -333
  112. data/spec/pg/type_map_by_class_spec.rb +0 -138
  113. data/spec/pg/type_map_by_column_spec.rb +0 -226
  114. data/spec/pg/type_map_by_mri_type_spec.rb +0 -136
  115. data/spec/pg/type_map_by_oid_spec.rb +0 -149
  116. data/spec/pg/type_map_in_ruby_spec.rb +0 -164
  117. data/spec/pg/type_map_spec.rb +0 -22
  118. data/spec/pg/type_spec.rb +0 -1123
  119. 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.
394
+ * Document-method: PG::Connection.conninfo_parse
415
395
  *
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.
423
- *
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,22 @@ 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
+ if (!port || port[0] == '\0')
706
+ return INT2NUM(DEF_PGPORT);
707
+ else
708
+ return INT2NUM(atoi(port));
680
709
  }
681
710
 
682
711
  /*
683
712
  * call-seq:
684
713
  * conn.tty()
685
714
  *
686
- * Returns the connected pgtty. (Obsolete)
715
+ * Obsolete function.
687
716
  */
688
717
  static VALUE
689
718
  pgconn_tty(VALUE self)
690
719
  {
691
- char *tty = PQtty(pg_get_pgconn(self));
692
- if (!tty) return Qnil;
693
- return rb_str_new2(tty);
720
+ return rb_str_new2("");
694
721
  }
695
722
 
696
723
  /*
@@ -708,7 +735,6 @@ pgconn_options(VALUE self)
708
735
  }
709
736
 
710
737
 
711
- #ifdef HAVE_PQCONNINFO
712
738
  /*
713
739
  * call-seq:
714
740
  * conn.conninfo -> hash
@@ -728,14 +754,20 @@ pgconn_conninfo( VALUE self )
728
754
 
729
755
  return array;
730
756
  }
731
- #endif
732
757
 
733
758
 
734
759
  /*
735
760
  * call-seq:
736
761
  * conn.status()
737
762
  *
738
- * Returns status of connection : CONNECTION_OK or CONNECTION_BAD
763
+ * Returns the status of the connection, which is one:
764
+ * PG::Constants::CONNECTION_OK
765
+ * PG::Constants::CONNECTION_BAD
766
+ *
767
+ * ... and other constants of kind PG::Constants::CONNECTION_*
768
+ *
769
+ * Example:
770
+ * PG.constants.grep(/CONNECTION_/).find{|c| PG.const_get(c) == conn.status} # => :CONNECTION_OK
739
771
  */
740
772
  static VALUE
741
773
  pgconn_status(VALUE self)
@@ -823,7 +855,10 @@ pgconn_server_version(VALUE self)
823
855
  * call-seq:
824
856
  * conn.error_message -> String
825
857
  *
826
- * Returns the error message about connection.
858
+ * Returns the error message most recently generated by an operation on the connection.
859
+ *
860
+ * Nearly all libpq functions will set a message for conn.error_message if they fail.
861
+ * Note that by libpq convention, a nonempty error_message result can consist of multiple lines, and will include a trailing newline.
827
862
  */
828
863
  static VALUE
829
864
  pgconn_error_message(VALUE self)
@@ -857,7 +892,8 @@ pgconn_socket(VALUE self)
857
892
  pg_deprecated(4, ("conn.socket is deprecated and should be replaced by conn.socket_io"));
858
893
 
859
894
  if( (sd = PQsocket(pg_get_pgconn(self))) < 0)
860
- rb_raise(rb_eConnectionBad, "PQsocket() can't get socket descriptor");
895
+ pg_raise_conn_error( rb_eConnectionBad, self, "PQsocket() can't get socket descriptor");
896
+
861
897
  return INT2NUM(sd);
862
898
  }
863
899
 
@@ -865,38 +901,45 @@ pgconn_socket(VALUE self)
865
901
  * call-seq:
866
902
  * conn.socket_io() -> IO
867
903
  *
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.
904
+ * Fetch an IO object created from the Connection's underlying socket.
905
+ * 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.
906
+ * <tt>IO#wait_*able</tt> is is <tt>Fiber.scheduler</tt> compatible in contrast to <tt>IO.select</tt>.
907
+ *
908
+ * The IO object can change while the connection is established, but is memorized afterwards.
909
+ * So be sure not to cache the IO object, but repeat calling <tt>conn.socket_io</tt> instead.
871
910
  *
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.
911
+ * Using this method also works on Windows in contrast to using #socket .
912
+ * 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
913
  */
876
914
  static VALUE
877
915
  pgconn_socket_io(VALUE self)
878
916
  {
879
917
  int sd;
880
918
  int ruby_sd;
881
- ID id_autoclose = rb_intern("autoclose=");
882
919
  t_pg_connection *this = pg_get_connection_safe( self );
920
+ VALUE cSocket;
883
921
  VALUE socket_io = this->socket_io;
884
922
 
885
923
  if ( !RTEST(socket_io) ) {
886
- if( (sd = PQsocket(this->pgconn)) < 0)
887
- rb_raise(rb_eConnectionBad, "PQsocket() can't get socket descriptor");
924
+ if( (sd = PQsocket(this->pgconn)) < 0){
925
+ pg_raise_conn_error( rb_eConnectionBad, self, "PQsocket() can't get socket descriptor");
926
+ }
888
927
 
889
928
  #ifdef _WIN32
890
929
  ruby_sd = rb_w32_wrap_io_handle((HANDLE)(intptr_t)sd, O_RDWR|O_BINARY|O_NOINHERIT);
930
+ if( ruby_sd == -1 )
931
+ pg_raise_conn_error( rb_eConnectionBad, self, "Could not wrap win32 socket handle");
932
+
891
933
  this->ruby_sd = ruby_sd;
892
934
  #else
893
935
  ruby_sd = sd;
894
936
  #endif
895
937
 
896
- socket_io = rb_funcall( rb_cIO, rb_intern("for_fd"), 1, INT2NUM(ruby_sd) );
938
+ cSocket = rb_const_get(rb_cObject, rb_intern("BasicSocket"));
939
+ socket_io = rb_funcall( cSocket, rb_intern("for_fd"), 1, INT2NUM(ruby_sd));
897
940
 
898
941
  /* Disable autoclose feature */
899
- rb_funcall( socket_io, id_autoclose, 1, Qfalse );
942
+ rb_funcall( socket_io, s_id_autoclose_set, 1, Qfalse );
900
943
 
901
944
  this->socket_io = socket_io;
902
945
  }
@@ -918,6 +961,51 @@ pgconn_backend_pid(VALUE self)
918
961
  return INT2NUM(PQbackendPID(pg_get_pgconn(self)));
919
962
  }
920
963
 
964
+ typedef struct
965
+ {
966
+ struct sockaddr_storage addr;
967
+ socklen_t salen;
968
+ } SockAddr;
969
+
970
+ /* Copy of struct pg_cancel from libpq-int.h
971
+ *
972
+ * See https://github.com/postgres/postgres/blame/master/src/interfaces/libpq/libpq-int.h#L577-L586
973
+ */
974
+ struct pg_cancel
975
+ {
976
+ SockAddr raddr; /* Remote address */
977
+ int be_pid; /* PID of backend --- needed for cancels */
978
+ int be_key; /* key of backend --- needed for cancels */
979
+ };
980
+
981
+ /*
982
+ * call-seq:
983
+ * conn.backend_key() -> Integer
984
+ *
985
+ * Returns the key of the backend server process for this connection.
986
+ * This key can be used to cancel queries on the server.
987
+ */
988
+ static VALUE
989
+ pgconn_backend_key(VALUE self)
990
+ {
991
+ int be_key;
992
+ struct pg_cancel *cancel;
993
+ PGconn *conn = pg_get_pgconn(self);
994
+
995
+ cancel = (struct pg_cancel*)PQgetCancel(conn);
996
+ if(cancel == NULL)
997
+ pg_raise_conn_error( rb_ePGerror, self, "Invalid connection!");
998
+
999
+ if( cancel->be_pid != PQbackendPID(conn) )
1000
+ rb_raise(rb_ePGerror,"Unexpected binary struct layout - please file a bug report at ruby-pg!");
1001
+
1002
+ be_key = cancel->be_key;
1003
+
1004
+ PQfreeCancel(cancel);
1005
+
1006
+ return INT2NUM(be_key);
1007
+ }
1008
+
921
1009
  /*
922
1010
  * call-seq:
923
1011
  * conn.connection_needs_password() -> Boolean
@@ -948,7 +1036,7 @@ pgconn_connection_used_password(VALUE self)
948
1036
  /* :TODO: get_ssl */
949
1037
 
950
1038
 
951
- static VALUE pgconn_exec_params( int, VALUE *, VALUE );
1039
+ static VALUE pgconn_sync_exec_params( int, VALUE *, VALUE );
952
1040
 
953
1041
  /*
954
1042
  * call-seq:
@@ -962,11 +1050,11 @@ static VALUE pgconn_exec_params( int, VALUE *, VALUE );
962
1050
  * However #async_exec has two advantages:
963
1051
  *
964
1052
  * 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
1053
+ * 2. Ruby VM gets notified about IO blocked operations and can pass them through <tt>Fiber.scheduler</tt>.
1054
+ * So only <tt>async_*</tt> methods are compatible to event based schedulers like the async gem.
967
1055
  */
968
1056
  static VALUE
969
- pgconn_exec(int argc, VALUE *argv, VALUE self)
1057
+ pgconn_sync_exec(int argc, VALUE *argv, VALUE self)
970
1058
  {
971
1059
  t_pg_connection *this = pg_get_connection_safe( self );
972
1060
  PGresult *result = NULL;
@@ -987,7 +1075,7 @@ pgconn_exec(int argc, VALUE *argv, VALUE self)
987
1075
  pg_deprecated(0, ("forwarding exec to exec_params is deprecated"));
988
1076
 
989
1077
  /* Otherwise, just call #exec_params instead for backward-compatibility */
990
- return pgconn_exec_params( argc, argv, self );
1078
+ return pgconn_sync_exec_params( argc, argv, self );
991
1079
 
992
1080
  }
993
1081
 
@@ -1019,7 +1107,7 @@ struct query_params_data {
1019
1107
  * Filled by alloc_query_params()
1020
1108
  */
1021
1109
 
1022
- /* Wraps the pointer of allocated memory, if function parameters dont't
1110
+ /* Wraps the pointer of allocated memory, if function parameters don't
1023
1111
  * fit in the memory_pool below.
1024
1112
  */
1025
1113
  VALUE heap_pool;
@@ -1037,7 +1125,7 @@ struct query_params_data {
1037
1125
  Oid *types;
1038
1126
 
1039
1127
  /* This array takes the string values for the timeframe of the query,
1040
- * if param value convertion is required
1128
+ * if param value conversion is required
1041
1129
  */
1042
1130
  VALUE gc_array;
1043
1131
 
@@ -1051,8 +1139,9 @@ struct query_params_data {
1051
1139
  };
1052
1140
 
1053
1141
  static void
1054
- free_typecast_heap_chain(struct linked_typecast_data *chain_entry)
1142
+ free_typecast_heap_chain(void *_chain_entry)
1055
1143
  {
1144
+ struct linked_typecast_data *chain_entry = (struct linked_typecast_data *)_chain_entry;
1056
1145
  while(chain_entry){
1057
1146
  struct linked_typecast_data *next = chain_entry->next;
1058
1147
  xfree(chain_entry);
@@ -1060,6 +1149,18 @@ free_typecast_heap_chain(struct linked_typecast_data *chain_entry)
1060
1149
  }
1061
1150
  }
1062
1151
 
1152
+ static const rb_data_type_t pg_typecast_buffer_type = {
1153
+ "PG::Connection typecast buffer chain",
1154
+ {
1155
+ (RUBY_DATA_FUNC) NULL,
1156
+ free_typecast_heap_chain,
1157
+ (size_t (*)(const void *))NULL,
1158
+ },
1159
+ 0,
1160
+ 0,
1161
+ RUBY_TYPED_FREE_IMMEDIATELY,
1162
+ };
1163
+
1063
1164
  static char *
1064
1165
  alloc_typecast_buf( VALUE *typecast_heap_chain, int len )
1065
1166
  {
@@ -1070,17 +1171,28 @@ alloc_typecast_buf( VALUE *typecast_heap_chain, int len )
1070
1171
  /* Did we already wrap a memory chain per T_DATA object? */
1071
1172
  if( NIL_P( *typecast_heap_chain ) ){
1072
1173
  /* 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 );
1174
+ *typecast_heap_chain = TypedData_Wrap_Struct( rb_cObject, &pg_typecast_buffer_type, allocated );
1074
1175
  allocated->next = NULL;
1075
1176
  } else {
1076
1177
  /* Append to the chain */
1077
- allocated->next = DATA_PTR( *typecast_heap_chain );
1078
- DATA_PTR( *typecast_heap_chain ) = allocated;
1178
+ allocated->next = RTYPEDDATA_DATA( *typecast_heap_chain );
1179
+ RTYPEDDATA_DATA( *typecast_heap_chain ) = allocated;
1079
1180
  }
1080
1181
 
1081
1182
  return &allocated->data[0];
1082
1183
  }
1083
1184
 
1185
+ static const rb_data_type_t pg_query_heap_pool_type = {
1186
+ "PG::Connection query heap pool",
1187
+ {
1188
+ (RUBY_DATA_FUNC) NULL,
1189
+ RUBY_TYPED_DEFAULT_FREE,
1190
+ (size_t (*)(const void *))NULL,
1191
+ },
1192
+ 0,
1193
+ 0,
1194
+ RUBY_TYPED_FREE_IMMEDIATELY,
1195
+ };
1084
1196
 
1085
1197
  static int
1086
1198
  alloc_query_params(struct query_params_data *paramsData)
@@ -1095,7 +1207,7 @@ alloc_query_params(struct query_params_data *paramsData)
1095
1207
 
1096
1208
  Check_Type(paramsData->params, T_ARRAY);
1097
1209
 
1098
- p_typemap = DATA_PTR( paramsData->typemap );
1210
+ p_typemap = RTYPEDDATA_DATA( paramsData->typemap );
1099
1211
  p_typemap->funcs.fit_to_query( paramsData->typemap, paramsData->params );
1100
1212
 
1101
1213
  paramsData->heap_pool = Qnil;
@@ -1114,7 +1226,7 @@ alloc_query_params(struct query_params_data *paramsData)
1114
1226
  /* Allocate one combined memory pool for all possible function parameters */
1115
1227
  memory_pool = (char*)xmalloc( required_pool_size );
1116
1228
  /* 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 );
1229
+ paramsData->heap_pool = TypedData_Wrap_Struct( rb_cObject, &pg_query_heap_pool_type, memory_pool );
1118
1230
  required_pool_size = 0;
1119
1231
  }else{
1120
1232
  /* Use stack memory for function parameters */
@@ -1227,12 +1339,11 @@ pgconn_query_assign_typemap( VALUE self, struct query_params_data *paramsData )
1227
1339
  /* Use default typemap for queries. It's type is checked when assigned. */
1228
1340
  paramsData->typemap = pg_get_connection(self)->type_map_for_queries;
1229
1341
  }else{
1342
+ t_typemap *tm;
1343
+ UNUSED(tm);
1344
+
1230
1345
  /* 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 );
1346
+ TypedData_Get_Struct(paramsData->typemap, t_typemap, &pg_typemap_type, tm);
1236
1347
  }
1237
1348
  }
1238
1349
 
@@ -1246,7 +1357,7 @@ pgconn_query_assign_typemap( VALUE self, struct query_params_data *paramsData )
1246
1357
  * 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
1358
  */
1248
1359
  static VALUE
1249
- pgconn_exec_params( int argc, VALUE *argv, VALUE self )
1360
+ pgconn_sync_exec_params( int argc, VALUE *argv, VALUE self )
1250
1361
  {
1251
1362
  t_pg_connection *this = pg_get_connection_safe( self );
1252
1363
  PGresult *result = NULL;
@@ -1266,7 +1377,7 @@ pgconn_exec_params( int argc, VALUE *argv, VALUE self )
1266
1377
  */
1267
1378
  if ( NIL_P(paramsData.params) ) {
1268
1379
  pg_deprecated(1, ("forwarding exec_params to exec is deprecated"));
1269
- return pgconn_exec( 1, argv, self );
1380
+ return pgconn_sync_exec( 1, argv, self );
1270
1381
  }
1271
1382
  pgconn_query_assign_typemap( self, &paramsData );
1272
1383
 
@@ -1297,7 +1408,7 @@ pgconn_exec_params( int argc, VALUE *argv, VALUE self )
1297
1408
  * It's not recommended to use explicit sync or async variants but #prepare instead, unless you have a good reason to do so.
1298
1409
  */
1299
1410
  static VALUE
1300
- pgconn_prepare(int argc, VALUE *argv, VALUE self)
1411
+ pgconn_sync_prepare(int argc, VALUE *argv, VALUE self)
1301
1412
  {
1302
1413
  t_pg_connection *this = pg_get_connection_safe( self );
1303
1414
  PGresult *result = NULL;
@@ -1346,7 +1457,7 @@ pgconn_prepare(int argc, VALUE *argv, VALUE self)
1346
1457
  * 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
1458
  */
1348
1459
  static VALUE
1349
- pgconn_exec_prepared(int argc, VALUE *argv, VALUE self)
1460
+ pgconn_sync_exec_prepared(int argc, VALUE *argv, VALUE self)
1350
1461
  {
1351
1462
  t_pg_connection *this = pg_get_connection_safe( self );
1352
1463
  PGresult *result = NULL;
@@ -1391,7 +1502,7 @@ pgconn_exec_prepared(int argc, VALUE *argv, VALUE self)
1391
1502
  * 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
1503
  */
1393
1504
  static VALUE
1394
- pgconn_describe_prepared(VALUE self, VALUE stmt_name)
1505
+ pgconn_sync_describe_prepared(VALUE self, VALUE stmt_name)
1395
1506
  {
1396
1507
  PGresult *result;
1397
1508
  VALUE rb_pgresult;
@@ -1419,8 +1530,7 @@ pgconn_describe_prepared(VALUE self, VALUE stmt_name)
1419
1530
  * 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
1531
  */
1421
1532
  static VALUE
1422
- pgconn_describe_portal(self, stmt_name)
1423
- VALUE self, stmt_name;
1533
+ pgconn_sync_describe_portal(VALUE self, VALUE stmt_name)
1424
1534
  {
1425
1535
  PGresult *result;
1426
1536
  VALUE rb_pgresult;
@@ -1454,6 +1564,9 @@ pgconn_describe_portal(self, stmt_name)
1454
1564
  * * +PGRES_NONFATAL_ERROR+
1455
1565
  * * +PGRES_FATAL_ERROR+
1456
1566
  * * +PGRES_COPY_BOTH+
1567
+ * * +PGRES_SINGLE_TUPLE+
1568
+ * * +PGRES_PIPELINE_SYNC+
1569
+ * * +PGRES_PIPELINE_ABORTED+
1457
1570
  */
1458
1571
  static VALUE
1459
1572
  pgconn_make_empty_pgresult(VALUE self, VALUE status)
@@ -1509,9 +1622,9 @@ pgconn_s_escape(VALUE self, VALUE string)
1509
1622
  if( !singleton ) {
1510
1623
  size = PQescapeStringConn(pg_get_pgconn(self), RSTRING_PTR(result),
1511
1624
  RSTRING_PTR(string), RSTRING_LEN(string), &error);
1512
- if(error) {
1513
- rb_raise(rb_ePGerror, "%s", PQerrorMessage(pg_get_pgconn(self)));
1514
- }
1625
+ if(error)
1626
+ pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(pg_get_pgconn(self)));
1627
+
1515
1628
  } else {
1516
1629
  size = PQescapeString(RSTRING_PTR(result), RSTRING_PTR(string), RSTRING_LEN(string));
1517
1630
  }
@@ -1607,7 +1720,6 @@ pgconn_escape_literal(VALUE self, VALUE string)
1607
1720
  {
1608
1721
  t_pg_connection *this = pg_get_connection_safe( self );
1609
1722
  char *escaped = NULL;
1610
- VALUE error;
1611
1723
  VALUE result = Qnil;
1612
1724
  int enc_idx = this->enc_idx;
1613
1725
 
@@ -1618,12 +1730,8 @@ pgconn_escape_literal(VALUE self, VALUE string)
1618
1730
 
1619
1731
  escaped = PQescapeLiteral(this->pgconn, RSTRING_PTR(string), RSTRING_LEN(string));
1620
1732
  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
- }
1733
+ pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(this->pgconn));
1734
+
1627
1735
  result = rb_str_new2(escaped);
1628
1736
  PQfreemem(escaped);
1629
1737
  PG_ENCODING_SET_NOCHECK(result, enc_idx);
@@ -1646,7 +1754,6 @@ pgconn_escape_identifier(VALUE self, VALUE string)
1646
1754
  {
1647
1755
  t_pg_connection *this = pg_get_connection_safe( self );
1648
1756
  char *escaped = NULL;
1649
- VALUE error;
1650
1757
  VALUE result = Qnil;
1651
1758
  int enc_idx = this->enc_idx;
1652
1759
 
@@ -1657,12 +1764,8 @@ pgconn_escape_identifier(VALUE self, VALUE string)
1657
1764
 
1658
1765
  escaped = PQescapeIdentifier(this->pgconn, RSTRING_PTR(string), RSTRING_LEN(string));
1659
1766
  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
- }
1767
+ pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(this->pgconn));
1768
+
1666
1769
  result = rb_str_new2(escaped);
1667
1770
  PQfreemem(escaped);
1668
1771
  PG_ENCODING_SET_NOCHECK(result, enc_idx);
@@ -1710,14 +1813,9 @@ static VALUE
1710
1813
  pgconn_set_single_row_mode(VALUE self)
1711
1814
  {
1712
1815
  PGconn *conn = pg_get_pgconn(self);
1713
- VALUE error;
1714
1816
 
1715
1817
  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
- }
1818
+ pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(conn));
1721
1819
 
1722
1820
  return self;
1723
1821
  }
@@ -1741,15 +1839,13 @@ static VALUE
1741
1839
  pgconn_send_query(int argc, VALUE *argv, VALUE self)
1742
1840
  {
1743
1841
  t_pg_connection *this = pg_get_connection_safe( self );
1744
- VALUE error;
1745
1842
 
1746
1843
  /* If called with no or nil parameters, use PQexec for compatibility */
1747
1844
  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
- }
1845
+ if(gvl_PQsendQuery(this->pgconn, pg_cstr_enc(argv[0], this->enc_idx)) == 0)
1846
+ pg_raise_conn_error( rb_eUnableToSend, self, "%s", PQerrorMessage(this->pgconn));
1847
+
1848
+ pgconn_wait_for_flush( self );
1753
1849
  return Qnil;
1754
1850
  }
1755
1851
 
@@ -1779,7 +1875,7 @@ pgconn_send_query(int argc, VALUE *argv, VALUE self)
1779
1875
  * or, it may be a String. If it is a string, that is equivalent to the hash:
1780
1876
  * { :value => <string value>, :type => 0, :format => 0 }
1781
1877
  *
1782
- * PostgreSQL bind parameters are represented as $1, $1, $2, etc.,
1878
+ * PostgreSQL bind parameters are represented as $1, $2, $3, etc.,
1783
1879
  * inside the SQL query. The 0th element of the +params+ array is bound
1784
1880
  * to $1, the 1st element is bound to $2, etc. +nil+ is treated as +NULL+.
1785
1881
  *
@@ -1805,7 +1901,6 @@ pgconn_send_query_params(int argc, VALUE *argv, VALUE self)
1805
1901
  t_pg_connection *this = pg_get_connection_safe( self );
1806
1902
  int result;
1807
1903
  VALUE command, in_res_fmt;
1808
- VALUE error;
1809
1904
  int nParams;
1810
1905
  int resultFormat;
1811
1906
  struct query_params_data paramsData = { this->enc_idx };
@@ -1822,11 +1917,10 @@ pgconn_send_query_params(int argc, VALUE *argv, VALUE self)
1822
1917
 
1823
1918
  free_query_params( &paramsData );
1824
1919
 
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
- }
1920
+ if(result == 0)
1921
+ pg_raise_conn_error( rb_eUnableToSend, self, "%s", PQerrorMessage(this->pgconn));
1922
+
1923
+ pgconn_wait_for_flush( self );
1830
1924
  return Qnil;
1831
1925
  }
1832
1926
 
@@ -1847,7 +1941,7 @@ pgconn_send_query_params(int argc, VALUE *argv, VALUE self)
1847
1941
  *
1848
1942
  * For example: "SELECT $1::int"
1849
1943
  *
1850
- * PostgreSQL bind parameters are represented as $1, $1, $2, etc.,
1944
+ * PostgreSQL bind parameters are represented as $1, $2, $3, etc.,
1851
1945
  * inside the SQL query.
1852
1946
  */
1853
1947
  static VALUE
@@ -1857,7 +1951,6 @@ pgconn_send_prepare(int argc, VALUE *argv, VALUE self)
1857
1951
  int result;
1858
1952
  VALUE name, command, in_paramtypes;
1859
1953
  VALUE param;
1860
- VALUE error;
1861
1954
  int i = 0;
1862
1955
  int nParams = 0;
1863
1956
  Oid *paramTypes = NULL;
@@ -1886,10 +1979,9 @@ pgconn_send_prepare(int argc, VALUE *argv, VALUE self)
1886
1979
  xfree(paramTypes);
1887
1980
 
1888
1981
  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);
1982
+ pg_raise_conn_error( rb_eUnableToSend, self, "%s", PQerrorMessage(this->pgconn));
1892
1983
  }
1984
+ pgconn_wait_for_flush( self );
1893
1985
  return Qnil;
1894
1986
  }
1895
1987
 
@@ -1911,7 +2003,7 @@ pgconn_send_prepare(int argc, VALUE *argv, VALUE self)
1911
2003
  * or, it may be a String. If it is a string, that is equivalent to the hash:
1912
2004
  * { :value => <string value>, :format => 0 }
1913
2005
  *
1914
- * PostgreSQL bind parameters are represented as $1, $1, $2, etc.,
2006
+ * PostgreSQL bind parameters are represented as $1, $2, $3, etc.,
1915
2007
  * inside the SQL query. The 0th element of the +params+ array is bound
1916
2008
  * to $1, the 1st element is bound to $2, etc. +nil+ is treated as +NULL+.
1917
2009
  *
@@ -1931,7 +2023,6 @@ pgconn_send_query_prepared(int argc, VALUE *argv, VALUE self)
1931
2023
  t_pg_connection *this = pg_get_connection_safe( self );
1932
2024
  int result;
1933
2025
  VALUE name, in_res_fmt;
1934
- VALUE error;
1935
2026
  int nParams;
1936
2027
  int resultFormat;
1937
2028
  struct query_params_data paramsData = { this->enc_idx };
@@ -1941,7 +2032,6 @@ pgconn_send_query_prepared(int argc, VALUE *argv, VALUE self)
1941
2032
 
1942
2033
  if(NIL_P(paramsData.params)) {
1943
2034
  paramsData.params = rb_ary_new2(0);
1944
- resultFormat = 0;
1945
2035
  }
1946
2036
  pgconn_query_assign_typemap( self, &paramsData );
1947
2037
 
@@ -1954,11 +2044,10 @@ pgconn_send_query_prepared(int argc, VALUE *argv, VALUE self)
1954
2044
 
1955
2045
  free_query_params( &paramsData );
1956
2046
 
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
- }
2047
+ if(result == 0)
2048
+ pg_raise_conn_error( rb_eUnableToSend, self, "%s", PQerrorMessage(this->pgconn));
2049
+
2050
+ pgconn_wait_for_flush( self );
1962
2051
  return Qnil;
1963
2052
  }
1964
2053
 
@@ -1972,14 +2061,12 @@ pgconn_send_query_prepared(int argc, VALUE *argv, VALUE self)
1972
2061
  static VALUE
1973
2062
  pgconn_send_describe_prepared(VALUE self, VALUE stmt_name)
1974
2063
  {
1975
- VALUE error;
1976
2064
  t_pg_connection *this = pg_get_connection_safe( self );
1977
2065
  /* 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
- }
2066
+ if(gvl_PQsendDescribePrepared(this->pgconn, pg_cstr_enc(stmt_name, this->enc_idx)) == 0)
2067
+ pg_raise_conn_error( rb_eUnableToSend, self, "%s", PQerrorMessage(this->pgconn));
2068
+
2069
+ pgconn_wait_for_flush( self );
1983
2070
  return Qnil;
1984
2071
  }
1985
2072
 
@@ -1994,36 +2081,18 @@ pgconn_send_describe_prepared(VALUE self, VALUE stmt_name)
1994
2081
  static VALUE
1995
2082
  pgconn_send_describe_portal(VALUE self, VALUE portal)
1996
2083
  {
1997
- VALUE error;
1998
2084
  t_pg_connection *this = pg_get_connection_safe( self );
1999
2085
  /* 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
- }
2086
+ if(gvl_PQsendDescribePortal(this->pgconn, pg_cstr_enc(portal, this->enc_idx)) == 0)
2087
+ pg_raise_conn_error( rb_eUnableToSend, self, "%s", PQerrorMessage(this->pgconn));
2088
+
2089
+ pgconn_wait_for_flush( self );
2005
2090
  return Qnil;
2006
2091
  }
2007
2092
 
2008
2093
 
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
2094
  static VALUE
2026
- pgconn_get_result(VALUE self)
2095
+ pgconn_sync_get_result(VALUE self)
2027
2096
  {
2028
2097
  PGconn *conn = pg_get_pgconn(self);
2029
2098
  PGresult *result;
@@ -2049,17 +2118,15 @@ pgconn_get_result(VALUE self)
2049
2118
  * or *notifies* to see if the state has changed.
2050
2119
  */
2051
2120
  static VALUE
2052
- pgconn_consume_input(self)
2053
- VALUE self;
2121
+ pgconn_consume_input(VALUE self)
2054
2122
  {
2055
- VALUE error;
2056
2123
  PGconn *conn = pg_get_pgconn(self);
2057
2124
  /* returns 0 on error */
2058
2125
  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);
2126
+ pgconn_close_socket_io(self);
2127
+ pg_raise_conn_error( rb_eConnectionBad, self, "%s", PQerrorMessage(conn));
2062
2128
  }
2129
+
2063
2130
  return Qnil;
2064
2131
  }
2065
2132
 
@@ -2068,37 +2135,18 @@ pgconn_consume_input(self)
2068
2135
  * conn.is_busy() -> Boolean
2069
2136
  *
2070
2137
  * Returns +true+ if a command is busy, that is, if
2071
- * PQgetResult would block. Otherwise returns +false+.
2138
+ * #get_result would block. Otherwise returns +false+.
2072
2139
  */
2073
2140
  static VALUE
2074
- pgconn_is_busy(self)
2075
- VALUE self;
2141
+ pgconn_is_busy(VALUE self)
2076
2142
  {
2077
2143
  return gvl_PQisBusy(pg_get_pgconn(self)) ? Qtrue : Qfalse;
2078
2144
  }
2079
2145
 
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
2146
  static VALUE
2097
- pgconn_setnonblocking(self, state)
2098
- VALUE self, state;
2147
+ pgconn_sync_setnonblocking(VALUE self, VALUE state)
2099
2148
  {
2100
2149
  int arg;
2101
- VALUE error;
2102
2150
  PGconn *conn = pg_get_pgconn(self);
2103
2151
  if(state == Qtrue)
2104
2152
  arg = 1;
@@ -2107,67 +2155,32 @@ pgconn_setnonblocking(self, state)
2107
2155
  else
2108
2156
  rb_raise(rb_eArgError, "Boolean value expected");
2109
2157
 
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
- }
2158
+ if(PQsetnonblocking(conn, arg) == -1)
2159
+ pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(conn));
2160
+
2115
2161
  return Qnil;
2116
2162
  }
2117
2163
 
2118
2164
 
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
2165
  static VALUE
2127
- pgconn_isnonblocking(self)
2128
- VALUE self;
2166
+ pgconn_sync_isnonblocking(VALUE self)
2129
2167
  {
2130
2168
  return PQisnonblocking(pg_get_pgconn(self)) ? Qtrue : Qfalse;
2131
2169
  }
2132
2170
 
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
2171
  static VALUE
2144
- pgconn_flush(self)
2145
- VALUE self;
2172
+ pgconn_sync_flush(VALUE self)
2146
2173
  {
2147
2174
  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
- }
2175
+ int ret = PQflush(conn);
2176
+ if(ret == -1)
2177
+ pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(conn));
2178
+
2156
2179
  return (ret) ? Qfalse : Qtrue;
2157
2180
  }
2158
2181
 
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
2182
  static VALUE
2170
- pgconn_cancel(VALUE self)
2183
+ pgconn_sync_cancel(VALUE self)
2171
2184
  {
2172
2185
  char errbuf[256];
2173
2186
  PGcancel *cancel;
@@ -2176,9 +2189,9 @@ pgconn_cancel(VALUE self)
2176
2189
 
2177
2190
  cancel = PQgetCancel(pg_get_pgconn(self));
2178
2191
  if(cancel == NULL)
2179
- rb_raise(rb_ePGerror,"Invalid connection!");
2192
+ pg_raise_conn_error( rb_ePGerror, self, "Invalid connection!");
2180
2193
 
2181
- ret = gvl_PQcancel(cancel, errbuf, 256);
2194
+ ret = gvl_PQcancel(cancel, errbuf, sizeof(errbuf));
2182
2195
  if(ret == 1)
2183
2196
  retval = Qnil;
2184
2197
  else
@@ -2229,55 +2242,63 @@ pgconn_notifies(VALUE self)
2229
2242
  return hash;
2230
2243
  }
2231
2244
 
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().
2245
+ #if defined(_WIN32)
2246
+
2247
+ /* We use a specialized implementation of rb_io_wait() on Windows.
2248
+ * This is because rb_io_wait() and rb_wait_for_single_fd() are very slow on Windows.
2237
2249
  */
2238
2250
 
2251
+ #if defined(HAVE_RUBY_FIBER_SCHEDULER_H)
2252
+ #include <ruby/fiber/scheduler.h>
2253
+ #endif
2254
+
2255
+ typedef enum {
2256
+ PG_RUBY_IO_READABLE = RB_WAITFD_IN,
2257
+ PG_RUBY_IO_WRITABLE = RB_WAITFD_OUT,
2258
+ PG_RUBY_IO_PRIORITY = RB_WAITFD_PRI,
2259
+ } pg_rb_io_event_t;
2260
+
2239
2261
  int rb_w32_wait_events( HANDLE *events, int num, DWORD timeout );
2240
2262
 
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;
2263
+ static VALUE
2264
+ pg_rb_thread_io_wait(VALUE io, VALUE events, VALUE timeout) {
2265
+ rb_io_t *fptr;
2266
+ struct timeval ptimeout;
2267
+
2246
2268
  struct timeval aborttime={0,0}, currtime, waittime;
2247
2269
  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");
2270
+ HANDLE hEvent = WSACreateEvent();
2253
2271
 
2254
- hEvent = WSACreateEvent();
2272
+ long rb_events = NUM2UINT(events);
2273
+ long w32_events = 0;
2274
+ DWORD wait_ret;
2255
2275
 
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
- }
2276
+ GetOpenFile((io), fptr);
2277
+ if( !NIL_P(timeout) ){
2278
+ ptimeout.tv_sec = (time_t)(NUM2DBL(timeout));
2279
+ ptimeout.tv_usec = (time_t)((NUM2DBL(timeout) - (double)ptimeout.tv_sec) * 1e6);
2261
2280
 
2262
- if ( ptimeout ) {
2263
2281
  gettimeofday(&currtime, NULL);
2264
- timeradd(&currtime, ptimeout, &aborttime);
2282
+ timeradd(&currtime, &ptimeout, &aborttime);
2265
2283
  }
2266
2284
 
2267
- while ( !(retval=is_readable(conn)) ) {
2268
- if ( WSAEventSelect(sd, hEvent, FD_READ|FD_CLOSE) == SOCKET_ERROR ) {
2285
+ if(rb_events & PG_RUBY_IO_READABLE) w32_events |= FD_READ | FD_ACCEPT | FD_CLOSE;
2286
+ if(rb_events & PG_RUBY_IO_WRITABLE) w32_events |= FD_WRITE | FD_CONNECT;
2287
+ if(rb_events & PG_RUBY_IO_PRIORITY) w32_events |= FD_OOB;
2288
+
2289
+ for(;;) {
2290
+ if ( WSAEventSelect(_get_osfhandle(fptr->fd), hEvent, w32_events) == SOCKET_ERROR ) {
2269
2291
  WSACloseEvent( hEvent );
2270
2292
  rb_raise( rb_eConnectionBad, "WSAEventSelect socket error: %d", WSAGetLastError() );
2271
2293
  }
2272
2294
 
2273
- if ( ptimeout ) {
2295
+ if ( !NIL_P(timeout) ) {
2274
2296
  gettimeofday(&currtime, NULL);
2275
2297
  timersub(&aborttime, &currtime, &waittime);
2276
2298
  timeout_milisec = (DWORD)( waittime.tv_sec * 1e3 + waittime.tv_usec / 1e3 );
2277
2299
  }
2278
2300
 
2279
- /* Is the given timeout valid? */
2280
- if( !ptimeout || (waittime.tv_sec >= 0 && waittime.tv_usec >= 0) ){
2301
+ if( NIL_P(timeout) || (waittime.tv_sec >= 0 && waittime.tv_usec >= 0) ){
2281
2302
  /* Wait for the socket to become readable before checking again */
2282
2303
  wait_ret = rb_w32_wait_events( &hEvent, 1, timeout_milisec );
2283
2304
  } else {
@@ -2286,9 +2307,11 @@ wait_socket_readable( PGconn *conn, struct timeval *ptimeout, void *(*is_readabl
2286
2307
 
2287
2308
  if ( wait_ret == WAIT_TIMEOUT ) {
2288
2309
  WSACloseEvent( hEvent );
2289
- return NULL;
2310
+ return UINT2NUM(0);
2290
2311
  } else if ( wait_ret == WAIT_OBJECT_0 ) {
2312
+ WSACloseEvent( hEvent );
2291
2313
  /* The event we were waiting for. */
2314
+ return UINT2NUM(rb_events);
2292
2315
  } else if ( wait_ret == WAIT_OBJECT_0 + 1) {
2293
2316
  /* This indicates interruption from timer thread, GC, exception
2294
2317
  * from other threads etc... */
@@ -2300,36 +2323,66 @@ wait_socket_readable( PGconn *conn, struct timeval *ptimeout, void *(*is_readabl
2300
2323
  WSACloseEvent( hEvent );
2301
2324
  rb_raise( rb_eConnectionBad, "Wait on socket abandoned (WaitForMultipleObjects)" );
2302
2325
  }
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
2326
  }
2327
+ }
2310
2328
 
2311
- WSACloseEvent( hEvent );
2312
- return retval;
2329
+ static VALUE
2330
+ pg_rb_io_wait(VALUE io, VALUE events, VALUE timeout) {
2331
+ #if defined(HAVE_RUBY_FIBER_SCHEDULER_H)
2332
+ /* We don't support Fiber.scheduler on Windows ruby-3.0 because there is no fast way to check whether a scheduler is active.
2333
+ * Fortunatelly ruby-3.1 offers a C-API for it.
2334
+ */
2335
+ VALUE scheduler = rb_fiber_scheduler_current();
2336
+
2337
+ if (!NIL_P(scheduler)) {
2338
+ return rb_io_wait(io, events, timeout);
2339
+ }
2340
+ #endif
2341
+ return pg_rb_thread_io_wait(io, events, timeout);
2313
2342
  }
2314
2343
 
2344
+ #elif defined(HAVE_RB_IO_WAIT)
2345
+
2346
+ /* Use our own function and constants names, to avoid conflicts with truffleruby-head on its road to ruby-3.0 compatibility. */
2347
+ #define pg_rb_io_wait rb_io_wait
2348
+ #define PG_RUBY_IO_READABLE RUBY_IO_READABLE
2349
+ #define PG_RUBY_IO_WRITABLE RUBY_IO_WRITABLE
2350
+ #define PG_RUBY_IO_PRIORITY RUBY_IO_PRIORITY
2351
+
2315
2352
  #else
2353
+ /* For compat with ruby < 3.0 */
2354
+
2355
+ typedef enum {
2356
+ PG_RUBY_IO_READABLE = RB_WAITFD_IN,
2357
+ PG_RUBY_IO_WRITABLE = RB_WAITFD_OUT,
2358
+ PG_RUBY_IO_PRIORITY = RB_WAITFD_PRI,
2359
+ } pg_rb_io_event_t;
2316
2360
 
2317
- /* non Win32 */
2361
+ static VALUE
2362
+ pg_rb_io_wait(VALUE io, VALUE events, VALUE timeout) {
2363
+ rb_io_t *fptr;
2364
+ struct timeval waittime;
2365
+ int res;
2366
+
2367
+ GetOpenFile((io), fptr);
2368
+ if( !NIL_P(timeout) ){
2369
+ waittime.tv_sec = (time_t)(NUM2DBL(timeout));
2370
+ waittime.tv_usec = (time_t)((NUM2DBL(timeout) - (double)waittime.tv_sec) * 1e6);
2371
+ }
2372
+ res = rb_wait_for_single_fd(fptr->fd, NUM2UINT(events), NIL_P(timeout) ? NULL : &waittime);
2373
+
2374
+ return UINT2NUM(res);
2375
+ }
2376
+ #endif
2318
2377
 
2319
2378
  static void *
2320
- wait_socket_readable( PGconn *conn, struct timeval *ptimeout, void *(*is_readable)(PGconn *))
2379
+ wait_socket_readable( VALUE self, struct timeval *ptimeout, void *(*is_readable)(PGconn *))
2321
2380
  {
2322
- int sd = PQsocket( conn );
2323
- int ret;
2381
+ VALUE ret;
2324
2382
  void *retval;
2325
2383
  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) );
2384
+ VALUE wait_timeout = Qnil;
2385
+ PGconn *conn = pg_get_pgconn(self);
2333
2386
 
2334
2387
  if ( ptimeout ) {
2335
2388
  gettimeofday(&currtime, NULL);
@@ -2340,36 +2393,80 @@ wait_socket_readable( PGconn *conn, struct timeval *ptimeout, void *(*is_readabl
2340
2393
  if ( ptimeout ) {
2341
2394
  gettimeofday(&currtime, NULL);
2342
2395
  timersub(&aborttime, &currtime, &waittime);
2396
+ wait_timeout = DBL2NUM((double)(waittime.tv_sec) + (double)(waittime.tv_usec) / 1000000.0);
2343
2397
  }
2344
2398
 
2345
2399
  /* Is the given timeout valid? */
2346
2400
  if( !ptimeout || (waittime.tv_sec >= 0 && waittime.tv_usec >= 0) ){
2401
+ VALUE socket_io;
2402
+
2403
+ /* before we wait for data, make sure everything has been sent */
2404
+ pgconn_async_flush(self);
2405
+ if ((retval=is_readable(conn)))
2406
+ return retval;
2407
+
2408
+ socket_io = pgconn_socket_io(self);
2347
2409
  /* Wait for the socket to become readable before checking again */
2348
- ret = rb_wait_for_single_fd( sd, RB_WAITFD_IN, ptimeout ? &waittime : NULL );
2410
+ ret = pg_rb_io_wait(socket_io, RB_INT2NUM(PG_RUBY_IO_READABLE), wait_timeout);
2349
2411
  } else {
2350
- ret = 0;
2351
- }
2352
-
2353
- if ( ret < 0 ){
2354
- rb_sys_fail( "rb_wait_for_single_fd()" );
2412
+ ret = Qfalse;
2355
2413
  }
2356
2414
 
2357
2415
  /* Return false if the select() timed out */
2358
- if ( ret == 0 ){
2416
+ if ( ret == Qfalse ){
2359
2417
  return NULL;
2360
2418
  }
2361
2419
 
2362
2420
  /* Check for connection errors (PQisBusy is true on connection errors) */
2363
2421
  if ( PQconsumeInput(conn) == 0 ){
2364
- rb_raise( rb_eConnectionBad, "PQconsumeInput() %s", PQerrorMessage(conn) );
2422
+ pgconn_close_socket_io(self);
2423
+ pg_raise_conn_error(rb_eConnectionBad, self, "PQconsumeInput() %s", PQerrorMessage(conn));
2365
2424
  }
2366
2425
  }
2367
2426
 
2368
2427
  return retval;
2369
2428
  }
2370
2429
 
2430
+ /*
2431
+ * call-seq:
2432
+ * conn.flush() -> Boolean
2433
+ *
2434
+ * Attempts to flush any queued output data to the server.
2435
+ * Returns +true+ if data is successfully flushed, +false+
2436
+ * if not. It can only return +false+ if connection is
2437
+ * in nonblocking mode.
2438
+ * Raises PG::Error if some other failure occurred.
2439
+ */
2440
+ static VALUE
2441
+ pgconn_async_flush(VALUE self)
2442
+ {
2443
+ while( pgconn_sync_flush(self) == Qfalse ){
2444
+ /* wait for the socket to become read- or write-ready */
2445
+ int events;
2446
+ VALUE socket_io = pgconn_socket_io(self);
2447
+ events = RB_NUM2INT(pg_rb_io_wait(socket_io, RB_INT2NUM(PG_RUBY_IO_READABLE | PG_RUBY_IO_WRITABLE), Qnil));
2371
2448
 
2372
- #endif
2449
+ if (events & PG_RUBY_IO_READABLE){
2450
+ pgconn_consume_input(self);
2451
+ }
2452
+ }
2453
+ return Qtrue;
2454
+ }
2455
+
2456
+ static VALUE
2457
+ pgconn_wait_for_flush( VALUE self ){
2458
+ if( !pg_get_connection_safe(self)->flush_data )
2459
+ return Qnil;
2460
+
2461
+ return pgconn_async_flush(self);
2462
+ }
2463
+
2464
+ static VALUE
2465
+ pgconn_flush_data_set( VALUE self, VALUE enabled ){
2466
+ t_pg_connection *conn = pg_get_connection(self);
2467
+ conn->flush_data = RTEST(enabled);
2468
+ return enabled;
2469
+ }
2373
2470
 
2374
2471
  static void *
2375
2472
  notify_readable(PGconn *conn)
@@ -2408,7 +2505,7 @@ pgconn_wait_for_notify(int argc, VALUE *argv, VALUE self)
2408
2505
  ptimeout = &timeout;
2409
2506
  }
2410
2507
 
2411
- pnotification = (PGnotify*) wait_socket_readable( this->pgconn, ptimeout, notify_readable);
2508
+ pnotification = (PGnotify*) wait_socket_readable( self, ptimeout, notify_readable);
2412
2509
 
2413
2510
  /* Return nil if the select timed out */
2414
2511
  if ( !pnotification ) return Qnil;
@@ -2429,28 +2526,8 @@ pgconn_wait_for_notify(int argc, VALUE *argv, VALUE self)
2429
2526
  }
2430
2527
 
2431
2528
 
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
2529
  static VALUE
2453
- pgconn_put_copy_data(int argc, VALUE *argv, VALUE self)
2530
+ pgconn_sync_put_copy_data(int argc, VALUE *argv, VALUE self)
2454
2531
  {
2455
2532
  int ret;
2456
2533
  int len;
@@ -2467,13 +2544,11 @@ pgconn_put_copy_data(int argc, VALUE *argv, VALUE self)
2467
2544
  if( NIL_P(this->encoder_for_put_copy_data) ){
2468
2545
  buffer = value;
2469
2546
  } else {
2470
- p_coder = DATA_PTR( this->encoder_for_put_copy_data );
2547
+ p_coder = RTYPEDDATA_DATA( this->encoder_for_put_copy_data );
2471
2548
  }
2472
- } else if( rb_obj_is_kind_of(encoder, rb_cPG_Coder) ) {
2473
- Data_Get_Struct( encoder, t_pg_coder, p_coder );
2474
2549
  } else {
2475
- rb_raise( rb_eTypeError, "wrong encoder type %s (expected some kind of PG::Coder)",
2476
- rb_obj_classname( encoder ) );
2550
+ /* Check argument type and use argument encoder */
2551
+ TypedData_Get_Struct(encoder, t_pg_coder, &pg_coder_type, p_coder);
2477
2552
  }
2478
2553
 
2479
2554
  if( p_coder ){
@@ -2496,36 +2571,19 @@ pgconn_put_copy_data(int argc, VALUE *argv, VALUE self)
2496
2571
  Check_Type(buffer, T_STRING);
2497
2572
 
2498
2573
  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
- }
2574
+ if(ret == -1)
2575
+ pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(this->pgconn));
2576
+
2504
2577
  RB_GC_GUARD(intermediate);
2505
2578
  RB_GC_GUARD(buffer);
2506
2579
 
2507
2580
  return (ret) ? Qtrue : Qfalse;
2508
2581
  }
2509
2582
 
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
2583
  static VALUE
2525
- pgconn_put_copy_end(int argc, VALUE *argv, VALUE self)
2584
+ pgconn_sync_put_copy_end(int argc, VALUE *argv, VALUE self)
2526
2585
  {
2527
2586
  VALUE str;
2528
- VALUE error;
2529
2587
  int ret;
2530
2588
  const char *error_message = NULL;
2531
2589
  t_pg_connection *this = pg_get_connection_safe( self );
@@ -2536,38 +2594,16 @@ pgconn_put_copy_end(int argc, VALUE *argv, VALUE self)
2536
2594
  error_message = pg_cstr_enc(str, this->enc_idx);
2537
2595
 
2538
2596
  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
- }
2597
+ if(ret == -1)
2598
+ pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(this->pgconn));
2599
+
2544
2600
  return (ret) ? Qtrue : Qfalse;
2545
2601
  }
2546
2602
 
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
2603
  static VALUE
2567
- pgconn_get_copy_data(int argc, VALUE *argv, VALUE self )
2604
+ pgconn_sync_get_copy_data(int argc, VALUE *argv, VALUE self )
2568
2605
  {
2569
2606
  VALUE async_in;
2570
- VALUE error;
2571
2607
  VALUE result;
2572
2608
  int ret;
2573
2609
  char *buffer;
@@ -2579,20 +2615,16 @@ pgconn_get_copy_data(int argc, VALUE *argv, VALUE self )
2579
2615
 
2580
2616
  if( NIL_P(decoder) ){
2581
2617
  if( !NIL_P(this->decoder_for_get_copy_data) ){
2582
- p_coder = DATA_PTR( this->decoder_for_get_copy_data );
2618
+ p_coder = RTYPEDDATA_DATA( this->decoder_for_get_copy_data );
2583
2619
  }
2584
- } else if( rb_obj_is_kind_of(decoder, rb_cPG_Coder) ) {
2585
- Data_Get_Struct( decoder, t_pg_coder, p_coder );
2586
2620
  } else {
2587
- rb_raise( rb_eTypeError, "wrong decoder type %s (expected some kind of PG::Coder)",
2588
- rb_obj_classname( decoder ) );
2621
+ /* Check argument type and use argument decoder */
2622
+ TypedData_Get_Struct(decoder, t_pg_coder, &pg_coder_type, p_coder);
2589
2623
  }
2590
2624
 
2591
2625
  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);
2626
+ if(ret == -2){ /* error */
2627
+ pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(this->pgconn));
2596
2628
  }
2597
2629
  if(ret == -1) { /* No data left */
2598
2630
  return Qnil;
@@ -2830,7 +2862,7 @@ notice_processor_proxy(void *arg, const char *message)
2830
2862
  * call-seq:
2831
2863
  * conn.set_notice_processor {|message| ... } -> Proc
2832
2864
  *
2833
- * See #set_notice_receiver for the desription of what this and the
2865
+ * See #set_notice_receiver for the description of what this and the
2834
2866
  * notice_processor methods do.
2835
2867
  *
2836
2868
  * This function takes a new block to act as the notice processor and returns
@@ -2884,68 +2916,27 @@ pgconn_get_client_encoding(VALUE self)
2884
2916
 
2885
2917
  /*
2886
2918
  * call-seq:
2887
- * conn.set_client_encoding( encoding )
2919
+ * conn.sync_set_client_encoding( encoding )
2888
2920
  *
2889
- * Sets the client encoding to the _encoding_ String.
2921
+ * This function has the same behavior as #async_set_client_encoding, but is implemented using the synchronous command processing API of libpq.
2922
+ * See #async_exec for the differences between the two API variants.
2923
+ * 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
2924
  */
2891
2925
  static VALUE
2892
- pgconn_set_client_encoding(VALUE self, VALUE str)
2926
+ pgconn_sync_set_client_encoding(VALUE self, VALUE str)
2893
2927
  {
2894
2928
  PGconn *conn = pg_get_pgconn( self );
2895
2929
 
2896
2930
  Check_Type(str, T_STRING);
2897
2931
 
2898
- if ( (gvl_PQsetClientEncoding(conn, StringValueCStr(str))) == -1 ) {
2899
- rb_raise(rb_ePGerror, "%s", PQerrorMessage(conn));
2900
- }
2932
+ if ( (gvl_PQsetClientEncoding(conn, StringValueCStr(str))) == -1 )
2933
+ pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(conn));
2934
+
2901
2935
  pgconn_set_internal_encoding_index( self );
2902
2936
 
2903
2937
  return Qnil;
2904
2938
  }
2905
2939
 
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
2940
 
2950
2941
  /*
2951
2942
  * call-seq:
@@ -3020,10 +3011,8 @@ get_result_readable(PGconn *conn)
3020
3011
  * If +true+ is returned, +conn.is_busy+ will return +false+
3021
3012
  * and +conn.get_result+ will not block.
3022
3013
  */
3023
- static VALUE
3014
+ VALUE
3024
3015
  pgconn_block( int argc, VALUE *argv, VALUE self ) {
3025
- PGconn *conn = pg_get_pgconn( self );
3026
-
3027
3016
  struct timeval timeout;
3028
3017
  struct timeval *ptimeout = NULL;
3029
3018
  VALUE timeout_in;
@@ -3037,7 +3026,7 @@ pgconn_block( int argc, VALUE *argv, VALUE self ) {
3037
3026
  ptimeout = &timeout;
3038
3027
  }
3039
3028
 
3040
- ret = wait_socket_readable( conn, ptimeout, get_result_readable);
3029
+ ret = wait_socket_readable( self, ptimeout, get_result_readable);
3041
3030
 
3042
3031
  if( !ret )
3043
3032
  return Qfalse;
@@ -3046,6 +3035,42 @@ pgconn_block( int argc, VALUE *argv, VALUE self ) {
3046
3035
  }
3047
3036
 
3048
3037
 
3038
+ /*
3039
+ * call-seq:
3040
+ * conn.sync_get_last_result( ) -> PG::Result
3041
+ *
3042
+ * This function has the same behavior as #async_get_last_result, but is implemented using the synchronous command processing API of libpq.
3043
+ * See #async_exec for the differences between the two API variants.
3044
+ * 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.
3045
+ */
3046
+ static VALUE
3047
+ pgconn_sync_get_last_result(VALUE self)
3048
+ {
3049
+ PGconn *conn = pg_get_pgconn(self);
3050
+ VALUE rb_pgresult = Qnil;
3051
+ PGresult *cur, *prev;
3052
+
3053
+
3054
+ cur = prev = NULL;
3055
+ while ((cur = gvl_PQgetResult(conn)) != NULL) {
3056
+ int status;
3057
+
3058
+ if (prev) PQclear(prev);
3059
+ prev = cur;
3060
+
3061
+ status = PQresultStatus(cur);
3062
+ if (status == PGRES_COPY_OUT || status == PGRES_COPY_IN || status == PGRES_COPY_BOTH)
3063
+ break;
3064
+ }
3065
+
3066
+ if (prev) {
3067
+ rb_pgresult = pg_new_result( prev, self );
3068
+ pg_result_check(rb_pgresult);
3069
+ }
3070
+
3071
+ return rb_pgresult;
3072
+ }
3073
+
3049
3074
  /*
3050
3075
  * call-seq:
3051
3076
  * conn.get_last_result( ) -> PG::Result
@@ -3056,27 +3081,36 @@ pgconn_block( int argc, VALUE *argv, VALUE self ) {
3056
3081
  * returns the last non-NULL result, or +nil+ if no
3057
3082
  * results are available.
3058
3083
  *
3084
+ * If the last result contains a bad result_status, an
3085
+ * appropriate exception is raised.
3086
+ *
3059
3087
  * This function is similar to #get_result
3060
3088
  * except that it is designed to get one and only
3061
- * one result.
3089
+ * one result and that it checks the result state.
3062
3090
  */
3063
3091
  static VALUE
3064
- pgconn_get_last_result(VALUE self)
3092
+ pgconn_async_get_last_result(VALUE self)
3065
3093
  {
3066
3094
  PGconn *conn = pg_get_pgconn(self);
3067
3095
  VALUE rb_pgresult = Qnil;
3068
3096
  PGresult *cur, *prev;
3069
3097
 
3070
-
3071
- cur = prev = NULL;
3072
- while ((cur = gvl_PQgetResult(conn)) != NULL) {
3098
+ cur = prev = NULL;
3099
+ for(;;) {
3073
3100
  int status;
3074
3101
 
3102
+ /* wait for input (without blocking) before reading each result */
3103
+ wait_socket_readable(self, NULL, get_result_readable);
3104
+
3105
+ cur = gvl_PQgetResult(conn);
3106
+ if (cur == NULL)
3107
+ break;
3108
+
3075
3109
  if (prev) PQclear(prev);
3076
3110
  prev = cur;
3077
3111
 
3078
3112
  status = PQresultStatus(cur);
3079
- if (status == PGRES_COPY_OUT || status == PGRES_COPY_IN)
3113
+ if (status == PGRES_COPY_OUT || status == PGRES_COPY_IN || status == PGRES_COPY_BOTH)
3080
3114
  break;
3081
3115
  }
3082
3116
 
@@ -3093,29 +3127,91 @@ pgconn_get_last_result(VALUE self)
3093
3127
  * conn.discard_results()
3094
3128
  *
3095
3129
  * Silently discard any prior query result that application didn't eat.
3096
- * This is done prior of Connection#exec and sibling methods and can
3097
- * be called explicitly when using the async API.
3130
+ * This is internally used prior to Connection#exec and sibling methods.
3131
+ * It doesn't raise an exception on connection errors, but returns +false+ instead.
3132
+ *
3133
+ * Returns:
3134
+ * * +nil+ when the connection is already idle
3135
+ * * +true+ when some results have been discarded
3136
+ * * +false+ when a failure occured and the connection was closed
3137
+ *
3098
3138
  */
3099
3139
  static VALUE
3100
3140
  pgconn_discard_results(VALUE self)
3101
3141
  {
3102
3142
  PGconn *conn = pg_get_pgconn(self);
3143
+ VALUE socket_io;
3144
+
3145
+ switch( PQtransactionStatus(conn) ) {
3146
+ case PQTRANS_IDLE:
3147
+ case PQTRANS_INTRANS:
3148
+ case PQTRANS_INERROR:
3149
+ return Qnil;
3150
+ default:;
3151
+ }
3103
3152
 
3104
- PGresult *cur;
3105
- while ((cur = gvl_PQgetResult(conn)) != NULL) {
3106
- int status = PQresultStatus(cur);
3153
+ socket_io = pgconn_socket_io(self);
3154
+
3155
+ for(;;) {
3156
+ PGresult *cur;
3157
+ int status;
3158
+
3159
+ /* pgconn_block() raises an exception in case of errors.
3160
+ * To avoid this call pg_rb_io_wait() and PQconsumeInput() without rb_raise().
3161
+ */
3162
+ while( gvl_PQisBusy(conn) ){
3163
+ int events;
3164
+
3165
+ switch( PQflush(conn) ) {
3166
+ case 1:
3167
+ events = RB_NUM2INT(pg_rb_io_wait(socket_io, RB_INT2NUM(PG_RUBY_IO_READABLE | PG_RUBY_IO_WRITABLE), Qnil));
3168
+ if (events & PG_RUBY_IO_READABLE){
3169
+ if ( PQconsumeInput(conn) == 0 ) goto error;
3170
+ }
3171
+ break;
3172
+ case 0:
3173
+ pg_rb_io_wait(socket_io, RB_INT2NUM(PG_RUBY_IO_READABLE), Qnil);
3174
+ if ( PQconsumeInput(conn) == 0 ) goto error;
3175
+ break;
3176
+ default:
3177
+ goto error;
3178
+ }
3179
+ }
3180
+
3181
+ cur = gvl_PQgetResult(conn);
3182
+ if( cur == NULL) break;
3183
+
3184
+ status = PQresultStatus(cur);
3107
3185
  PQclear(cur);
3108
3186
  if (status == PGRES_COPY_IN){
3109
- gvl_PQputCopyEnd(conn, "COPY terminated by new PQexec");
3187
+ while( gvl_PQputCopyEnd(conn, "COPY terminated by new query or discard_results") == 0 ){
3188
+ pgconn_async_flush(self);
3189
+ }
3110
3190
  }
3111
3191
  if (status == PGRES_COPY_OUT){
3112
- char *buffer = NULL;
3113
- while( gvl_PQgetCopyData(conn, &buffer, 0) > 0)
3114
- PQfreemem(buffer);
3192
+ for(;;) {
3193
+ char *buffer = NULL;
3194
+ int st = gvl_PQgetCopyData(conn, &buffer, 1);
3195
+ if( st == 0 ) {
3196
+ /* would block -> wait for readable data */
3197
+ pg_rb_io_wait(socket_io, RB_INT2NUM(PG_RUBY_IO_READABLE), Qnil);
3198
+ if ( PQconsumeInput(conn) == 0 ) goto error;
3199
+ } else if( st > 0 ) {
3200
+ /* some data retrieved -> discard it */
3201
+ PQfreemem(buffer);
3202
+ } else {
3203
+ /* no more data */
3204
+ break;
3205
+ }
3206
+ }
3115
3207
  }
3116
3208
  }
3117
3209
 
3118
- return Qnil;
3210
+ return Qtrue;
3211
+
3212
+ error:
3213
+ pgconn_close_socket_io(self);
3214
+ return Qfalse;
3119
3215
  }
3120
3216
 
3121
3217
  /*
@@ -3138,6 +3234,7 @@ pgconn_discard_results(VALUE self)
3138
3234
  * #exec is an alias for #async_exec which is almost identical to #sync_exec .
3139
3235
  * #sync_exec is implemented on the simpler synchronous command processing API of libpq, whereas
3140
3236
  * #async_exec is implemented on the asynchronous API and on ruby's IO mechanisms.
3237
+ * Only #async_exec is compatible to <tt>Fiber.scheduler</tt> based asynchronous IO processing introduced in ruby-3.0.
3141
3238
  * Both methods ensure that other threads can process while waiting for the server to
3142
3239
  * complete the request, but #sync_exec blocks all signals to be processed until the query is finished.
3143
3240
  * This is most notably visible by a delayed reaction to Control+C.
@@ -3152,8 +3249,7 @@ pgconn_async_exec(int argc, VALUE *argv, VALUE self)
3152
3249
 
3153
3250
  pgconn_discard_results( self );
3154
3251
  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 );
3252
+ rb_pgresult = pgconn_async_get_last_result( self );
3157
3253
 
3158
3254
  if ( rb_block_given_p() ) {
3159
3255
  return rb_ensure( rb_yield, rb_pgresult, pg_result_clear, rb_pgresult );
@@ -3182,7 +3278,7 @@ pgconn_async_exec(int argc, VALUE *argv, VALUE self)
3182
3278
  * or, it may be a String. If it is a string, that is equivalent to the hash:
3183
3279
  * { :value => <string value>, :type => 0, :format => 0 }
3184
3280
  *
3185
- * PostgreSQL bind parameters are represented as $1, $1, $2, etc.,
3281
+ * PostgreSQL bind parameters are represented as $1, $2, $3, etc.,
3186
3282
  * inside the SQL query. The 0th element of the +params+ array is bound
3187
3283
  * to $1, the 1st element is bound to $2, etc. +nil+ is treated as +NULL+.
3188
3284
  *
@@ -3225,8 +3321,7 @@ pgconn_async_exec_params(int argc, VALUE *argv, VALUE self)
3225
3321
  } else {
3226
3322
  pgconn_send_query_params( argc, argv, self );
3227
3323
  }
3228
- pgconn_block( 0, NULL, self ); /* wait for input (without blocking) before reading the last result */
3229
- rb_pgresult = pgconn_get_last_result( self );
3324
+ rb_pgresult = pgconn_async_get_last_result( self );
3230
3325
 
3231
3326
  if ( rb_block_given_p() ) {
3232
3327
  return rb_ensure( rb_yield, rb_pgresult, pg_result_clear, rb_pgresult );
@@ -3252,7 +3347,7 @@ pgconn_async_exec_params(int argc, VALUE *argv, VALUE self)
3252
3347
  *
3253
3348
  * For example: "SELECT $1::int"
3254
3349
  *
3255
- * PostgreSQL bind parameters are represented as $1, $1, $2, etc.,
3350
+ * PostgreSQL bind parameters are represented as $1, $2, $3, etc.,
3256
3351
  * inside the SQL query.
3257
3352
  *
3258
3353
  * See also corresponding {libpq function}[https://www.postgresql.org/docs/current/libpq-exec.html#LIBPQ-PQPREPARE].
@@ -3264,8 +3359,7 @@ pgconn_async_prepare(int argc, VALUE *argv, VALUE self)
3264
3359
 
3265
3360
  pgconn_discard_results( self );
3266
3361
  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 );
3362
+ rb_pgresult = pgconn_async_get_last_result( self );
3269
3363
 
3270
3364
  if ( rb_block_given_p() ) {
3271
3365
  return rb_ensure( rb_yield, rb_pgresult, pg_result_clear, rb_pgresult );
@@ -3292,7 +3386,7 @@ pgconn_async_prepare(int argc, VALUE *argv, VALUE self)
3292
3386
  * or, it may be a String. If it is a string, that is equivalent to the hash:
3293
3387
  * { :value => <string value>, :format => 0 }
3294
3388
  *
3295
- * PostgreSQL bind parameters are represented as $1, $1, $2, etc.,
3389
+ * PostgreSQL bind parameters are represented as $1, $2, $3, etc.,
3296
3390
  * inside the SQL query. The 0th element of the +params+ array is bound
3297
3391
  * to $1, the 1st element is bound to $2, etc. +nil+ is treated as +NULL+.
3298
3392
  *
@@ -3318,8 +3412,7 @@ pgconn_async_exec_prepared(int argc, VALUE *argv, VALUE self)
3318
3412
 
3319
3413
  pgconn_discard_results( self );
3320
3414
  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 );
3415
+ rb_pgresult = pgconn_async_get_last_result( self );
3323
3416
 
3324
3417
  if ( rb_block_given_p() ) {
3325
3418
  return rb_ensure( rb_yield, rb_pgresult, pg_result_clear, rb_pgresult );
@@ -3343,8 +3436,7 @@ pgconn_async_describe_portal(VALUE self, VALUE portal)
3343
3436
 
3344
3437
  pgconn_discard_results( self );
3345
3438
  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 );
3439
+ rb_pgresult = pgconn_async_get_last_result( self );
3348
3440
 
3349
3441
  if ( rb_block_given_p() ) {
3350
3442
  return rb_ensure( rb_yield, rb_pgresult, pg_result_clear, rb_pgresult );
@@ -3368,8 +3460,7 @@ pgconn_async_describe_prepared(VALUE self, VALUE stmt_name)
3368
3460
 
3369
3461
  pgconn_discard_results( self );
3370
3462
  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 );
3463
+ rb_pgresult = pgconn_async_get_last_result( self );
3373
3464
 
3374
3465
  if ( rb_block_given_p() ) {
3375
3466
  return rb_ensure( rb_yield, rb_pgresult, pg_result_clear, rb_pgresult );
@@ -3457,10 +3548,134 @@ pgconn_ssl_attribute_names(VALUE self)
3457
3548
  #endif
3458
3549
 
3459
3550
 
3551
+ #ifdef HAVE_PQENTERPIPELINEMODE
3552
+ /*
3553
+ * call-seq:
3554
+ * conn.pipeline_status -> Integer
3555
+ *
3556
+ * Returns the current pipeline mode status of the libpq connection.
3557
+ *
3558
+ * PQpipelineStatus can return one of the following values:
3559
+ *
3560
+ * * PQ_PIPELINE_ON - The libpq connection is in pipeline mode.
3561
+ * * PQ_PIPELINE_OFF - The libpq connection is not in pipeline mode.
3562
+ * * PQ_PIPELINE_ABORTED - The libpq connection is in pipeline mode and an error occurred while processing the current pipeline.
3563
+ * The aborted flag is cleared when PQgetResult returns a result of type PGRES_PIPELINE_SYNC.
3564
+ *
3565
+ * Available since PostgreSQL-14
3566
+ */
3567
+ static VALUE
3568
+ pgconn_pipeline_status(VALUE self)
3569
+ {
3570
+ int res = PQpipelineStatus(pg_get_pgconn(self));
3571
+ return INT2FIX(res);
3572
+ }
3573
+
3574
+
3575
+ /*
3576
+ * call-seq:
3577
+ * conn.enter_pipeline_mode -> nil
3578
+ *
3579
+ * Causes a connection to enter pipeline mode if it is currently idle or already in pipeline mode.
3580
+ *
3581
+ * 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.
3582
+ * This function does not actually send anything to the server, it just changes the libpq connection state.
3583
+ *
3584
+ * Available since PostgreSQL-14
3585
+ */
3586
+ static VALUE
3587
+ pgconn_enter_pipeline_mode(VALUE self)
3588
+ {
3589
+ PGconn *conn = pg_get_pgconn(self);
3590
+ int res = PQenterPipelineMode(conn);
3591
+ if( res != 1 )
3592
+ pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(conn));
3593
+
3594
+ return Qnil;
3595
+ }
3596
+
3597
+ /*
3598
+ * call-seq:
3599
+ * conn.exit_pipeline_mode -> nil
3600
+ *
3601
+ * Causes a connection to exit pipeline mode if it is currently in pipeline mode with an empty queue and no pending results.
3602
+ *
3603
+ * Takes no action if not in pipeline mode.
3604
+ * 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.
3605
+ *
3606
+ * Available since PostgreSQL-14
3607
+ */
3608
+ static VALUE
3609
+ pgconn_exit_pipeline_mode(VALUE self)
3610
+ {
3611
+ PGconn *conn = pg_get_pgconn(self);
3612
+ int res = PQexitPipelineMode(conn);
3613
+ if( res != 1 )
3614
+ pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(conn));
3615
+
3616
+ return Qnil;
3617
+ }
3618
+
3619
+
3620
+ /*
3621
+ * call-seq:
3622
+ * conn.pipeline_sync -> nil
3623
+ *
3624
+ * Marks a synchronization point in a pipeline by sending a sync message and flushing the send buffer.
3625
+ * This serves as the delimiter of an implicit transaction and an error recovery point; see Section 34.5.1.3 of the PostgreSQL documentation.
3626
+ *
3627
+ * Raises PG::Error if the connection is not in pipeline mode or sending a sync message failed.
3628
+ *
3629
+ * Available since PostgreSQL-14
3630
+ */
3631
+ static VALUE
3632
+ pgconn_pipeline_sync(VALUE self)
3633
+ {
3634
+ PGconn *conn = pg_get_pgconn(self);
3635
+ int res = PQpipelineSync(conn);
3636
+ if( res != 1 )
3637
+ pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(conn));
3638
+
3639
+ return Qnil;
3640
+ }
3641
+
3642
+ /*
3643
+ * call-seq:
3644
+ * conn.pipeline_sync -> nil
3645
+ *
3646
+ * Sends a request for the server to flush its output buffer.
3647
+ *
3648
+ * 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.
3649
+ * This function is useful to cause the server to flush its output buffer in pipeline mode without establishing a synchronization point.
3650
+ * Note that the request is not itself flushed to the server automatically; use Connection#flush if necessary.
3651
+ *
3652
+ * Available since PostgreSQL-14
3653
+ */
3654
+ static VALUE
3655
+ pgconn_send_flush_request(VALUE self)
3656
+ {
3657
+ PGconn *conn = pg_get_pgconn(self);
3658
+ int res = PQsendFlushRequest(conn);
3659
+ if( res != 1 )
3660
+ pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(conn));
3661
+
3662
+ return Qnil;
3663
+ }
3664
+
3665
+ #endif
3666
+
3460
3667
  /**************************************************************************
3461
3668
  * LARGE OBJECT SUPPORT
3462
3669
  **************************************************************************/
3463
3670
 
3671
+ #define BLOCKING_BEGIN(conn) do { \
3672
+ int old_nonblocking = PQisnonblocking(conn); \
3673
+ PQsetnonblocking(conn, 0);
3674
+
3675
+ #define BLOCKING_END(th) \
3676
+ PQsetnonblocking(conn, old_nonblocking); \
3677
+ } while(0);
3678
+
3464
3679
  /*
3465
3680
  * call-seq:
3466
3681
  * conn.lo_creat( [mode] ) -> Integer
@@ -3481,9 +3696,12 @@ pgconn_locreat(int argc, VALUE *argv, VALUE self)
3481
3696
  else
3482
3697
  mode = NUM2INT(nmode);
3483
3698
 
3484
- lo_oid = lo_creat(conn, mode);
3699
+ BLOCKING_BEGIN(conn)
3700
+ lo_oid = lo_creat(conn, mode);
3701
+ BLOCKING_END(conn)
3702
+
3485
3703
  if (lo_oid == 0)
3486
- rb_raise(rb_ePGerror, "lo_creat failed");
3704
+ pg_raise_conn_error( rb_ePGerror, self, "lo_creat failed");
3487
3705
 
3488
3706
  return UINT2NUM(lo_oid);
3489
3707
  }
@@ -3504,7 +3722,7 @@ pgconn_locreate(VALUE self, VALUE in_lo_oid)
3504
3722
 
3505
3723
  ret = lo_create(conn, lo_oid);
3506
3724
  if (ret == InvalidOid)
3507
- rb_raise(rb_ePGerror, "lo_create failed");
3725
+ pg_raise_conn_error( rb_ePGerror, self, "lo_create failed");
3508
3726
 
3509
3727
  return UINT2NUM(ret);
3510
3728
  }
@@ -3526,9 +3744,12 @@ pgconn_loimport(VALUE self, VALUE filename)
3526
3744
 
3527
3745
  Check_Type(filename, T_STRING);
3528
3746
 
3529
- lo_oid = lo_import(conn, StringValueCStr(filename));
3747
+ BLOCKING_BEGIN(conn)
3748
+ lo_oid = lo_import(conn, StringValueCStr(filename));
3749
+ BLOCKING_END(conn)
3750
+
3530
3751
  if (lo_oid == 0) {
3531
- rb_raise(rb_ePGerror, "%s", PQerrorMessage(conn));
3752
+ pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(conn));
3532
3753
  }
3533
3754
  return UINT2NUM(lo_oid);
3534
3755
  }
@@ -3544,12 +3765,17 @@ pgconn_loexport(VALUE self, VALUE lo_oid, VALUE filename)
3544
3765
  {
3545
3766
  PGconn *conn = pg_get_pgconn(self);
3546
3767
  Oid oid;
3768
+ int ret;
3547
3769
  Check_Type(filename, T_STRING);
3548
3770
 
3549
3771
  oid = NUM2UINT(lo_oid);
3550
3772
 
3551
- if (lo_export(conn, oid, StringValueCStr(filename)) < 0) {
3552
- rb_raise(rb_ePGerror, "%s", PQerrorMessage(conn));
3773
+ BLOCKING_BEGIN(conn)
3774
+ ret = lo_export(conn, oid, StringValueCStr(filename));
3775
+ BLOCKING_END(conn)
3776
+
3777
+ if (ret < 0) {
3778
+ pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(conn));
3553
3779
  }
3554
3780
  return Qnil;
3555
3781
  }
@@ -3579,8 +3805,12 @@ pgconn_loopen(int argc, VALUE *argv, VALUE self)
3579
3805
  else
3580
3806
  mode = NUM2INT(nmode);
3581
3807
 
3582
- if((fd = lo_open(conn, lo_oid, mode)) < 0) {
3583
- rb_raise(rb_ePGerror, "can't open large object: %s", PQerrorMessage(conn));
3808
+ BLOCKING_BEGIN(conn)
3809
+ fd = lo_open(conn, lo_oid, mode);
3810
+ BLOCKING_END(conn)
3811
+
3812
+ if(fd < 0) {
3813
+ pg_raise_conn_error( rb_ePGerror, self, "can't open large object: %s", PQerrorMessage(conn));
3584
3814
  }
3585
3815
  return INT2FIX(fd);
3586
3816
  }
@@ -3602,11 +3832,15 @@ pgconn_lowrite(VALUE self, VALUE in_lo_desc, VALUE buffer)
3602
3832
  Check_Type(buffer, T_STRING);
3603
3833
 
3604
3834
  if( RSTRING_LEN(buffer) < 0) {
3605
- rb_raise(rb_ePGerror, "write buffer zero string");
3835
+ pg_raise_conn_error( rb_ePGerror, self, "write buffer zero string");
3606
3836
  }
3607
- if((n = lo_write(conn, fd, StringValuePtr(buffer),
3608
- RSTRING_LEN(buffer))) < 0) {
3609
- rb_raise(rb_ePGerror, "lo_write failed: %s", PQerrorMessage(conn));
3837
+ BLOCKING_BEGIN(conn)
3838
+ n = lo_write(conn, fd, StringValuePtr(buffer),
3839
+ RSTRING_LEN(buffer));
3840
+ BLOCKING_END(conn)
3841
+
3842
+ if(n < 0) {
3843
+ pg_raise_conn_error( rb_ePGerror, self, "lo_write failed: %s", PQerrorMessage(conn));
3610
3844
  }
3611
3845
 
3612
3846
  return INT2FIX(n);
@@ -3629,16 +3863,17 @@ pgconn_loread(VALUE self, VALUE in_lo_desc, VALUE in_len)
3629
3863
  VALUE str;
3630
3864
  char *buffer;
3631
3865
 
3632
- buffer = ALLOC_N(char, len);
3633
- if(buffer == NULL)
3634
- rb_raise(rb_eNoMemError, "ALLOC failed!");
3866
+ if (len < 0)
3867
+ pg_raise_conn_error( rb_ePGerror, self, "negative length %d given", len);
3635
3868
 
3636
- if (len < 0){
3637
- rb_raise(rb_ePGerror,"nagative length %d given", len);
3638
- }
3869
+ buffer = ALLOC_N(char, len);
3639
3870
 
3640
- if((ret = lo_read(conn, lo_desc, buffer, len)) < 0)
3641
- rb_raise(rb_ePGerror, "lo_read failed");
3871
+ BLOCKING_BEGIN(conn)
3872
+ ret = lo_read(conn, lo_desc, buffer, len);
3873
+ BLOCKING_END(conn)
3874
+
3875
+ if(ret < 0)
3876
+ pg_raise_conn_error( rb_ePGerror, self, "lo_read failed");
3642
3877
 
3643
3878
  if(ret == 0) {
3644
3879
  xfree(buffer);
@@ -3667,8 +3902,12 @@ pgconn_lolseek(VALUE self, VALUE in_lo_desc, VALUE offset, VALUE whence)
3667
3902
  int lo_desc = NUM2INT(in_lo_desc);
3668
3903
  int ret;
3669
3904
 
3670
- if((ret = lo_lseek(conn, lo_desc, NUM2INT(offset), NUM2INT(whence))) < 0) {
3671
- rb_raise(rb_ePGerror, "lo_lseek failed");
3905
+ BLOCKING_BEGIN(conn)
3906
+ ret = lo_lseek(conn, lo_desc, NUM2INT(offset), NUM2INT(whence));
3907
+ BLOCKING_END(conn)
3908
+
3909
+ if(ret < 0) {
3910
+ pg_raise_conn_error( rb_ePGerror, self, "lo_lseek failed");
3672
3911
  }
3673
3912
 
3674
3913
  return INT2FIX(ret);
@@ -3687,8 +3926,12 @@ pgconn_lotell(VALUE self, VALUE in_lo_desc)
3687
3926
  PGconn *conn = pg_get_pgconn(self);
3688
3927
  int lo_desc = NUM2INT(in_lo_desc);
3689
3928
 
3690
- if((position = lo_tell(conn, lo_desc)) < 0)
3691
- rb_raise(rb_ePGerror,"lo_tell failed");
3929
+ BLOCKING_BEGIN(conn)
3930
+ position = lo_tell(conn, lo_desc);
3931
+ BLOCKING_END(conn)
3932
+
3933
+ if(position < 0)
3934
+ pg_raise_conn_error( rb_ePGerror, self, "lo_tell failed");
3692
3935
 
3693
3936
  return INT2FIX(position);
3694
3937
  }
@@ -3705,9 +3948,14 @@ pgconn_lotruncate(VALUE self, VALUE in_lo_desc, VALUE in_len)
3705
3948
  PGconn *conn = pg_get_pgconn(self);
3706
3949
  int lo_desc = NUM2INT(in_lo_desc);
3707
3950
  size_t len = NUM2INT(in_len);
3951
+ int ret;
3708
3952
 
3709
- if(lo_truncate(conn,lo_desc,len) < 0)
3710
- rb_raise(rb_ePGerror,"lo_truncate failed");
3953
+ BLOCKING_BEGIN(conn)
3954
+ ret = lo_truncate(conn,lo_desc,len);
3955
+ BLOCKING_END(conn)
3956
+
3957
+ if(ret < 0)
3958
+ pg_raise_conn_error( rb_ePGerror, self, "lo_truncate failed");
3711
3959
 
3712
3960
  return Qnil;
3713
3961
  }
@@ -3723,9 +3971,14 @@ pgconn_loclose(VALUE self, VALUE in_lo_desc)
3723
3971
  {
3724
3972
  PGconn *conn = pg_get_pgconn(self);
3725
3973
  int lo_desc = NUM2INT(in_lo_desc);
3974
+ int ret;
3975
+
3976
+ BLOCKING_BEGIN(conn)
3977
+ ret = lo_close(conn,lo_desc);
3978
+ BLOCKING_END(conn)
3726
3979
 
3727
- if(lo_close(conn,lo_desc) < 0)
3728
- rb_raise(rb_ePGerror,"lo_close failed");
3980
+ if(ret < 0)
3981
+ pg_raise_conn_error( rb_ePGerror, self, "lo_close failed");
3729
3982
 
3730
3983
  return Qnil;
3731
3984
  }
@@ -3741,9 +3994,14 @@ pgconn_lounlink(VALUE self, VALUE in_oid)
3741
3994
  {
3742
3995
  PGconn *conn = pg_get_pgconn(self);
3743
3996
  Oid oid = NUM2UINT(in_oid);
3997
+ int ret;
3998
+
3999
+ BLOCKING_BEGIN(conn)
4000
+ ret = lo_unlink(conn,oid);
4001
+ BLOCKING_END(conn)
3744
4002
 
3745
- if(lo_unlink(conn,oid) < 0)
3746
- rb_raise(rb_ePGerror,"lo_unlink failed");
4003
+ if(ret < 0)
4004
+ pg_raise_conn_error( rb_ePGerror, self, "lo_unlink failed");
3747
4005
 
3748
4006
  return Qnil;
3749
4007
  }
@@ -3801,11 +4059,11 @@ static VALUE
3801
4059
  pgconn_internal_encoding_set(VALUE self, VALUE enc)
3802
4060
  {
3803
4061
  if (NIL_P(enc)) {
3804
- pgconn_set_client_encoding( self, rb_usascii_str_new_cstr("SQL_ASCII") );
4062
+ pgconn_sync_set_client_encoding( self, rb_usascii_str_new_cstr("SQL_ASCII") );
3805
4063
  return enc;
3806
4064
  }
3807
4065
  else if ( TYPE(enc) == T_STRING && strcasecmp("JOHAB", StringValueCStr(enc)) == 0 ) {
3808
- pgconn_set_client_encoding(self, rb_usascii_str_new_cstr("JOHAB"));
4066
+ pgconn_sync_set_client_encoding(self, rb_usascii_str_new_cstr("JOHAB"));
3809
4067
  return enc;
3810
4068
  }
3811
4069
  else {
@@ -3843,16 +4101,33 @@ pgconn_external_encoding(VALUE self)
3843
4101
  return rb_enc_from_encoding( enc );
3844
4102
  }
3845
4103
 
4104
+ /*
4105
+ * call-seq:
4106
+ * conn.set_client_encoding( encoding )
4107
+ *
4108
+ * Sets the client encoding to the _encoding_ String.
4109
+ */
4110
+ static VALUE
4111
+ pgconn_async_set_client_encoding(VALUE self, VALUE encname)
4112
+ {
4113
+ VALUE query_format, query;
4114
+
4115
+ Check_Type(encname, T_STRING);
4116
+ query_format = rb_str_new_cstr("set client_encoding to '%s'");
4117
+ query = rb_funcall(query_format, rb_intern("%"), 1, encname);
4118
+
4119
+ pgconn_async_exec(1, &query, self);
4120
+ pgconn_set_internal_encoding_index( self );
4121
+
4122
+ return Qnil;
4123
+ }
3846
4124
 
3847
4125
  static VALUE
3848
4126
  pgconn_set_client_encoding_async1( VALUE args )
3849
4127
  {
3850
4128
  VALUE self = ((VALUE*)args)[0];
3851
4129
  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);
4130
+ pgconn_async_set_client_encoding(self, encname);
3856
4131
  return 0;
3857
4132
  }
3858
4133
 
@@ -3867,9 +4142,9 @@ pgconn_set_client_encoding_async2( VALUE arg, VALUE ex )
3867
4142
 
3868
4143
 
3869
4144
  static VALUE
3870
- pgconn_set_client_encoding_async( VALUE self, const char *encname )
4145
+ pgconn_set_client_encoding_async( VALUE self, VALUE encname )
3871
4146
  {
3872
- VALUE args[] = { self, rb_str_new_cstr(encname) };
4147
+ VALUE args[] = { self, encname };
3873
4148
  return rb_rescue(pgconn_set_client_encoding_async1, (VALUE)&args, pgconn_set_client_encoding_async2, Qnil);
3874
4149
  }
3875
4150
 
@@ -3891,10 +4166,9 @@ pgconn_set_default_encoding( VALUE self )
3891
4166
 
3892
4167
  if (( enc = rb_default_internal_encoding() )) {
3893
4168
  encname = pg_get_rb_encoding_as_pg_encoding( enc );
3894
- if ( pgconn_set_client_encoding_async(self, encname) != 0 )
4169
+ if ( pgconn_set_client_encoding_async(self, rb_str_new_cstr(encname)) != 0 )
3895
4170
  rb_warning( "Failed to set the default_internal encoding to %s: '%s'",
3896
4171
  encname, PQerrorMessage(conn) );
3897
- pgconn_set_internal_encoding_index( self );
3898
4172
  return rb_enc_from_encoding( enc );
3899
4173
  } else {
3900
4174
  pgconn_set_internal_encoding_index( self );
@@ -3916,12 +4190,12 @@ static VALUE
3916
4190
  pgconn_type_map_for_queries_set(VALUE self, VALUE typemap)
3917
4191
  {
3918
4192
  t_pg_connection *this = pg_get_connection( self );
4193
+ t_typemap *tm;
4194
+ UNUSED(tm);
4195
+
4196
+ /* Check type of method param */
4197
+ TypedData_Get_Struct(typemap, t_typemap, &pg_typemap_type, tm);
3919
4198
 
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
4199
  this->type_map_for_queries = typemap;
3926
4200
 
3927
4201
  return typemap;
@@ -3956,12 +4230,10 @@ static VALUE
3956
4230
  pgconn_type_map_for_results_set(VALUE self, VALUE typemap)
3957
4231
  {
3958
4232
  t_pg_connection *this = pg_get_connection( self );
4233
+ t_typemap *tm;
4234
+ UNUSED(tm);
3959
4235
 
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);
4236
+ TypedData_Get_Struct(typemap, t_typemap, &pg_typemap_type, tm);
3965
4237
  this->type_map_for_results = typemap;
3966
4238
 
3967
4239
  return typemap;
@@ -3996,20 +4268,19 @@ pgconn_type_map_for_results_get(VALUE self)
3996
4268
  *
3997
4269
  */
3998
4270
  static VALUE
3999
- pgconn_encoder_for_put_copy_data_set(VALUE self, VALUE typemap)
4271
+ pgconn_encoder_for_put_copy_data_set(VALUE self, VALUE encoder)
4000
4272
  {
4001
4273
  t_pg_connection *this = pg_get_connection( self );
4002
4274
 
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);
4275
+ if( encoder != Qnil ){
4276
+ t_pg_coder *co;
4277
+ UNUSED(co);
4278
+ /* Check argument type */
4279
+ TypedData_Get_Struct(encoder, t_pg_coder, &pg_coder_type, co);
4009
4280
  }
4010
- this->encoder_for_put_copy_data = typemap;
4281
+ this->encoder_for_put_copy_data = encoder;
4011
4282
 
4012
- return typemap;
4283
+ return encoder;
4013
4284
  }
4014
4285
 
4015
4286
  /*
@@ -4045,20 +4316,19 @@ pgconn_encoder_for_put_copy_data_get(VALUE self)
4045
4316
  *
4046
4317
  */
4047
4318
  static VALUE
4048
- pgconn_decoder_for_get_copy_data_set(VALUE self, VALUE typemap)
4319
+ pgconn_decoder_for_get_copy_data_set(VALUE self, VALUE decoder)
4049
4320
  {
4050
4321
  t_pg_connection *this = pg_get_connection( self );
4051
4322
 
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);
4323
+ if( decoder != Qnil ){
4324
+ t_pg_coder *co;
4325
+ UNUSED(co);
4326
+ /* Check argument type */
4327
+ TypedData_Get_Struct(decoder, t_pg_coder, &pg_coder_type, co);
4058
4328
  }
4059
- this->decoder_for_get_copy_data = typemap;
4329
+ this->decoder_for_get_copy_data = decoder;
4060
4330
 
4061
- return typemap;
4331
+ return decoder;
4062
4332
  }
4063
4333
 
4064
4334
  /*
@@ -4138,9 +4408,10 @@ pgconn_field_name_type_get(VALUE self)
4138
4408
  * Document-class: PG::Connection
4139
4409
  */
4140
4410
  void
4141
- init_pg_connection()
4411
+ init_pg_connection(void)
4142
4412
  {
4143
4413
  s_id_encode = rb_intern("encode");
4414
+ s_id_autoclose_set = rb_intern("autoclose=");
4144
4415
  sym_type = ID2SYM(rb_intern("type"));
4145
4416
  sym_format = ID2SYM(rb_intern("format"));
4146
4417
  sym_value = ID2SYM(rb_intern("value"));
@@ -4156,10 +4427,6 @@ init_pg_connection()
4156
4427
  /****** PG::Connection CLASS METHODS ******/
4157
4428
  rb_define_alloc_func( rb_cPGconn, pgconn_s_allocate );
4158
4429
 
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
4430
  rb_define_singleton_method(rb_cPGconn, "escape_string", pgconn_s_escape, 1);
4164
4431
  SINGLETON_ALIAS(rb_cPGconn, "escape", "escape_string");
4165
4432
  rb_define_singleton_method(rb_cPGconn, "escape_bytea", pgconn_s_escape_bytea, 1);
@@ -4168,14 +4435,15 @@ init_pg_connection()
4168
4435
  rb_define_singleton_method(rb_cPGconn, "quote_ident", pgconn_s_quote_ident, 1);
4169
4436
  rb_define_singleton_method(rb_cPGconn, "connect_start", pgconn_s_connect_start, -1);
4170
4437
  rb_define_singleton_method(rb_cPGconn, "conndefaults", pgconn_s_conndefaults, 0);
4171
- rb_define_singleton_method(rb_cPGconn, "ping", pgconn_s_ping, -1);
4438
+ rb_define_singleton_method(rb_cPGconn, "conninfo_parse", pgconn_s_conninfo_parse, 1);
4439
+ rb_define_singleton_method(rb_cPGconn, "sync_ping", pgconn_s_sync_ping, -1);
4440
+ rb_define_singleton_method(rb_cPGconn, "sync_connect", pgconn_s_sync_connect, -1);
4172
4441
 
4173
4442
  /****** PG::Connection INSTANCE METHODS: Connection Control ******/
4174
- rb_define_method(rb_cPGconn, "initialize", pgconn_init, -1);
4175
4443
  rb_define_method(rb_cPGconn, "connect_poll", pgconn_connect_poll, 0);
4176
4444
  rb_define_method(rb_cPGconn, "finish", pgconn_finish, 0);
4177
4445
  rb_define_method(rb_cPGconn, "finished?", pgconn_finished_p, 0);
4178
- rb_define_method(rb_cPGconn, "reset", pgconn_reset, 0);
4446
+ rb_define_method(rb_cPGconn, "sync_reset", pgconn_sync_reset, 0);
4179
4447
  rb_define_method(rb_cPGconn, "reset_start", pgconn_reset_start, 0);
4180
4448
  rb_define_method(rb_cPGconn, "reset_poll", pgconn_reset_poll, 0);
4181
4449
  rb_define_alias(rb_cPGconn, "close", "finish");
@@ -4185,11 +4453,12 @@ init_pg_connection()
4185
4453
  rb_define_method(rb_cPGconn, "user", pgconn_user, 0);
4186
4454
  rb_define_method(rb_cPGconn, "pass", pgconn_pass, 0);
4187
4455
  rb_define_method(rb_cPGconn, "host", pgconn_host, 0);
4456
+ #if defined(HAVE_PQRESULTMEMORYSIZE)
4457
+ rb_define_method(rb_cPGconn, "hostaddr", pgconn_hostaddr, 0);
4458
+ #endif
4188
4459
  rb_define_method(rb_cPGconn, "port", pgconn_port, 0);
4189
4460
  rb_define_method(rb_cPGconn, "tty", pgconn_tty, 0);
4190
- #ifdef HAVE_PQCONNINFO
4191
4461
  rb_define_method(rb_cPGconn, "conninfo", pgconn_conninfo, 0);
4192
- #endif
4193
4462
  rb_define_method(rb_cPGconn, "options", pgconn_options, 0);
4194
4463
  rb_define_method(rb_cPGconn, "status", pgconn_status, 0);
4195
4464
  rb_define_method(rb_cPGconn, "transaction_status", pgconn_transaction_status, 0);
@@ -4200,17 +4469,18 @@ init_pg_connection()
4200
4469
  rb_define_method(rb_cPGconn, "socket", pgconn_socket, 0);
4201
4470
  rb_define_method(rb_cPGconn, "socket_io", pgconn_socket_io, 0);
4202
4471
  rb_define_method(rb_cPGconn, "backend_pid", pgconn_backend_pid, 0);
4472
+ rb_define_method(rb_cPGconn, "backend_key", pgconn_backend_key, 0);
4203
4473
  rb_define_method(rb_cPGconn, "connection_needs_password", pgconn_connection_needs_password, 0);
4204
4474
  rb_define_method(rb_cPGconn, "connection_used_password", pgconn_connection_used_password, 0);
4205
4475
  /* rb_define_method(rb_cPGconn, "getssl", pgconn_getssl, 0); */
4206
4476
 
4207
4477
  /****** 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);
4478
+ rb_define_method(rb_cPGconn, "sync_exec", pgconn_sync_exec, -1);
4479
+ rb_define_method(rb_cPGconn, "sync_exec_params", pgconn_sync_exec_params, -1);
4480
+ rb_define_method(rb_cPGconn, "sync_prepare", pgconn_sync_prepare, -1);
4481
+ rb_define_method(rb_cPGconn, "sync_exec_prepared", pgconn_sync_exec_prepared, -1);
4482
+ rb_define_method(rb_cPGconn, "sync_describe_prepared", pgconn_sync_describe_prepared, 1);
4483
+ rb_define_method(rb_cPGconn, "sync_describe_portal", pgconn_sync_describe_portal, 1);
4214
4484
 
4215
4485
  rb_define_method(rb_cPGconn, "exec", pgconn_async_exec, -1);
4216
4486
  rb_define_method(rb_cPGconn, "exec_params", pgconn_async_exec_params, -1);
@@ -4243,25 +4513,26 @@ init_pg_connection()
4243
4513
  rb_define_method(rb_cPGconn, "send_query_prepared", pgconn_send_query_prepared, -1);
4244
4514
  rb_define_method(rb_cPGconn, "send_describe_prepared", pgconn_send_describe_prepared, 1);
4245
4515
  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);
4516
+ rb_define_method(rb_cPGconn, "sync_get_result", pgconn_sync_get_result, 0);
4247
4517
  rb_define_method(rb_cPGconn, "consume_input", pgconn_consume_input, 0);
4248
4518
  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);
4519
+ rb_define_method(rb_cPGconn, "sync_setnonblocking", pgconn_sync_setnonblocking, 1);
4520
+ rb_define_method(rb_cPGconn, "sync_isnonblocking", pgconn_sync_isnonblocking, 0);
4521
+ rb_define_method(rb_cPGconn, "sync_flush", pgconn_sync_flush, 0);
4522
+ rb_define_method(rb_cPGconn, "flush", pgconn_async_flush, 0);
4523
+ rb_define_alias(rb_cPGconn, "async_flush", "flush");
4253
4524
  rb_define_method(rb_cPGconn, "discard_results", pgconn_discard_results, 0);
4254
4525
 
4255
4526
  /****** PG::Connection INSTANCE METHODS: Cancelling Queries in Progress ******/
4256
- rb_define_method(rb_cPGconn, "cancel", pgconn_cancel, 0);
4527
+ rb_define_method(rb_cPGconn, "sync_cancel", pgconn_sync_cancel, 0);
4257
4528
 
4258
4529
  /****** PG::Connection INSTANCE METHODS: NOTIFY ******/
4259
4530
  rb_define_method(rb_cPGconn, "notifies", pgconn_notifies, 0);
4260
4531
 
4261
4532
  /****** 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);
4533
+ rb_define_method(rb_cPGconn, "sync_put_copy_data", pgconn_sync_put_copy_data, -1);
4534
+ rb_define_method(rb_cPGconn, "sync_put_copy_end", pgconn_sync_put_copy_end, -1);
4535
+ rb_define_method(rb_cPGconn, "sync_get_copy_data", pgconn_sync_get_copy_data, -1);
4265
4536
 
4266
4537
  /****** PG::Connection INSTANCE METHODS: Control Functions ******/
4267
4538
  rb_define_method(rb_cPGconn, "set_error_verbosity", pgconn_set_error_verbosity, 1);
@@ -4277,16 +4548,20 @@ init_pg_connection()
4277
4548
 
4278
4549
  /****** PG::Connection INSTANCE METHODS: Other ******/
4279
4550
  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);
4551
+ rb_define_method(rb_cPGconn, "sync_set_client_encoding", pgconn_sync_set_client_encoding, 1);
4552
+ rb_define_method(rb_cPGconn, "set_client_encoding", pgconn_async_set_client_encoding, 1);
4553
+ rb_define_alias(rb_cPGconn, "async_set_client_encoding", "set_client_encoding");
4281
4554
  rb_define_alias(rb_cPGconn, "client_encoding=", "set_client_encoding");
4282
- rb_define_method(rb_cPGconn, "transaction", pgconn_transaction, 0);
4283
4555
  rb_define_method(rb_cPGconn, "block", pgconn_block, -1);
4556
+ rb_define_private_method(rb_cPGconn, "flush_data=", pgconn_flush_data_set, 1);
4284
4557
  rb_define_method(rb_cPGconn, "wait_for_notify", pgconn_wait_for_notify, -1);
4285
4558
  rb_define_alias(rb_cPGconn, "notifies_wait", "wait_for_notify");
4286
4559
  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);
4560
+ rb_define_method(rb_cPGconn, "sync_get_last_result", pgconn_sync_get_last_result, 0);
4561
+ rb_define_method(rb_cPGconn, "get_last_result", pgconn_async_get_last_result, 0);
4562
+ rb_define_alias(rb_cPGconn, "async_get_last_result", "get_last_result");
4288
4563
  #ifdef HAVE_PQENCRYPTPASSWORDCONN
4289
- rb_define_method(rb_cPGconn, "encrypt_password", pgconn_encrypt_password, -1);
4564
+ rb_define_method(rb_cPGconn, "sync_encrypt_password", pgconn_sync_encrypt_password, -1);
4290
4565
  #endif
4291
4566
 
4292
4567
  #ifdef HAVE_PQSSLATTRIBUTE
@@ -4295,6 +4570,14 @@ init_pg_connection()
4295
4570
  rb_define_method(rb_cPGconn, "ssl_attribute_names", pgconn_ssl_attribute_names, 0);
4296
4571
  #endif
4297
4572
 
4573
+ #ifdef HAVE_PQENTERPIPELINEMODE
4574
+ rb_define_method(rb_cPGconn, "pipeline_status", pgconn_pipeline_status, 0);
4575
+ rb_define_method(rb_cPGconn, "enter_pipeline_mode", pgconn_enter_pipeline_mode, 0);
4576
+ rb_define_method(rb_cPGconn, "exit_pipeline_mode", pgconn_exit_pipeline_mode, 0);
4577
+ rb_define_method(rb_cPGconn, "pipeline_sync", pgconn_pipeline_sync, 0);
4578
+ rb_define_method(rb_cPGconn, "send_flush_request", pgconn_send_flush_request, 0);
4579
+ #endif
4580
+
4298
4581
  /****** PG::Connection INSTANCE METHODS: Large Object Support ******/
4299
4582
  rb_define_method(rb_cPGconn, "lo_creat", pgconn_locreat, -1);
4300
4583
  rb_define_alias(rb_cPGconn, "locreat", "lo_creat");