pg 1.2.2 → 1.3.0.rc3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (103) 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 +85 -0
  6. data/.github/workflows/source-gem.yml +129 -0
  7. data/.gitignore +13 -0
  8. data/.hgsigs +34 -0
  9. data/.hgtags +41 -0
  10. data/.irbrc +23 -0
  11. data/.pryrc +23 -0
  12. data/.tm_properties +21 -0
  13. data/.travis.yml +49 -0
  14. data/Gemfile +14 -0
  15. data/History.rdoc +86 -7
  16. data/Manifest.txt +0 -1
  17. data/README.rdoc +8 -7
  18. data/Rakefile +28 -139
  19. data/Rakefile.cross +17 -17
  20. data/certs/ged.pem +24 -0
  21. data/ext/errorcodes.def +8 -0
  22. data/ext/errorcodes.txt +3 -1
  23. data/ext/extconf.rb +90 -19
  24. data/ext/gvl_wrappers.c +4 -0
  25. data/ext/gvl_wrappers.h +23 -0
  26. data/ext/pg.c +59 -4
  27. data/ext/pg.h +18 -0
  28. data/ext/pg_coder.c +90 -24
  29. data/ext/pg_connection.c +615 -533
  30. data/ext/pg_copy_coder.c +45 -15
  31. data/ext/pg_record_coder.c +38 -9
  32. data/ext/pg_result.c +61 -31
  33. data/ext/pg_text_decoder.c +1 -1
  34. data/ext/pg_text_encoder.c +6 -6
  35. data/ext/pg_tuple.c +47 -21
  36. data/ext/pg_type_map.c +41 -8
  37. data/ext/pg_type_map_all_strings.c +14 -1
  38. data/ext/pg_type_map_by_class.c +50 -21
  39. data/ext/pg_type_map_by_column.c +64 -28
  40. data/ext/pg_type_map_by_mri_type.c +47 -18
  41. data/ext/pg_type_map_by_oid.c +52 -23
  42. data/ext/pg_type_map_in_ruby.c +50 -19
  43. data/ext/pg_util.c +2 -2
  44. data/lib/pg/basic_type_map_based_on_result.rb +47 -0
  45. data/lib/pg/basic_type_map_for_queries.rb +193 -0
  46. data/lib/pg/basic_type_map_for_results.rb +81 -0
  47. data/lib/pg/basic_type_registry.rb +296 -0
  48. data/lib/pg/coder.rb +1 -1
  49. data/lib/pg/connection.rb +586 -57
  50. data/lib/pg/version.rb +4 -0
  51. data/lib/pg.rb +40 -27
  52. data/misc/openssl-pg-segfault.rb +31 -0
  53. data/misc/postgres/History.txt +9 -0
  54. data/misc/postgres/Manifest.txt +5 -0
  55. data/misc/postgres/README.txt +21 -0
  56. data/misc/postgres/Rakefile +21 -0
  57. data/misc/postgres/lib/postgres.rb +16 -0
  58. data/misc/ruby-pg/History.txt +9 -0
  59. data/misc/ruby-pg/Manifest.txt +5 -0
  60. data/misc/ruby-pg/README.txt +21 -0
  61. data/misc/ruby-pg/Rakefile +21 -0
  62. data/misc/ruby-pg/lib/ruby/pg.rb +16 -0
  63. data/pg.gemspec +32 -0
  64. data/sample/array_insert.rb +20 -0
  65. data/sample/async_api.rb +106 -0
  66. data/sample/async_copyto.rb +39 -0
  67. data/sample/async_mixed.rb +56 -0
  68. data/sample/check_conn.rb +21 -0
  69. data/sample/copydata.rb +71 -0
  70. data/sample/copyfrom.rb +81 -0
  71. data/sample/copyto.rb +19 -0
  72. data/sample/cursor.rb +21 -0
  73. data/sample/disk_usage_report.rb +177 -0
  74. data/sample/issue-119.rb +94 -0
  75. data/sample/losample.rb +69 -0
  76. data/sample/minimal-testcase.rb +17 -0
  77. data/sample/notify_wait.rb +72 -0
  78. data/sample/pg_statistics.rb +285 -0
  79. data/sample/replication_monitor.rb +222 -0
  80. data/sample/test_binary_values.rb +33 -0
  81. data/sample/wal_shipper.rb +434 -0
  82. data/sample/warehouse_partitions.rb +311 -0
  83. data.tar.gz.sig +0 -0
  84. metadata +87 -226
  85. metadata.gz.sig +0 -0
  86. data/ChangeLog +0 -0
  87. data/lib/pg/basic_type_mapping.rb +0 -522
  88. data/spec/data/expected_trace.out +0 -26
  89. data/spec/data/random_binary_data +0 -0
  90. data/spec/helpers.rb +0 -382
  91. data/spec/pg/basic_type_mapping_spec.rb +0 -645
  92. data/spec/pg/connection_spec.rb +0 -1911
  93. data/spec/pg/connection_sync_spec.rb +0 -41
  94. data/spec/pg/result_spec.rb +0 -681
  95. data/spec/pg/tuple_spec.rb +0 -333
  96. data/spec/pg/type_map_by_class_spec.rb +0 -138
  97. data/spec/pg/type_map_by_column_spec.rb +0 -226
  98. data/spec/pg/type_map_by_mri_type_spec.rb +0 -136
  99. data/spec/pg/type_map_by_oid_spec.rb +0 -149
  100. data/spec/pg/type_map_in_ruby_spec.rb +0 -164
  101. data/spec/pg/type_map_spec.rb +0 -22
  102. data/spec/pg/type_spec.rb +0 -1123
  103. 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,7 +21,9 @@ 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;
24
27
 
25
28
  /*
26
29
  * Global functions
@@ -33,7 +36,7 @@ t_pg_connection *
33
36
  pg_get_connection( VALUE self )
34
37
  {
35
38
  t_pg_connection *this;
36
- Data_Get_Struct( self, t_pg_connection, this);
39
+ TypedData_Get_Struct( self, t_pg_connection, &pg_connection_type, this);
37
40
 
38
41
  return this;
39
42
  }
@@ -46,7 +49,7 @@ static t_pg_connection *
46
49
  pg_get_connection_safe( VALUE self )
47
50
  {
48
51
  t_pg_connection *this;
49
- Data_Get_Struct( self, t_pg_connection, this);
52
+ TypedData_Get_Struct( self, t_pg_connection, &pg_connection_type, this);
50
53
 
51
54
  if ( !this->pgconn )
52
55
  rb_raise( rb_eConnectionBad, "connection is closed" );
@@ -65,7 +68,7 @@ PGconn *
65
68
  pg_get_pgconn( VALUE self )
66
69
  {
67
70
  t_pg_connection *this;
68
- Data_Get_Struct( self, t_pg_connection, this);
71
+ TypedData_Get_Struct( self, t_pg_connection, &pg_connection_type, this);
69
72
 
70
73
  if ( !this->pgconn )
71
74
  rb_raise( rb_eConnectionBad, "connection is closed" );
@@ -145,16 +148,31 @@ static const char *pg_cstr_enc(VALUE str, int enc_idx){
145
148
  * GC Mark function
146
149
  */
147
150
  static void
148
- pgconn_gc_mark( t_pg_connection *this )
151
+ pgconn_gc_mark( void *_this )
149
152
  {
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 );
153
+ t_pg_connection *this = (t_pg_connection *)_this;
154
+ rb_gc_mark_movable( this->socket_io );
155
+ rb_gc_mark_movable( this->notice_receiver );
156
+ rb_gc_mark_movable( this->notice_processor );
157
+ rb_gc_mark_movable( this->type_map_for_queries );
158
+ rb_gc_mark_movable( this->type_map_for_results );
159
+ rb_gc_mark_movable( this->trace_stream );
160
+ rb_gc_mark_movable( this->encoder_for_put_copy_data );
161
+ rb_gc_mark_movable( this->decoder_for_get_copy_data );
162
+ }
163
+
164
+ static void
165
+ pgconn_gc_compact( void *_this )
166
+ {
167
+ t_pg_connection *this = (t_pg_connection *)_this;
168
+ pg_gc_location( this->socket_io );
169
+ pg_gc_location( this->notice_receiver );
170
+ pg_gc_location( this->notice_processor );
171
+ pg_gc_location( this->type_map_for_queries );
172
+ pg_gc_location( this->type_map_for_results );
173
+ pg_gc_location( this->trace_stream );
174
+ pg_gc_location( this->encoder_for_put_copy_data );
175
+ pg_gc_location( this->decoder_for_get_copy_data );
158
176
  }
159
177
 
160
178
 
@@ -162,11 +180,15 @@ pgconn_gc_mark( t_pg_connection *this )
162
180
  * GC Free function
163
181
  */
164
182
  static void
165
- pgconn_gc_free( t_pg_connection *this )
183
+ pgconn_gc_free( void *_this )
166
184
  {
185
+ t_pg_connection *this = (t_pg_connection *)_this;
167
186
  #if defined(_WIN32)
168
- if ( RTEST(this->socket_io) )
169
- rb_w32_unwrap_io_handle( this->ruby_sd );
187
+ if ( RTEST(this->socket_io) ) {
188
+ if( rb_w32_unwrap_io_handle(this->ruby_sd) ){
189
+ rb_warn("pg: Could not unwrap win32 socket handle by garbage collector");
190
+ }
191
+ }
170
192
  #endif
171
193
  if (this->pgconn != NULL)
172
194
  PQfinish( this->pgconn );
@@ -174,6 +196,29 @@ pgconn_gc_free( t_pg_connection *this )
174
196
  xfree(this);
175
197
  }
176
198
 
199
+ /*
200
+ * Object Size function
201
+ */
202
+ static size_t
203
+ pgconn_memsize( const void *_this )
204
+ {
205
+ const t_pg_connection *this = (const t_pg_connection *)_this;
206
+ return sizeof(*this);
207
+ }
208
+
209
+ static const rb_data_type_t pg_connection_type = {
210
+ "PG::Connection",
211
+ {
212
+ pgconn_gc_mark,
213
+ pgconn_gc_free,
214
+ pgconn_memsize,
215
+ pg_compact_callback(pgconn_gc_compact),
216
+ },
217
+ 0,
218
+ 0,
219
+ 0,
220
+ };
221
+
177
222
 
178
223
  /**************************************************************************
179
224
  * Class Methods
@@ -189,7 +234,7 @@ static VALUE
189
234
  pgconn_s_allocate( VALUE klass )
190
235
  {
191
236
  t_pg_connection *this;
192
- VALUE self = Data_Make_Struct( klass, t_pg_connection, pgconn_gc_mark, pgconn_gc_free, this );
237
+ VALUE self = TypedData_Make_Struct( klass, t_pg_connection, &pg_connection_type, this );
193
238
 
194
239
  this->pgconn = NULL;
195
240
  this->socket_io = Qnil;
@@ -204,65 +249,13 @@ pgconn_s_allocate( VALUE klass )
204
249
  return self;
205
250
  }
206
251
 
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
252
  static VALUE
261
- pgconn_init(int argc, VALUE *argv, VALUE self)
253
+ pgconn_s_sync_connect(int argc, VALUE *argv, VALUE klass)
262
254
  {
263
255
  t_pg_connection *this;
264
256
  VALUE conninfo;
265
257
  VALUE error;
258
+ VALUE self = pgconn_s_allocate( klass );
266
259
 
267
260
  this = pg_get_connection( self );
268
261
  conninfo = rb_funcall2( rb_cPGconn, rb_intern("parse_connect_args"), argc, argv );
@@ -335,34 +328,14 @@ pgconn_s_connect_start( int argc, VALUE *argv, VALUE klass )
335
328
  return rb_conn;
336
329
  }
337
330
 
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
331
  static VALUE
359
- pgconn_s_ping( int argc, VALUE *argv, VALUE klass )
332
+ pgconn_s_sync_ping( int argc, VALUE *argv, VALUE klass )
360
333
  {
361
334
  PGPing ping;
362
335
  VALUE conninfo;
363
336
 
364
337
  conninfo = rb_funcall2( klass, rb_intern("parse_connect_args"), argc, argv );
365
- ping = PQping( StringValueCStr(conninfo) );
338
+ ping = gvl_PQping( StringValueCStr(conninfo) );
366
339
 
367
340
  return INT2FIX((int)ping);
368
341
  }
@@ -405,30 +378,8 @@ pgconn_s_conndefaults(VALUE self)
405
378
 
406
379
 
407
380
  #ifdef HAVE_PQENCRYPTPASSWORDCONN
408
- /*
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.
423
- *
424
- * Return value is the encrypted password.
425
- * The caller can assume the string doesn't contain any special characters that would require escaping.
426
- *
427
- * Available since PostgreSQL-10.
428
- * See also corresponding {libpq function}[https://www.postgresql.org/docs/current/libpq-misc.html#LIBPQ-PQENCRYPTPASSWORDCONN].
429
- */
430
381
  static VALUE
431
- pgconn_encrypt_password(int argc, VALUE *argv, VALUE self)
382
+ pgconn_sync_encrypt_password(int argc, VALUE *argv, VALUE self)
432
383
  {
433
384
  char *encrypted = NULL;
434
385
  VALUE rval = Qnil;
@@ -523,6 +474,11 @@ pgconn_connect_poll(VALUE self)
523
474
  {
524
475
  PostgresPollingStatusType status;
525
476
  status = gvl_PQconnectPoll(pg_get_pgconn(self));
477
+
478
+ if ( status == PGRES_POLLING_FAILED ) {
479
+ pgconn_close_socket_io(self);
480
+ }
481
+
526
482
  return INT2FIX((int)status);
527
483
  }
528
484
 
@@ -559,15 +515,8 @@ pgconn_finished_p( VALUE self )
559
515
  }
560
516
 
561
517
 
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
518
  static VALUE
570
- pgconn_reset( VALUE self )
519
+ pgconn_sync_reset( VALUE self )
571
520
  {
572
521
  pgconn_close_socket_io( self );
573
522
  gvl_PQreset( pg_get_pgconn(self) );
@@ -606,6 +555,11 @@ pgconn_reset_poll(VALUE self)
606
555
  {
607
556
  PostgresPollingStatusType status;
608
557
  status = gvl_PQresetPoll(pg_get_pgconn(self));
558
+
559
+ if ( status == PGRES_POLLING_FAILED ) {
560
+ pgconn_close_socket_io(self);
561
+ }
562
+
609
563
  return INT2FIX((int)status);
610
564
  }
611
565
 
@@ -676,21 +630,19 @@ static VALUE
676
630
  pgconn_port(VALUE self)
677
631
  {
678
632
  char* port = PQport(pg_get_pgconn(self));
679
- return INT2NUM(atol(port));
633
+ return INT2NUM(atoi(port));
680
634
  }
681
635
 
682
636
  /*
683
637
  * call-seq:
684
638
  * conn.tty()
685
639
  *
686
- * Returns the connected pgtty. (Obsolete)
640
+ * Obsolete function.
687
641
  */
688
642
  static VALUE
689
643
  pgconn_tty(VALUE self)
690
644
  {
691
- char *tty = PQtty(pg_get_pgconn(self));
692
- if (!tty) return Qnil;
693
- return rb_str_new2(tty);
645
+ return rb_str_new2("");
694
646
  }
695
647
 
696
648
  /*
@@ -708,7 +660,6 @@ pgconn_options(VALUE self)
708
660
  }
709
661
 
710
662
 
711
- #ifdef HAVE_PQCONNINFO
712
663
  /*
713
664
  * call-seq:
714
665
  * conn.conninfo -> hash
@@ -728,14 +679,17 @@ pgconn_conninfo( VALUE self )
728
679
 
729
680
  return array;
730
681
  }
731
- #endif
732
682
 
733
683
 
734
684
  /*
735
685
  * call-seq:
736
686
  * conn.status()
737
687
  *
738
- * Returns status of connection : CONNECTION_OK or CONNECTION_BAD
688
+ * Returns the status of the connection, which is one:
689
+ * PG::Constants::CONNECTION_OK
690
+ * PG::Constants::CONNECTION_BAD
691
+ *
692
+ * ... and other constants of kind PG::Constants::CONNECTION_*
739
693
  */
740
694
  static VALUE
741
695
  pgconn_status(VALUE self)
@@ -823,7 +777,10 @@ pgconn_server_version(VALUE self)
823
777
  * call-seq:
824
778
  * conn.error_message -> String
825
779
  *
826
- * Returns the error message about connection.
780
+ * Returns the error message most recently generated by an operation on the connection.
781
+ *
782
+ * Nearly all libpq functions will set a message for conn.error_message if they fail.
783
+ * Note that by libpq convention, a nonempty error_message result can consist of multiple lines, and will include a trailing newline.
827
784
  */
828
785
  static VALUE
829
786
  pgconn_error_message(VALUE self)
@@ -878,8 +835,8 @@ pgconn_socket_io(VALUE self)
878
835
  {
879
836
  int sd;
880
837
  int ruby_sd;
881
- ID id_autoclose = rb_intern("autoclose=");
882
838
  t_pg_connection *this = pg_get_connection_safe( self );
839
+ VALUE cSocket;
883
840
  VALUE socket_io = this->socket_io;
884
841
 
885
842
  if ( !RTEST(socket_io) ) {
@@ -888,15 +845,19 @@ pgconn_socket_io(VALUE self)
888
845
 
889
846
  #ifdef _WIN32
890
847
  ruby_sd = rb_w32_wrap_io_handle((HANDLE)(intptr_t)sd, O_RDWR|O_BINARY|O_NOINHERIT);
848
+ if( ruby_sd == -1 ){
849
+ rb_raise(rb_eConnectionBad, "Could not wrap win32 socket handle");
850
+ }
891
851
  this->ruby_sd = ruby_sd;
892
852
  #else
893
853
  ruby_sd = sd;
894
854
  #endif
895
855
 
896
- socket_io = rb_funcall( rb_cIO, rb_intern("for_fd"), 1, INT2NUM(ruby_sd) );
856
+ cSocket = rb_const_get(rb_cObject, rb_intern("BasicSocket"));
857
+ socket_io = rb_funcall( cSocket, rb_intern("for_fd"), 1, INT2NUM(ruby_sd));
897
858
 
898
859
  /* Disable autoclose feature */
899
- rb_funcall( socket_io, id_autoclose, 1, Qfalse );
860
+ rb_funcall( socket_io, s_id_autoclose_set, 1, Qfalse );
900
861
 
901
862
  this->socket_io = socket_io;
902
863
  }
@@ -918,6 +879,51 @@ pgconn_backend_pid(VALUE self)
918
879
  return INT2NUM(PQbackendPID(pg_get_pgconn(self)));
919
880
  }
920
881
 
882
+ typedef struct
883
+ {
884
+ struct sockaddr_storage addr;
885
+ socklen_t salen;
886
+ } SockAddr;
887
+
888
+ /* Copy of struct pg_cancel from libpq-int.h
889
+ *
890
+ * See https://github.com/postgres/postgres/blame/master/src/interfaces/libpq/libpq-int.h#L577-L586
891
+ */
892
+ struct pg_cancel
893
+ {
894
+ SockAddr raddr; /* Remote address */
895
+ int be_pid; /* PID of backend --- needed for cancels */
896
+ int be_key; /* key of backend --- needed for cancels */
897
+ };
898
+
899
+ /*
900
+ * call-seq:
901
+ * conn.backend_key() -> Integer
902
+ *
903
+ * Returns the key of the backend server process for this connection.
904
+ * This key can be used to cancel queries on the server.
905
+ */
906
+ static VALUE
907
+ pgconn_backend_key(VALUE self)
908
+ {
909
+ int be_key;
910
+ struct pg_cancel *cancel;
911
+ PGconn *conn = pg_get_pgconn(self);
912
+
913
+ cancel = (struct pg_cancel*)PQgetCancel(conn);
914
+ if(cancel == NULL)
915
+ rb_raise(rb_ePGerror,"Invalid connection!");
916
+
917
+ if( cancel->be_pid != PQbackendPID(conn) )
918
+ rb_raise(rb_ePGerror,"Unexpected binary struct layout - please file a bug report at ruby-pg!");
919
+
920
+ be_key = cancel->be_key;
921
+
922
+ PQfreeCancel(cancel);
923
+
924
+ return INT2NUM(be_key);
925
+ }
926
+
921
927
  /*
922
928
  * call-seq:
923
929
  * conn.connection_needs_password() -> Boolean
@@ -948,7 +954,7 @@ pgconn_connection_used_password(VALUE self)
948
954
  /* :TODO: get_ssl */
949
955
 
950
956
 
951
- static VALUE pgconn_exec_params( int, VALUE *, VALUE );
957
+ static VALUE pgconn_sync_exec_params( int, VALUE *, VALUE );
952
958
 
953
959
  /*
954
960
  * call-seq:
@@ -962,11 +968,11 @@ static VALUE pgconn_exec_params( int, VALUE *, VALUE );
962
968
  * However #async_exec has two advantages:
963
969
  *
964
970
  * 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
971
+ * 2. Ruby VM gets notified about IO blocked operations and can pass them through <tt>Fiber.scheduler</tt>.
972
+ * So only <tt>async_*</tt> methods are compatible to event based schedulers like the async gem.
967
973
  */
968
974
  static VALUE
969
- pgconn_exec(int argc, VALUE *argv, VALUE self)
975
+ pgconn_sync_exec(int argc, VALUE *argv, VALUE self)
970
976
  {
971
977
  t_pg_connection *this = pg_get_connection_safe( self );
972
978
  PGresult *result = NULL;
@@ -987,7 +993,7 @@ pgconn_exec(int argc, VALUE *argv, VALUE self)
987
993
  pg_deprecated(0, ("forwarding exec to exec_params is deprecated"));
988
994
 
989
995
  /* Otherwise, just call #exec_params instead for backward-compatibility */
990
- return pgconn_exec_params( argc, argv, self );
996
+ return pgconn_sync_exec_params( argc, argv, self );
991
997
 
992
998
  }
993
999
 
@@ -1019,7 +1025,7 @@ struct query_params_data {
1019
1025
  * Filled by alloc_query_params()
1020
1026
  */
1021
1027
 
1022
- /* Wraps the pointer of allocated memory, if function parameters dont't
1028
+ /* Wraps the pointer of allocated memory, if function parameters don't
1023
1029
  * fit in the memory_pool below.
1024
1030
  */
1025
1031
  VALUE heap_pool;
@@ -1037,7 +1043,7 @@ struct query_params_data {
1037
1043
  Oid *types;
1038
1044
 
1039
1045
  /* This array takes the string values for the timeframe of the query,
1040
- * if param value convertion is required
1046
+ * if param value conversion is required
1041
1047
  */
1042
1048
  VALUE gc_array;
1043
1049
 
@@ -1051,8 +1057,9 @@ struct query_params_data {
1051
1057
  };
1052
1058
 
1053
1059
  static void
1054
- free_typecast_heap_chain(struct linked_typecast_data *chain_entry)
1060
+ free_typecast_heap_chain(void *_chain_entry)
1055
1061
  {
1062
+ struct linked_typecast_data *chain_entry = (struct linked_typecast_data *)_chain_entry;
1056
1063
  while(chain_entry){
1057
1064
  struct linked_typecast_data *next = chain_entry->next;
1058
1065
  xfree(chain_entry);
@@ -1060,6 +1067,18 @@ free_typecast_heap_chain(struct linked_typecast_data *chain_entry)
1060
1067
  }
1061
1068
  }
1062
1069
 
1070
+ static const rb_data_type_t pg_typecast_buffer_type = {
1071
+ "PG::Connection typecast buffer chain",
1072
+ {
1073
+ (RUBY_DATA_FUNC) NULL,
1074
+ free_typecast_heap_chain,
1075
+ (size_t (*)(const void *))NULL,
1076
+ },
1077
+ 0,
1078
+ 0,
1079
+ RUBY_TYPED_FREE_IMMEDIATELY,
1080
+ };
1081
+
1063
1082
  static char *
1064
1083
  alloc_typecast_buf( VALUE *typecast_heap_chain, int len )
1065
1084
  {
@@ -1070,17 +1089,28 @@ alloc_typecast_buf( VALUE *typecast_heap_chain, int len )
1070
1089
  /* Did we already wrap a memory chain per T_DATA object? */
1071
1090
  if( NIL_P( *typecast_heap_chain ) ){
1072
1091
  /* 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 );
1092
+ *typecast_heap_chain = TypedData_Wrap_Struct( rb_cObject, &pg_typecast_buffer_type, allocated );
1074
1093
  allocated->next = NULL;
1075
1094
  } else {
1076
1095
  /* Append to the chain */
1077
- allocated->next = DATA_PTR( *typecast_heap_chain );
1078
- DATA_PTR( *typecast_heap_chain ) = allocated;
1096
+ allocated->next = RTYPEDDATA_DATA( *typecast_heap_chain );
1097
+ RTYPEDDATA_DATA( *typecast_heap_chain ) = allocated;
1079
1098
  }
1080
1099
 
1081
1100
  return &allocated->data[0];
1082
1101
  }
1083
1102
 
1103
+ static const rb_data_type_t pg_query_heap_pool_type = {
1104
+ "PG::Connection query heap pool",
1105
+ {
1106
+ (RUBY_DATA_FUNC) NULL,
1107
+ RUBY_TYPED_DEFAULT_FREE,
1108
+ (size_t (*)(const void *))NULL,
1109
+ },
1110
+ 0,
1111
+ 0,
1112
+ RUBY_TYPED_FREE_IMMEDIATELY,
1113
+ };
1084
1114
 
1085
1115
  static int
1086
1116
  alloc_query_params(struct query_params_data *paramsData)
@@ -1095,7 +1125,7 @@ alloc_query_params(struct query_params_data *paramsData)
1095
1125
 
1096
1126
  Check_Type(paramsData->params, T_ARRAY);
1097
1127
 
1098
- p_typemap = DATA_PTR( paramsData->typemap );
1128
+ p_typemap = RTYPEDDATA_DATA( paramsData->typemap );
1099
1129
  p_typemap->funcs.fit_to_query( paramsData->typemap, paramsData->params );
1100
1130
 
1101
1131
  paramsData->heap_pool = Qnil;
@@ -1114,7 +1144,7 @@ alloc_query_params(struct query_params_data *paramsData)
1114
1144
  /* Allocate one combined memory pool for all possible function parameters */
1115
1145
  memory_pool = (char*)xmalloc( required_pool_size );
1116
1146
  /* 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 );
1147
+ paramsData->heap_pool = TypedData_Wrap_Struct( rb_cObject, &pg_query_heap_pool_type, memory_pool );
1118
1148
  required_pool_size = 0;
1119
1149
  }else{
1120
1150
  /* Use stack memory for function parameters */
@@ -1227,12 +1257,11 @@ pgconn_query_assign_typemap( VALUE self, struct query_params_data *paramsData )
1227
1257
  /* Use default typemap for queries. It's type is checked when assigned. */
1228
1258
  paramsData->typemap = pg_get_connection(self)->type_map_for_queries;
1229
1259
  }else{
1260
+ t_typemap *tm;
1261
+ UNUSED(tm);
1262
+
1230
1263
  /* 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 );
1264
+ TypedData_Get_Struct(paramsData->typemap, t_typemap, &pg_typemap_type, tm);
1236
1265
  }
1237
1266
  }
1238
1267
 
@@ -1246,7 +1275,7 @@ pgconn_query_assign_typemap( VALUE self, struct query_params_data *paramsData )
1246
1275
  * 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
1276
  */
1248
1277
  static VALUE
1249
- pgconn_exec_params( int argc, VALUE *argv, VALUE self )
1278
+ pgconn_sync_exec_params( int argc, VALUE *argv, VALUE self )
1250
1279
  {
1251
1280
  t_pg_connection *this = pg_get_connection_safe( self );
1252
1281
  PGresult *result = NULL;
@@ -1266,7 +1295,7 @@ pgconn_exec_params( int argc, VALUE *argv, VALUE self )
1266
1295
  */
1267
1296
  if ( NIL_P(paramsData.params) ) {
1268
1297
  pg_deprecated(1, ("forwarding exec_params to exec is deprecated"));
1269
- return pgconn_exec( 1, argv, self );
1298
+ return pgconn_sync_exec( 1, argv, self );
1270
1299
  }
1271
1300
  pgconn_query_assign_typemap( self, &paramsData );
1272
1301
 
@@ -1297,7 +1326,7 @@ pgconn_exec_params( int argc, VALUE *argv, VALUE self )
1297
1326
  * It's not recommended to use explicit sync or async variants but #prepare instead, unless you have a good reason to do so.
1298
1327
  */
1299
1328
  static VALUE
1300
- pgconn_prepare(int argc, VALUE *argv, VALUE self)
1329
+ pgconn_sync_prepare(int argc, VALUE *argv, VALUE self)
1301
1330
  {
1302
1331
  t_pg_connection *this = pg_get_connection_safe( self );
1303
1332
  PGresult *result = NULL;
@@ -1346,7 +1375,7 @@ pgconn_prepare(int argc, VALUE *argv, VALUE self)
1346
1375
  * 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
1376
  */
1348
1377
  static VALUE
1349
- pgconn_exec_prepared(int argc, VALUE *argv, VALUE self)
1378
+ pgconn_sync_exec_prepared(int argc, VALUE *argv, VALUE self)
1350
1379
  {
1351
1380
  t_pg_connection *this = pg_get_connection_safe( self );
1352
1381
  PGresult *result = NULL;
@@ -1391,7 +1420,7 @@ pgconn_exec_prepared(int argc, VALUE *argv, VALUE self)
1391
1420
  * 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
1421
  */
1393
1422
  static VALUE
1394
- pgconn_describe_prepared(VALUE self, VALUE stmt_name)
1423
+ pgconn_sync_describe_prepared(VALUE self, VALUE stmt_name)
1395
1424
  {
1396
1425
  PGresult *result;
1397
1426
  VALUE rb_pgresult;
@@ -1419,7 +1448,7 @@ pgconn_describe_prepared(VALUE self, VALUE stmt_name)
1419
1448
  * 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
1449
  */
1421
1450
  static VALUE
1422
- pgconn_describe_portal(self, stmt_name)
1451
+ pgconn_sync_describe_portal(self, stmt_name)
1423
1452
  VALUE self, stmt_name;
1424
1453
  {
1425
1454
  PGresult *result;
@@ -1454,6 +1483,9 @@ pgconn_describe_portal(self, stmt_name)
1454
1483
  * * +PGRES_NONFATAL_ERROR+
1455
1484
  * * +PGRES_FATAL_ERROR+
1456
1485
  * * +PGRES_COPY_BOTH+
1486
+ * * +PGRES_SINGLE_TUPLE+
1487
+ * * +PGRES_PIPELINE_SYNC+
1488
+ * * +PGRES_PIPELINE_ABORTED+
1457
1489
  */
1458
1490
  static VALUE
1459
1491
  pgconn_make_empty_pgresult(VALUE self, VALUE status)
@@ -1750,6 +1782,7 @@ pgconn_send_query(int argc, VALUE *argv, VALUE self)
1750
1782
  rb_iv_set(error, "@connection", self);
1751
1783
  rb_exc_raise(error);
1752
1784
  }
1785
+ pgconn_wait_for_flush( self );
1753
1786
  return Qnil;
1754
1787
  }
1755
1788
 
@@ -1779,7 +1812,7 @@ pgconn_send_query(int argc, VALUE *argv, VALUE self)
1779
1812
  * or, it may be a String. If it is a string, that is equivalent to the hash:
1780
1813
  * { :value => <string value>, :type => 0, :format => 0 }
1781
1814
  *
1782
- * PostgreSQL bind parameters are represented as $1, $1, $2, etc.,
1815
+ * PostgreSQL bind parameters are represented as $1, $2, $3, etc.,
1783
1816
  * inside the SQL query. The 0th element of the +params+ array is bound
1784
1817
  * to $1, the 1st element is bound to $2, etc. +nil+ is treated as +NULL+.
1785
1818
  *
@@ -1827,6 +1860,7 @@ pgconn_send_query_params(int argc, VALUE *argv, VALUE self)
1827
1860
  rb_iv_set(error, "@connection", self);
1828
1861
  rb_exc_raise(error);
1829
1862
  }
1863
+ pgconn_wait_for_flush( self );
1830
1864
  return Qnil;
1831
1865
  }
1832
1866
 
@@ -1847,7 +1881,7 @@ pgconn_send_query_params(int argc, VALUE *argv, VALUE self)
1847
1881
  *
1848
1882
  * For example: "SELECT $1::int"
1849
1883
  *
1850
- * PostgreSQL bind parameters are represented as $1, $1, $2, etc.,
1884
+ * PostgreSQL bind parameters are represented as $1, $2, $3, etc.,
1851
1885
  * inside the SQL query.
1852
1886
  */
1853
1887
  static VALUE
@@ -1890,6 +1924,7 @@ pgconn_send_prepare(int argc, VALUE *argv, VALUE self)
1890
1924
  rb_iv_set(error, "@connection", self);
1891
1925
  rb_exc_raise(error);
1892
1926
  }
1927
+ pgconn_wait_for_flush( self );
1893
1928
  return Qnil;
1894
1929
  }
1895
1930
 
@@ -1911,7 +1946,7 @@ pgconn_send_prepare(int argc, VALUE *argv, VALUE self)
1911
1946
  * or, it may be a String. If it is a string, that is equivalent to the hash:
1912
1947
  * { :value => <string value>, :format => 0 }
1913
1948
  *
1914
- * PostgreSQL bind parameters are represented as $1, $1, $2, etc.,
1949
+ * PostgreSQL bind parameters are represented as $1, $2, $3, etc.,
1915
1950
  * inside the SQL query. The 0th element of the +params+ array is bound
1916
1951
  * to $1, the 1st element is bound to $2, etc. +nil+ is treated as +NULL+.
1917
1952
  *
@@ -1941,7 +1976,6 @@ pgconn_send_query_prepared(int argc, VALUE *argv, VALUE self)
1941
1976
 
1942
1977
  if(NIL_P(paramsData.params)) {
1943
1978
  paramsData.params = rb_ary_new2(0);
1944
- resultFormat = 0;
1945
1979
  }
1946
1980
  pgconn_query_assign_typemap( self, &paramsData );
1947
1981
 
@@ -1959,6 +1993,7 @@ pgconn_send_query_prepared(int argc, VALUE *argv, VALUE self)
1959
1993
  rb_iv_set(error, "@connection", self);
1960
1994
  rb_exc_raise(error);
1961
1995
  }
1996
+ pgconn_wait_for_flush( self );
1962
1997
  return Qnil;
1963
1998
  }
1964
1999
 
@@ -1980,6 +2015,7 @@ pgconn_send_describe_prepared(VALUE self, VALUE stmt_name)
1980
2015
  rb_iv_set(error, "@connection", self);
1981
2016
  rb_exc_raise(error);
1982
2017
  }
2018
+ pgconn_wait_for_flush( self );
1983
2019
  return Qnil;
1984
2020
  }
1985
2021
 
@@ -2002,28 +2038,13 @@ pgconn_send_describe_portal(VALUE self, VALUE portal)
2002
2038
  rb_iv_set(error, "@connection", self);
2003
2039
  rb_exc_raise(error);
2004
2040
  }
2041
+ pgconn_wait_for_flush( self );
2005
2042
  return Qnil;
2006
2043
  }
2007
2044
 
2008
2045
 
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
2046
  static VALUE
2026
- pgconn_get_result(VALUE self)
2047
+ pgconn_sync_get_result(VALUE self)
2027
2048
  {
2028
2049
  PGconn *conn = pg_get_pgconn(self);
2029
2050
  PGresult *result;
@@ -2056,6 +2077,7 @@ pgconn_consume_input(self)
2056
2077
  PGconn *conn = pg_get_pgconn(self);
2057
2078
  /* returns 0 on error */
2058
2079
  if(PQconsumeInput(conn) == 0) {
2080
+ pgconn_close_socket_io(self);
2059
2081
  error = rb_exc_new2(rb_eConnectionBad, PQerrorMessage(conn));
2060
2082
  rb_iv_set(error, "@connection", self);
2061
2083
  rb_exc_raise(error);
@@ -2068,7 +2090,7 @@ pgconn_consume_input(self)
2068
2090
  * conn.is_busy() -> Boolean
2069
2091
  *
2070
2092
  * Returns +true+ if a command is busy, that is, if
2071
- * PQgetResult would block. Otherwise returns +false+.
2093
+ * #get_result would block. Otherwise returns +false+.
2072
2094
  */
2073
2095
  static VALUE
2074
2096
  pgconn_is_busy(self)
@@ -2077,24 +2099,8 @@ pgconn_is_busy(self)
2077
2099
  return gvl_PQisBusy(pg_get_pgconn(self)) ? Qtrue : Qfalse;
2078
2100
  }
2079
2101
 
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
2102
  static VALUE
2097
- pgconn_setnonblocking(self, state)
2103
+ pgconn_sync_setnonblocking(self, state)
2098
2104
  VALUE self, state;
2099
2105
  {
2100
2106
  int arg;
@@ -2116,33 +2122,15 @@ pgconn_setnonblocking(self, state)
2116
2122
  }
2117
2123
 
2118
2124
 
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
2125
  static VALUE
2127
- pgconn_isnonblocking(self)
2126
+ pgconn_sync_isnonblocking(self)
2128
2127
  VALUE self;
2129
2128
  {
2130
2129
  return PQisnonblocking(pg_get_pgconn(self)) ? Qtrue : Qfalse;
2131
2130
  }
2132
2131
 
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
2132
  static VALUE
2144
- pgconn_flush(self)
2145
- VALUE self;
2133
+ pgconn_sync_flush(VALUE self)
2146
2134
  {
2147
2135
  PGconn *conn = pg_get_pgconn(self);
2148
2136
  int ret;
@@ -2156,18 +2144,8 @@ pgconn_flush(self)
2156
2144
  return (ret) ? Qfalse : Qtrue;
2157
2145
  }
2158
2146
 
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
2147
  static VALUE
2170
- pgconn_cancel(VALUE self)
2148
+ pgconn_sync_cancel(VALUE self)
2171
2149
  {
2172
2150
  char errbuf[256];
2173
2151
  PGcancel *cancel;
@@ -2178,7 +2156,7 @@ pgconn_cancel(VALUE self)
2178
2156
  if(cancel == NULL)
2179
2157
  rb_raise(rb_ePGerror,"Invalid connection!");
2180
2158
 
2181
- ret = gvl_PQcancel(cancel, errbuf, 256);
2159
+ ret = gvl_PQcancel(cancel, errbuf, sizeof(errbuf));
2182
2160
  if(ret == 1)
2183
2161
  retval = Qnil;
2184
2162
  else
@@ -2229,107 +2207,58 @@ pgconn_notifies(VALUE self)
2229
2207
  return hash;
2230
2208
  }
2231
2209
 
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().
2237
- */
2238
2210
 
2239
- int rb_w32_wait_events( HANDLE *events, int num, DWORD timeout );
2211
+ #if defined(HAVE_RB_IO_WAIT)
2240
2212
 
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;
2246
- struct timeval aborttime={0,0}, currtime, waittime;
2247
- 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");
2253
-
2254
- hEvent = WSACreateEvent();
2255
-
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
- }
2261
-
2262
- if ( ptimeout ) {
2263
- gettimeofday(&currtime, NULL);
2264
- timeradd(&currtime, ptimeout, &aborttime);
2265
- }
2213
+ /* Use our own function and constants names, to avoid conflicts with truffleruby-head on its road to ruby-3.0 compatibility. */
2214
+ #define pg_rb_io_wait rb_io_wait
2215
+ #define PG_RUBY_IO_READABLE RUBY_IO_READABLE
2216
+ #define PG_RUBY_IO_WRITABLE RUBY_IO_WRITABLE
2217
+ #define PG_RUBY_IO_PRIORITY RUBY_IO_PRIORITY
2266
2218
 
2267
- while ( !(retval=is_readable(conn)) ) {
2268
- if ( WSAEventSelect(sd, hEvent, FD_READ|FD_CLOSE) == SOCKET_ERROR ) {
2269
- WSACloseEvent( hEvent );
2270
- rb_raise( rb_eConnectionBad, "WSAEventSelect socket error: %d", WSAGetLastError() );
2271
- }
2272
-
2273
- if ( ptimeout ) {
2274
- gettimeofday(&currtime, NULL);
2275
- timersub(&aborttime, &currtime, &waittime);
2276
- timeout_milisec = (DWORD)( waittime.tv_sec * 1e3 + waittime.tv_usec / 1e3 );
2277
- }
2278
-
2279
- /* Is the given timeout valid? */
2280
- if( !ptimeout || (waittime.tv_sec >= 0 && waittime.tv_usec >= 0) ){
2281
- /* Wait for the socket to become readable before checking again */
2282
- wait_ret = rb_w32_wait_events( &hEvent, 1, timeout_milisec );
2283
- } else {
2284
- wait_ret = WAIT_TIMEOUT;
2285
- }
2219
+ #else
2220
+ /* For compat with ruby < 3.0 */
2286
2221
 
2287
- if ( wait_ret == WAIT_TIMEOUT ) {
2288
- WSACloseEvent( hEvent );
2289
- return NULL;
2290
- } else if ( wait_ret == WAIT_OBJECT_0 ) {
2291
- /* The event we were waiting for. */
2292
- } else if ( wait_ret == WAIT_OBJECT_0 + 1) {
2293
- /* This indicates interruption from timer thread, GC, exception
2294
- * from other threads etc... */
2295
- rb_thread_check_ints();
2296
- } else if ( wait_ret == WAIT_FAILED ) {
2297
- WSACloseEvent( hEvent );
2298
- rb_raise( rb_eConnectionBad, "Wait on socket error (WaitForMultipleObjects): %lu", GetLastError() );
2299
- } else {
2300
- WSACloseEvent( hEvent );
2301
- rb_raise( rb_eConnectionBad, "Wait on socket abandoned (WaitForMultipleObjects)" );
2302
- }
2222
+ typedef enum {
2223
+ PG_RUBY_IO_READABLE = RB_WAITFD_IN,
2224
+ PG_RUBY_IO_WRITABLE = RB_WAITFD_OUT,
2225
+ PG_RUBY_IO_PRIORITY = RB_WAITFD_PRI,
2226
+ } pg_rb_io_event_t;
2303
2227
 
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
- }
2228
+ static VALUE
2229
+ pg_rb_io_wait(VALUE io, VALUE events, VALUE timeout) {
2230
+ rb_io_t *fptr;
2231
+ struct timeval waittime;
2232
+ int res;
2233
+
2234
+ GetOpenFile((io), fptr);
2235
+ if( !NIL_P(timeout) ){
2236
+ waittime.tv_sec = (time_t)(NUM2DBL(timeout));
2237
+ waittime.tv_usec = (time_t)(NUM2DBL(timeout) - (double)waittime.tv_sec);
2309
2238
  }
2239
+ res = rb_wait_for_single_fd(fptr->fd, NUM2UINT(events), NIL_P(timeout) ? NULL : &waittime);
2310
2240
 
2311
- WSACloseEvent( hEvent );
2312
- return retval;
2241
+ return UINT2NUM(res);
2313
2242
  }
2314
-
2315
- #else
2316
-
2317
- /* non Win32 */
2243
+ #endif
2318
2244
 
2319
2245
  static void *
2320
- wait_socket_readable( PGconn *conn, struct timeval *ptimeout, void *(*is_readable)(PGconn *))
2246
+ wait_socket_readable( VALUE self, struct timeval *ptimeout, void *(*is_readable)(PGconn *))
2321
2247
  {
2322
- int sd = PQsocket( conn );
2323
- int ret;
2248
+ VALUE socket_io;
2249
+ VALUE ret;
2324
2250
  void *retval;
2325
2251
  struct timeval aborttime={0,0}, currtime, waittime;
2252
+ VALUE wait_timeout = Qnil;
2253
+ PGconn *conn = pg_get_pgconn(self);
2326
2254
 
2327
- if ( sd < 0 )
2328
- rb_raise(rb_eConnectionBad, "PQsocket() can't get socket descriptor");
2255
+ socket_io = pgconn_socket_io(self);
2329
2256
 
2330
2257
  /* Check for connection errors (PQisBusy is true on connection errors) */
2331
- if ( PQconsumeInput(conn) == 0 )
2258
+ if ( PQconsumeInput(conn) == 0 ) {
2259
+ pgconn_close_socket_io(self);
2332
2260
  rb_raise( rb_eConnectionBad, "PQconsumeInput() %s", PQerrorMessage(conn) );
2261
+ }
2333
2262
 
2334
2263
  if ( ptimeout ) {
2335
2264
  gettimeofday(&currtime, NULL);
@@ -2340,27 +2269,25 @@ wait_socket_readable( PGconn *conn, struct timeval *ptimeout, void *(*is_readabl
2340
2269
  if ( ptimeout ) {
2341
2270
  gettimeofday(&currtime, NULL);
2342
2271
  timersub(&aborttime, &currtime, &waittime);
2272
+ wait_timeout = DBL2NUM((double)(waittime.tv_sec) + (double)(waittime.tv_usec) / 1000000.0);
2343
2273
  }
2344
2274
 
2345
2275
  /* Is the given timeout valid? */
2346
2276
  if( !ptimeout || (waittime.tv_sec >= 0 && waittime.tv_usec >= 0) ){
2347
2277
  /* Wait for the socket to become readable before checking again */
2348
- ret = rb_wait_for_single_fd( sd, RB_WAITFD_IN, ptimeout ? &waittime : NULL );
2278
+ ret = pg_rb_io_wait(socket_io, RB_INT2NUM(PG_RUBY_IO_READABLE), wait_timeout);
2349
2279
  } else {
2350
- ret = 0;
2351
- }
2352
-
2353
- if ( ret < 0 ){
2354
- rb_sys_fail( "rb_wait_for_single_fd()" );
2280
+ ret = Qfalse;
2355
2281
  }
2356
2282
 
2357
2283
  /* Return false if the select() timed out */
2358
- if ( ret == 0 ){
2284
+ if ( ret == Qfalse ){
2359
2285
  return NULL;
2360
2286
  }
2361
2287
 
2362
2288
  /* Check for connection errors (PQisBusy is true on connection errors) */
2363
2289
  if ( PQconsumeInput(conn) == 0 ){
2290
+ pgconn_close_socket_io(self);
2364
2291
  rb_raise( rb_eConnectionBad, "PQconsumeInput() %s", PQerrorMessage(conn) );
2365
2292
  }
2366
2293
  }
@@ -2368,8 +2295,45 @@ wait_socket_readable( PGconn *conn, struct timeval *ptimeout, void *(*is_readabl
2368
2295
  return retval;
2369
2296
  }
2370
2297
 
2298
+ /*
2299
+ * call-seq:
2300
+ * conn.flush() -> Boolean
2301
+ *
2302
+ * Attempts to flush any queued output data to the server.
2303
+ * Returns +true+ if data is successfully flushed, +false+
2304
+ * if not (can only return +false+ if connection is
2305
+ * nonblocking.
2306
+ * Raises PG::Error if some other failure occurred.
2307
+ */
2308
+ static VALUE
2309
+ pgconn_async_flush(VALUE self)
2310
+ {
2311
+ while( pgconn_sync_flush(self) == Qfalse ){
2312
+ /* wait for the socket to become read- or write-ready */
2313
+ int events;
2314
+ VALUE socket_io = pgconn_socket_io(self);
2315
+ events = RB_NUM2INT(pg_rb_io_wait(socket_io, RB_INT2NUM(PG_RUBY_IO_READABLE | PG_RUBY_IO_WRITABLE), Qnil));
2316
+
2317
+ if (events & PG_RUBY_IO_READABLE)
2318
+ pgconn_consume_input(self);
2319
+ }
2320
+ return Qtrue;
2321
+ }
2322
+
2323
+ static VALUE
2324
+ pgconn_wait_for_flush( VALUE self ){
2325
+ if( !pg_get_connection_safe(self)->flush_data )
2326
+ return Qnil;
2371
2327
 
2372
- #endif
2328
+ return pgconn_async_flush(self);
2329
+ }
2330
+
2331
+ static VALUE
2332
+ pgconn_flush_data_set( VALUE self, VALUE enabled ){
2333
+ t_pg_connection *conn = pg_get_connection(self);
2334
+ conn->flush_data = RTEST(enabled);
2335
+ return enabled;
2336
+ }
2373
2337
 
2374
2338
  static void *
2375
2339
  notify_readable(PGconn *conn)
@@ -2408,7 +2372,7 @@ pgconn_wait_for_notify(int argc, VALUE *argv, VALUE self)
2408
2372
  ptimeout = &timeout;
2409
2373
  }
2410
2374
 
2411
- pnotification = (PGnotify*) wait_socket_readable( this->pgconn, ptimeout, notify_readable);
2375
+ pnotification = (PGnotify*) wait_socket_readable( self, ptimeout, notify_readable);
2412
2376
 
2413
2377
  /* Return nil if the select timed out */
2414
2378
  if ( !pnotification ) return Qnil;
@@ -2429,28 +2393,8 @@ pgconn_wait_for_notify(int argc, VALUE *argv, VALUE self)
2429
2393
  }
2430
2394
 
2431
2395
 
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
2396
  static VALUE
2453
- pgconn_put_copy_data(int argc, VALUE *argv, VALUE self)
2397
+ pgconn_sync_put_copy_data(int argc, VALUE *argv, VALUE self)
2454
2398
  {
2455
2399
  int ret;
2456
2400
  int len;
@@ -2467,13 +2411,11 @@ pgconn_put_copy_data(int argc, VALUE *argv, VALUE self)
2467
2411
  if( NIL_P(this->encoder_for_put_copy_data) ){
2468
2412
  buffer = value;
2469
2413
  } else {
2470
- p_coder = DATA_PTR( this->encoder_for_put_copy_data );
2414
+ p_coder = RTYPEDDATA_DATA( this->encoder_for_put_copy_data );
2471
2415
  }
2472
- } else if( rb_obj_is_kind_of(encoder, rb_cPG_Coder) ) {
2473
- Data_Get_Struct( encoder, t_pg_coder, p_coder );
2474
2416
  } else {
2475
- rb_raise( rb_eTypeError, "wrong encoder type %s (expected some kind of PG::Coder)",
2476
- rb_obj_classname( encoder ) );
2417
+ /* Check argument type and use argument encoder */
2418
+ TypedData_Get_Struct(encoder, t_pg_coder, &pg_coder_type, p_coder);
2477
2419
  }
2478
2420
 
2479
2421
  if( p_coder ){
@@ -2507,22 +2449,8 @@ pgconn_put_copy_data(int argc, VALUE *argv, VALUE self)
2507
2449
  return (ret) ? Qtrue : Qfalse;
2508
2450
  }
2509
2451
 
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
2452
  static VALUE
2525
- pgconn_put_copy_end(int argc, VALUE *argv, VALUE self)
2453
+ pgconn_sync_put_copy_end(int argc, VALUE *argv, VALUE self)
2526
2454
  {
2527
2455
  VALUE str;
2528
2456
  VALUE error;
@@ -2544,27 +2472,8 @@ pgconn_put_copy_end(int argc, VALUE *argv, VALUE self)
2544
2472
  return (ret) ? Qtrue : Qfalse;
2545
2473
  }
2546
2474
 
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
2475
  static VALUE
2567
- pgconn_get_copy_data(int argc, VALUE *argv, VALUE self )
2476
+ pgconn_sync_get_copy_data(int argc, VALUE *argv, VALUE self )
2568
2477
  {
2569
2478
  VALUE async_in;
2570
2479
  VALUE error;
@@ -2579,13 +2488,11 @@ pgconn_get_copy_data(int argc, VALUE *argv, VALUE self )
2579
2488
 
2580
2489
  if( NIL_P(decoder) ){
2581
2490
  if( !NIL_P(this->decoder_for_get_copy_data) ){
2582
- p_coder = DATA_PTR( this->decoder_for_get_copy_data );
2491
+ p_coder = RTYPEDDATA_DATA( this->decoder_for_get_copy_data );
2583
2492
  }
2584
- } else if( rb_obj_is_kind_of(decoder, rb_cPG_Coder) ) {
2585
- Data_Get_Struct( decoder, t_pg_coder, p_coder );
2586
2493
  } else {
2587
- rb_raise( rb_eTypeError, "wrong decoder type %s (expected some kind of PG::Coder)",
2588
- rb_obj_classname( decoder ) );
2494
+ /* Check argument type and use argument decoder */
2495
+ TypedData_Get_Struct(decoder, t_pg_coder, &pg_coder_type, p_coder);
2589
2496
  }
2590
2497
 
2591
2498
  ret = gvl_PQgetCopyData(this->pgconn, &buffer, RTEST(async_in));
@@ -2830,7 +2737,7 @@ notice_processor_proxy(void *arg, const char *message)
2830
2737
  * call-seq:
2831
2738
  * conn.set_notice_processor {|message| ... } -> Proc
2832
2739
  *
2833
- * See #set_notice_receiver for the desription of what this and the
2740
+ * See #set_notice_receiver for the description of what this and the
2834
2741
  * notice_processor methods do.
2835
2742
  *
2836
2743
  * This function takes a new block to act as the notice processor and returns
@@ -2884,12 +2791,14 @@ pgconn_get_client_encoding(VALUE self)
2884
2791
 
2885
2792
  /*
2886
2793
  * call-seq:
2887
- * conn.set_client_encoding( encoding )
2794
+ * conn.sync_set_client_encoding( encoding )
2888
2795
  *
2889
- * Sets the client encoding to the _encoding_ String.
2796
+ * This function has the same behavior as #async_set_client_encoding, but is implemented using the synchronous command processing API of libpq.
2797
+ * See #async_exec for the differences between the two API variants.
2798
+ * 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
2799
  */
2891
2800
  static VALUE
2892
- pgconn_set_client_encoding(VALUE self, VALUE str)
2801
+ pgconn_sync_set_client_encoding(VALUE self, VALUE str)
2893
2802
  {
2894
2803
  PGconn *conn = pg_get_pgconn( self );
2895
2804
 
@@ -2903,49 +2812,6 @@ pgconn_set_client_encoding(VALUE self, VALUE str)
2903
2812
  return Qnil;
2904
2813
  }
2905
2814
 
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
2815
 
2950
2816
  /*
2951
2817
  * call-seq:
@@ -3022,8 +2888,6 @@ get_result_readable(PGconn *conn)
3022
2888
  */
3023
2889
  static VALUE
3024
2890
  pgconn_block( int argc, VALUE *argv, VALUE self ) {
3025
- PGconn *conn = pg_get_pgconn( self );
3026
-
3027
2891
  struct timeval timeout;
3028
2892
  struct timeval *ptimeout = NULL;
3029
2893
  VALUE timeout_in;
@@ -3037,7 +2901,7 @@ pgconn_block( int argc, VALUE *argv, VALUE self ) {
3037
2901
  ptimeout = &timeout;
3038
2902
  }
3039
2903
 
3040
- ret = wait_socket_readable( conn, ptimeout, get_result_readable);
2904
+ ret = wait_socket_readable( self, ptimeout, get_result_readable);
3041
2905
 
3042
2906
  if( !ret )
3043
2907
  return Qfalse;
@@ -3046,6 +2910,42 @@ pgconn_block( int argc, VALUE *argv, VALUE self ) {
3046
2910
  }
3047
2911
 
3048
2912
 
2913
+ /*
2914
+ * call-seq:
2915
+ * conn.sync_get_last_result( ) -> PG::Result
2916
+ *
2917
+ * This function has the same behavior as #async_get_last_result, 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 #get_last_result instead, unless you have a good reason to do so.
2920
+ */
2921
+ static VALUE
2922
+ pgconn_sync_get_last_result(VALUE self)
2923
+ {
2924
+ PGconn *conn = pg_get_pgconn(self);
2925
+ VALUE rb_pgresult = Qnil;
2926
+ PGresult *cur, *prev;
2927
+
2928
+
2929
+ cur = prev = NULL;
2930
+ while ((cur = gvl_PQgetResult(conn)) != NULL) {
2931
+ int status;
2932
+
2933
+ if (prev) PQclear(prev);
2934
+ prev = cur;
2935
+
2936
+ status = PQresultStatus(cur);
2937
+ if (status == PGRES_COPY_OUT || status == PGRES_COPY_IN || status == PGRES_COPY_BOTH)
2938
+ break;
2939
+ }
2940
+
2941
+ if (prev) {
2942
+ rb_pgresult = pg_new_result( prev, self );
2943
+ pg_result_check(rb_pgresult);
2944
+ }
2945
+
2946
+ return rb_pgresult;
2947
+ }
2948
+
3049
2949
  /*
3050
2950
  * call-seq:
3051
2951
  * conn.get_last_result( ) -> PG::Result
@@ -3056,27 +2956,35 @@ pgconn_block( int argc, VALUE *argv, VALUE self ) {
3056
2956
  * returns the last non-NULL result, or +nil+ if no
3057
2957
  * results are available.
3058
2958
  *
2959
+ * If the last result contains a bad result_status, an
2960
+ * appropriate exception is raised.
2961
+ *
3059
2962
  * This function is similar to #get_result
3060
2963
  * except that it is designed to get one and only
3061
- * one result.
2964
+ * one result and that it checks the result state.
3062
2965
  */
3063
2966
  static VALUE
3064
- pgconn_get_last_result(VALUE self)
2967
+ pgconn_async_get_last_result(VALUE self)
3065
2968
  {
3066
2969
  PGconn *conn = pg_get_pgconn(self);
3067
2970
  VALUE rb_pgresult = Qnil;
3068
2971
  PGresult *cur, *prev;
3069
2972
 
3070
-
3071
- cur = prev = NULL;
3072
- while ((cur = gvl_PQgetResult(conn)) != NULL) {
2973
+ cur = prev = NULL;
2974
+ for(;;) {
3073
2975
  int status;
3074
2976
 
2977
+ pgconn_block( 0, NULL, self ); /* wait for input (without blocking) before reading the last result */
2978
+
2979
+ cur = gvl_PQgetResult(conn);
2980
+ if (cur == NULL)
2981
+ break;
2982
+
3075
2983
  if (prev) PQclear(prev);
3076
2984
  prev = cur;
3077
2985
 
3078
2986
  status = PQresultStatus(cur);
3079
- if (status == PGRES_COPY_OUT || status == PGRES_COPY_IN)
2987
+ if (status == PGRES_COPY_OUT || status == PGRES_COPY_IN || status == PGRES_COPY_BOTH)
3080
2988
  break;
3081
2989
  }
3082
2990
 
@@ -3100,22 +3008,60 @@ static VALUE
3100
3008
  pgconn_discard_results(VALUE self)
3101
3009
  {
3102
3010
  PGconn *conn = pg_get_pgconn(self);
3011
+ VALUE socket_io;
3103
3012
 
3104
- PGresult *cur;
3105
- while ((cur = gvl_PQgetResult(conn)) != NULL) {
3106
- int status = PQresultStatus(cur);
3013
+ if( PQtransactionStatus(conn) == PQTRANS_IDLE ) {
3014
+ return Qnil;
3015
+ }
3016
+
3017
+ socket_io = pgconn_socket_io(self);
3018
+
3019
+ for(;;) {
3020
+ PGresult *cur;
3021
+ int status;
3022
+
3023
+ /* pgconn_block() raises an exception in case of errors.
3024
+ * To avoid this call pg_rb_io_wait() and PQconsumeInput() without rb_raise().
3025
+ */
3026
+ while( gvl_PQisBusy(conn) ){
3027
+ pg_rb_io_wait(socket_io, RB_INT2NUM(PG_RUBY_IO_READABLE), Qnil);
3028
+ if ( PQconsumeInput(conn) == 0 ) {
3029
+ pgconn_close_socket_io(self);
3030
+ return Qfalse;
3031
+ }
3032
+ }
3033
+
3034
+ cur = gvl_PQgetResult(conn);
3035
+ if( cur == NULL) break;
3036
+
3037
+ status = PQresultStatus(cur);
3107
3038
  PQclear(cur);
3108
3039
  if (status == PGRES_COPY_IN){
3109
3040
  gvl_PQputCopyEnd(conn, "COPY terminated by new PQexec");
3110
3041
  }
3111
3042
  if (status == PGRES_COPY_OUT){
3112
- char *buffer = NULL;
3113
- while( gvl_PQgetCopyData(conn, &buffer, 0) > 0)
3114
- PQfreemem(buffer);
3043
+ for(;;) {
3044
+ char *buffer = NULL;
3045
+ int st = gvl_PQgetCopyData(conn, &buffer, 1);
3046
+ if( st == 0 ) {
3047
+ /* would block -> wait for readable data */
3048
+ pg_rb_io_wait(socket_io, RB_INT2NUM(PG_RUBY_IO_READABLE), Qnil);
3049
+ if ( PQconsumeInput(conn) == 0 ) {
3050
+ pgconn_close_socket_io(self);
3051
+ return Qfalse;
3052
+ }
3053
+ } else if( st > 0 ) {
3054
+ /* some data retrieved -> discard it */
3055
+ PQfreemem(buffer);
3056
+ } else {
3057
+ /* no more data */
3058
+ break;
3059
+ }
3060
+ }
3115
3061
  }
3116
3062
  }
3117
3063
 
3118
- return Qnil;
3064
+ return Qtrue;
3119
3065
  }
3120
3066
 
3121
3067
  /*
@@ -3138,6 +3084,7 @@ pgconn_discard_results(VALUE self)
3138
3084
  * #exec is an alias for #async_exec which is almost identical to #sync_exec .
3139
3085
  * #sync_exec is implemented on the simpler synchronous command processing API of libpq, whereas
3140
3086
  * #async_exec is implemented on the asynchronous API and on ruby's IO mechanisms.
3087
+ * Only #async_exec is compatible to <tt>Fiber.scheduler</tt> based asynchronous IO processing introduced in ruby-3.0.
3141
3088
  * Both methods ensure that other threads can process while waiting for the server to
3142
3089
  * complete the request, but #sync_exec blocks all signals to be processed until the query is finished.
3143
3090
  * This is most notably visible by a delayed reaction to Control+C.
@@ -3152,8 +3099,7 @@ pgconn_async_exec(int argc, VALUE *argv, VALUE self)
3152
3099
 
3153
3100
  pgconn_discard_results( self );
3154
3101
  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 );
3102
+ rb_pgresult = pgconn_async_get_last_result( self );
3157
3103
 
3158
3104
  if ( rb_block_given_p() ) {
3159
3105
  return rb_ensure( rb_yield, rb_pgresult, pg_result_clear, rb_pgresult );
@@ -3182,7 +3128,7 @@ pgconn_async_exec(int argc, VALUE *argv, VALUE self)
3182
3128
  * or, it may be a String. If it is a string, that is equivalent to the hash:
3183
3129
  * { :value => <string value>, :type => 0, :format => 0 }
3184
3130
  *
3185
- * PostgreSQL bind parameters are represented as $1, $1, $2, etc.,
3131
+ * PostgreSQL bind parameters are represented as $1, $2, $3, etc.,
3186
3132
  * inside the SQL query. The 0th element of the +params+ array is bound
3187
3133
  * to $1, the 1st element is bound to $2, etc. +nil+ is treated as +NULL+.
3188
3134
  *
@@ -3225,8 +3171,7 @@ pgconn_async_exec_params(int argc, VALUE *argv, VALUE self)
3225
3171
  } else {
3226
3172
  pgconn_send_query_params( argc, argv, self );
3227
3173
  }
3228
- pgconn_block( 0, NULL, self ); /* wait for input (without blocking) before reading the last result */
3229
- rb_pgresult = pgconn_get_last_result( self );
3174
+ rb_pgresult = pgconn_async_get_last_result( self );
3230
3175
 
3231
3176
  if ( rb_block_given_p() ) {
3232
3177
  return rb_ensure( rb_yield, rb_pgresult, pg_result_clear, rb_pgresult );
@@ -3252,7 +3197,7 @@ pgconn_async_exec_params(int argc, VALUE *argv, VALUE self)
3252
3197
  *
3253
3198
  * For example: "SELECT $1::int"
3254
3199
  *
3255
- * PostgreSQL bind parameters are represented as $1, $1, $2, etc.,
3200
+ * PostgreSQL bind parameters are represented as $1, $2, $3, etc.,
3256
3201
  * inside the SQL query.
3257
3202
  *
3258
3203
  * See also corresponding {libpq function}[https://www.postgresql.org/docs/current/libpq-exec.html#LIBPQ-PQPREPARE].
@@ -3264,8 +3209,7 @@ pgconn_async_prepare(int argc, VALUE *argv, VALUE self)
3264
3209
 
3265
3210
  pgconn_discard_results( self );
3266
3211
  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 );
3212
+ rb_pgresult = pgconn_async_get_last_result( self );
3269
3213
 
3270
3214
  if ( rb_block_given_p() ) {
3271
3215
  return rb_ensure( rb_yield, rb_pgresult, pg_result_clear, rb_pgresult );
@@ -3292,7 +3236,7 @@ pgconn_async_prepare(int argc, VALUE *argv, VALUE self)
3292
3236
  * or, it may be a String. If it is a string, that is equivalent to the hash:
3293
3237
  * { :value => <string value>, :format => 0 }
3294
3238
  *
3295
- * PostgreSQL bind parameters are represented as $1, $1, $2, etc.,
3239
+ * PostgreSQL bind parameters are represented as $1, $2, $3, etc.,
3296
3240
  * inside the SQL query. The 0th element of the +params+ array is bound
3297
3241
  * to $1, the 1st element is bound to $2, etc. +nil+ is treated as +NULL+.
3298
3242
  *
@@ -3318,8 +3262,7 @@ pgconn_async_exec_prepared(int argc, VALUE *argv, VALUE self)
3318
3262
 
3319
3263
  pgconn_discard_results( self );
3320
3264
  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 );
3265
+ rb_pgresult = pgconn_async_get_last_result( self );
3323
3266
 
3324
3267
  if ( rb_block_given_p() ) {
3325
3268
  return rb_ensure( rb_yield, rb_pgresult, pg_result_clear, rb_pgresult );
@@ -3343,8 +3286,7 @@ pgconn_async_describe_portal(VALUE self, VALUE portal)
3343
3286
 
3344
3287
  pgconn_discard_results( self );
3345
3288
  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 );
3289
+ rb_pgresult = pgconn_async_get_last_result( self );
3348
3290
 
3349
3291
  if ( rb_block_given_p() ) {
3350
3292
  return rb_ensure( rb_yield, rb_pgresult, pg_result_clear, rb_pgresult );
@@ -3368,8 +3310,7 @@ pgconn_async_describe_prepared(VALUE self, VALUE stmt_name)
3368
3310
 
3369
3311
  pgconn_discard_results( self );
3370
3312
  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 );
3313
+ rb_pgresult = pgconn_async_get_last_result( self );
3373
3314
 
3374
3315
  if ( rb_block_given_p() ) {
3375
3316
  return rb_ensure( rb_yield, rb_pgresult, pg_result_clear, rb_pgresult );
@@ -3457,6 +3398,126 @@ pgconn_ssl_attribute_names(VALUE self)
3457
3398
  #endif
3458
3399
 
3459
3400
 
3401
+ #ifdef HAVE_PQENTERPIPELINEMODE
3402
+ /*
3403
+ * call-seq:
3404
+ * conn.pipeline_status -> Integer
3405
+ *
3406
+ * Returns the current pipeline mode status of the libpq connection.
3407
+ *
3408
+ * PQpipelineStatus can return one of the following values:
3409
+ *
3410
+ * * PQ_PIPELINE_ON - The libpq connection is in pipeline mode.
3411
+ * * PQ_PIPELINE_OFF - The libpq connection is not in pipeline mode.
3412
+ * * PQ_PIPELINE_ABORTED - The libpq connection is in pipeline mode and an error occurred while processing the current pipeline.
3413
+ * The aborted flag is cleared when PQgetResult returns a result of type PGRES_PIPELINE_SYNC.
3414
+ *
3415
+ * Available since PostgreSQL-14
3416
+ */
3417
+ static VALUE
3418
+ pgconn_pipeline_status(VALUE self)
3419
+ {
3420
+ int res = PQpipelineStatus(pg_get_pgconn(self));
3421
+ return INT2FIX(res);
3422
+ }
3423
+
3424
+
3425
+ /*
3426
+ * call-seq:
3427
+ * conn.enter_pipeline_mode -> nil
3428
+ *
3429
+ * Causes a connection to enter pipeline mode if it is currently idle or already in pipeline mode.
3430
+ *
3431
+ * 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.
3432
+ * This function does not actually send anything to the server, it just changes the libpq connection state.
3433
+ *
3434
+ * Available since PostgreSQL-14
3435
+ */
3436
+ static VALUE
3437
+ pgconn_enter_pipeline_mode(VALUE self)
3438
+ {
3439
+ PGconn *conn = pg_get_pgconn(self);
3440
+ int res = PQenterPipelineMode(conn);
3441
+ if( res == 1 ) {
3442
+ return Qnil;
3443
+ } else {
3444
+ rb_raise(rb_ePGerror, "%s", PQerrorMessage(conn));
3445
+ }
3446
+ }
3447
+
3448
+ /*
3449
+ * call-seq:
3450
+ * conn.exit_pipeline_mode -> nil
3451
+ *
3452
+ * Causes a connection to exit pipeline mode if it is currently in pipeline mode with an empty queue and no pending results.
3453
+ *
3454
+ * Takes no action if not in pipeline mode.
3455
+ * 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.
3456
+ *
3457
+ * Available since PostgreSQL-14
3458
+ */
3459
+ static VALUE
3460
+ pgconn_exit_pipeline_mode(VALUE self)
3461
+ {
3462
+ PGconn *conn = pg_get_pgconn(self);
3463
+ int res = PQexitPipelineMode(conn);
3464
+ if( res == 1 ) {
3465
+ return Qnil;
3466
+ } else {
3467
+ rb_raise(rb_ePGerror, "%s", PQerrorMessage(conn));
3468
+ }
3469
+ }
3470
+
3471
+
3472
+ /*
3473
+ * call-seq:
3474
+ * conn.pipeline_sync -> nil
3475
+ *
3476
+ * Marks a synchronization point in a pipeline by sending a sync message and flushing the send buffer.
3477
+ * This serves as the delimiter of an implicit transaction and an error recovery point; see Section 34.5.1.3 of the PostgreSQL documentation.
3478
+ *
3479
+ * Raises PG::Error if the connection is not in pipeline mode or sending a sync message failed.
3480
+ *
3481
+ * Available since PostgreSQL-14
3482
+ */
3483
+ static VALUE
3484
+ pgconn_pipeline_sync(VALUE self)
3485
+ {
3486
+ PGconn *conn = pg_get_pgconn(self);
3487
+ int res = PQpipelineSync(conn);
3488
+ if( res == 1 ) {
3489
+ return Qnil;
3490
+ } else {
3491
+ rb_raise(rb_ePGerror, "%s", PQerrorMessage(conn));
3492
+ }
3493
+ }
3494
+
3495
+ /*
3496
+ * call-seq:
3497
+ * conn.pipeline_sync -> nil
3498
+ *
3499
+ * Sends a request for the server to flush its output buffer.
3500
+ *
3501
+ * 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.
3502
+ * This function is useful to cause the server to flush its output buffer in pipeline mode without establishing a synchronization point.
3503
+ * Note that the request is not itself flushed to the server automatically; use Connection#flush if necessary.
3504
+ *
3505
+ * Available since PostgreSQL-14
3506
+ */
3507
+ static VALUE
3508
+ pgconn_send_flush_request(VALUE self)
3509
+ {
3510
+ PGconn *conn = pg_get_pgconn(self);
3511
+ int res = PQsendFlushRequest(conn);
3512
+ if( res == 1 ) {
3513
+ return Qnil;
3514
+ } else {
3515
+ rb_raise(rb_ePGerror, "%s", PQerrorMessage(conn));
3516
+ }
3517
+ }
3518
+
3519
+ #endif
3520
+
3460
3521
  /**************************************************************************
3461
3522
  * LARGE OBJECT SUPPORT
3462
3523
  **************************************************************************/
@@ -3801,11 +3862,11 @@ static VALUE
3801
3862
  pgconn_internal_encoding_set(VALUE self, VALUE enc)
3802
3863
  {
3803
3864
  if (NIL_P(enc)) {
3804
- pgconn_set_client_encoding( self, rb_usascii_str_new_cstr("SQL_ASCII") );
3865
+ pgconn_sync_set_client_encoding( self, rb_usascii_str_new_cstr("SQL_ASCII") );
3805
3866
  return enc;
3806
3867
  }
3807
3868
  else if ( TYPE(enc) == T_STRING && strcasecmp("JOHAB", StringValueCStr(enc)) == 0 ) {
3808
- pgconn_set_client_encoding(self, rb_usascii_str_new_cstr("JOHAB"));
3869
+ pgconn_sync_set_client_encoding(self, rb_usascii_str_new_cstr("JOHAB"));
3809
3870
  return enc;
3810
3871
  }
3811
3872
  else {
@@ -3843,16 +3904,33 @@ pgconn_external_encoding(VALUE self)
3843
3904
  return rb_enc_from_encoding( enc );
3844
3905
  }
3845
3906
 
3907
+ /*
3908
+ * call-seq:
3909
+ * conn.set_client_encoding( encoding )
3910
+ *
3911
+ * Sets the client encoding to the _encoding_ String.
3912
+ */
3913
+ static VALUE
3914
+ pgconn_async_set_client_encoding(VALUE self, VALUE encname)
3915
+ {
3916
+ VALUE query_format, query;
3917
+
3918
+ Check_Type(encname, T_STRING);
3919
+ query_format = rb_str_new_cstr("set client_encoding to '%s'");
3920
+ query = rb_funcall(query_format, rb_intern("%"), 1, encname);
3921
+
3922
+ pgconn_async_exec(1, &query, self);
3923
+ pgconn_set_internal_encoding_index( self );
3924
+
3925
+ return Qnil;
3926
+ }
3846
3927
 
3847
3928
  static VALUE
3848
3929
  pgconn_set_client_encoding_async1( VALUE args )
3849
3930
  {
3850
3931
  VALUE self = ((VALUE*)args)[0];
3851
3932
  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);
3933
+ pgconn_async_set_client_encoding(self, encname);
3856
3934
  return 0;
3857
3935
  }
3858
3936
 
@@ -3867,9 +3945,9 @@ pgconn_set_client_encoding_async2( VALUE arg, VALUE ex )
3867
3945
 
3868
3946
 
3869
3947
  static VALUE
3870
- pgconn_set_client_encoding_async( VALUE self, const char *encname )
3948
+ pgconn_set_client_encoding_async( VALUE self, VALUE encname )
3871
3949
  {
3872
- VALUE args[] = { self, rb_str_new_cstr(encname) };
3950
+ VALUE args[] = { self, encname };
3873
3951
  return rb_rescue(pgconn_set_client_encoding_async1, (VALUE)&args, pgconn_set_client_encoding_async2, Qnil);
3874
3952
  }
3875
3953
 
@@ -3891,10 +3969,9 @@ pgconn_set_default_encoding( VALUE self )
3891
3969
 
3892
3970
  if (( enc = rb_default_internal_encoding() )) {
3893
3971
  encname = pg_get_rb_encoding_as_pg_encoding( enc );
3894
- if ( pgconn_set_client_encoding_async(self, encname) != 0 )
3972
+ if ( pgconn_set_client_encoding_async(self, rb_str_new_cstr(encname)) != 0 )
3895
3973
  rb_warning( "Failed to set the default_internal encoding to %s: '%s'",
3896
3974
  encname, PQerrorMessage(conn) );
3897
- pgconn_set_internal_encoding_index( self );
3898
3975
  return rb_enc_from_encoding( enc );
3899
3976
  } else {
3900
3977
  pgconn_set_internal_encoding_index( self );
@@ -3916,12 +3993,12 @@ static VALUE
3916
3993
  pgconn_type_map_for_queries_set(VALUE self, VALUE typemap)
3917
3994
  {
3918
3995
  t_pg_connection *this = pg_get_connection( self );
3996
+ t_typemap *tm;
3997
+ UNUSED(tm);
3998
+
3999
+ /* Check type of method param */
4000
+ TypedData_Get_Struct(typemap, t_typemap, &pg_typemap_type, tm);
3919
4001
 
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
4002
  this->type_map_for_queries = typemap;
3926
4003
 
3927
4004
  return typemap;
@@ -3956,12 +4033,10 @@ static VALUE
3956
4033
  pgconn_type_map_for_results_set(VALUE self, VALUE typemap)
3957
4034
  {
3958
4035
  t_pg_connection *this = pg_get_connection( self );
4036
+ t_typemap *tm;
4037
+ UNUSED(tm);
3959
4038
 
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);
4039
+ TypedData_Get_Struct(typemap, t_typemap, &pg_typemap_type, tm);
3965
4040
  this->type_map_for_results = typemap;
3966
4041
 
3967
4042
  return typemap;
@@ -3996,20 +4071,19 @@ pgconn_type_map_for_results_get(VALUE self)
3996
4071
  *
3997
4072
  */
3998
4073
  static VALUE
3999
- pgconn_encoder_for_put_copy_data_set(VALUE self, VALUE typemap)
4074
+ pgconn_encoder_for_put_copy_data_set(VALUE self, VALUE encoder)
4000
4075
  {
4001
4076
  t_pg_connection *this = pg_get_connection( self );
4002
4077
 
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);
4078
+ if( encoder != Qnil ){
4079
+ t_pg_coder *co;
4080
+ UNUSED(co);
4081
+ /* Check argument type */
4082
+ TypedData_Get_Struct(encoder, t_pg_coder, &pg_coder_type, co);
4009
4083
  }
4010
- this->encoder_for_put_copy_data = typemap;
4084
+ this->encoder_for_put_copy_data = encoder;
4011
4085
 
4012
- return typemap;
4086
+ return encoder;
4013
4087
  }
4014
4088
 
4015
4089
  /*
@@ -4045,20 +4119,19 @@ pgconn_encoder_for_put_copy_data_get(VALUE self)
4045
4119
  *
4046
4120
  */
4047
4121
  static VALUE
4048
- pgconn_decoder_for_get_copy_data_set(VALUE self, VALUE typemap)
4122
+ pgconn_decoder_for_get_copy_data_set(VALUE self, VALUE decoder)
4049
4123
  {
4050
4124
  t_pg_connection *this = pg_get_connection( self );
4051
4125
 
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);
4126
+ if( decoder != Qnil ){
4127
+ t_pg_coder *co;
4128
+ UNUSED(co);
4129
+ /* Check argument type */
4130
+ TypedData_Get_Struct(decoder, t_pg_coder, &pg_coder_type, co);
4058
4131
  }
4059
- this->decoder_for_get_copy_data = typemap;
4132
+ this->decoder_for_get_copy_data = decoder;
4060
4133
 
4061
- return typemap;
4134
+ return decoder;
4062
4135
  }
4063
4136
 
4064
4137
  /*
@@ -4141,6 +4214,7 @@ void
4141
4214
  init_pg_connection()
4142
4215
  {
4143
4216
  s_id_encode = rb_intern("encode");
4217
+ s_id_autoclose_set = rb_intern("autoclose=");
4144
4218
  sym_type = ID2SYM(rb_intern("type"));
4145
4219
  sym_format = ID2SYM(rb_intern("format"));
4146
4220
  sym_value = ID2SYM(rb_intern("value"));
@@ -4156,10 +4230,6 @@ init_pg_connection()
4156
4230
  /****** PG::Connection CLASS METHODS ******/
4157
4231
  rb_define_alloc_func( rb_cPGconn, pgconn_s_allocate );
4158
4232
 
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
4233
  rb_define_singleton_method(rb_cPGconn, "escape_string", pgconn_s_escape, 1);
4164
4234
  SINGLETON_ALIAS(rb_cPGconn, "escape", "escape_string");
4165
4235
  rb_define_singleton_method(rb_cPGconn, "escape_bytea", pgconn_s_escape_bytea, 1);
@@ -4168,14 +4238,14 @@ init_pg_connection()
4168
4238
  rb_define_singleton_method(rb_cPGconn, "quote_ident", pgconn_s_quote_ident, 1);
4169
4239
  rb_define_singleton_method(rb_cPGconn, "connect_start", pgconn_s_connect_start, -1);
4170
4240
  rb_define_singleton_method(rb_cPGconn, "conndefaults", pgconn_s_conndefaults, 0);
4171
- rb_define_singleton_method(rb_cPGconn, "ping", pgconn_s_ping, -1);
4241
+ rb_define_singleton_method(rb_cPGconn, "sync_ping", pgconn_s_sync_ping, -1);
4242
+ rb_define_singleton_method(rb_cPGconn, "sync_connect", pgconn_s_sync_connect, -1);
4172
4243
 
4173
4244
  /****** PG::Connection INSTANCE METHODS: Connection Control ******/
4174
- rb_define_method(rb_cPGconn, "initialize", pgconn_init, -1);
4175
4245
  rb_define_method(rb_cPGconn, "connect_poll", pgconn_connect_poll, 0);
4176
4246
  rb_define_method(rb_cPGconn, "finish", pgconn_finish, 0);
4177
4247
  rb_define_method(rb_cPGconn, "finished?", pgconn_finished_p, 0);
4178
- rb_define_method(rb_cPGconn, "reset", pgconn_reset, 0);
4248
+ rb_define_method(rb_cPGconn, "sync_reset", pgconn_sync_reset, 0);
4179
4249
  rb_define_method(rb_cPGconn, "reset_start", pgconn_reset_start, 0);
4180
4250
  rb_define_method(rb_cPGconn, "reset_poll", pgconn_reset_poll, 0);
4181
4251
  rb_define_alias(rb_cPGconn, "close", "finish");
@@ -4187,9 +4257,7 @@ init_pg_connection()
4187
4257
  rb_define_method(rb_cPGconn, "host", pgconn_host, 0);
4188
4258
  rb_define_method(rb_cPGconn, "port", pgconn_port, 0);
4189
4259
  rb_define_method(rb_cPGconn, "tty", pgconn_tty, 0);
4190
- #ifdef HAVE_PQCONNINFO
4191
4260
  rb_define_method(rb_cPGconn, "conninfo", pgconn_conninfo, 0);
4192
- #endif
4193
4261
  rb_define_method(rb_cPGconn, "options", pgconn_options, 0);
4194
4262
  rb_define_method(rb_cPGconn, "status", pgconn_status, 0);
4195
4263
  rb_define_method(rb_cPGconn, "transaction_status", pgconn_transaction_status, 0);
@@ -4200,17 +4268,18 @@ init_pg_connection()
4200
4268
  rb_define_method(rb_cPGconn, "socket", pgconn_socket, 0);
4201
4269
  rb_define_method(rb_cPGconn, "socket_io", pgconn_socket_io, 0);
4202
4270
  rb_define_method(rb_cPGconn, "backend_pid", pgconn_backend_pid, 0);
4271
+ rb_define_method(rb_cPGconn, "backend_key", pgconn_backend_key, 0);
4203
4272
  rb_define_method(rb_cPGconn, "connection_needs_password", pgconn_connection_needs_password, 0);
4204
4273
  rb_define_method(rb_cPGconn, "connection_used_password", pgconn_connection_used_password, 0);
4205
4274
  /* rb_define_method(rb_cPGconn, "getssl", pgconn_getssl, 0); */
4206
4275
 
4207
4276
  /****** 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);
4277
+ rb_define_method(rb_cPGconn, "sync_exec", pgconn_sync_exec, -1);
4278
+ rb_define_method(rb_cPGconn, "sync_exec_params", pgconn_sync_exec_params, -1);
4279
+ rb_define_method(rb_cPGconn, "sync_prepare", pgconn_sync_prepare, -1);
4280
+ rb_define_method(rb_cPGconn, "sync_exec_prepared", pgconn_sync_exec_prepared, -1);
4281
+ rb_define_method(rb_cPGconn, "sync_describe_prepared", pgconn_sync_describe_prepared, 1);
4282
+ rb_define_method(rb_cPGconn, "sync_describe_portal", pgconn_sync_describe_portal, 1);
4214
4283
 
4215
4284
  rb_define_method(rb_cPGconn, "exec", pgconn_async_exec, -1);
4216
4285
  rb_define_method(rb_cPGconn, "exec_params", pgconn_async_exec_params, -1);
@@ -4243,25 +4312,26 @@ init_pg_connection()
4243
4312
  rb_define_method(rb_cPGconn, "send_query_prepared", pgconn_send_query_prepared, -1);
4244
4313
  rb_define_method(rb_cPGconn, "send_describe_prepared", pgconn_send_describe_prepared, 1);
4245
4314
  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);
4315
+ rb_define_method(rb_cPGconn, "sync_get_result", pgconn_sync_get_result, 0);
4247
4316
  rb_define_method(rb_cPGconn, "consume_input", pgconn_consume_input, 0);
4248
4317
  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);
4318
+ rb_define_method(rb_cPGconn, "sync_setnonblocking", pgconn_sync_setnonblocking, 1);
4319
+ rb_define_method(rb_cPGconn, "sync_isnonblocking", pgconn_sync_isnonblocking, 0);
4320
+ rb_define_method(rb_cPGconn, "sync_flush", pgconn_sync_flush, 0);
4321
+ rb_define_method(rb_cPGconn, "flush", pgconn_async_flush, 0);
4322
+ rb_define_alias(rb_cPGconn, "async_flush", "flush");
4253
4323
  rb_define_method(rb_cPGconn, "discard_results", pgconn_discard_results, 0);
4254
4324
 
4255
4325
  /****** PG::Connection INSTANCE METHODS: Cancelling Queries in Progress ******/
4256
- rb_define_method(rb_cPGconn, "cancel", pgconn_cancel, 0);
4326
+ rb_define_method(rb_cPGconn, "sync_cancel", pgconn_sync_cancel, 0);
4257
4327
 
4258
4328
  /****** PG::Connection INSTANCE METHODS: NOTIFY ******/
4259
4329
  rb_define_method(rb_cPGconn, "notifies", pgconn_notifies, 0);
4260
4330
 
4261
4331
  /****** 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);
4332
+ rb_define_method(rb_cPGconn, "sync_put_copy_data", pgconn_sync_put_copy_data, -1);
4333
+ rb_define_method(rb_cPGconn, "sync_put_copy_end", pgconn_sync_put_copy_end, -1);
4334
+ rb_define_method(rb_cPGconn, "sync_get_copy_data", pgconn_sync_get_copy_data, -1);
4265
4335
 
4266
4336
  /****** PG::Connection INSTANCE METHODS: Control Functions ******/
4267
4337
  rb_define_method(rb_cPGconn, "set_error_verbosity", pgconn_set_error_verbosity, 1);
@@ -4277,16 +4347,20 @@ init_pg_connection()
4277
4347
 
4278
4348
  /****** PG::Connection INSTANCE METHODS: Other ******/
4279
4349
  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);
4350
+ rb_define_method(rb_cPGconn, "sync_set_client_encoding", pgconn_sync_set_client_encoding, 1);
4351
+ rb_define_method(rb_cPGconn, "set_client_encoding", pgconn_async_set_client_encoding, 1);
4352
+ rb_define_alias(rb_cPGconn, "async_set_client_encoding", "set_client_encoding");
4281
4353
  rb_define_alias(rb_cPGconn, "client_encoding=", "set_client_encoding");
4282
- rb_define_method(rb_cPGconn, "transaction", pgconn_transaction, 0);
4283
4354
  rb_define_method(rb_cPGconn, "block", pgconn_block, -1);
4355
+ rb_define_private_method(rb_cPGconn, "flush_data=", pgconn_flush_data_set, 1);
4284
4356
  rb_define_method(rb_cPGconn, "wait_for_notify", pgconn_wait_for_notify, -1);
4285
4357
  rb_define_alias(rb_cPGconn, "notifies_wait", "wait_for_notify");
4286
4358
  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);
4359
+ rb_define_method(rb_cPGconn, "sync_get_last_result", pgconn_sync_get_last_result, 0);
4360
+ rb_define_method(rb_cPGconn, "get_last_result", pgconn_async_get_last_result, 0);
4361
+ rb_define_alias(rb_cPGconn, "async_get_last_result", "get_last_result");
4288
4362
  #ifdef HAVE_PQENCRYPTPASSWORDCONN
4289
- rb_define_method(rb_cPGconn, "encrypt_password", pgconn_encrypt_password, -1);
4363
+ rb_define_method(rb_cPGconn, "sync_encrypt_password", pgconn_sync_encrypt_password, -1);
4290
4364
  #endif
4291
4365
 
4292
4366
  #ifdef HAVE_PQSSLATTRIBUTE
@@ -4295,6 +4369,14 @@ init_pg_connection()
4295
4369
  rb_define_method(rb_cPGconn, "ssl_attribute_names", pgconn_ssl_attribute_names, 0);
4296
4370
  #endif
4297
4371
 
4372
+ #ifdef HAVE_PQENTERPIPELINEMODE
4373
+ rb_define_method(rb_cPGconn, "pipeline_status", pgconn_pipeline_status, 0);
4374
+ rb_define_method(rb_cPGconn, "enter_pipeline_mode", pgconn_enter_pipeline_mode, 0);
4375
+ rb_define_method(rb_cPGconn, "exit_pipeline_mode", pgconn_exit_pipeline_mode, 0);
4376
+ rb_define_method(rb_cPGconn, "pipeline_sync", pgconn_pipeline_sync, 0);
4377
+ rb_define_method(rb_cPGconn, "send_flush_request", pgconn_send_flush_request, 0);
4378
+ #endif
4379
+
4298
4380
  /****** PG::Connection INSTANCE METHODS: Large Object Support ******/
4299
4381
  rb_define_method(rb_cPGconn, "lo_creat", pgconn_locreat, -1);
4300
4382
  rb_define_alias(rb_cPGconn, "locreat", "lo_creat");