pg 1.2.3 → 1.4.4

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