pg 1.2.3 → 1.5.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (134) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data/.appveyor.yml +42 -0
  4. data/.gems +6 -0
  5. data/.github/workflows/binary-gems.yml +117 -0
  6. data/.github/workflows/source-gem.yml +141 -0
  7. data/.gitignore +22 -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 +17 -0
  15. data/History.md +901 -0
  16. data/Manifest.txt +0 -1
  17. data/README.ja.md +300 -0
  18. data/README.md +286 -0
  19. data/Rakefile +36 -135
  20. data/Rakefile.cross +13 -13
  21. data/certs/ged.pem +24 -0
  22. data/certs/kanis@comcard.de.pem +20 -0
  23. data/certs/larskanis-2022.pem +26 -0
  24. data/certs/larskanis-2023.pem +24 -0
  25. data/certs/larskanis-2024.pem +24 -0
  26. data/ext/errorcodes.def +12 -0
  27. data/ext/errorcodes.rb +0 -0
  28. data/ext/errorcodes.txt +4 -1
  29. data/ext/extconf.rb +104 -25
  30. data/ext/gvl_wrappers.c +4 -0
  31. data/ext/gvl_wrappers.h +23 -0
  32. data/ext/pg.c +73 -58
  33. data/ext/pg.h +28 -5
  34. data/ext/pg_binary_decoder.c +80 -1
  35. data/ext/pg_binary_encoder.c +225 -1
  36. data/ext/pg_coder.c +96 -33
  37. data/ext/pg_connection.c +1032 -704
  38. data/ext/pg_copy_coder.c +351 -33
  39. data/ext/pg_errors.c +1 -1
  40. data/ext/pg_record_coder.c +50 -19
  41. data/ext/pg_result.c +177 -64
  42. data/ext/pg_text_decoder.c +29 -11
  43. data/ext/pg_text_encoder.c +29 -16
  44. data/ext/pg_tuple.c +83 -60
  45. data/ext/pg_type_map.c +44 -10
  46. data/ext/pg_type_map_all_strings.c +17 -3
  47. data/ext/pg_type_map_by_class.c +54 -27
  48. data/ext/pg_type_map_by_column.c +73 -31
  49. data/ext/pg_type_map_by_mri_type.c +48 -19
  50. data/ext/pg_type_map_by_oid.c +59 -27
  51. data/ext/pg_type_map_in_ruby.c +55 -21
  52. data/ext/pg_util.c +2 -2
  53. data/lib/pg/basic_type_map_based_on_result.rb +67 -0
  54. data/lib/pg/basic_type_map_for_queries.rb +202 -0
  55. data/lib/pg/basic_type_map_for_results.rb +104 -0
  56. data/lib/pg/basic_type_registry.rb +303 -0
  57. data/lib/pg/binary_decoder/date.rb +9 -0
  58. data/lib/pg/binary_decoder/timestamp.rb +26 -0
  59. data/lib/pg/binary_encoder/timestamp.rb +20 -0
  60. data/lib/pg/coder.rb +15 -13
  61. data/lib/pg/connection.rb +752 -83
  62. data/lib/pg/exceptions.rb +14 -1
  63. data/lib/pg/text_decoder/date.rb +18 -0
  64. data/lib/pg/text_decoder/inet.rb +9 -0
  65. data/lib/pg/text_decoder/json.rb +14 -0
  66. data/lib/pg/text_decoder/numeric.rb +9 -0
  67. data/lib/pg/text_decoder/timestamp.rb +30 -0
  68. data/lib/pg/text_encoder/date.rb +12 -0
  69. data/lib/pg/text_encoder/inet.rb +28 -0
  70. data/lib/pg/text_encoder/json.rb +14 -0
  71. data/lib/pg/text_encoder/numeric.rb +9 -0
  72. data/lib/pg/text_encoder/timestamp.rb +24 -0
  73. data/lib/pg/version.rb +4 -0
  74. data/lib/pg.rb +94 -39
  75. data/misc/openssl-pg-segfault.rb +31 -0
  76. data/misc/postgres/History.txt +9 -0
  77. data/misc/postgres/Manifest.txt +5 -0
  78. data/misc/postgres/README.txt +21 -0
  79. data/misc/postgres/Rakefile +21 -0
  80. data/misc/postgres/lib/postgres.rb +16 -0
  81. data/misc/ruby-pg/History.txt +9 -0
  82. data/misc/ruby-pg/Manifest.txt +5 -0
  83. data/misc/ruby-pg/README.txt +21 -0
  84. data/misc/ruby-pg/Rakefile +21 -0
  85. data/misc/ruby-pg/lib/ruby/pg.rb +16 -0
  86. data/pg.gemspec +34 -0
  87. data/rakelib/task_extension.rb +46 -0
  88. data/sample/array_insert.rb +20 -0
  89. data/sample/async_api.rb +102 -0
  90. data/sample/async_copyto.rb +39 -0
  91. data/sample/async_mixed.rb +56 -0
  92. data/sample/check_conn.rb +21 -0
  93. data/sample/copydata.rb +71 -0
  94. data/sample/copyfrom.rb +81 -0
  95. data/sample/copyto.rb +19 -0
  96. data/sample/cursor.rb +21 -0
  97. data/sample/disk_usage_report.rb +177 -0
  98. data/sample/issue-119.rb +94 -0
  99. data/sample/losample.rb +69 -0
  100. data/sample/minimal-testcase.rb +17 -0
  101. data/sample/notify_wait.rb +72 -0
  102. data/sample/pg_statistics.rb +285 -0
  103. data/sample/replication_monitor.rb +222 -0
  104. data/sample/test_binary_values.rb +33 -0
  105. data/sample/wal_shipper.rb +434 -0
  106. data/sample/warehouse_partitions.rb +311 -0
  107. data.tar.gz.sig +0 -0
  108. metadata +137 -210
  109. metadata.gz.sig +0 -0
  110. data/ChangeLog +0 -0
  111. data/History.rdoc +0 -578
  112. data/README.ja.rdoc +0 -13
  113. data/README.rdoc +0 -213
  114. data/lib/pg/basic_type_mapping.rb +0 -522
  115. data/lib/pg/binary_decoder.rb +0 -23
  116. data/lib/pg/constants.rb +0 -12
  117. data/lib/pg/text_decoder.rb +0 -46
  118. data/lib/pg/text_encoder.rb +0 -59
  119. data/spec/data/expected_trace.out +0 -26
  120. data/spec/data/random_binary_data +0 -0
  121. data/spec/helpers.rb +0 -380
  122. data/spec/pg/basic_type_mapping_spec.rb +0 -630
  123. data/spec/pg/connection_spec.rb +0 -1949
  124. data/spec/pg/connection_sync_spec.rb +0 -41
  125. data/spec/pg/result_spec.rb +0 -681
  126. data/spec/pg/tuple_spec.rb +0 -333
  127. data/spec/pg/type_map_by_class_spec.rb +0 -138
  128. data/spec/pg/type_map_by_column_spec.rb +0 -226
  129. data/spec/pg/type_map_by_mri_type_spec.rb +0 -136
  130. data/spec/pg/type_map_by_oid_spec.rb +0 -149
  131. data/spec/pg/type_map_in_ruby_spec.rb +0 -164
  132. data/spec/pg/type_map_spec.rb +0 -22
  133. data/spec/pg/type_spec.rb +0 -1123
  134. data/spec/pg_spec.rb +0 -50
data/ext/pg_connection.c CHANGED
@@ -12,20 +12,41 @@
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
 
18
- static PQnoticeReceiver default_notice_receiver = NULL;
19
- static PQnoticeProcessor default_notice_processor = NULL;
20
-
21
19
  static VALUE pgconn_finish( VALUE );
22
20
  static VALUE pgconn_set_default_encoding( VALUE self );
21
+ static VALUE pgconn_wait_for_flush( VALUE self );
23
22
  static void pgconn_set_internal_encoding_index( VALUE );
23
+ static const rb_data_type_t pg_connection_type;
24
+ static VALUE pgconn_async_flush(VALUE self);
24
25
 
25
26
  /*
26
27
  * Global functions
27
28
  */
28
29
 
30
+ /*
31
+ * Convenience function to raise connection errors
32
+ */
33
+ #ifdef __GNUC__
34
+ __attribute__((format(printf, 3, 4)))
35
+ #endif
36
+ static void
37
+ pg_raise_conn_error( VALUE klass, VALUE self, const char *format, ...)
38
+ {
39
+ VALUE msg, error;
40
+ va_list ap;
41
+
42
+ va_start(ap, format);
43
+ msg = rb_vsprintf(format, ap);
44
+ va_end(ap);
45
+ error = rb_exc_new_str(klass, msg);
46
+ rb_iv_set(error, "@connection", self);
47
+ rb_exc_raise(error);
48
+ }
49
+
29
50
  /*
30
51
  * Fetch the PG::Connection object data pointer.
31
52
  */
@@ -33,7 +54,7 @@ t_pg_connection *
33
54
  pg_get_connection( VALUE self )
34
55
  {
35
56
  t_pg_connection *this;
36
- Data_Get_Struct( self, t_pg_connection, this);
57
+ TypedData_Get_Struct( self, t_pg_connection, &pg_connection_type, this);
37
58
 
38
59
  return this;
39
60
  }
@@ -46,10 +67,10 @@ static t_pg_connection *
46
67
  pg_get_connection_safe( VALUE self )
47
68
  {
48
69
  t_pg_connection *this;
49
- Data_Get_Struct( self, t_pg_connection, this);
70
+ TypedData_Get_Struct( self, t_pg_connection, &pg_connection_type, this);
50
71
 
51
72
  if ( !this->pgconn )
52
- rb_raise( rb_eConnectionBad, "connection is closed" );
73
+ pg_raise_conn_error( rb_eConnectionBad, self, "connection is closed");
53
74
 
54
75
  return this;
55
76
  }
@@ -65,10 +86,11 @@ PGconn *
65
86
  pg_get_pgconn( VALUE self )
66
87
  {
67
88
  t_pg_connection *this;
68
- Data_Get_Struct( self, t_pg_connection, this);
89
+ TypedData_Get_Struct( self, t_pg_connection, &pg_connection_type, this);
69
90
 
70
- if ( !this->pgconn )
71
- rb_raise( rb_eConnectionBad, "connection is closed" );
91
+ if ( !this->pgconn ){
92
+ pg_raise_conn_error( rb_eConnectionBad, self, "connection is closed");
93
+ }
72
94
 
73
95
  return this->pgconn;
74
96
  }
@@ -86,14 +108,13 @@ pgconn_close_socket_io( VALUE self )
86
108
 
87
109
  if ( RTEST(socket_io) ) {
88
110
  #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
- }
111
+ if( rb_w32_unwrap_io_handle(this->ruby_sd) )
112
+ pg_raise_conn_error( rb_eConnectionBad, self, "Could not unwrap win32 socket handle");
92
113
  #endif
93
114
  rb_funcall( socket_io, rb_intern("close"), 0 );
94
115
  }
95
116
 
96
- this->socket_io = Qnil;
117
+ RB_OBJ_WRITE(self, &this->socket_io, Qnil);
97
118
  }
98
119
 
99
120
 
@@ -145,16 +166,31 @@ static const char *pg_cstr_enc(VALUE str, int enc_idx){
145
166
  * GC Mark function
146
167
  */
147
168
  static void
148
- pgconn_gc_mark( t_pg_connection *this )
169
+ pgconn_gc_mark( void *_this )
170
+ {
171
+ t_pg_connection *this = (t_pg_connection *)_this;
172
+ rb_gc_mark_movable( this->socket_io );
173
+ rb_gc_mark_movable( this->notice_receiver );
174
+ rb_gc_mark_movable( this->notice_processor );
175
+ rb_gc_mark_movable( this->type_map_for_queries );
176
+ rb_gc_mark_movable( this->type_map_for_results );
177
+ rb_gc_mark_movable( this->trace_stream );
178
+ rb_gc_mark_movable( this->encoder_for_put_copy_data );
179
+ rb_gc_mark_movable( this->decoder_for_get_copy_data );
180
+ }
181
+
182
+ static void
183
+ pgconn_gc_compact( void *_this )
149
184
  {
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 );
185
+ t_pg_connection *this = (t_pg_connection *)_this;
186
+ pg_gc_location( this->socket_io );
187
+ pg_gc_location( this->notice_receiver );
188
+ pg_gc_location( this->notice_processor );
189
+ pg_gc_location( this->type_map_for_queries );
190
+ pg_gc_location( this->type_map_for_results );
191
+ pg_gc_location( this->trace_stream );
192
+ pg_gc_location( this->encoder_for_put_copy_data );
193
+ pg_gc_location( this->decoder_for_get_copy_data );
158
194
  }
159
195
 
160
196
 
@@ -162,11 +198,15 @@ pgconn_gc_mark( t_pg_connection *this )
162
198
  * GC Free function
163
199
  */
164
200
  static void
165
- pgconn_gc_free( t_pg_connection *this )
201
+ pgconn_gc_free( void *_this )
166
202
  {
203
+ t_pg_connection *this = (t_pg_connection *)_this;
167
204
  #if defined(_WIN32)
168
- if ( RTEST(this->socket_io) )
169
- rb_w32_unwrap_io_handle( this->ruby_sd );
205
+ if ( RTEST(this->socket_io) ) {
206
+ if( rb_w32_unwrap_io_handle(this->ruby_sd) ){
207
+ rb_warn("pg: Could not unwrap win32 socket handle by garbage collector");
208
+ }
209
+ }
170
210
  #endif
171
211
  if (this->pgconn != NULL)
172
212
  PQfinish( this->pgconn );
@@ -174,6 +214,29 @@ pgconn_gc_free( t_pg_connection *this )
174
214
  xfree(this);
175
215
  }
176
216
 
217
+ /*
218
+ * Object Size function
219
+ */
220
+ static size_t
221
+ pgconn_memsize( const void *_this )
222
+ {
223
+ const t_pg_connection *this = (const t_pg_connection *)_this;
224
+ return sizeof(*this);
225
+ }
226
+
227
+ static const rb_data_type_t pg_connection_type = {
228
+ "PG::Connection",
229
+ {
230
+ pgconn_gc_mark,
231
+ pgconn_gc_free,
232
+ pgconn_memsize,
233
+ pg_compact_callback(pgconn_gc_compact),
234
+ },
235
+ 0,
236
+ 0,
237
+ RUBY_TYPED_WB_PROTECTED,
238
+ };
239
+
177
240
 
178
241
  /**************************************************************************
179
242
  * Class Methods
@@ -189,93 +252,38 @@ static VALUE
189
252
  pgconn_s_allocate( VALUE klass )
190
253
  {
191
254
  t_pg_connection *this;
192
- VALUE self = Data_Make_Struct( klass, t_pg_connection, pgconn_gc_mark, pgconn_gc_free, this );
255
+ VALUE self = TypedData_Make_Struct( klass, t_pg_connection, &pg_connection_type, this );
193
256
 
194
257
  this->pgconn = NULL;
195
- this->socket_io = Qnil;
196
- this->notice_receiver = Qnil;
197
- this->notice_processor = Qnil;
198
- this->type_map_for_queries = pg_typemap_all_strings;
199
- this->type_map_for_results = pg_typemap_all_strings;
200
- this->encoder_for_put_copy_data = Qnil;
201
- this->decoder_for_get_copy_data = Qnil;
202
- this->trace_stream = Qnil;
258
+ RB_OBJ_WRITE(self, &this->socket_io, Qnil);
259
+ RB_OBJ_WRITE(self, &this->notice_receiver, Qnil);
260
+ RB_OBJ_WRITE(self, &this->notice_processor, Qnil);
261
+ RB_OBJ_WRITE(self, &this->type_map_for_queries, pg_typemap_all_strings);
262
+ RB_OBJ_WRITE(self, &this->type_map_for_results, pg_typemap_all_strings);
263
+ RB_OBJ_WRITE(self, &this->encoder_for_put_copy_data, Qnil);
264
+ RB_OBJ_WRITE(self, &this->decoder_for_get_copy_data, Qnil);
265
+ RB_OBJ_WRITE(self, &this->trace_stream, Qnil);
266
+ rb_ivar_set(self, rb_intern("@calls_to_put_copy_data"), INT2FIX(0));
203
267
 
204
268
  return self;
205
269
  }
206
270
 
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
271
  static VALUE
261
- pgconn_init(int argc, VALUE *argv, VALUE self)
272
+ pgconn_s_sync_connect(int argc, VALUE *argv, VALUE klass)
262
273
  {
263
274
  t_pg_connection *this;
264
275
  VALUE conninfo;
265
- VALUE error;
276
+ VALUE self = pgconn_s_allocate( klass );
266
277
 
267
278
  this = pg_get_connection( self );
268
279
  conninfo = rb_funcall2( rb_cPGconn, rb_intern("parse_connect_args"), argc, argv );
269
280
  this->pgconn = gvl_PQconnectdb(StringValueCStr(conninfo));
270
281
 
271
282
  if(this->pgconn == NULL)
272
- rb_raise(rb_ePGerror, "PQconnectdb() unable to allocate structure");
283
+ rb_raise(rb_ePGerror, "PQconnectdb() unable to allocate PGconn structure");
273
284
 
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
- }
285
+ if (PQstatus(this->pgconn) == CONNECTION_BAD)
286
+ pg_raise_conn_error( rb_eConnectionBad, self, "%s", PQerrorMessage(this->pgconn));
279
287
 
280
288
  pgconn_set_default_encoding( self );
281
289
 
@@ -308,7 +316,6 @@ pgconn_s_connect_start( int argc, VALUE *argv, VALUE klass )
308
316
  {
309
317
  VALUE rb_conn;
310
318
  VALUE conninfo;
311
- VALUE error;
312
319
  t_pg_connection *this;
313
320
 
314
321
  /*
@@ -321,13 +328,10 @@ pgconn_s_connect_start( int argc, VALUE *argv, VALUE klass )
321
328
  this->pgconn = gvl_PQconnectStart( StringValueCStr(conninfo) );
322
329
 
323
330
  if( this->pgconn == NULL )
324
- rb_raise(rb_ePGerror, "PQconnectStart() unable to allocate structure");
331
+ rb_raise(rb_ePGerror, "PQconnectStart() unable to allocate PGconn structure");
325
332
 
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
- }
333
+ if ( PQstatus(this->pgconn) == CONNECTION_BAD )
334
+ pg_raise_conn_error( rb_eConnectionBad, rb_conn, "%s", PQerrorMessage(this->pgconn));
331
335
 
332
336
  if ( rb_block_given_p() ) {
333
337
  return rb_ensure( rb_yield, rb_conn, pgconn_finish, rb_conn );
@@ -335,34 +339,14 @@ pgconn_s_connect_start( int argc, VALUE *argv, VALUE klass )
335
339
  return rb_conn;
336
340
  }
337
341
 
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
342
  static VALUE
359
- pgconn_s_ping( int argc, VALUE *argv, VALUE klass )
343
+ pgconn_s_sync_ping( int argc, VALUE *argv, VALUE klass )
360
344
  {
361
345
  PGPing ping;
362
346
  VALUE conninfo;
363
347
 
364
348
  conninfo = rb_funcall2( klass, rb_intern("parse_connect_args"), argc, argv );
365
- ping = PQping( StringValueCStr(conninfo) );
349
+ ping = gvl_PQping( StringValueCStr(conninfo) );
366
350
 
367
351
  return INT2FIX((int)ping);
368
352
  }
@@ -403,32 +387,40 @@ pgconn_s_conndefaults(VALUE self)
403
387
  return array;
404
388
  }
405
389
 
406
-
407
- #ifdef HAVE_PQENCRYPTPASSWORDCONN
408
390
  /*
409
- * call-seq:
410
- * conn.encrypt_password( password, username, algorithm=nil ) -> String
391
+ * Document-method: PG::Connection.conninfo_parse
411
392
  *
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.
393
+ * call-seq:
394
+ * PG::Connection.conninfo_parse(conninfo_string) -> Array
426
395
  *
427
- * Available since PostgreSQL-10.
428
- * See also corresponding {libpq function}[https://www.postgresql.org/docs/current/libpq-misc.html#LIBPQ-PQENCRYPTPASSWORDCONN].
396
+ * Returns parsed connection options from the provided connection string as an array of hashes.
397
+ * Each hash has the same keys as PG::Connection.conndefaults() .
398
+ * The values from the +conninfo_string+ are stored in the +:val+ key.
429
399
  */
430
400
  static VALUE
431
- pgconn_encrypt_password(int argc, VALUE *argv, VALUE self)
401
+ pgconn_s_conninfo_parse(VALUE self, VALUE conninfo)
402
+ {
403
+ VALUE array;
404
+ char *errmsg = NULL;
405
+ PQconninfoOption *options = PQconninfoParse(StringValueCStr(conninfo), &errmsg);
406
+ if(errmsg){
407
+ VALUE error = rb_str_new_cstr(errmsg);
408
+ PQfreemem(errmsg);
409
+ rb_raise(rb_ePGerror, "%"PRIsVALUE, error);
410
+ }
411
+ array = pgconn_make_conninfo_array( options );
412
+
413
+ PQconninfoFree(options);
414
+
415
+ UNUSED( self );
416
+
417
+ return array;
418
+ }
419
+
420
+
421
+ #ifdef HAVE_PQENCRYPTPASSWORDCONN
422
+ static VALUE
423
+ pgconn_sync_encrypt_password(int argc, VALUE *argv, VALUE self)
432
424
  {
433
425
  char *encrypted = NULL;
434
426
  VALUE rval = Qnil;
@@ -445,7 +437,7 @@ pgconn_encrypt_password(int argc, VALUE *argv, VALUE self)
445
437
  rval = rb_str_new2( encrypted );
446
438
  PQfreemem( encrypted );
447
439
  } else {
448
- rb_raise(rb_ePGerror, "%s", PQerrorMessage(conn));
440
+ pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(conn));
449
441
  }
450
442
 
451
443
  return rval;
@@ -499,17 +491,18 @@ pgconn_s_encrypt_password(VALUE self, VALUE password, VALUE username)
499
491
  * the asynchronous connection is ready
500
492
  *
501
493
  * Example:
502
- * conn = PG::Connection.connect_start("dbname=mydatabase")
503
- * socket = conn.socket_io
494
+ * require "io/wait"
495
+ *
496
+ * conn = PG::Connection.connect_start(dbname: 'mydatabase')
504
497
  * status = conn.connect_poll
505
498
  * while(status != PG::PGRES_POLLING_OK) do
506
499
  * # do some work while waiting for the connection to complete
507
500
  * if(status == PG::PGRES_POLLING_READING)
508
- * if(not select([socket], [], [], 10.0))
501
+ * unless conn.socket_io.wait_readable(10.0)
509
502
  * raise "Asynchronous connection timed out!"
510
503
  * end
511
504
  * elsif(status == PG::PGRES_POLLING_WRITING)
512
- * if(not select([], [socket], [], 10.0))
505
+ * unless conn.socket_io.wait_writable(10.0)
513
506
  * raise "Asynchronous connection timed out!"
514
507
  * end
515
508
  * end
@@ -523,6 +516,9 @@ pgconn_connect_poll(VALUE self)
523
516
  {
524
517
  PostgresPollingStatusType status;
525
518
  status = gvl_PQconnectPoll(pg_get_pgconn(self));
519
+
520
+ pgconn_close_socket_io(self);
521
+
526
522
  return INT2FIX((int)status);
527
523
  }
528
524
 
@@ -559,21 +555,35 @@ pgconn_finished_p( VALUE self )
559
555
  }
560
556
 
561
557
 
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
558
  static VALUE
570
- pgconn_reset( VALUE self )
559
+ pgconn_sync_reset( VALUE self )
571
560
  {
572
561
  pgconn_close_socket_io( self );
573
562
  gvl_PQreset( pg_get_pgconn(self) );
574
563
  return self;
575
564
  }
576
565
 
566
+ static VALUE
567
+ pgconn_reset_start2( VALUE self, VALUE conninfo )
568
+ {
569
+ t_pg_connection *this = pg_get_connection( self );
570
+
571
+ /* Close old connection */
572
+ pgconn_close_socket_io( self );
573
+ PQfinish( this->pgconn );
574
+
575
+ /* Start new connection */
576
+ this->pgconn = gvl_PQconnectStart( StringValueCStr(conninfo) );
577
+
578
+ if( this->pgconn == NULL )
579
+ rb_raise(rb_ePGerror, "PQconnectStart() unable to allocate PGconn structure");
580
+
581
+ if ( PQstatus(this->pgconn) == CONNECTION_BAD )
582
+ pg_raise_conn_error( rb_eConnectionBad, self, "%s", PQerrorMessage(this->pgconn));
583
+
584
+ return Qnil;
585
+ }
586
+
577
587
  /*
578
588
  * call-seq:
579
589
  * conn.reset_start() -> nil
@@ -589,7 +599,7 @@ pgconn_reset_start(VALUE self)
589
599
  {
590
600
  pgconn_close_socket_io( self );
591
601
  if(gvl_PQresetStart(pg_get_pgconn(self)) == 0)
592
- rb_raise(rb_eUnableToSend, "reset has failed");
602
+ pg_raise_conn_error( rb_eUnableToSend, self, "reset has failed");
593
603
  return Qnil;
594
604
  }
595
605
 
@@ -606,6 +616,9 @@ pgconn_reset_poll(VALUE self)
606
616
  {
607
617
  PostgresPollingStatusType status;
608
618
  status = gvl_PQresetPoll(pg_get_pgconn(self));
619
+
620
+ pgconn_close_socket_io(self);
621
+
609
622
  return INT2FIX((int)status);
610
623
  }
611
624
 
@@ -656,7 +669,18 @@ pgconn_pass(VALUE self)
656
669
  * call-seq:
657
670
  * conn.host()
658
671
  *
659
- * Returns the connected server name.
672
+ * Returns the server host name of the active connection.
673
+ * This can be a host name, an IP address, or a directory path if the connection is via Unix socket.
674
+ * (The path case can be distinguished because it will always be an absolute path, beginning with +/+ .)
675
+ *
676
+ * If the connection parameters specified both host and hostaddr, then +host+ will return the host information.
677
+ * If only hostaddr was specified, then that is returned.
678
+ * If multiple hosts were specified in the connection parameters, +host+ returns the host actually connected to.
679
+ *
680
+ * 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.
681
+ *
682
+ * 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.
683
+ * The status of the connection can be checked using the function Connection#status .
660
684
  */
661
685
  static VALUE
662
686
  pgconn_host(VALUE self)
@@ -666,6 +690,26 @@ pgconn_host(VALUE self)
666
690
  return rb_str_new2(host);
667
691
  }
668
692
 
693
+ /* PQhostaddr() appeared in PostgreSQL-12 together with PQresultMemorySize() */
694
+ #if defined(HAVE_PQRESULTMEMORYSIZE)
695
+ /*
696
+ * call-seq:
697
+ * conn.hostaddr()
698
+ *
699
+ * Returns the server IP address of the active connection.
700
+ * This can be the address that a host name resolved to, or an IP address provided through the hostaddr parameter.
701
+ * 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.
702
+ *
703
+ */
704
+ static VALUE
705
+ pgconn_hostaddr(VALUE self)
706
+ {
707
+ char *host = PQhostaddr(pg_get_pgconn(self));
708
+ if (!host) return Qnil;
709
+ return rb_str_new2(host);
710
+ }
711
+ #endif
712
+
669
713
  /*
670
714
  * call-seq:
671
715
  * conn.port()
@@ -676,21 +720,22 @@ static VALUE
676
720
  pgconn_port(VALUE self)
677
721
  {
678
722
  char* port = PQport(pg_get_pgconn(self));
679
- return INT2NUM(atol(port));
723
+ if (!port || port[0] == '\0')
724
+ return INT2NUM(DEF_PGPORT);
725
+ else
726
+ return INT2NUM(atoi(port));
680
727
  }
681
728
 
682
729
  /*
683
730
  * call-seq:
684
731
  * conn.tty()
685
732
  *
686
- * Returns the connected pgtty. (Obsolete)
733
+ * Obsolete function.
687
734
  */
688
735
  static VALUE
689
736
  pgconn_tty(VALUE self)
690
737
  {
691
- char *tty = PQtty(pg_get_pgconn(self));
692
- if (!tty) return Qnil;
693
- return rb_str_new2(tty);
738
+ return rb_str_new2("");
694
739
  }
695
740
 
696
741
  /*
@@ -708,7 +753,6 @@ pgconn_options(VALUE self)
708
753
  }
709
754
 
710
755
 
711
- #ifdef HAVE_PQCONNINFO
712
756
  /*
713
757
  * call-seq:
714
758
  * conn.conninfo -> hash
@@ -728,14 +772,24 @@ pgconn_conninfo( VALUE self )
728
772
 
729
773
  return array;
730
774
  }
731
- #endif
732
775
 
733
776
 
734
777
  /*
735
778
  * call-seq:
736
779
  * conn.status()
737
780
  *
738
- * Returns status of connection : CONNECTION_OK or CONNECTION_BAD
781
+ * Returns the status of the connection, which is one:
782
+ * PG::Constants::CONNECTION_OK
783
+ * PG::Constants::CONNECTION_BAD
784
+ *
785
+ * ... and other constants of kind PG::Constants::CONNECTION_*
786
+ *
787
+ * This method returns the status of the last command from memory.
788
+ * It doesn't do any socket access hence is not suitable to test the connectivity.
789
+ * See check_socket for a way to verify the socket state.
790
+ *
791
+ * Example:
792
+ * PG.constants.grep(/CONNECTION_/).find{|c| PG.const_get(c) == conn.status} # => :CONNECTION_OK
739
793
  */
740
794
  static VALUE
741
795
  pgconn_status(VALUE self)
@@ -823,7 +877,10 @@ pgconn_server_version(VALUE self)
823
877
  * call-seq:
824
878
  * conn.error_message -> String
825
879
  *
826
- * Returns the error message about connection.
880
+ * Returns the error message most recently generated by an operation on the connection.
881
+ *
882
+ * Nearly all libpq functions will set a message for conn.error_message if they fail.
883
+ * Note that by libpq convention, a nonempty error_message result can consist of multiple lines, and will include a trailing newline.
827
884
  */
828
885
  static VALUE
829
886
  pgconn_error_message(VALUE self)
@@ -857,7 +914,8 @@ pgconn_socket(VALUE self)
857
914
  pg_deprecated(4, ("conn.socket is deprecated and should be replaced by conn.socket_io"));
858
915
 
859
916
  if( (sd = PQsocket(pg_get_pgconn(self))) < 0)
860
- rb_raise(rb_eConnectionBad, "PQsocket() can't get socket descriptor");
917
+ pg_raise_conn_error( rb_eConnectionBad, self, "PQsocket() can't get socket descriptor");
918
+
861
919
  return INT2NUM(sd);
862
920
  }
863
921
 
@@ -865,40 +923,47 @@ pgconn_socket(VALUE self)
865
923
  * call-seq:
866
924
  * conn.socket_io() -> IO
867
925
  *
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.
926
+ * Fetch an IO object created from the Connection's underlying socket.
927
+ * 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.
928
+ * <tt>IO#wait_*able</tt> is is <tt>Fiber.scheduler</tt> compatible in contrast to <tt>IO.select</tt>.
871
929
  *
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.
930
+ * The IO object can change while the connection is established, but is memorized afterwards.
931
+ * So be sure not to cache the IO object, but repeat calling <tt>conn.socket_io</tt> instead.
932
+ *
933
+ * Using this method also works on Windows in contrast to using #socket .
934
+ * 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
935
  */
876
936
  static VALUE
877
937
  pgconn_socket_io(VALUE self)
878
938
  {
879
939
  int sd;
880
940
  int ruby_sd;
881
- ID id_autoclose = rb_intern("autoclose=");
882
941
  t_pg_connection *this = pg_get_connection_safe( self );
942
+ VALUE cSocket;
883
943
  VALUE socket_io = this->socket_io;
884
944
 
885
945
  if ( !RTEST(socket_io) ) {
886
- if( (sd = PQsocket(this->pgconn)) < 0)
887
- rb_raise(rb_eConnectionBad, "PQsocket() can't get socket descriptor");
946
+ if( (sd = PQsocket(this->pgconn)) < 0){
947
+ pg_raise_conn_error( rb_eConnectionBad, self, "PQsocket() can't get socket descriptor");
948
+ }
888
949
 
889
950
  #ifdef _WIN32
890
951
  ruby_sd = rb_w32_wrap_io_handle((HANDLE)(intptr_t)sd, O_RDWR|O_BINARY|O_NOINHERIT);
952
+ if( ruby_sd == -1 )
953
+ pg_raise_conn_error( rb_eConnectionBad, self, "Could not wrap win32 socket handle");
954
+
891
955
  this->ruby_sd = ruby_sd;
892
956
  #else
893
957
  ruby_sd = sd;
894
958
  #endif
895
959
 
896
- socket_io = rb_funcall( rb_cIO, rb_intern("for_fd"), 1, INT2NUM(ruby_sd) );
960
+ cSocket = rb_const_get(rb_cObject, rb_intern("BasicSocket"));
961
+ socket_io = rb_funcall( cSocket, rb_intern("for_fd"), 1, INT2NUM(ruby_sd));
897
962
 
898
963
  /* Disable autoclose feature */
899
- rb_funcall( socket_io, id_autoclose, 1, Qfalse );
964
+ rb_funcall( socket_io, s_id_autoclose_set, 1, Qfalse );
900
965
 
901
- this->socket_io = socket_io;
966
+ RB_OBJ_WRITE(self, &this->socket_io, socket_io);
902
967
  }
903
968
 
904
969
  return socket_io;
@@ -918,6 +983,51 @@ pgconn_backend_pid(VALUE self)
918
983
  return INT2NUM(PQbackendPID(pg_get_pgconn(self)));
919
984
  }
920
985
 
986
+ typedef struct
987
+ {
988
+ struct sockaddr_storage addr;
989
+ socklen_t salen;
990
+ } SockAddr;
991
+
992
+ /* Copy of struct pg_cancel from libpq-int.h
993
+ *
994
+ * See https://github.com/postgres/postgres/blame/master/src/interfaces/libpq/libpq-int.h#L577-L586
995
+ */
996
+ struct pg_cancel
997
+ {
998
+ SockAddr raddr; /* Remote address */
999
+ int be_pid; /* PID of backend --- needed for cancels */
1000
+ int be_key; /* key of backend --- needed for cancels */
1001
+ };
1002
+
1003
+ /*
1004
+ * call-seq:
1005
+ * conn.backend_key() -> Integer
1006
+ *
1007
+ * Returns the key of the backend server process for this connection.
1008
+ * This key can be used to cancel queries on the server.
1009
+ */
1010
+ static VALUE
1011
+ pgconn_backend_key(VALUE self)
1012
+ {
1013
+ int be_key;
1014
+ struct pg_cancel *cancel;
1015
+ PGconn *conn = pg_get_pgconn(self);
1016
+
1017
+ cancel = (struct pg_cancel*)PQgetCancel(conn);
1018
+ if(cancel == NULL)
1019
+ pg_raise_conn_error( rb_ePGerror, self, "Invalid connection!");
1020
+
1021
+ if( cancel->be_pid != PQbackendPID(conn) )
1022
+ rb_raise(rb_ePGerror,"Unexpected binary struct layout - please file a bug report at ruby-pg!");
1023
+
1024
+ be_key = cancel->be_key;
1025
+
1026
+ PQfreeCancel(cancel);
1027
+
1028
+ return INT2NUM(be_key);
1029
+ }
1030
+
921
1031
  /*
922
1032
  * call-seq:
923
1033
  * conn.connection_needs_password() -> Boolean
@@ -948,7 +1058,7 @@ pgconn_connection_used_password(VALUE self)
948
1058
  /* :TODO: get_ssl */
949
1059
 
950
1060
 
951
- static VALUE pgconn_exec_params( int, VALUE *, VALUE );
1061
+ static VALUE pgconn_sync_exec_params( int, VALUE *, VALUE );
952
1062
 
953
1063
  /*
954
1064
  * call-seq:
@@ -962,11 +1072,11 @@ static VALUE pgconn_exec_params( int, VALUE *, VALUE );
962
1072
  * However #async_exec has two advantages:
963
1073
  *
964
1074
  * 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
1075
+ * 2. Ruby VM gets notified about IO blocked operations and can pass them through <tt>Fiber.scheduler</tt>.
1076
+ * So only <tt>async_*</tt> methods are compatible to event based schedulers like the async gem.
967
1077
  */
968
1078
  static VALUE
969
- pgconn_exec(int argc, VALUE *argv, VALUE self)
1079
+ pgconn_sync_exec(int argc, VALUE *argv, VALUE self)
970
1080
  {
971
1081
  t_pg_connection *this = pg_get_connection_safe( self );
972
1082
  PGresult *result = NULL;
@@ -987,7 +1097,7 @@ pgconn_exec(int argc, VALUE *argv, VALUE self)
987
1097
  pg_deprecated(0, ("forwarding exec to exec_params is deprecated"));
988
1098
 
989
1099
  /* Otherwise, just call #exec_params instead for backward-compatibility */
990
- return pgconn_exec_params( argc, argv, self );
1100
+ return pgconn_sync_exec_params( argc, argv, self );
991
1101
 
992
1102
  }
993
1103
 
@@ -1019,7 +1129,7 @@ struct query_params_data {
1019
1129
  * Filled by alloc_query_params()
1020
1130
  */
1021
1131
 
1022
- /* Wraps the pointer of allocated memory, if function parameters dont't
1132
+ /* Wraps the pointer of allocated memory, if function parameters don't
1023
1133
  * fit in the memory_pool below.
1024
1134
  */
1025
1135
  VALUE heap_pool;
@@ -1037,7 +1147,7 @@ struct query_params_data {
1037
1147
  Oid *types;
1038
1148
 
1039
1149
  /* This array takes the string values for the timeframe of the query,
1040
- * if param value convertion is required
1150
+ * if param value conversion is required
1041
1151
  */
1042
1152
  VALUE gc_array;
1043
1153
 
@@ -1051,8 +1161,9 @@ struct query_params_data {
1051
1161
  };
1052
1162
 
1053
1163
  static void
1054
- free_typecast_heap_chain(struct linked_typecast_data *chain_entry)
1164
+ free_typecast_heap_chain(void *_chain_entry)
1055
1165
  {
1166
+ struct linked_typecast_data *chain_entry = (struct linked_typecast_data *)_chain_entry;
1056
1167
  while(chain_entry){
1057
1168
  struct linked_typecast_data *next = chain_entry->next;
1058
1169
  xfree(chain_entry);
@@ -1060,6 +1171,18 @@ free_typecast_heap_chain(struct linked_typecast_data *chain_entry)
1060
1171
  }
1061
1172
  }
1062
1173
 
1174
+ static const rb_data_type_t pg_typecast_buffer_type = {
1175
+ "PG::Connection typecast buffer chain",
1176
+ {
1177
+ (RUBY_DATA_FUNC) NULL,
1178
+ free_typecast_heap_chain,
1179
+ (size_t (*)(const void *))NULL,
1180
+ },
1181
+ 0,
1182
+ 0,
1183
+ RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
1184
+ };
1185
+
1063
1186
  static char *
1064
1187
  alloc_typecast_buf( VALUE *typecast_heap_chain, int len )
1065
1188
  {
@@ -1070,17 +1193,28 @@ alloc_typecast_buf( VALUE *typecast_heap_chain, int len )
1070
1193
  /* Did we already wrap a memory chain per T_DATA object? */
1071
1194
  if( NIL_P( *typecast_heap_chain ) ){
1072
1195
  /* 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 );
1196
+ *typecast_heap_chain = TypedData_Wrap_Struct( rb_cObject, &pg_typecast_buffer_type, allocated );
1074
1197
  allocated->next = NULL;
1075
1198
  } else {
1076
1199
  /* Append to the chain */
1077
- allocated->next = DATA_PTR( *typecast_heap_chain );
1078
- DATA_PTR( *typecast_heap_chain ) = allocated;
1200
+ allocated->next = RTYPEDDATA_DATA( *typecast_heap_chain );
1201
+ RTYPEDDATA_DATA( *typecast_heap_chain ) = allocated;
1079
1202
  }
1080
1203
 
1081
1204
  return &allocated->data[0];
1082
1205
  }
1083
1206
 
1207
+ static const rb_data_type_t pg_query_heap_pool_type = {
1208
+ "PG::Connection query heap pool",
1209
+ {
1210
+ (RUBY_DATA_FUNC) NULL,
1211
+ RUBY_TYPED_DEFAULT_FREE,
1212
+ (size_t (*)(const void *))NULL,
1213
+ },
1214
+ 0,
1215
+ 0,
1216
+ RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
1217
+ };
1084
1218
 
1085
1219
  static int
1086
1220
  alloc_query_params(struct query_params_data *paramsData)
@@ -1095,7 +1229,7 @@ alloc_query_params(struct query_params_data *paramsData)
1095
1229
 
1096
1230
  Check_Type(paramsData->params, T_ARRAY);
1097
1231
 
1098
- p_typemap = DATA_PTR( paramsData->typemap );
1232
+ p_typemap = RTYPEDDATA_DATA( paramsData->typemap );
1099
1233
  p_typemap->funcs.fit_to_query( paramsData->typemap, paramsData->params );
1100
1234
 
1101
1235
  paramsData->heap_pool = Qnil;
@@ -1114,7 +1248,7 @@ alloc_query_params(struct query_params_data *paramsData)
1114
1248
  /* Allocate one combined memory pool for all possible function parameters */
1115
1249
  memory_pool = (char*)xmalloc( required_pool_size );
1116
1250
  /* 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 );
1251
+ paramsData->heap_pool = TypedData_Wrap_Struct( rb_cObject, &pg_query_heap_pool_type, memory_pool );
1118
1252
  required_pool_size = 0;
1119
1253
  }else{
1120
1254
  /* Use stack memory for function parameters */
@@ -1227,12 +1361,11 @@ pgconn_query_assign_typemap( VALUE self, struct query_params_data *paramsData )
1227
1361
  /* Use default typemap for queries. It's type is checked when assigned. */
1228
1362
  paramsData->typemap = pg_get_connection(self)->type_map_for_queries;
1229
1363
  }else{
1364
+ t_typemap *tm;
1365
+ UNUSED(tm);
1366
+
1230
1367
  /* 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 );
1368
+ TypedData_Get_Struct(paramsData->typemap, t_typemap, &pg_typemap_type, tm);
1236
1369
  }
1237
1370
  }
1238
1371
 
@@ -1246,7 +1379,7 @@ pgconn_query_assign_typemap( VALUE self, struct query_params_data *paramsData )
1246
1379
  * 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
1380
  */
1248
1381
  static VALUE
1249
- pgconn_exec_params( int argc, VALUE *argv, VALUE self )
1382
+ pgconn_sync_exec_params( int argc, VALUE *argv, VALUE self )
1250
1383
  {
1251
1384
  t_pg_connection *this = pg_get_connection_safe( self );
1252
1385
  PGresult *result = NULL;
@@ -1266,7 +1399,7 @@ pgconn_exec_params( int argc, VALUE *argv, VALUE self )
1266
1399
  */
1267
1400
  if ( NIL_P(paramsData.params) ) {
1268
1401
  pg_deprecated(1, ("forwarding exec_params to exec is deprecated"));
1269
- return pgconn_exec( 1, argv, self );
1402
+ return pgconn_sync_exec( 1, argv, self );
1270
1403
  }
1271
1404
  pgconn_query_assign_typemap( self, &paramsData );
1272
1405
 
@@ -1297,7 +1430,7 @@ pgconn_exec_params( int argc, VALUE *argv, VALUE self )
1297
1430
  * It's not recommended to use explicit sync or async variants but #prepare instead, unless you have a good reason to do so.
1298
1431
  */
1299
1432
  static VALUE
1300
- pgconn_prepare(int argc, VALUE *argv, VALUE self)
1433
+ pgconn_sync_prepare(int argc, VALUE *argv, VALUE self)
1301
1434
  {
1302
1435
  t_pg_connection *this = pg_get_connection_safe( self );
1303
1436
  PGresult *result = NULL;
@@ -1346,7 +1479,7 @@ pgconn_prepare(int argc, VALUE *argv, VALUE self)
1346
1479
  * 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
1480
  */
1348
1481
  static VALUE
1349
- pgconn_exec_prepared(int argc, VALUE *argv, VALUE self)
1482
+ pgconn_sync_exec_prepared(int argc, VALUE *argv, VALUE self)
1350
1483
  {
1351
1484
  t_pg_connection *this = pg_get_connection_safe( self );
1352
1485
  PGresult *result = NULL;
@@ -1391,7 +1524,7 @@ pgconn_exec_prepared(int argc, VALUE *argv, VALUE self)
1391
1524
  * 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
1525
  */
1393
1526
  static VALUE
1394
- pgconn_describe_prepared(VALUE self, VALUE stmt_name)
1527
+ pgconn_sync_describe_prepared(VALUE self, VALUE stmt_name)
1395
1528
  {
1396
1529
  PGresult *result;
1397
1530
  VALUE rb_pgresult;
@@ -1419,8 +1552,7 @@ pgconn_describe_prepared(VALUE self, VALUE stmt_name)
1419
1552
  * 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
1553
  */
1421
1554
  static VALUE
1422
- pgconn_describe_portal(self, stmt_name)
1423
- VALUE self, stmt_name;
1555
+ pgconn_sync_describe_portal(VALUE self, VALUE stmt_name)
1424
1556
  {
1425
1557
  PGresult *result;
1426
1558
  VALUE rb_pgresult;
@@ -1454,6 +1586,9 @@ pgconn_describe_portal(self, stmt_name)
1454
1586
  * * +PGRES_NONFATAL_ERROR+
1455
1587
  * * +PGRES_FATAL_ERROR+
1456
1588
  * * +PGRES_COPY_BOTH+
1589
+ * * +PGRES_SINGLE_TUPLE+
1590
+ * * +PGRES_PIPELINE_SYNC+
1591
+ * * +PGRES_PIPELINE_ABORTED+
1457
1592
  */
1458
1593
  static VALUE
1459
1594
  pgconn_make_empty_pgresult(VALUE self, VALUE status)
@@ -1509,9 +1644,9 @@ pgconn_s_escape(VALUE self, VALUE string)
1509
1644
  if( !singleton ) {
1510
1645
  size = PQescapeStringConn(pg_get_pgconn(self), RSTRING_PTR(result),
1511
1646
  RSTRING_PTR(string), RSTRING_LEN(string), &error);
1512
- if(error) {
1513
- rb_raise(rb_ePGerror, "%s", PQerrorMessage(pg_get_pgconn(self)));
1514
- }
1647
+ if(error)
1648
+ pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(pg_get_pgconn(self)));
1649
+
1515
1650
  } else {
1516
1651
  size = PQescapeString(RSTRING_PTR(result), RSTRING_PTR(string), RSTRING_LEN(string));
1517
1652
  }
@@ -1607,7 +1742,6 @@ pgconn_escape_literal(VALUE self, VALUE string)
1607
1742
  {
1608
1743
  t_pg_connection *this = pg_get_connection_safe( self );
1609
1744
  char *escaped = NULL;
1610
- VALUE error;
1611
1745
  VALUE result = Qnil;
1612
1746
  int enc_idx = this->enc_idx;
1613
1747
 
@@ -1618,12 +1752,8 @@ pgconn_escape_literal(VALUE self, VALUE string)
1618
1752
 
1619
1753
  escaped = PQescapeLiteral(this->pgconn, RSTRING_PTR(string), RSTRING_LEN(string));
1620
1754
  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
- }
1755
+ pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(this->pgconn));
1756
+
1627
1757
  result = rb_str_new2(escaped);
1628
1758
  PQfreemem(escaped);
1629
1759
  PG_ENCODING_SET_NOCHECK(result, enc_idx);
@@ -1646,7 +1776,6 @@ pgconn_escape_identifier(VALUE self, VALUE string)
1646
1776
  {
1647
1777
  t_pg_connection *this = pg_get_connection_safe( self );
1648
1778
  char *escaped = NULL;
1649
- VALUE error;
1650
1779
  VALUE result = Qnil;
1651
1780
  int enc_idx = this->enc_idx;
1652
1781
 
@@ -1657,12 +1786,8 @@ pgconn_escape_identifier(VALUE self, VALUE string)
1657
1786
 
1658
1787
  escaped = PQescapeIdentifier(this->pgconn, RSTRING_PTR(string), RSTRING_LEN(string));
1659
1788
  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
- }
1789
+ pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(this->pgconn));
1790
+
1666
1791
  result = rb_str_new2(escaped);
1667
1792
  PQfreemem(escaped);
1668
1793
  PG_ENCODING_SET_NOCHECK(result, enc_idx);
@@ -1710,14 +1835,10 @@ static VALUE
1710
1835
  pgconn_set_single_row_mode(VALUE self)
1711
1836
  {
1712
1837
  PGconn *conn = pg_get_pgconn(self);
1713
- VALUE error;
1714
1838
 
1839
+ rb_check_frozen(self);
1715
1840
  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
- }
1841
+ pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(conn));
1721
1842
 
1722
1843
  return self;
1723
1844
  }
@@ -1741,15 +1862,13 @@ static VALUE
1741
1862
  pgconn_send_query(int argc, VALUE *argv, VALUE self)
1742
1863
  {
1743
1864
  t_pg_connection *this = pg_get_connection_safe( self );
1744
- VALUE error;
1745
1865
 
1746
1866
  /* If called with no or nil parameters, use PQexec for compatibility */
1747
1867
  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
- }
1868
+ if(gvl_PQsendQuery(this->pgconn, pg_cstr_enc(argv[0], this->enc_idx)) == 0)
1869
+ pg_raise_conn_error( rb_eUnableToSend, self, "%s", PQerrorMessage(this->pgconn));
1870
+
1871
+ pgconn_wait_for_flush( self );
1753
1872
  return Qnil;
1754
1873
  }
1755
1874
 
@@ -1779,7 +1898,7 @@ pgconn_send_query(int argc, VALUE *argv, VALUE self)
1779
1898
  * or, it may be a String. If it is a string, that is equivalent to the hash:
1780
1899
  * { :value => <string value>, :type => 0, :format => 0 }
1781
1900
  *
1782
- * PostgreSQL bind parameters are represented as $1, $1, $2, etc.,
1901
+ * PostgreSQL bind parameters are represented as $1, $2, $3, etc.,
1783
1902
  * inside the SQL query. The 0th element of the +params+ array is bound
1784
1903
  * to $1, the 1st element is bound to $2, etc. +nil+ is treated as +NULL+.
1785
1904
  *
@@ -1805,7 +1924,6 @@ pgconn_send_query_params(int argc, VALUE *argv, VALUE self)
1805
1924
  t_pg_connection *this = pg_get_connection_safe( self );
1806
1925
  int result;
1807
1926
  VALUE command, in_res_fmt;
1808
- VALUE error;
1809
1927
  int nParams;
1810
1928
  int resultFormat;
1811
1929
  struct query_params_data paramsData = { this->enc_idx };
@@ -1822,11 +1940,10 @@ pgconn_send_query_params(int argc, VALUE *argv, VALUE self)
1822
1940
 
1823
1941
  free_query_params( &paramsData );
1824
1942
 
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
- }
1943
+ if(result == 0)
1944
+ pg_raise_conn_error( rb_eUnableToSend, self, "%s", PQerrorMessage(this->pgconn));
1945
+
1946
+ pgconn_wait_for_flush( self );
1830
1947
  return Qnil;
1831
1948
  }
1832
1949
 
@@ -1847,7 +1964,7 @@ pgconn_send_query_params(int argc, VALUE *argv, VALUE self)
1847
1964
  *
1848
1965
  * For example: "SELECT $1::int"
1849
1966
  *
1850
- * PostgreSQL bind parameters are represented as $1, $1, $2, etc.,
1967
+ * PostgreSQL bind parameters are represented as $1, $2, $3, etc.,
1851
1968
  * inside the SQL query.
1852
1969
  */
1853
1970
  static VALUE
@@ -1857,7 +1974,6 @@ pgconn_send_prepare(int argc, VALUE *argv, VALUE self)
1857
1974
  int result;
1858
1975
  VALUE name, command, in_paramtypes;
1859
1976
  VALUE param;
1860
- VALUE error;
1861
1977
  int i = 0;
1862
1978
  int nParams = 0;
1863
1979
  Oid *paramTypes = NULL;
@@ -1886,10 +2002,9 @@ pgconn_send_prepare(int argc, VALUE *argv, VALUE self)
1886
2002
  xfree(paramTypes);
1887
2003
 
1888
2004
  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);
2005
+ pg_raise_conn_error( rb_eUnableToSend, self, "%s", PQerrorMessage(this->pgconn));
1892
2006
  }
2007
+ pgconn_wait_for_flush( self );
1893
2008
  return Qnil;
1894
2009
  }
1895
2010
 
@@ -1911,7 +2026,7 @@ pgconn_send_prepare(int argc, VALUE *argv, VALUE self)
1911
2026
  * or, it may be a String. If it is a string, that is equivalent to the hash:
1912
2027
  * { :value => <string value>, :format => 0 }
1913
2028
  *
1914
- * PostgreSQL bind parameters are represented as $1, $1, $2, etc.,
2029
+ * PostgreSQL bind parameters are represented as $1, $2, $3, etc.,
1915
2030
  * inside the SQL query. The 0th element of the +params+ array is bound
1916
2031
  * to $1, the 1st element is bound to $2, etc. +nil+ is treated as +NULL+.
1917
2032
  *
@@ -1931,7 +2046,6 @@ pgconn_send_query_prepared(int argc, VALUE *argv, VALUE self)
1931
2046
  t_pg_connection *this = pg_get_connection_safe( self );
1932
2047
  int result;
1933
2048
  VALUE name, in_res_fmt;
1934
- VALUE error;
1935
2049
  int nParams;
1936
2050
  int resultFormat;
1937
2051
  struct query_params_data paramsData = { this->enc_idx };
@@ -1941,7 +2055,6 @@ pgconn_send_query_prepared(int argc, VALUE *argv, VALUE self)
1941
2055
 
1942
2056
  if(NIL_P(paramsData.params)) {
1943
2057
  paramsData.params = rb_ary_new2(0);
1944
- resultFormat = 0;
1945
2058
  }
1946
2059
  pgconn_query_assign_typemap( self, &paramsData );
1947
2060
 
@@ -1954,11 +2067,10 @@ pgconn_send_query_prepared(int argc, VALUE *argv, VALUE self)
1954
2067
 
1955
2068
  free_query_params( &paramsData );
1956
2069
 
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
- }
2070
+ if(result == 0)
2071
+ pg_raise_conn_error( rb_eUnableToSend, self, "%s", PQerrorMessage(this->pgconn));
2072
+
2073
+ pgconn_wait_for_flush( self );
1962
2074
  return Qnil;
1963
2075
  }
1964
2076
 
@@ -1972,14 +2084,12 @@ pgconn_send_query_prepared(int argc, VALUE *argv, VALUE self)
1972
2084
  static VALUE
1973
2085
  pgconn_send_describe_prepared(VALUE self, VALUE stmt_name)
1974
2086
  {
1975
- VALUE error;
1976
2087
  t_pg_connection *this = pg_get_connection_safe( self );
1977
2088
  /* 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
- }
2089
+ if(gvl_PQsendDescribePrepared(this->pgconn, pg_cstr_enc(stmt_name, this->enc_idx)) == 0)
2090
+ pg_raise_conn_error( rb_eUnableToSend, self, "%s", PQerrorMessage(this->pgconn));
2091
+
2092
+ pgconn_wait_for_flush( self );
1983
2093
  return Qnil;
1984
2094
  }
1985
2095
 
@@ -1994,36 +2104,18 @@ pgconn_send_describe_prepared(VALUE self, VALUE stmt_name)
1994
2104
  static VALUE
1995
2105
  pgconn_send_describe_portal(VALUE self, VALUE portal)
1996
2106
  {
1997
- VALUE error;
1998
2107
  t_pg_connection *this = pg_get_connection_safe( self );
1999
2108
  /* 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
- }
2109
+ if(gvl_PQsendDescribePortal(this->pgconn, pg_cstr_enc(portal, this->enc_idx)) == 0)
2110
+ pg_raise_conn_error( rb_eUnableToSend, self, "%s", PQerrorMessage(this->pgconn));
2111
+
2112
+ pgconn_wait_for_flush( self );
2005
2113
  return Qnil;
2006
2114
  }
2007
2115
 
2008
2116
 
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
2117
  static VALUE
2026
- pgconn_get_result(VALUE self)
2118
+ pgconn_sync_get_result(VALUE self)
2027
2119
  {
2028
2120
  PGconn *conn = pg_get_pgconn(self);
2029
2121
  PGresult *result;
@@ -2049,17 +2141,15 @@ pgconn_get_result(VALUE self)
2049
2141
  * or *notifies* to see if the state has changed.
2050
2142
  */
2051
2143
  static VALUE
2052
- pgconn_consume_input(self)
2053
- VALUE self;
2144
+ pgconn_consume_input(VALUE self)
2054
2145
  {
2055
- VALUE error;
2056
2146
  PGconn *conn = pg_get_pgconn(self);
2057
2147
  /* returns 0 on error */
2058
2148
  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);
2149
+ pgconn_close_socket_io(self);
2150
+ pg_raise_conn_error( rb_eConnectionBad, self, "%s", PQerrorMessage(conn));
2062
2151
  }
2152
+
2063
2153
  return Qnil;
2064
2154
  }
2065
2155
 
@@ -2068,38 +2158,20 @@ pgconn_consume_input(self)
2068
2158
  * conn.is_busy() -> Boolean
2069
2159
  *
2070
2160
  * Returns +true+ if a command is busy, that is, if
2071
- * PQgetResult would block. Otherwise returns +false+.
2161
+ * #get_result would block. Otherwise returns +false+.
2072
2162
  */
2073
2163
  static VALUE
2074
- pgconn_is_busy(self)
2075
- VALUE self;
2164
+ pgconn_is_busy(VALUE self)
2076
2165
  {
2077
2166
  return gvl_PQisBusy(pg_get_pgconn(self)) ? Qtrue : Qfalse;
2078
2167
  }
2079
2168
 
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
2169
  static VALUE
2097
- pgconn_setnonblocking(self, state)
2098
- VALUE self, state;
2170
+ pgconn_sync_setnonblocking(VALUE self, VALUE state)
2099
2171
  {
2100
2172
  int arg;
2101
- VALUE error;
2102
2173
  PGconn *conn = pg_get_pgconn(self);
2174
+ rb_check_frozen(self);
2103
2175
  if(state == Qtrue)
2104
2176
  arg = 1;
2105
2177
  else if (state == Qfalse)
@@ -2107,67 +2179,32 @@ pgconn_setnonblocking(self, state)
2107
2179
  else
2108
2180
  rb_raise(rb_eArgError, "Boolean value expected");
2109
2181
 
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
- }
2182
+ if(PQsetnonblocking(conn, arg) == -1)
2183
+ pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(conn));
2184
+
2115
2185
  return Qnil;
2116
2186
  }
2117
2187
 
2118
2188
 
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
2189
  static VALUE
2127
- pgconn_isnonblocking(self)
2128
- VALUE self;
2190
+ pgconn_sync_isnonblocking(VALUE self)
2129
2191
  {
2130
2192
  return PQisnonblocking(pg_get_pgconn(self)) ? Qtrue : Qfalse;
2131
2193
  }
2132
2194
 
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
2195
  static VALUE
2144
- pgconn_flush(self)
2145
- VALUE self;
2196
+ pgconn_sync_flush(VALUE self)
2146
2197
  {
2147
2198
  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
- }
2199
+ int ret = PQflush(conn);
2200
+ if(ret == -1)
2201
+ pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(conn));
2202
+
2156
2203
  return (ret) ? Qfalse : Qtrue;
2157
2204
  }
2158
2205
 
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
2206
  static VALUE
2170
- pgconn_cancel(VALUE self)
2207
+ pgconn_sync_cancel(VALUE self)
2171
2208
  {
2172
2209
  char errbuf[256];
2173
2210
  PGcancel *cancel;
@@ -2176,9 +2213,9 @@ pgconn_cancel(VALUE self)
2176
2213
 
2177
2214
  cancel = PQgetCancel(pg_get_pgconn(self));
2178
2215
  if(cancel == NULL)
2179
- rb_raise(rb_ePGerror,"Invalid connection!");
2216
+ pg_raise_conn_error( rb_ePGerror, self, "Invalid connection!");
2180
2217
 
2181
- ret = gvl_PQcancel(cancel, errbuf, 256);
2218
+ ret = gvl_PQcancel(cancel, errbuf, sizeof(errbuf));
2182
2219
  if(ret == 1)
2183
2220
  retval = Qnil;
2184
2221
  else
@@ -2229,55 +2266,63 @@ pgconn_notifies(VALUE self)
2229
2266
  return hash;
2230
2267
  }
2231
2268
 
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().
2269
+ #if defined(_WIN32)
2270
+
2271
+ /* We use a specialized implementation of rb_io_wait() on Windows.
2272
+ * This is because rb_io_wait() and rb_wait_for_single_fd() are very slow on Windows.
2237
2273
  */
2238
2274
 
2275
+ #if defined(HAVE_RUBY_FIBER_SCHEDULER_H)
2276
+ #include <ruby/fiber/scheduler.h>
2277
+ #endif
2278
+
2279
+ typedef enum {
2280
+ PG_RUBY_IO_READABLE = RB_WAITFD_IN,
2281
+ PG_RUBY_IO_WRITABLE = RB_WAITFD_OUT,
2282
+ PG_RUBY_IO_PRIORITY = RB_WAITFD_PRI,
2283
+ } pg_rb_io_event_t;
2284
+
2239
2285
  int rb_w32_wait_events( HANDLE *events, int num, DWORD timeout );
2240
2286
 
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;
2287
+ static VALUE
2288
+ pg_rb_thread_io_wait(VALUE io, VALUE events, VALUE timeout) {
2289
+ rb_io_t *fptr;
2290
+ struct timeval ptimeout;
2291
+
2246
2292
  struct timeval aborttime={0,0}, currtime, waittime;
2247
2293
  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");
2294
+ HANDLE hEvent = WSACreateEvent();
2253
2295
 
2254
- hEvent = WSACreateEvent();
2296
+ long rb_events = NUM2UINT(events);
2297
+ long w32_events = 0;
2298
+ DWORD wait_ret;
2255
2299
 
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
- }
2300
+ GetOpenFile((io), fptr);
2301
+ if( !NIL_P(timeout) ){
2302
+ ptimeout.tv_sec = (time_t)(NUM2DBL(timeout));
2303
+ ptimeout.tv_usec = (time_t)((NUM2DBL(timeout) - (double)ptimeout.tv_sec) * 1e6);
2261
2304
 
2262
- if ( ptimeout ) {
2263
2305
  gettimeofday(&currtime, NULL);
2264
- timeradd(&currtime, ptimeout, &aborttime);
2306
+ timeradd(&currtime, &ptimeout, &aborttime);
2265
2307
  }
2266
2308
 
2267
- while ( !(retval=is_readable(conn)) ) {
2268
- if ( WSAEventSelect(sd, hEvent, FD_READ|FD_CLOSE) == SOCKET_ERROR ) {
2309
+ if(rb_events & PG_RUBY_IO_READABLE) w32_events |= FD_READ | FD_ACCEPT | FD_CLOSE;
2310
+ if(rb_events & PG_RUBY_IO_WRITABLE) w32_events |= FD_WRITE | FD_CONNECT;
2311
+ if(rb_events & PG_RUBY_IO_PRIORITY) w32_events |= FD_OOB;
2312
+
2313
+ for(;;) {
2314
+ if ( WSAEventSelect(_get_osfhandle(fptr->fd), hEvent, w32_events) == SOCKET_ERROR ) {
2269
2315
  WSACloseEvent( hEvent );
2270
2316
  rb_raise( rb_eConnectionBad, "WSAEventSelect socket error: %d", WSAGetLastError() );
2271
2317
  }
2272
2318
 
2273
- if ( ptimeout ) {
2319
+ if ( !NIL_P(timeout) ) {
2274
2320
  gettimeofday(&currtime, NULL);
2275
2321
  timersub(&aborttime, &currtime, &waittime);
2276
2322
  timeout_milisec = (DWORD)( waittime.tv_sec * 1e3 + waittime.tv_usec / 1e3 );
2277
2323
  }
2278
2324
 
2279
- /* Is the given timeout valid? */
2280
- if( !ptimeout || (waittime.tv_sec >= 0 && waittime.tv_usec >= 0) ){
2325
+ if( NIL_P(timeout) || (waittime.tv_sec >= 0 && waittime.tv_usec >= 0) ){
2281
2326
  /* Wait for the socket to become readable before checking again */
2282
2327
  wait_ret = rb_w32_wait_events( &hEvent, 1, timeout_milisec );
2283
2328
  } else {
@@ -2286,9 +2331,11 @@ wait_socket_readable( PGconn *conn, struct timeval *ptimeout, void *(*is_readabl
2286
2331
 
2287
2332
  if ( wait_ret == WAIT_TIMEOUT ) {
2288
2333
  WSACloseEvent( hEvent );
2289
- return NULL;
2334
+ return UINT2NUM(0);
2290
2335
  } else if ( wait_ret == WAIT_OBJECT_0 ) {
2336
+ WSACloseEvent( hEvent );
2291
2337
  /* The event we were waiting for. */
2338
+ return UINT2NUM(rb_events);
2292
2339
  } else if ( wait_ret == WAIT_OBJECT_0 + 1) {
2293
2340
  /* This indicates interruption from timer thread, GC, exception
2294
2341
  * from other threads etc... */
@@ -2300,36 +2347,66 @@ wait_socket_readable( PGconn *conn, struct timeval *ptimeout, void *(*is_readabl
2300
2347
  WSACloseEvent( hEvent );
2301
2348
  rb_raise( rb_eConnectionBad, "Wait on socket abandoned (WaitForMultipleObjects)" );
2302
2349
  }
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
2350
  }
2351
+ }
2310
2352
 
2311
- WSACloseEvent( hEvent );
2312
- return retval;
2353
+ static VALUE
2354
+ pg_rb_io_wait(VALUE io, VALUE events, VALUE timeout) {
2355
+ #if defined(HAVE_RUBY_FIBER_SCHEDULER_H)
2356
+ /* We don't support Fiber.scheduler on Windows ruby-3.0 because there is no fast way to check whether a scheduler is active.
2357
+ * Fortunatelly ruby-3.1 offers a C-API for it.
2358
+ */
2359
+ VALUE scheduler = rb_fiber_scheduler_current();
2360
+
2361
+ if (!NIL_P(scheduler)) {
2362
+ return rb_io_wait(io, events, timeout);
2363
+ }
2364
+ #endif
2365
+ return pg_rb_thread_io_wait(io, events, timeout);
2313
2366
  }
2314
2367
 
2368
+ #elif defined(HAVE_RB_IO_WAIT)
2369
+
2370
+ /* Use our own function and constants names, to avoid conflicts with truffleruby-head on its road to ruby-3.0 compatibility. */
2371
+ #define pg_rb_io_wait rb_io_wait
2372
+ #define PG_RUBY_IO_READABLE RUBY_IO_READABLE
2373
+ #define PG_RUBY_IO_WRITABLE RUBY_IO_WRITABLE
2374
+ #define PG_RUBY_IO_PRIORITY RUBY_IO_PRIORITY
2375
+
2315
2376
  #else
2377
+ /* For compat with ruby < 3.0 */
2316
2378
 
2317
- /* non Win32 */
2379
+ typedef enum {
2380
+ PG_RUBY_IO_READABLE = RB_WAITFD_IN,
2381
+ PG_RUBY_IO_WRITABLE = RB_WAITFD_OUT,
2382
+ PG_RUBY_IO_PRIORITY = RB_WAITFD_PRI,
2383
+ } pg_rb_io_event_t;
2384
+
2385
+ static VALUE
2386
+ pg_rb_io_wait(VALUE io, VALUE events, VALUE timeout) {
2387
+ rb_io_t *fptr;
2388
+ struct timeval waittime;
2389
+ int res;
2390
+
2391
+ GetOpenFile((io), fptr);
2392
+ if( !NIL_P(timeout) ){
2393
+ waittime.tv_sec = (time_t)(NUM2DBL(timeout));
2394
+ waittime.tv_usec = (time_t)((NUM2DBL(timeout) - (double)waittime.tv_sec) * 1e6);
2395
+ }
2396
+ res = rb_wait_for_single_fd(fptr->fd, NUM2UINT(events), NIL_P(timeout) ? NULL : &waittime);
2397
+
2398
+ return UINT2NUM(res);
2399
+ }
2400
+ #endif
2318
2401
 
2319
2402
  static void *
2320
- wait_socket_readable( PGconn *conn, struct timeval *ptimeout, void *(*is_readable)(PGconn *))
2403
+ wait_socket_readable( VALUE self, struct timeval *ptimeout, void *(*is_readable)(PGconn *))
2321
2404
  {
2322
- int sd = PQsocket( conn );
2323
- int ret;
2405
+ VALUE ret;
2324
2406
  void *retval;
2325
2407
  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) );
2408
+ VALUE wait_timeout = Qnil;
2409
+ PGconn *conn = pg_get_pgconn(self);
2333
2410
 
2334
2411
  if ( ptimeout ) {
2335
2412
  gettimeofday(&currtime, NULL);
@@ -2340,36 +2417,81 @@ wait_socket_readable( PGconn *conn, struct timeval *ptimeout, void *(*is_readabl
2340
2417
  if ( ptimeout ) {
2341
2418
  gettimeofday(&currtime, NULL);
2342
2419
  timersub(&aborttime, &currtime, &waittime);
2420
+ wait_timeout = DBL2NUM((double)(waittime.tv_sec) + (double)(waittime.tv_usec) / 1000000.0);
2343
2421
  }
2344
2422
 
2345
2423
  /* Is the given timeout valid? */
2346
2424
  if( !ptimeout || (waittime.tv_sec >= 0 && waittime.tv_usec >= 0) ){
2425
+ VALUE socket_io;
2426
+
2427
+ /* before we wait for data, make sure everything has been sent */
2428
+ pgconn_async_flush(self);
2429
+ if ((retval=is_readable(conn)))
2430
+ return retval;
2431
+
2432
+ socket_io = pgconn_socket_io(self);
2347
2433
  /* Wait for the socket to become readable before checking again */
2348
- ret = rb_wait_for_single_fd( sd, RB_WAITFD_IN, ptimeout ? &waittime : NULL );
2434
+ ret = pg_rb_io_wait(socket_io, RB_INT2NUM(PG_RUBY_IO_READABLE), wait_timeout);
2349
2435
  } else {
2350
- ret = 0;
2351
- }
2352
-
2353
- if ( ret < 0 ){
2354
- rb_sys_fail( "rb_wait_for_single_fd()" );
2436
+ ret = Qfalse;
2355
2437
  }
2356
2438
 
2357
2439
  /* Return false if the select() timed out */
2358
- if ( ret == 0 ){
2440
+ if ( ret == Qfalse ){
2359
2441
  return NULL;
2360
2442
  }
2361
2443
 
2362
2444
  /* Check for connection errors (PQisBusy is true on connection errors) */
2363
2445
  if ( PQconsumeInput(conn) == 0 ){
2364
- rb_raise( rb_eConnectionBad, "PQconsumeInput() %s", PQerrorMessage(conn) );
2446
+ pgconn_close_socket_io(self);
2447
+ pg_raise_conn_error(rb_eConnectionBad, self, "PQconsumeInput() %s", PQerrorMessage(conn));
2365
2448
  }
2366
2449
  }
2367
2450
 
2368
2451
  return retval;
2369
2452
  }
2370
2453
 
2454
+ /*
2455
+ * call-seq:
2456
+ * conn.flush() -> Boolean
2457
+ *
2458
+ * Attempts to flush any queued output data to the server.
2459
+ * Returns +true+ if data is successfully flushed, +false+
2460
+ * if not. It can only return +false+ if connection is
2461
+ * in nonblocking mode.
2462
+ * Raises PG::Error if some other failure occurred.
2463
+ */
2464
+ static VALUE
2465
+ pgconn_async_flush(VALUE self)
2466
+ {
2467
+ while( pgconn_sync_flush(self) == Qfalse ){
2468
+ /* wait for the socket to become read- or write-ready */
2469
+ int events;
2470
+ VALUE socket_io = pgconn_socket_io(self);
2471
+ events = RB_NUM2INT(pg_rb_io_wait(socket_io, RB_INT2NUM(PG_RUBY_IO_READABLE | PG_RUBY_IO_WRITABLE), Qnil));
2371
2472
 
2372
- #endif
2473
+ if (events & PG_RUBY_IO_READABLE){
2474
+ pgconn_consume_input(self);
2475
+ }
2476
+ }
2477
+ return Qtrue;
2478
+ }
2479
+
2480
+ static VALUE
2481
+ pgconn_wait_for_flush( VALUE self ){
2482
+ if( !pg_get_connection_safe(self)->flush_data )
2483
+ return Qnil;
2484
+
2485
+ return pgconn_async_flush(self);
2486
+ }
2487
+
2488
+ static VALUE
2489
+ pgconn_flush_data_set( VALUE self, VALUE enabled ){
2490
+ t_pg_connection *conn = pg_get_connection(self);
2491
+ rb_check_frozen(self);
2492
+ conn->flush_data = RTEST(enabled);
2493
+ return enabled;
2494
+ }
2373
2495
 
2374
2496
  static void *
2375
2497
  notify_readable(PGconn *conn)
@@ -2408,7 +2530,7 @@ pgconn_wait_for_notify(int argc, VALUE *argv, VALUE self)
2408
2530
  ptimeout = &timeout;
2409
2531
  }
2410
2532
 
2411
- pnotification = (PGnotify*) wait_socket_readable( this->pgconn, ptimeout, notify_readable);
2533
+ pnotification = (PGnotify*) wait_socket_readable( self, ptimeout, notify_readable);
2412
2534
 
2413
2535
  /* Return nil if the select timed out */
2414
2536
  if ( !pnotification ) return Qnil;
@@ -2429,28 +2551,8 @@ pgconn_wait_for_notify(int argc, VALUE *argv, VALUE self)
2429
2551
  }
2430
2552
 
2431
2553
 
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
2554
  static VALUE
2453
- pgconn_put_copy_data(int argc, VALUE *argv, VALUE self)
2555
+ pgconn_sync_put_copy_data(int argc, VALUE *argv, VALUE self)
2454
2556
  {
2455
2557
  int ret;
2456
2558
  int len;
@@ -2467,13 +2569,11 @@ pgconn_put_copy_data(int argc, VALUE *argv, VALUE self)
2467
2569
  if( NIL_P(this->encoder_for_put_copy_data) ){
2468
2570
  buffer = value;
2469
2571
  } else {
2470
- p_coder = DATA_PTR( this->encoder_for_put_copy_data );
2572
+ p_coder = RTYPEDDATA_DATA( this->encoder_for_put_copy_data );
2471
2573
  }
2472
- } else if( rb_obj_is_kind_of(encoder, rb_cPG_Coder) ) {
2473
- Data_Get_Struct( encoder, t_pg_coder, p_coder );
2474
2574
  } else {
2475
- rb_raise( rb_eTypeError, "wrong encoder type %s (expected some kind of PG::Coder)",
2476
- rb_obj_classname( encoder ) );
2575
+ /* Check argument type and use argument encoder */
2576
+ TypedData_Get_Struct(encoder, t_pg_coder, &pg_coder_type, p_coder);
2477
2577
  }
2478
2578
 
2479
2579
  if( p_coder ){
@@ -2496,36 +2596,19 @@ pgconn_put_copy_data(int argc, VALUE *argv, VALUE self)
2496
2596
  Check_Type(buffer, T_STRING);
2497
2597
 
2498
2598
  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
- }
2599
+ if(ret == -1)
2600
+ pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(this->pgconn));
2601
+
2504
2602
  RB_GC_GUARD(intermediate);
2505
2603
  RB_GC_GUARD(buffer);
2506
2604
 
2507
2605
  return (ret) ? Qtrue : Qfalse;
2508
2606
  }
2509
2607
 
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
2608
  static VALUE
2525
- pgconn_put_copy_end(int argc, VALUE *argv, VALUE self)
2609
+ pgconn_sync_put_copy_end(int argc, VALUE *argv, VALUE self)
2526
2610
  {
2527
2611
  VALUE str;
2528
- VALUE error;
2529
2612
  int ret;
2530
2613
  const char *error_message = NULL;
2531
2614
  t_pg_connection *this = pg_get_connection_safe( self );
@@ -2536,38 +2619,16 @@ pgconn_put_copy_end(int argc, VALUE *argv, VALUE self)
2536
2619
  error_message = pg_cstr_enc(str, this->enc_idx);
2537
2620
 
2538
2621
  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
- }
2622
+ if(ret == -1)
2623
+ pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(this->pgconn));
2624
+
2544
2625
  return (ret) ? Qtrue : Qfalse;
2545
2626
  }
2546
2627
 
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
2628
  static VALUE
2567
- pgconn_get_copy_data(int argc, VALUE *argv, VALUE self )
2629
+ pgconn_sync_get_copy_data(int argc, VALUE *argv, VALUE self )
2568
2630
  {
2569
2631
  VALUE async_in;
2570
- VALUE error;
2571
2632
  VALUE result;
2572
2633
  int ret;
2573
2634
  char *buffer;
@@ -2579,20 +2640,16 @@ pgconn_get_copy_data(int argc, VALUE *argv, VALUE self )
2579
2640
 
2580
2641
  if( NIL_P(decoder) ){
2581
2642
  if( !NIL_P(this->decoder_for_get_copy_data) ){
2582
- p_coder = DATA_PTR( this->decoder_for_get_copy_data );
2643
+ p_coder = RTYPEDDATA_DATA( this->decoder_for_get_copy_data );
2583
2644
  }
2584
- } else if( rb_obj_is_kind_of(decoder, rb_cPG_Coder) ) {
2585
- Data_Get_Struct( decoder, t_pg_coder, p_coder );
2586
2645
  } else {
2587
- rb_raise( rb_eTypeError, "wrong decoder type %s (expected some kind of PG::Coder)",
2588
- rb_obj_classname( decoder ) );
2646
+ /* Check argument type and use argument decoder */
2647
+ TypedData_Get_Struct(decoder, t_pg_coder, &pg_coder_type, p_coder);
2589
2648
  }
2590
2649
 
2591
2650
  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);
2651
+ if(ret == -2){ /* error */
2652
+ pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(this->pgconn));
2596
2653
  }
2597
2654
  if(ret == -1) { /* No data left */
2598
2655
  return Qnil;
@@ -2686,6 +2743,7 @@ pgconn_trace(VALUE self, VALUE stream)
2686
2743
  VALUE new_file;
2687
2744
  t_pg_connection *this = pg_get_connection_safe( self );
2688
2745
 
2746
+ rb_check_frozen(self);
2689
2747
  if(!rb_respond_to(stream,rb_intern("fileno")))
2690
2748
  rb_raise(rb_eArgError, "stream does not respond to method: fileno");
2691
2749
 
@@ -2707,7 +2765,7 @@ pgconn_trace(VALUE self, VALUE stream)
2707
2765
  rb_raise(rb_eArgError, "stream is not writable");
2708
2766
 
2709
2767
  new_file = rb_funcall(rb_cIO, rb_intern("new"), 1, INT2NUM(new_fd));
2710
- this->trace_stream = new_file;
2768
+ RB_OBJ_WRITE(self, &this->trace_stream, new_file);
2711
2769
 
2712
2770
  PQtrace(this->pgconn, new_fp);
2713
2771
  return Qnil;
@@ -2726,7 +2784,7 @@ pgconn_untrace(VALUE self)
2726
2784
 
2727
2785
  PQuntrace(this->pgconn);
2728
2786
  rb_funcall(this->trace_stream, rb_intern("close"), 0);
2729
- this->trace_stream = Qnil;
2787
+ RB_OBJ_WRITE(self, &this->trace_stream, Qnil);
2730
2788
  return Qnil;
2731
2789
  }
2732
2790
 
@@ -2785,13 +2843,14 @@ pgconn_set_notice_receiver(VALUE self)
2785
2843
  VALUE proc, old_proc;
2786
2844
  t_pg_connection *this = pg_get_connection_safe( self );
2787
2845
 
2846
+ rb_check_frozen(self);
2788
2847
  /* If default_notice_receiver is unset, assume that the current
2789
2848
  * notice receiver is the default, and save it to a global variable.
2790
2849
  * This should not be a problem because the default receiver is
2791
2850
  * always the same, so won't vary among connections.
2792
2851
  */
2793
- if(default_notice_receiver == NULL)
2794
- default_notice_receiver = PQsetNoticeReceiver(this->pgconn, NULL, NULL);
2852
+ if(this->default_notice_receiver == NULL)
2853
+ this->default_notice_receiver = PQsetNoticeReceiver(this->pgconn, NULL, NULL);
2795
2854
 
2796
2855
  old_proc = this->notice_receiver;
2797
2856
  if( rb_block_given_p() ) {
@@ -2800,10 +2859,10 @@ pgconn_set_notice_receiver(VALUE self)
2800
2859
  } else {
2801
2860
  /* if no block is given, set back to default */
2802
2861
  proc = Qnil;
2803
- PQsetNoticeReceiver(this->pgconn, default_notice_receiver, NULL);
2862
+ PQsetNoticeReceiver(this->pgconn, this->default_notice_receiver, NULL);
2804
2863
  }
2805
2864
 
2806
- this->notice_receiver = proc;
2865
+ RB_OBJ_WRITE(self, &this->notice_receiver, proc);
2807
2866
  return old_proc;
2808
2867
  }
2809
2868
 
@@ -2818,10 +2877,10 @@ notice_processor_proxy(void *arg, const char *message)
2818
2877
  VALUE self = (VALUE)arg;
2819
2878
  t_pg_connection *this = pg_get_connection( self );
2820
2879
 
2821
- if (this->notice_receiver != Qnil) {
2880
+ if (this->notice_processor != Qnil) {
2822
2881
  VALUE message_str = rb_str_new2(message);
2823
2882
  PG_ENCODING_SET_NOCHECK( message_str, this->enc_idx );
2824
- rb_funcall(this->notice_receiver, rb_intern("call"), 1, message_str);
2883
+ rb_funcall(this->notice_processor, rb_intern("call"), 1, message_str);
2825
2884
  }
2826
2885
  return;
2827
2886
  }
@@ -2830,7 +2889,7 @@ notice_processor_proxy(void *arg, const char *message)
2830
2889
  * call-seq:
2831
2890
  * conn.set_notice_processor {|message| ... } -> Proc
2832
2891
  *
2833
- * See #set_notice_receiver for the desription of what this and the
2892
+ * See #set_notice_receiver for the description of what this and the
2834
2893
  * notice_processor methods do.
2835
2894
  *
2836
2895
  * This function takes a new block to act as the notice processor and returns
@@ -2845,25 +2904,26 @@ pgconn_set_notice_processor(VALUE self)
2845
2904
  VALUE proc, old_proc;
2846
2905
  t_pg_connection *this = pg_get_connection_safe( self );
2847
2906
 
2907
+ rb_check_frozen(self);
2848
2908
  /* If default_notice_processor is unset, assume that the current
2849
2909
  * notice processor is the default, and save it to a global variable.
2850
2910
  * This should not be a problem because the default processor is
2851
2911
  * always the same, so won't vary among connections.
2852
2912
  */
2853
- if(default_notice_processor == NULL)
2854
- default_notice_processor = PQsetNoticeProcessor(this->pgconn, NULL, NULL);
2913
+ if(this->default_notice_processor == NULL)
2914
+ this->default_notice_processor = PQsetNoticeProcessor(this->pgconn, NULL, NULL);
2855
2915
 
2856
- old_proc = this->notice_receiver;
2916
+ old_proc = this->notice_processor;
2857
2917
  if( rb_block_given_p() ) {
2858
2918
  proc = rb_block_proc();
2859
2919
  PQsetNoticeProcessor(this->pgconn, gvl_notice_processor_proxy, (void *)self);
2860
2920
  } else {
2861
2921
  /* if no block is given, set back to default */
2862
2922
  proc = Qnil;
2863
- PQsetNoticeProcessor(this->pgconn, default_notice_processor, NULL);
2923
+ PQsetNoticeProcessor(this->pgconn, this->default_notice_processor, NULL);
2864
2924
  }
2865
2925
 
2866
- this->notice_receiver = proc;
2926
+ RB_OBJ_WRITE(self, &this->notice_processor, proc);
2867
2927
  return old_proc;
2868
2928
  }
2869
2929
 
@@ -2884,68 +2944,28 @@ pgconn_get_client_encoding(VALUE self)
2884
2944
 
2885
2945
  /*
2886
2946
  * call-seq:
2887
- * conn.set_client_encoding( encoding )
2947
+ * conn.sync_set_client_encoding( encoding )
2888
2948
  *
2889
- * Sets the client encoding to the _encoding_ String.
2949
+ * This function has the same behavior as #async_set_client_encoding, but is implemented using the synchronous command processing API of libpq.
2950
+ * See #async_exec for the differences between the two API variants.
2951
+ * 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
2952
  */
2891
2953
  static VALUE
2892
- pgconn_set_client_encoding(VALUE self, VALUE str)
2954
+ pgconn_sync_set_client_encoding(VALUE self, VALUE str)
2893
2955
  {
2894
2956
  PGconn *conn = pg_get_pgconn( self );
2895
2957
 
2958
+ rb_check_frozen(self);
2896
2959
  Check_Type(str, T_STRING);
2897
2960
 
2898
- if ( (gvl_PQsetClientEncoding(conn, StringValueCStr(str))) == -1 ) {
2899
- rb_raise(rb_ePGerror, "%s", PQerrorMessage(conn));
2900
- }
2961
+ if ( (gvl_PQsetClientEncoding(conn, StringValueCStr(str))) == -1 )
2962
+ pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(conn));
2963
+
2901
2964
  pgconn_set_internal_encoding_index( self );
2902
2965
 
2903
2966
  return Qnil;
2904
2967
  }
2905
2968
 
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
2969
 
2950
2970
  /*
2951
2971
  * call-seq:
@@ -3020,10 +3040,8 @@ get_result_readable(PGconn *conn)
3020
3040
  * If +true+ is returned, +conn.is_busy+ will return +false+
3021
3041
  * and +conn.get_result+ will not block.
3022
3042
  */
3023
- static VALUE
3043
+ VALUE
3024
3044
  pgconn_block( int argc, VALUE *argv, VALUE self ) {
3025
- PGconn *conn = pg_get_pgconn( self );
3026
-
3027
3045
  struct timeval timeout;
3028
3046
  struct timeval *ptimeout = NULL;
3029
3047
  VALUE timeout_in;
@@ -3037,7 +3055,7 @@ pgconn_block( int argc, VALUE *argv, VALUE self ) {
3037
3055
  ptimeout = &timeout;
3038
3056
  }
3039
3057
 
3040
- ret = wait_socket_readable( conn, ptimeout, get_result_readable);
3058
+ ret = wait_socket_readable( self, ptimeout, get_result_readable);
3041
3059
 
3042
3060
  if( !ret )
3043
3061
  return Qfalse;
@@ -3046,6 +3064,42 @@ pgconn_block( int argc, VALUE *argv, VALUE self ) {
3046
3064
  }
3047
3065
 
3048
3066
 
3067
+ /*
3068
+ * call-seq:
3069
+ * conn.sync_get_last_result( ) -> PG::Result
3070
+ *
3071
+ * This function has the same behavior as #async_get_last_result, but is implemented using the synchronous command processing API of libpq.
3072
+ * See #async_exec for the differences between the two API variants.
3073
+ * 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.
3074
+ */
3075
+ static VALUE
3076
+ pgconn_sync_get_last_result(VALUE self)
3077
+ {
3078
+ PGconn *conn = pg_get_pgconn(self);
3079
+ VALUE rb_pgresult = Qnil;
3080
+ PGresult *cur, *prev;
3081
+
3082
+
3083
+ cur = prev = NULL;
3084
+ while ((cur = gvl_PQgetResult(conn)) != NULL) {
3085
+ int status;
3086
+
3087
+ if (prev) PQclear(prev);
3088
+ prev = cur;
3089
+
3090
+ status = PQresultStatus(cur);
3091
+ if (status == PGRES_COPY_OUT || status == PGRES_COPY_IN || status == PGRES_COPY_BOTH)
3092
+ break;
3093
+ }
3094
+
3095
+ if (prev) {
3096
+ rb_pgresult = pg_new_result( prev, self );
3097
+ pg_result_check(rb_pgresult);
3098
+ }
3099
+
3100
+ return rb_pgresult;
3101
+ }
3102
+
3049
3103
  /*
3050
3104
  * call-seq:
3051
3105
  * conn.get_last_result( ) -> PG::Result
@@ -3056,27 +3110,36 @@ pgconn_block( int argc, VALUE *argv, VALUE self ) {
3056
3110
  * returns the last non-NULL result, or +nil+ if no
3057
3111
  * results are available.
3058
3112
  *
3113
+ * If the last result contains a bad result_status, an
3114
+ * appropriate exception is raised.
3115
+ *
3059
3116
  * This function is similar to #get_result
3060
3117
  * except that it is designed to get one and only
3061
- * one result.
3118
+ * one result and that it checks the result state.
3062
3119
  */
3063
3120
  static VALUE
3064
- pgconn_get_last_result(VALUE self)
3121
+ pgconn_async_get_last_result(VALUE self)
3065
3122
  {
3066
3123
  PGconn *conn = pg_get_pgconn(self);
3067
3124
  VALUE rb_pgresult = Qnil;
3068
3125
  PGresult *cur, *prev;
3069
3126
 
3070
-
3071
3127
  cur = prev = NULL;
3072
- while ((cur = gvl_PQgetResult(conn)) != NULL) {
3128
+ for(;;) {
3073
3129
  int status;
3074
3130
 
3131
+ /* wait for input (without blocking) before reading each result */
3132
+ wait_socket_readable(self, NULL, get_result_readable);
3133
+
3134
+ cur = gvl_PQgetResult(conn);
3135
+ if (cur == NULL)
3136
+ break;
3137
+
3075
3138
  if (prev) PQclear(prev);
3076
3139
  prev = cur;
3077
3140
 
3078
3141
  status = PQresultStatus(cur);
3079
- if (status == PGRES_COPY_OUT || status == PGRES_COPY_IN)
3142
+ if (status == PGRES_COPY_OUT || status == PGRES_COPY_IN || status == PGRES_COPY_BOTH)
3080
3143
  break;
3081
3144
  }
3082
3145
 
@@ -3093,29 +3156,91 @@ pgconn_get_last_result(VALUE self)
3093
3156
  * conn.discard_results()
3094
3157
  *
3095
3158
  * Silently discard any prior query result that application didn't eat.
3096
- * This is done prior of Connection#exec and sibling methods and can
3097
- * be called explicitly when using the async API.
3159
+ * This is internally used prior to Connection#exec and sibling methods.
3160
+ * It doesn't raise an exception on connection errors, but returns +false+ instead.
3161
+ *
3162
+ * Returns:
3163
+ * * +nil+ when the connection is already idle
3164
+ * * +true+ when some results have been discarded
3165
+ * * +false+ when a failure occured and the connection was closed
3166
+ *
3098
3167
  */
3099
3168
  static VALUE
3100
3169
  pgconn_discard_results(VALUE self)
3101
3170
  {
3102
3171
  PGconn *conn = pg_get_pgconn(self);
3172
+ VALUE socket_io;
3173
+
3174
+ switch( PQtransactionStatus(conn) ) {
3175
+ case PQTRANS_IDLE:
3176
+ case PQTRANS_INTRANS:
3177
+ case PQTRANS_INERROR:
3178
+ return Qnil;
3179
+ default:;
3180
+ }
3103
3181
 
3104
- PGresult *cur;
3105
- while ((cur = gvl_PQgetResult(conn)) != NULL) {
3106
- int status = PQresultStatus(cur);
3182
+ socket_io = pgconn_socket_io(self);
3183
+
3184
+ for(;;) {
3185
+ PGresult *cur;
3186
+ int status;
3187
+
3188
+ /* pgconn_block() raises an exception in case of errors.
3189
+ * To avoid this call pg_rb_io_wait() and PQconsumeInput() without rb_raise().
3190
+ */
3191
+ while( gvl_PQisBusy(conn) ){
3192
+ int events;
3193
+
3194
+ switch( PQflush(conn) ) {
3195
+ case 1:
3196
+ events = RB_NUM2INT(pg_rb_io_wait(socket_io, RB_INT2NUM(PG_RUBY_IO_READABLE | PG_RUBY_IO_WRITABLE), Qnil));
3197
+ if (events & PG_RUBY_IO_READABLE){
3198
+ if ( PQconsumeInput(conn) == 0 ) goto error;
3199
+ }
3200
+ break;
3201
+ case 0:
3202
+ pg_rb_io_wait(socket_io, RB_INT2NUM(PG_RUBY_IO_READABLE), Qnil);
3203
+ if ( PQconsumeInput(conn) == 0 ) goto error;
3204
+ break;
3205
+ default:
3206
+ goto error;
3207
+ }
3208
+ }
3209
+
3210
+ cur = gvl_PQgetResult(conn);
3211
+ if( cur == NULL) break;
3212
+
3213
+ status = PQresultStatus(cur);
3107
3214
  PQclear(cur);
3108
3215
  if (status == PGRES_COPY_IN){
3109
- gvl_PQputCopyEnd(conn, "COPY terminated by new PQexec");
3216
+ while( gvl_PQputCopyEnd(conn, "COPY terminated by new query or discard_results") == 0 ){
3217
+ pgconn_async_flush(self);
3218
+ }
3110
3219
  }
3111
3220
  if (status == PGRES_COPY_OUT){
3112
- char *buffer = NULL;
3113
- while( gvl_PQgetCopyData(conn, &buffer, 0) > 0)
3114
- PQfreemem(buffer);
3221
+ for(;;) {
3222
+ char *buffer = NULL;
3223
+ int st = gvl_PQgetCopyData(conn, &buffer, 1);
3224
+ if( st == 0 ) {
3225
+ /* would block -> wait for readable data */
3226
+ pg_rb_io_wait(socket_io, RB_INT2NUM(PG_RUBY_IO_READABLE), Qnil);
3227
+ if ( PQconsumeInput(conn) == 0 ) goto error;
3228
+ } else if( st > 0 ) {
3229
+ /* some data retrieved -> discard it */
3230
+ PQfreemem(buffer);
3231
+ } else {
3232
+ /* no more data */
3233
+ break;
3234
+ }
3235
+ }
3115
3236
  }
3116
3237
  }
3117
3238
 
3118
- return Qnil;
3239
+ return Qtrue;
3240
+
3241
+ error:
3242
+ pgconn_close_socket_io(self);
3243
+ return Qfalse;
3119
3244
  }
3120
3245
 
3121
3246
  /*
@@ -3138,6 +3263,7 @@ pgconn_discard_results(VALUE self)
3138
3263
  * #exec is an alias for #async_exec which is almost identical to #sync_exec .
3139
3264
  * #sync_exec is implemented on the simpler synchronous command processing API of libpq, whereas
3140
3265
  * #async_exec is implemented on the asynchronous API and on ruby's IO mechanisms.
3266
+ * Only #async_exec is compatible to <tt>Fiber.scheduler</tt> based asynchronous IO processing introduced in ruby-3.0.
3141
3267
  * Both methods ensure that other threads can process while waiting for the server to
3142
3268
  * complete the request, but #sync_exec blocks all signals to be processed until the query is finished.
3143
3269
  * This is most notably visible by a delayed reaction to Control+C.
@@ -3152,8 +3278,7 @@ pgconn_async_exec(int argc, VALUE *argv, VALUE self)
3152
3278
 
3153
3279
  pgconn_discard_results( self );
3154
3280
  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 );
3281
+ rb_pgresult = pgconn_async_get_last_result( self );
3157
3282
 
3158
3283
  if ( rb_block_given_p() ) {
3159
3284
  return rb_ensure( rb_yield, rb_pgresult, pg_result_clear, rb_pgresult );
@@ -3182,7 +3307,7 @@ pgconn_async_exec(int argc, VALUE *argv, VALUE self)
3182
3307
  * or, it may be a String. If it is a string, that is equivalent to the hash:
3183
3308
  * { :value => <string value>, :type => 0, :format => 0 }
3184
3309
  *
3185
- * PostgreSQL bind parameters are represented as $1, $1, $2, etc.,
3310
+ * PostgreSQL bind parameters are represented as $1, $2, $3, etc.,
3186
3311
  * inside the SQL query. The 0th element of the +params+ array is bound
3187
3312
  * to $1, the 1st element is bound to $2, etc. +nil+ is treated as +NULL+.
3188
3313
  *
@@ -3225,8 +3350,7 @@ pgconn_async_exec_params(int argc, VALUE *argv, VALUE self)
3225
3350
  } else {
3226
3351
  pgconn_send_query_params( argc, argv, self );
3227
3352
  }
3228
- pgconn_block( 0, NULL, self ); /* wait for input (without blocking) before reading the last result */
3229
- rb_pgresult = pgconn_get_last_result( self );
3353
+ rb_pgresult = pgconn_async_get_last_result( self );
3230
3354
 
3231
3355
  if ( rb_block_given_p() ) {
3232
3356
  return rb_ensure( rb_yield, rb_pgresult, pg_result_clear, rb_pgresult );
@@ -3252,7 +3376,7 @@ pgconn_async_exec_params(int argc, VALUE *argv, VALUE self)
3252
3376
  *
3253
3377
  * For example: "SELECT $1::int"
3254
3378
  *
3255
- * PostgreSQL bind parameters are represented as $1, $1, $2, etc.,
3379
+ * PostgreSQL bind parameters are represented as $1, $2, $3, etc.,
3256
3380
  * inside the SQL query.
3257
3381
  *
3258
3382
  * See also corresponding {libpq function}[https://www.postgresql.org/docs/current/libpq-exec.html#LIBPQ-PQPREPARE].
@@ -3264,8 +3388,7 @@ pgconn_async_prepare(int argc, VALUE *argv, VALUE self)
3264
3388
 
3265
3389
  pgconn_discard_results( self );
3266
3390
  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 );
3391
+ rb_pgresult = pgconn_async_get_last_result( self );
3269
3392
 
3270
3393
  if ( rb_block_given_p() ) {
3271
3394
  return rb_ensure( rb_yield, rb_pgresult, pg_result_clear, rb_pgresult );
@@ -3292,7 +3415,7 @@ pgconn_async_prepare(int argc, VALUE *argv, VALUE self)
3292
3415
  * or, it may be a String. If it is a string, that is equivalent to the hash:
3293
3416
  * { :value => <string value>, :format => 0 }
3294
3417
  *
3295
- * PostgreSQL bind parameters are represented as $1, $1, $2, etc.,
3418
+ * PostgreSQL bind parameters are represented as $1, $2, $3, etc.,
3296
3419
  * inside the SQL query. The 0th element of the +params+ array is bound
3297
3420
  * to $1, the 1st element is bound to $2, etc. +nil+ is treated as +NULL+.
3298
3421
  *
@@ -3318,8 +3441,7 @@ pgconn_async_exec_prepared(int argc, VALUE *argv, VALUE self)
3318
3441
 
3319
3442
  pgconn_discard_results( self );
3320
3443
  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 );
3444
+ rb_pgresult = pgconn_async_get_last_result( self );
3323
3445
 
3324
3446
  if ( rb_block_given_p() ) {
3325
3447
  return rb_ensure( rb_yield, rb_pgresult, pg_result_clear, rb_pgresult );
@@ -3343,8 +3465,7 @@ pgconn_async_describe_portal(VALUE self, VALUE portal)
3343
3465
 
3344
3466
  pgconn_discard_results( self );
3345
3467
  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 );
3468
+ rb_pgresult = pgconn_async_get_last_result( self );
3348
3469
 
3349
3470
  if ( rb_block_given_p() ) {
3350
3471
  return rb_ensure( rb_yield, rb_pgresult, pg_result_clear, rb_pgresult );
@@ -3368,8 +3489,7 @@ pgconn_async_describe_prepared(VALUE self, VALUE stmt_name)
3368
3489
 
3369
3490
  pgconn_discard_results( self );
3370
3491
  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 );
3492
+ rb_pgresult = pgconn_async_get_last_result( self );
3373
3493
 
3374
3494
  if ( rb_block_given_p() ) {
3375
3495
  return rb_ensure( rb_yield, rb_pgresult, pg_result_clear, rb_pgresult );
@@ -3457,10 +3577,134 @@ pgconn_ssl_attribute_names(VALUE self)
3457
3577
  #endif
3458
3578
 
3459
3579
 
3580
+ #ifdef HAVE_PQENTERPIPELINEMODE
3581
+ /*
3582
+ * call-seq:
3583
+ * conn.pipeline_status -> Integer
3584
+ *
3585
+ * Returns the current pipeline mode status of the libpq connection.
3586
+ *
3587
+ * PQpipelineStatus can return one of the following values:
3588
+ *
3589
+ * * PQ_PIPELINE_ON - The libpq connection is in pipeline mode.
3590
+ * * PQ_PIPELINE_OFF - The libpq connection is not in pipeline mode.
3591
+ * * PQ_PIPELINE_ABORTED - The libpq connection is in pipeline mode and an error occurred while processing the current pipeline.
3592
+ * The aborted flag is cleared when PQgetResult returns a result of type PGRES_PIPELINE_SYNC.
3593
+ *
3594
+ * Available since PostgreSQL-14
3595
+ */
3596
+ static VALUE
3597
+ pgconn_pipeline_status(VALUE self)
3598
+ {
3599
+ int res = PQpipelineStatus(pg_get_pgconn(self));
3600
+ return INT2FIX(res);
3601
+ }
3602
+
3603
+
3604
+ /*
3605
+ * call-seq:
3606
+ * conn.enter_pipeline_mode -> nil
3607
+ *
3608
+ * Causes a connection to enter pipeline mode if it is currently idle or already in pipeline mode.
3609
+ *
3610
+ * 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.
3611
+ * This function does not actually send anything to the server, it just changes the libpq connection state.
3612
+ *
3613
+ * Available since PostgreSQL-14
3614
+ */
3615
+ static VALUE
3616
+ pgconn_enter_pipeline_mode(VALUE self)
3617
+ {
3618
+ PGconn *conn = pg_get_pgconn(self);
3619
+ int res = PQenterPipelineMode(conn);
3620
+ if( res != 1 )
3621
+ pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(conn));
3622
+
3623
+ return Qnil;
3624
+ }
3625
+
3626
+ /*
3627
+ * call-seq:
3628
+ * conn.exit_pipeline_mode -> nil
3629
+ *
3630
+ * Causes a connection to exit pipeline mode if it is currently in pipeline mode with an empty queue and no pending results.
3631
+ *
3632
+ * Takes no action if not in pipeline mode.
3633
+ * 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.
3634
+ *
3635
+ * Available since PostgreSQL-14
3636
+ */
3637
+ static VALUE
3638
+ pgconn_exit_pipeline_mode(VALUE self)
3639
+ {
3640
+ PGconn *conn = pg_get_pgconn(self);
3641
+ int res = PQexitPipelineMode(conn);
3642
+ if( res != 1 )
3643
+ pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(conn));
3644
+
3645
+ return Qnil;
3646
+ }
3647
+
3648
+
3649
+ /*
3650
+ * call-seq:
3651
+ * conn.pipeline_sync -> nil
3652
+ *
3653
+ * Marks a synchronization point in a pipeline by sending a sync message and flushing the send buffer.
3654
+ * This serves as the delimiter of an implicit transaction and an error recovery point; see Section 34.5.1.3 of the PostgreSQL documentation.
3655
+ *
3656
+ * Raises PG::Error if the connection is not in pipeline mode or sending a sync message failed.
3657
+ *
3658
+ * Available since PostgreSQL-14
3659
+ */
3660
+ static VALUE
3661
+ pgconn_pipeline_sync(VALUE self)
3662
+ {
3663
+ PGconn *conn = pg_get_pgconn(self);
3664
+ int res = PQpipelineSync(conn);
3665
+ if( res != 1 )
3666
+ pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(conn));
3667
+
3668
+ return Qnil;
3669
+ }
3670
+
3671
+ /*
3672
+ * call-seq:
3673
+ * conn.pipeline_sync -> nil
3674
+ *
3675
+ * Sends a request for the server to flush its output buffer.
3676
+ *
3677
+ * 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.
3678
+ * This function is useful to cause the server to flush its output buffer in pipeline mode without establishing a synchronization point.
3679
+ * Note that the request is not itself flushed to the server automatically; use Connection#flush if necessary.
3680
+ *
3681
+ * Available since PostgreSQL-14
3682
+ */
3683
+ static VALUE
3684
+ pgconn_send_flush_request(VALUE self)
3685
+ {
3686
+ PGconn *conn = pg_get_pgconn(self);
3687
+ int res = PQsendFlushRequest(conn);
3688
+ if( res != 1 )
3689
+ pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(conn));
3690
+
3691
+ return Qnil;
3692
+ }
3693
+
3694
+ #endif
3695
+
3460
3696
  /**************************************************************************
3461
3697
  * LARGE OBJECT SUPPORT
3462
3698
  **************************************************************************/
3463
3699
 
3700
+ #define BLOCKING_BEGIN(conn) do { \
3701
+ int old_nonblocking = PQisnonblocking(conn); \
3702
+ PQsetnonblocking(conn, 0);
3703
+
3704
+ #define BLOCKING_END(th) \
3705
+ PQsetnonblocking(conn, old_nonblocking); \
3706
+ } while(0);
3707
+
3464
3708
  /*
3465
3709
  * call-seq:
3466
3710
  * conn.lo_creat( [mode] ) -> Integer
@@ -3481,9 +3725,12 @@ pgconn_locreat(int argc, VALUE *argv, VALUE self)
3481
3725
  else
3482
3726
  mode = NUM2INT(nmode);
3483
3727
 
3484
- lo_oid = lo_creat(conn, mode);
3728
+ BLOCKING_BEGIN(conn)
3729
+ lo_oid = lo_creat(conn, mode);
3730
+ BLOCKING_END(conn)
3731
+
3485
3732
  if (lo_oid == 0)
3486
- rb_raise(rb_ePGerror, "lo_creat failed");
3733
+ pg_raise_conn_error( rb_ePGerror, self, "lo_creat failed");
3487
3734
 
3488
3735
  return UINT2NUM(lo_oid);
3489
3736
  }
@@ -3504,7 +3751,7 @@ pgconn_locreate(VALUE self, VALUE in_lo_oid)
3504
3751
 
3505
3752
  ret = lo_create(conn, lo_oid);
3506
3753
  if (ret == InvalidOid)
3507
- rb_raise(rb_ePGerror, "lo_create failed");
3754
+ pg_raise_conn_error( rb_ePGerror, self, "lo_create failed");
3508
3755
 
3509
3756
  return UINT2NUM(ret);
3510
3757
  }
@@ -3526,9 +3773,12 @@ pgconn_loimport(VALUE self, VALUE filename)
3526
3773
 
3527
3774
  Check_Type(filename, T_STRING);
3528
3775
 
3529
- lo_oid = lo_import(conn, StringValueCStr(filename));
3776
+ BLOCKING_BEGIN(conn)
3777
+ lo_oid = lo_import(conn, StringValueCStr(filename));
3778
+ BLOCKING_END(conn)
3779
+
3530
3780
  if (lo_oid == 0) {
3531
- rb_raise(rb_ePGerror, "%s", PQerrorMessage(conn));
3781
+ pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(conn));
3532
3782
  }
3533
3783
  return UINT2NUM(lo_oid);
3534
3784
  }
@@ -3544,12 +3794,17 @@ pgconn_loexport(VALUE self, VALUE lo_oid, VALUE filename)
3544
3794
  {
3545
3795
  PGconn *conn = pg_get_pgconn(self);
3546
3796
  Oid oid;
3797
+ int ret;
3547
3798
  Check_Type(filename, T_STRING);
3548
3799
 
3549
3800
  oid = NUM2UINT(lo_oid);
3550
3801
 
3551
- if (lo_export(conn, oid, StringValueCStr(filename)) < 0) {
3552
- rb_raise(rb_ePGerror, "%s", PQerrorMessage(conn));
3802
+ BLOCKING_BEGIN(conn)
3803
+ ret = lo_export(conn, oid, StringValueCStr(filename));
3804
+ BLOCKING_END(conn)
3805
+
3806
+ if (ret < 0) {
3807
+ pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(conn));
3553
3808
  }
3554
3809
  return Qnil;
3555
3810
  }
@@ -3579,8 +3834,12 @@ pgconn_loopen(int argc, VALUE *argv, VALUE self)
3579
3834
  else
3580
3835
  mode = NUM2INT(nmode);
3581
3836
 
3582
- if((fd = lo_open(conn, lo_oid, mode)) < 0) {
3583
- rb_raise(rb_ePGerror, "can't open large object: %s", PQerrorMessage(conn));
3837
+ BLOCKING_BEGIN(conn)
3838
+ fd = lo_open(conn, lo_oid, mode);
3839
+ BLOCKING_END(conn)
3840
+
3841
+ if(fd < 0) {
3842
+ pg_raise_conn_error( rb_ePGerror, self, "can't open large object: %s", PQerrorMessage(conn));
3584
3843
  }
3585
3844
  return INT2FIX(fd);
3586
3845
  }
@@ -3602,11 +3861,15 @@ pgconn_lowrite(VALUE self, VALUE in_lo_desc, VALUE buffer)
3602
3861
  Check_Type(buffer, T_STRING);
3603
3862
 
3604
3863
  if( RSTRING_LEN(buffer) < 0) {
3605
- rb_raise(rb_ePGerror, "write buffer zero string");
3864
+ pg_raise_conn_error( rb_ePGerror, self, "write buffer zero string");
3606
3865
  }
3607
- if((n = lo_write(conn, fd, StringValuePtr(buffer),
3608
- RSTRING_LEN(buffer))) < 0) {
3609
- rb_raise(rb_ePGerror, "lo_write failed: %s", PQerrorMessage(conn));
3866
+ BLOCKING_BEGIN(conn)
3867
+ n = lo_write(conn, fd, StringValuePtr(buffer),
3868
+ RSTRING_LEN(buffer));
3869
+ BLOCKING_END(conn)
3870
+
3871
+ if(n < 0) {
3872
+ pg_raise_conn_error( rb_ePGerror, self, "lo_write failed: %s", PQerrorMessage(conn));
3610
3873
  }
3611
3874
 
3612
3875
  return INT2FIX(n);
@@ -3629,16 +3892,17 @@ pgconn_loread(VALUE self, VALUE in_lo_desc, VALUE in_len)
3629
3892
  VALUE str;
3630
3893
  char *buffer;
3631
3894
 
3632
- buffer = ALLOC_N(char, len);
3633
- if(buffer == NULL)
3634
- rb_raise(rb_eNoMemError, "ALLOC failed!");
3895
+ if (len < 0)
3896
+ pg_raise_conn_error( rb_ePGerror, self, "negative length %d given", len);
3635
3897
 
3636
- if (len < 0){
3637
- rb_raise(rb_ePGerror,"nagative length %d given", len);
3638
- }
3898
+ buffer = ALLOC_N(char, len);
3899
+
3900
+ BLOCKING_BEGIN(conn)
3901
+ ret = lo_read(conn, lo_desc, buffer, len);
3902
+ BLOCKING_END(conn)
3639
3903
 
3640
- if((ret = lo_read(conn, lo_desc, buffer, len)) < 0)
3641
- rb_raise(rb_ePGerror, "lo_read failed");
3904
+ if(ret < 0)
3905
+ pg_raise_conn_error( rb_ePGerror, self, "lo_read failed");
3642
3906
 
3643
3907
  if(ret == 0) {
3644
3908
  xfree(buffer);
@@ -3667,8 +3931,12 @@ pgconn_lolseek(VALUE self, VALUE in_lo_desc, VALUE offset, VALUE whence)
3667
3931
  int lo_desc = NUM2INT(in_lo_desc);
3668
3932
  int ret;
3669
3933
 
3670
- if((ret = lo_lseek(conn, lo_desc, NUM2INT(offset), NUM2INT(whence))) < 0) {
3671
- rb_raise(rb_ePGerror, "lo_lseek failed");
3934
+ BLOCKING_BEGIN(conn)
3935
+ ret = lo_lseek(conn, lo_desc, NUM2INT(offset), NUM2INT(whence));
3936
+ BLOCKING_END(conn)
3937
+
3938
+ if(ret < 0) {
3939
+ pg_raise_conn_error( rb_ePGerror, self, "lo_lseek failed");
3672
3940
  }
3673
3941
 
3674
3942
  return INT2FIX(ret);
@@ -3687,8 +3955,12 @@ pgconn_lotell(VALUE self, VALUE in_lo_desc)
3687
3955
  PGconn *conn = pg_get_pgconn(self);
3688
3956
  int lo_desc = NUM2INT(in_lo_desc);
3689
3957
 
3690
- if((position = lo_tell(conn, lo_desc)) < 0)
3691
- rb_raise(rb_ePGerror,"lo_tell failed");
3958
+ BLOCKING_BEGIN(conn)
3959
+ position = lo_tell(conn, lo_desc);
3960
+ BLOCKING_END(conn)
3961
+
3962
+ if(position < 0)
3963
+ pg_raise_conn_error( rb_ePGerror, self, "lo_tell failed");
3692
3964
 
3693
3965
  return INT2FIX(position);
3694
3966
  }
@@ -3705,9 +3977,14 @@ pgconn_lotruncate(VALUE self, VALUE in_lo_desc, VALUE in_len)
3705
3977
  PGconn *conn = pg_get_pgconn(self);
3706
3978
  int lo_desc = NUM2INT(in_lo_desc);
3707
3979
  size_t len = NUM2INT(in_len);
3980
+ int ret;
3981
+
3982
+ BLOCKING_BEGIN(conn)
3983
+ ret = lo_truncate(conn,lo_desc,len);
3984
+ BLOCKING_END(conn)
3708
3985
 
3709
- if(lo_truncate(conn,lo_desc,len) < 0)
3710
- rb_raise(rb_ePGerror,"lo_truncate failed");
3986
+ if(ret < 0)
3987
+ pg_raise_conn_error( rb_ePGerror, self, "lo_truncate failed");
3711
3988
 
3712
3989
  return Qnil;
3713
3990
  }
@@ -3723,9 +4000,14 @@ pgconn_loclose(VALUE self, VALUE in_lo_desc)
3723
4000
  {
3724
4001
  PGconn *conn = pg_get_pgconn(self);
3725
4002
  int lo_desc = NUM2INT(in_lo_desc);
4003
+ int ret;
4004
+
4005
+ BLOCKING_BEGIN(conn)
4006
+ ret = lo_close(conn,lo_desc);
4007
+ BLOCKING_END(conn)
3726
4008
 
3727
- if(lo_close(conn,lo_desc) < 0)
3728
- rb_raise(rb_ePGerror,"lo_close failed");
4009
+ if(ret < 0)
4010
+ pg_raise_conn_error( rb_ePGerror, self, "lo_close failed");
3729
4011
 
3730
4012
  return Qnil;
3731
4013
  }
@@ -3741,9 +4023,14 @@ pgconn_lounlink(VALUE self, VALUE in_oid)
3741
4023
  {
3742
4024
  PGconn *conn = pg_get_pgconn(self);
3743
4025
  Oid oid = NUM2UINT(in_oid);
4026
+ int ret;
4027
+
4028
+ BLOCKING_BEGIN(conn)
4029
+ ret = lo_unlink(conn,oid);
4030
+ BLOCKING_END(conn)
3744
4031
 
3745
- if(lo_unlink(conn,oid) < 0)
3746
- rb_raise(rb_ePGerror,"lo_unlink failed");
4032
+ if(ret < 0)
4033
+ pg_raise_conn_error( rb_ePGerror, self, "lo_unlink failed");
3747
4034
 
3748
4035
  return Qnil;
3749
4036
  }
@@ -3800,12 +4087,13 @@ static VALUE pgconn_external_encoding(VALUE self);
3800
4087
  static VALUE
3801
4088
  pgconn_internal_encoding_set(VALUE self, VALUE enc)
3802
4089
  {
4090
+ rb_check_frozen(self);
3803
4091
  if (NIL_P(enc)) {
3804
- pgconn_set_client_encoding( self, rb_usascii_str_new_cstr("SQL_ASCII") );
4092
+ pgconn_sync_set_client_encoding( self, rb_usascii_str_new_cstr("SQL_ASCII") );
3805
4093
  return enc;
3806
4094
  }
3807
4095
  else if ( TYPE(enc) == T_STRING && strcasecmp("JOHAB", StringValueCStr(enc)) == 0 ) {
3808
- pgconn_set_client_encoding(self, rb_usascii_str_new_cstr("JOHAB"));
4096
+ pgconn_sync_set_client_encoding(self, rb_usascii_str_new_cstr("JOHAB"));
3809
4097
  return enc;
3810
4098
  }
3811
4099
  else {
@@ -3843,16 +4131,34 @@ pgconn_external_encoding(VALUE self)
3843
4131
  return rb_enc_from_encoding( enc );
3844
4132
  }
3845
4133
 
4134
+ /*
4135
+ * call-seq:
4136
+ * conn.set_client_encoding( encoding )
4137
+ *
4138
+ * Sets the client encoding to the _encoding_ String.
4139
+ */
4140
+ static VALUE
4141
+ pgconn_async_set_client_encoding(VALUE self, VALUE encname)
4142
+ {
4143
+ VALUE query_format, query;
4144
+
4145
+ rb_check_frozen(self);
4146
+ Check_Type(encname, T_STRING);
4147
+ query_format = rb_str_new_cstr("set client_encoding to '%s'");
4148
+ query = rb_funcall(query_format, rb_intern("%"), 1, encname);
4149
+
4150
+ pgconn_async_exec(1, &query, self);
4151
+ pgconn_set_internal_encoding_index( self );
4152
+
4153
+ return Qnil;
4154
+ }
3846
4155
 
3847
4156
  static VALUE
3848
4157
  pgconn_set_client_encoding_async1( VALUE args )
3849
4158
  {
3850
4159
  VALUE self = ((VALUE*)args)[0];
3851
4160
  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);
4161
+ pgconn_async_set_client_encoding(self, encname);
3856
4162
  return 0;
3857
4163
  }
3858
4164
 
@@ -3867,9 +4173,9 @@ pgconn_set_client_encoding_async2( VALUE arg, VALUE ex )
3867
4173
 
3868
4174
 
3869
4175
  static VALUE
3870
- pgconn_set_client_encoding_async( VALUE self, const char *encname )
4176
+ pgconn_set_client_encoding_async( VALUE self, VALUE encname )
3871
4177
  {
3872
- VALUE args[] = { self, rb_str_new_cstr(encname) };
4178
+ VALUE args[] = { self, encname };
3873
4179
  return rb_rescue(pgconn_set_client_encoding_async1, (VALUE)&args, pgconn_set_client_encoding_async2, Qnil);
3874
4180
  }
3875
4181
 
@@ -3886,16 +4192,23 @@ static VALUE
3886
4192
  pgconn_set_default_encoding( VALUE self )
3887
4193
  {
3888
4194
  PGconn *conn = pg_get_pgconn( self );
3889
- rb_encoding *enc;
3890
- const char *encname;
3891
-
3892
- if (( enc = rb_default_internal_encoding() )) {
3893
- encname = pg_get_rb_encoding_as_pg_encoding( enc );
3894
- if ( pgconn_set_client_encoding_async(self, encname) != 0 )
3895
- rb_warning( "Failed to set the default_internal encoding to %s: '%s'",
3896
- encname, PQerrorMessage(conn) );
4195
+ rb_encoding *rb_enc;
4196
+
4197
+ rb_check_frozen(self);
4198
+ if (( rb_enc = rb_default_internal_encoding() )) {
4199
+ rb_encoding * conn_encoding = pg_conn_enc_get( conn );
4200
+
4201
+ /* Don't set the server encoding, if it's unnecessary.
4202
+ * This is important for connection proxies, who disallow configuration settings.
4203
+ */
4204
+ if ( conn_encoding != rb_enc ) {
4205
+ const char *encname = pg_get_rb_encoding_as_pg_encoding( rb_enc );
4206
+ if ( pgconn_set_client_encoding_async(self, rb_str_new_cstr(encname)) != 0 )
4207
+ rb_warning( "Failed to set the default_internal encoding to %s: '%s'",
4208
+ encname, PQerrorMessage(conn) );
4209
+ }
3897
4210
  pgconn_set_internal_encoding_index( self );
3898
- return rb_enc_from_encoding( enc );
4211
+ return rb_enc_from_encoding( rb_enc );
3899
4212
  } else {
3900
4213
  pgconn_set_internal_encoding_index( self );
3901
4214
  return Qnil;
@@ -3916,13 +4229,14 @@ static VALUE
3916
4229
  pgconn_type_map_for_queries_set(VALUE self, VALUE typemap)
3917
4230
  {
3918
4231
  t_pg_connection *this = pg_get_connection( self );
4232
+ t_typemap *tm;
4233
+ UNUSED(tm);
3919
4234
 
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
- this->type_map_for_queries = typemap;
4235
+ rb_check_frozen(self);
4236
+ /* Check type of method param */
4237
+ TypedData_Get_Struct(typemap, t_typemap, &pg_typemap_type, tm);
4238
+
4239
+ RB_OBJ_WRITE(self, &this->type_map_for_queries, typemap);
3926
4240
 
3927
4241
  return typemap;
3928
4242
  }
@@ -3956,13 +4270,12 @@ static VALUE
3956
4270
  pgconn_type_map_for_results_set(VALUE self, VALUE typemap)
3957
4271
  {
3958
4272
  t_pg_connection *this = pg_get_connection( self );
4273
+ t_typemap *tm;
4274
+ UNUSED(tm);
3959
4275
 
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);
3965
- this->type_map_for_results = typemap;
4276
+ rb_check_frozen(self);
4277
+ TypedData_Get_Struct(typemap, t_typemap, &pg_typemap_type, tm);
4278
+ RB_OBJ_WRITE(self, &this->type_map_for_results, typemap);
3966
4279
 
3967
4280
  return typemap;
3968
4281
  }
@@ -3996,20 +4309,20 @@ pgconn_type_map_for_results_get(VALUE self)
3996
4309
  *
3997
4310
  */
3998
4311
  static VALUE
3999
- pgconn_encoder_for_put_copy_data_set(VALUE self, VALUE typemap)
4312
+ pgconn_encoder_for_put_copy_data_set(VALUE self, VALUE encoder)
4000
4313
  {
4001
4314
  t_pg_connection *this = pg_get_connection( self );
4002
4315
 
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);
4316
+ rb_check_frozen(self);
4317
+ if( encoder != Qnil ){
4318
+ t_pg_coder *co;
4319
+ UNUSED(co);
4320
+ /* Check argument type */
4321
+ TypedData_Get_Struct(encoder, t_pg_coder, &pg_coder_type, co);
4009
4322
  }
4010
- this->encoder_for_put_copy_data = typemap;
4323
+ RB_OBJ_WRITE(self, &this->encoder_for_put_copy_data, encoder);
4011
4324
 
4012
- return typemap;
4325
+ return encoder;
4013
4326
  }
4014
4327
 
4015
4328
  /*
@@ -4045,20 +4358,20 @@ pgconn_encoder_for_put_copy_data_get(VALUE self)
4045
4358
  *
4046
4359
  */
4047
4360
  static VALUE
4048
- pgconn_decoder_for_get_copy_data_set(VALUE self, VALUE typemap)
4361
+ pgconn_decoder_for_get_copy_data_set(VALUE self, VALUE decoder)
4049
4362
  {
4050
4363
  t_pg_connection *this = pg_get_connection( self );
4051
4364
 
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);
4365
+ rb_check_frozen(self);
4366
+ if( decoder != Qnil ){
4367
+ t_pg_coder *co;
4368
+ UNUSED(co);
4369
+ /* Check argument type */
4370
+ TypedData_Get_Struct(decoder, t_pg_coder, &pg_coder_type, co);
4058
4371
  }
4059
- this->decoder_for_get_copy_data = typemap;
4372
+ RB_OBJ_WRITE(self, &this->decoder_for_get_copy_data, decoder);
4060
4373
 
4061
- return typemap;
4374
+ return decoder;
4062
4375
  }
4063
4376
 
4064
4377
  /*
@@ -4102,6 +4415,7 @@ pgconn_field_name_type_set(VALUE self, VALUE sym)
4102
4415
  {
4103
4416
  t_pg_connection *this = pg_get_connection( self );
4104
4417
 
4418
+ rb_check_frozen(self);
4105
4419
  this->flags &= ~PG_RESULT_FIELD_NAMES_MASK;
4106
4420
  if( sym == sym_symbol ) this->flags |= PG_RESULT_FIELD_NAMES_SYMBOL;
4107
4421
  else if ( sym == sym_static_symbol ) this->flags |= PG_RESULT_FIELD_NAMES_STATIC_SYMBOL;
@@ -4138,9 +4452,10 @@ pgconn_field_name_type_get(VALUE self)
4138
4452
  * Document-class: PG::Connection
4139
4453
  */
4140
4454
  void
4141
- init_pg_connection()
4455
+ init_pg_connection(void)
4142
4456
  {
4143
4457
  s_id_encode = rb_intern("encode");
4458
+ s_id_autoclose_set = rb_intern("autoclose=");
4144
4459
  sym_type = ID2SYM(rb_intern("type"));
4145
4460
  sym_format = ID2SYM(rb_intern("format"));
4146
4461
  sym_value = ID2SYM(rb_intern("value"));
@@ -4156,10 +4471,6 @@ init_pg_connection()
4156
4471
  /****** PG::Connection CLASS METHODS ******/
4157
4472
  rb_define_alloc_func( rb_cPGconn, pgconn_s_allocate );
4158
4473
 
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
4474
  rb_define_singleton_method(rb_cPGconn, "escape_string", pgconn_s_escape, 1);
4164
4475
  SINGLETON_ALIAS(rb_cPGconn, "escape", "escape_string");
4165
4476
  rb_define_singleton_method(rb_cPGconn, "escape_bytea", pgconn_s_escape_bytea, 1);
@@ -4168,15 +4479,17 @@ init_pg_connection()
4168
4479
  rb_define_singleton_method(rb_cPGconn, "quote_ident", pgconn_s_quote_ident, 1);
4169
4480
  rb_define_singleton_method(rb_cPGconn, "connect_start", pgconn_s_connect_start, -1);
4170
4481
  rb_define_singleton_method(rb_cPGconn, "conndefaults", pgconn_s_conndefaults, 0);
4171
- rb_define_singleton_method(rb_cPGconn, "ping", pgconn_s_ping, -1);
4482
+ rb_define_singleton_method(rb_cPGconn, "conninfo_parse", pgconn_s_conninfo_parse, 1);
4483
+ rb_define_singleton_method(rb_cPGconn, "sync_ping", pgconn_s_sync_ping, -1);
4484
+ rb_define_singleton_method(rb_cPGconn, "sync_connect", pgconn_s_sync_connect, -1);
4172
4485
 
4173
4486
  /****** PG::Connection INSTANCE METHODS: Connection Control ******/
4174
- rb_define_method(rb_cPGconn, "initialize", pgconn_init, -1);
4175
4487
  rb_define_method(rb_cPGconn, "connect_poll", pgconn_connect_poll, 0);
4176
4488
  rb_define_method(rb_cPGconn, "finish", pgconn_finish, 0);
4177
4489
  rb_define_method(rb_cPGconn, "finished?", pgconn_finished_p, 0);
4178
- rb_define_method(rb_cPGconn, "reset", pgconn_reset, 0);
4490
+ rb_define_method(rb_cPGconn, "sync_reset", pgconn_sync_reset, 0);
4179
4491
  rb_define_method(rb_cPGconn, "reset_start", pgconn_reset_start, 0);
4492
+ rb_define_private_method(rb_cPGconn, "reset_start2", pgconn_reset_start2, 1);
4180
4493
  rb_define_method(rb_cPGconn, "reset_poll", pgconn_reset_poll, 0);
4181
4494
  rb_define_alias(rb_cPGconn, "close", "finish");
4182
4495
 
@@ -4185,11 +4498,12 @@ init_pg_connection()
4185
4498
  rb_define_method(rb_cPGconn, "user", pgconn_user, 0);
4186
4499
  rb_define_method(rb_cPGconn, "pass", pgconn_pass, 0);
4187
4500
  rb_define_method(rb_cPGconn, "host", pgconn_host, 0);
4501
+ #if defined(HAVE_PQRESULTMEMORYSIZE)
4502
+ rb_define_method(rb_cPGconn, "hostaddr", pgconn_hostaddr, 0);
4503
+ #endif
4188
4504
  rb_define_method(rb_cPGconn, "port", pgconn_port, 0);
4189
4505
  rb_define_method(rb_cPGconn, "tty", pgconn_tty, 0);
4190
- #ifdef HAVE_PQCONNINFO
4191
4506
  rb_define_method(rb_cPGconn, "conninfo", pgconn_conninfo, 0);
4192
- #endif
4193
4507
  rb_define_method(rb_cPGconn, "options", pgconn_options, 0);
4194
4508
  rb_define_method(rb_cPGconn, "status", pgconn_status, 0);
4195
4509
  rb_define_method(rb_cPGconn, "transaction_status", pgconn_transaction_status, 0);
@@ -4200,17 +4514,18 @@ init_pg_connection()
4200
4514
  rb_define_method(rb_cPGconn, "socket", pgconn_socket, 0);
4201
4515
  rb_define_method(rb_cPGconn, "socket_io", pgconn_socket_io, 0);
4202
4516
  rb_define_method(rb_cPGconn, "backend_pid", pgconn_backend_pid, 0);
4517
+ rb_define_method(rb_cPGconn, "backend_key", pgconn_backend_key, 0);
4203
4518
  rb_define_method(rb_cPGconn, "connection_needs_password", pgconn_connection_needs_password, 0);
4204
4519
  rb_define_method(rb_cPGconn, "connection_used_password", pgconn_connection_used_password, 0);
4205
4520
  /* rb_define_method(rb_cPGconn, "getssl", pgconn_getssl, 0); */
4206
4521
 
4207
4522
  /****** 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);
4523
+ rb_define_method(rb_cPGconn, "sync_exec", pgconn_sync_exec, -1);
4524
+ rb_define_method(rb_cPGconn, "sync_exec_params", pgconn_sync_exec_params, -1);
4525
+ rb_define_method(rb_cPGconn, "sync_prepare", pgconn_sync_prepare, -1);
4526
+ rb_define_method(rb_cPGconn, "sync_exec_prepared", pgconn_sync_exec_prepared, -1);
4527
+ rb_define_method(rb_cPGconn, "sync_describe_prepared", pgconn_sync_describe_prepared, 1);
4528
+ rb_define_method(rb_cPGconn, "sync_describe_portal", pgconn_sync_describe_portal, 1);
4214
4529
 
4215
4530
  rb_define_method(rb_cPGconn, "exec", pgconn_async_exec, -1);
4216
4531
  rb_define_method(rb_cPGconn, "exec_params", pgconn_async_exec_params, -1);
@@ -4243,25 +4558,26 @@ init_pg_connection()
4243
4558
  rb_define_method(rb_cPGconn, "send_query_prepared", pgconn_send_query_prepared, -1);
4244
4559
  rb_define_method(rb_cPGconn, "send_describe_prepared", pgconn_send_describe_prepared, 1);
4245
4560
  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);
4561
+ rb_define_method(rb_cPGconn, "sync_get_result", pgconn_sync_get_result, 0);
4247
4562
  rb_define_method(rb_cPGconn, "consume_input", pgconn_consume_input, 0);
4248
4563
  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);
4564
+ rb_define_method(rb_cPGconn, "sync_setnonblocking", pgconn_sync_setnonblocking, 1);
4565
+ rb_define_method(rb_cPGconn, "sync_isnonblocking", pgconn_sync_isnonblocking, 0);
4566
+ rb_define_method(rb_cPGconn, "sync_flush", pgconn_sync_flush, 0);
4567
+ rb_define_method(rb_cPGconn, "flush", pgconn_async_flush, 0);
4568
+ rb_define_alias(rb_cPGconn, "async_flush", "flush");
4253
4569
  rb_define_method(rb_cPGconn, "discard_results", pgconn_discard_results, 0);
4254
4570
 
4255
4571
  /****** PG::Connection INSTANCE METHODS: Cancelling Queries in Progress ******/
4256
- rb_define_method(rb_cPGconn, "cancel", pgconn_cancel, 0);
4572
+ rb_define_method(rb_cPGconn, "sync_cancel", pgconn_sync_cancel, 0);
4257
4573
 
4258
4574
  /****** PG::Connection INSTANCE METHODS: NOTIFY ******/
4259
4575
  rb_define_method(rb_cPGconn, "notifies", pgconn_notifies, 0);
4260
4576
 
4261
4577
  /****** 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);
4578
+ rb_define_method(rb_cPGconn, "sync_put_copy_data", pgconn_sync_put_copy_data, -1);
4579
+ rb_define_method(rb_cPGconn, "sync_put_copy_end", pgconn_sync_put_copy_end, -1);
4580
+ rb_define_method(rb_cPGconn, "sync_get_copy_data", pgconn_sync_get_copy_data, -1);
4265
4581
 
4266
4582
  /****** PG::Connection INSTANCE METHODS: Control Functions ******/
4267
4583
  rb_define_method(rb_cPGconn, "set_error_verbosity", pgconn_set_error_verbosity, 1);
@@ -4277,16 +4593,20 @@ init_pg_connection()
4277
4593
 
4278
4594
  /****** PG::Connection INSTANCE METHODS: Other ******/
4279
4595
  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);
4596
+ rb_define_method(rb_cPGconn, "sync_set_client_encoding", pgconn_sync_set_client_encoding, 1);
4597
+ rb_define_method(rb_cPGconn, "set_client_encoding", pgconn_async_set_client_encoding, 1);
4598
+ rb_define_alias(rb_cPGconn, "async_set_client_encoding", "set_client_encoding");
4281
4599
  rb_define_alias(rb_cPGconn, "client_encoding=", "set_client_encoding");
4282
- rb_define_method(rb_cPGconn, "transaction", pgconn_transaction, 0);
4283
4600
  rb_define_method(rb_cPGconn, "block", pgconn_block, -1);
4601
+ rb_define_private_method(rb_cPGconn, "flush_data=", pgconn_flush_data_set, 1);
4284
4602
  rb_define_method(rb_cPGconn, "wait_for_notify", pgconn_wait_for_notify, -1);
4285
4603
  rb_define_alias(rb_cPGconn, "notifies_wait", "wait_for_notify");
4286
4604
  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);
4605
+ rb_define_method(rb_cPGconn, "sync_get_last_result", pgconn_sync_get_last_result, 0);
4606
+ rb_define_method(rb_cPGconn, "get_last_result", pgconn_async_get_last_result, 0);
4607
+ rb_define_alias(rb_cPGconn, "async_get_last_result", "get_last_result");
4288
4608
  #ifdef HAVE_PQENCRYPTPASSWORDCONN
4289
- rb_define_method(rb_cPGconn, "encrypt_password", pgconn_encrypt_password, -1);
4609
+ rb_define_method(rb_cPGconn, "sync_encrypt_password", pgconn_sync_encrypt_password, -1);
4290
4610
  #endif
4291
4611
 
4292
4612
  #ifdef HAVE_PQSSLATTRIBUTE
@@ -4295,6 +4615,14 @@ init_pg_connection()
4295
4615
  rb_define_method(rb_cPGconn, "ssl_attribute_names", pgconn_ssl_attribute_names, 0);
4296
4616
  #endif
4297
4617
 
4618
+ #ifdef HAVE_PQENTERPIPELINEMODE
4619
+ rb_define_method(rb_cPGconn, "pipeline_status", pgconn_pipeline_status, 0);
4620
+ rb_define_method(rb_cPGconn, "enter_pipeline_mode", pgconn_enter_pipeline_mode, 0);
4621
+ rb_define_method(rb_cPGconn, "exit_pipeline_mode", pgconn_exit_pipeline_mode, 0);
4622
+ rb_define_method(rb_cPGconn, "pipeline_sync", pgconn_pipeline_sync, 0);
4623
+ rb_define_method(rb_cPGconn, "send_flush_request", pgconn_send_flush_request, 0);
4624
+ #endif
4625
+
4298
4626
  /****** PG::Connection INSTANCE METHODS: Large Object Support ******/
4299
4627
  rb_define_method(rb_cPGconn, "lo_creat", pgconn_locreat, -1);
4300
4628
  rb_define_alias(rb_cPGconn, "locreat", "lo_creat");