pg 1.2.3 → 1.5.6

Sign up to get free protection for your applications and to get access to all the features.
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");