pg 1.2.3 → 1.5.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (136) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data/.appveyor.yml +42 -0
  4. data/.gems +6 -0
  5. data/.github/workflows/binary-gems.yml +117 -0
  6. data/.github/workflows/source-gem.yml +137 -0
  7. data/.gitignore +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 +14 -0
  15. data/History.md +876 -0
  16. data/Manifest.txt +0 -1
  17. data/README.ja.md +276 -0
  18. data/README.md +286 -0
  19. data/Rakefile +33 -135
  20. data/Rakefile.cross +12 -13
  21. data/certs/ged.pem +24 -0
  22. data/certs/larskanis-2022.pem +26 -0
  23. data/certs/larskanis-2023.pem +24 -0
  24. data/ext/errorcodes.def +12 -0
  25. data/ext/errorcodes.rb +0 -0
  26. data/ext/errorcodes.txt +4 -1
  27. data/ext/extconf.rb +100 -25
  28. data/ext/gvl_wrappers.c +4 -0
  29. data/ext/gvl_wrappers.h +23 -0
  30. data/ext/pg.c +72 -57
  31. data/ext/pg.h +28 -4
  32. data/ext/pg_binary_decoder.c +80 -1
  33. data/ext/pg_binary_encoder.c +225 -1
  34. data/ext/pg_coder.c +96 -33
  35. data/ext/pg_connection.c +996 -697
  36. data/ext/pg_copy_coder.c +351 -33
  37. data/ext/pg_errors.c +1 -1
  38. data/ext/pg_record_coder.c +50 -19
  39. data/ext/pg_result.c +177 -64
  40. data/ext/pg_text_decoder.c +29 -11
  41. data/ext/pg_text_encoder.c +29 -16
  42. data/ext/pg_tuple.c +83 -60
  43. data/ext/pg_type_map.c +44 -10
  44. data/ext/pg_type_map_all_strings.c +17 -3
  45. data/ext/pg_type_map_by_class.c +54 -27
  46. data/ext/pg_type_map_by_column.c +73 -31
  47. data/ext/pg_type_map_by_mri_type.c +48 -19
  48. data/ext/pg_type_map_by_oid.c +59 -27
  49. data/ext/pg_type_map_in_ruby.c +55 -21
  50. data/ext/pg_util.c +2 -2
  51. data/lib/pg/basic_type_map_based_on_result.rb +67 -0
  52. data/lib/pg/basic_type_map_for_queries.rb +198 -0
  53. data/lib/pg/basic_type_map_for_results.rb +104 -0
  54. data/lib/pg/basic_type_registry.rb +299 -0
  55. data/lib/pg/binary_decoder/date.rb +9 -0
  56. data/lib/pg/binary_decoder/timestamp.rb +26 -0
  57. data/lib/pg/binary_encoder/timestamp.rb +20 -0
  58. data/lib/pg/coder.rb +15 -13
  59. data/lib/pg/connection.rb +743 -83
  60. data/lib/pg/exceptions.rb +14 -1
  61. data/lib/pg/text_decoder/date.rb +18 -0
  62. data/lib/pg/text_decoder/inet.rb +9 -0
  63. data/lib/pg/text_decoder/json.rb +14 -0
  64. data/lib/pg/text_decoder/numeric.rb +9 -0
  65. data/lib/pg/text_decoder/timestamp.rb +30 -0
  66. data/lib/pg/text_encoder/date.rb +12 -0
  67. data/lib/pg/text_encoder/inet.rb +28 -0
  68. data/lib/pg/text_encoder/json.rb +14 -0
  69. data/lib/pg/text_encoder/numeric.rb +9 -0
  70. data/lib/pg/text_encoder/timestamp.rb +24 -0
  71. data/lib/pg/version.rb +4 -0
  72. data/lib/pg.rb +94 -39
  73. data/misc/openssl-pg-segfault.rb +31 -0
  74. data/misc/postgres/History.txt +9 -0
  75. data/misc/postgres/Manifest.txt +5 -0
  76. data/misc/postgres/README.txt +21 -0
  77. data/misc/postgres/Rakefile +21 -0
  78. data/misc/postgres/lib/postgres.rb +16 -0
  79. data/misc/ruby-pg/History.txt +9 -0
  80. data/misc/ruby-pg/Manifest.txt +5 -0
  81. data/misc/ruby-pg/README.txt +21 -0
  82. data/misc/ruby-pg/Rakefile +21 -0
  83. data/misc/ruby-pg/lib/ruby/pg.rb +16 -0
  84. data/pg.gemspec +34 -0
  85. data/rakelib/task_extension.rb +46 -0
  86. data/sample/array_insert.rb +20 -0
  87. data/sample/async_api.rb +102 -0
  88. data/sample/async_copyto.rb +39 -0
  89. data/sample/async_mixed.rb +56 -0
  90. data/sample/check_conn.rb +21 -0
  91. data/sample/copydata.rb +71 -0
  92. data/sample/copyfrom.rb +81 -0
  93. data/sample/copyto.rb +19 -0
  94. data/sample/cursor.rb +21 -0
  95. data/sample/disk_usage_report.rb +177 -0
  96. data/sample/issue-119.rb +94 -0
  97. data/sample/losample.rb +69 -0
  98. data/sample/minimal-testcase.rb +17 -0
  99. data/sample/notify_wait.rb +72 -0
  100. data/sample/pg_statistics.rb +285 -0
  101. data/sample/replication_monitor.rb +222 -0
  102. data/sample/test_binary_values.rb +33 -0
  103. data/sample/wal_shipper.rb +434 -0
  104. data/sample/warehouse_partitions.rb +311 -0
  105. data/translation/.po4a-version +7 -0
  106. data/translation/po/all.pot +910 -0
  107. data/translation/po/ja.po +1047 -0
  108. data/translation/po4a.cfg +12 -0
  109. data.tar.gz.sig +0 -0
  110. metadata +142 -210
  111. metadata.gz.sig +0 -0
  112. data/ChangeLog +0 -0
  113. data/History.rdoc +0 -578
  114. data/README.ja.rdoc +0 -13
  115. data/README.rdoc +0 -213
  116. data/lib/pg/basic_type_mapping.rb +0 -522
  117. data/lib/pg/binary_decoder.rb +0 -23
  118. data/lib/pg/constants.rb +0 -12
  119. data/lib/pg/text_decoder.rb +0 -46
  120. data/lib/pg/text_encoder.rb +0 -59
  121. data/spec/data/expected_trace.out +0 -26
  122. data/spec/data/random_binary_data +0 -0
  123. data/spec/helpers.rb +0 -380
  124. data/spec/pg/basic_type_mapping_spec.rb +0 -630
  125. data/spec/pg/connection_spec.rb +0 -1949
  126. data/spec/pg/connection_sync_spec.rb +0 -41
  127. data/spec/pg/result_spec.rb +0 -681
  128. data/spec/pg/tuple_spec.rb +0 -333
  129. data/spec/pg/type_map_by_class_spec.rb +0 -138
  130. data/spec/pg/type_map_by_column_spec.rb +0 -226
  131. data/spec/pg/type_map_by_mri_type_spec.rb +0 -136
  132. data/spec/pg/type_map_by_oid_spec.rb +0 -149
  133. data/spec/pg/type_map_in_ruby_spec.rb +0 -164
  134. data/spec/pg/type_map_spec.rb +0 -22
  135. data/spec/pg/type_spec.rb +0 -1123
  136. 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,15 +555,8 @@ 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) );
@@ -589,7 +578,7 @@ pgconn_reset_start(VALUE self)
589
578
  {
590
579
  pgconn_close_socket_io( self );
591
580
  if(gvl_PQresetStart(pg_get_pgconn(self)) == 0)
592
- rb_raise(rb_eUnableToSend, "reset has failed");
581
+ pg_raise_conn_error( rb_eUnableToSend, self, "reset has failed");
593
582
  return Qnil;
594
583
  }
595
584
 
@@ -606,6 +595,9 @@ pgconn_reset_poll(VALUE self)
606
595
  {
607
596
  PostgresPollingStatusType status;
608
597
  status = gvl_PQresetPoll(pg_get_pgconn(self));
598
+
599
+ pgconn_close_socket_io(self);
600
+
609
601
  return INT2FIX((int)status);
610
602
  }
611
603
 
@@ -656,7 +648,18 @@ pgconn_pass(VALUE self)
656
648
  * call-seq:
657
649
  * conn.host()
658
650
  *
659
- * Returns the connected server name.
651
+ * Returns the server host name of the active connection.
652
+ * This can be a host name, an IP address, or a directory path if the connection is via Unix socket.
653
+ * (The path case can be distinguished because it will always be an absolute path, beginning with +/+ .)
654
+ *
655
+ * If the connection parameters specified both host and hostaddr, then +host+ will return the host information.
656
+ * If only hostaddr was specified, then that is returned.
657
+ * If multiple hosts were specified in the connection parameters, +host+ returns the host actually connected to.
658
+ *
659
+ * 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.
660
+ *
661
+ * 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.
662
+ * The status of the connection can be checked using the function Connection#status .
660
663
  */
661
664
  static VALUE
662
665
  pgconn_host(VALUE self)
@@ -666,6 +669,26 @@ pgconn_host(VALUE self)
666
669
  return rb_str_new2(host);
667
670
  }
668
671
 
672
+ /* PQhostaddr() appeared in PostgreSQL-12 together with PQresultMemorySize() */
673
+ #if defined(HAVE_PQRESULTMEMORYSIZE)
674
+ /*
675
+ * call-seq:
676
+ * conn.hostaddr()
677
+ *
678
+ * Returns the server IP address of the active connection.
679
+ * This can be the address that a host name resolved to, or an IP address provided through the hostaddr parameter.
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
+ */
683
+ static VALUE
684
+ pgconn_hostaddr(VALUE self)
685
+ {
686
+ char *host = PQhostaddr(pg_get_pgconn(self));
687
+ if (!host) return Qnil;
688
+ return rb_str_new2(host);
689
+ }
690
+ #endif
691
+
669
692
  /*
670
693
  * call-seq:
671
694
  * conn.port()
@@ -676,21 +699,22 @@ static VALUE
676
699
  pgconn_port(VALUE self)
677
700
  {
678
701
  char* port = PQport(pg_get_pgconn(self));
679
- return INT2NUM(atol(port));
702
+ if (!port || port[0] == '\0')
703
+ return INT2NUM(DEF_PGPORT);
704
+ else
705
+ return INT2NUM(atoi(port));
680
706
  }
681
707
 
682
708
  /*
683
709
  * call-seq:
684
710
  * conn.tty()
685
711
  *
686
- * Returns the connected pgtty. (Obsolete)
712
+ * Obsolete function.
687
713
  */
688
714
  static VALUE
689
715
  pgconn_tty(VALUE self)
690
716
  {
691
- char *tty = PQtty(pg_get_pgconn(self));
692
- if (!tty) return Qnil;
693
- return rb_str_new2(tty);
717
+ return rb_str_new2("");
694
718
  }
695
719
 
696
720
  /*
@@ -708,7 +732,6 @@ pgconn_options(VALUE self)
708
732
  }
709
733
 
710
734
 
711
- #ifdef HAVE_PQCONNINFO
712
735
  /*
713
736
  * call-seq:
714
737
  * conn.conninfo -> hash
@@ -728,14 +751,24 @@ pgconn_conninfo( VALUE self )
728
751
 
729
752
  return array;
730
753
  }
731
- #endif
732
754
 
733
755
 
734
756
  /*
735
757
  * call-seq:
736
758
  * conn.status()
737
759
  *
738
- * Returns status of connection : CONNECTION_OK or CONNECTION_BAD
760
+ * Returns the status of the connection, which is one:
761
+ * PG::Constants::CONNECTION_OK
762
+ * PG::Constants::CONNECTION_BAD
763
+ *
764
+ * ... and other constants of kind PG::Constants::CONNECTION_*
765
+ *
766
+ * This method returns the status of the last command from memory.
767
+ * It doesn't do any socket access hence is not suitable to test the connectivity.
768
+ * See check_socket for a way to verify the socket state.
769
+ *
770
+ * Example:
771
+ * PG.constants.grep(/CONNECTION_/).find{|c| PG.const_get(c) == conn.status} # => :CONNECTION_OK
739
772
  */
740
773
  static VALUE
741
774
  pgconn_status(VALUE self)
@@ -823,7 +856,10 @@ pgconn_server_version(VALUE self)
823
856
  * call-seq:
824
857
  * conn.error_message -> String
825
858
  *
826
- * Returns the error message about connection.
859
+ * Returns the error message most recently generated by an operation on the connection.
860
+ *
861
+ * Nearly all libpq functions will set a message for conn.error_message if they fail.
862
+ * Note that by libpq convention, a nonempty error_message result can consist of multiple lines, and will include a trailing newline.
827
863
  */
828
864
  static VALUE
829
865
  pgconn_error_message(VALUE self)
@@ -857,7 +893,8 @@ pgconn_socket(VALUE self)
857
893
  pg_deprecated(4, ("conn.socket is deprecated and should be replaced by conn.socket_io"));
858
894
 
859
895
  if( (sd = PQsocket(pg_get_pgconn(self))) < 0)
860
- rb_raise(rb_eConnectionBad, "PQsocket() can't get socket descriptor");
896
+ pg_raise_conn_error( rb_eConnectionBad, self, "PQsocket() can't get socket descriptor");
897
+
861
898
  return INT2NUM(sd);
862
899
  }
863
900
 
@@ -865,40 +902,47 @@ pgconn_socket(VALUE self)
865
902
  * call-seq:
866
903
  * conn.socket_io() -> IO
867
904
  *
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.
905
+ * Fetch an IO object created from the Connection's underlying socket.
906
+ * 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.
907
+ * <tt>IO#wait_*able</tt> is is <tt>Fiber.scheduler</tt> compatible in contrast to <tt>IO.select</tt>.
908
+ *
909
+ * The IO object can change while the connection is established, but is memorized afterwards.
910
+ * So be sure not to cache the IO object, but repeat calling <tt>conn.socket_io</tt> instead.
871
911
  *
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.
912
+ * Using this method also works on Windows in contrast to using #socket .
913
+ * 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
914
  */
876
915
  static VALUE
877
916
  pgconn_socket_io(VALUE self)
878
917
  {
879
918
  int sd;
880
919
  int ruby_sd;
881
- ID id_autoclose = rb_intern("autoclose=");
882
920
  t_pg_connection *this = pg_get_connection_safe( self );
921
+ VALUE cSocket;
883
922
  VALUE socket_io = this->socket_io;
884
923
 
885
924
  if ( !RTEST(socket_io) ) {
886
- if( (sd = PQsocket(this->pgconn)) < 0)
887
- rb_raise(rb_eConnectionBad, "PQsocket() can't get socket descriptor");
925
+ if( (sd = PQsocket(this->pgconn)) < 0){
926
+ pg_raise_conn_error( rb_eConnectionBad, self, "PQsocket() can't get socket descriptor");
927
+ }
888
928
 
889
929
  #ifdef _WIN32
890
930
  ruby_sd = rb_w32_wrap_io_handle((HANDLE)(intptr_t)sd, O_RDWR|O_BINARY|O_NOINHERIT);
931
+ if( ruby_sd == -1 )
932
+ pg_raise_conn_error( rb_eConnectionBad, self, "Could not wrap win32 socket handle");
933
+
891
934
  this->ruby_sd = ruby_sd;
892
935
  #else
893
936
  ruby_sd = sd;
894
937
  #endif
895
938
 
896
- socket_io = rb_funcall( rb_cIO, rb_intern("for_fd"), 1, INT2NUM(ruby_sd) );
939
+ cSocket = rb_const_get(rb_cObject, rb_intern("BasicSocket"));
940
+ socket_io = rb_funcall( cSocket, rb_intern("for_fd"), 1, INT2NUM(ruby_sd));
897
941
 
898
942
  /* Disable autoclose feature */
899
- rb_funcall( socket_io, id_autoclose, 1, Qfalse );
943
+ rb_funcall( socket_io, s_id_autoclose_set, 1, Qfalse );
900
944
 
901
- this->socket_io = socket_io;
945
+ RB_OBJ_WRITE(self, &this->socket_io, socket_io);
902
946
  }
903
947
 
904
948
  return socket_io;
@@ -918,6 +962,51 @@ pgconn_backend_pid(VALUE self)
918
962
  return INT2NUM(PQbackendPID(pg_get_pgconn(self)));
919
963
  }
920
964
 
965
+ typedef struct
966
+ {
967
+ struct sockaddr_storage addr;
968
+ socklen_t salen;
969
+ } SockAddr;
970
+
971
+ /* Copy of struct pg_cancel from libpq-int.h
972
+ *
973
+ * See https://github.com/postgres/postgres/blame/master/src/interfaces/libpq/libpq-int.h#L577-L586
974
+ */
975
+ struct pg_cancel
976
+ {
977
+ SockAddr raddr; /* Remote address */
978
+ int be_pid; /* PID of backend --- needed for cancels */
979
+ int be_key; /* key of backend --- needed for cancels */
980
+ };
981
+
982
+ /*
983
+ * call-seq:
984
+ * conn.backend_key() -> Integer
985
+ *
986
+ * Returns the key of the backend server process for this connection.
987
+ * This key can be used to cancel queries on the server.
988
+ */
989
+ static VALUE
990
+ pgconn_backend_key(VALUE self)
991
+ {
992
+ int be_key;
993
+ struct pg_cancel *cancel;
994
+ PGconn *conn = pg_get_pgconn(self);
995
+
996
+ cancel = (struct pg_cancel*)PQgetCancel(conn);
997
+ if(cancel == NULL)
998
+ pg_raise_conn_error( rb_ePGerror, self, "Invalid connection!");
999
+
1000
+ if( cancel->be_pid != PQbackendPID(conn) )
1001
+ rb_raise(rb_ePGerror,"Unexpected binary struct layout - please file a bug report at ruby-pg!");
1002
+
1003
+ be_key = cancel->be_key;
1004
+
1005
+ PQfreeCancel(cancel);
1006
+
1007
+ return INT2NUM(be_key);
1008
+ }
1009
+
921
1010
  /*
922
1011
  * call-seq:
923
1012
  * conn.connection_needs_password() -> Boolean
@@ -948,7 +1037,7 @@ pgconn_connection_used_password(VALUE self)
948
1037
  /* :TODO: get_ssl */
949
1038
 
950
1039
 
951
- static VALUE pgconn_exec_params( int, VALUE *, VALUE );
1040
+ static VALUE pgconn_sync_exec_params( int, VALUE *, VALUE );
952
1041
 
953
1042
  /*
954
1043
  * call-seq:
@@ -962,11 +1051,11 @@ static VALUE pgconn_exec_params( int, VALUE *, VALUE );
962
1051
  * However #async_exec has two advantages:
963
1052
  *
964
1053
  * 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
1054
+ * 2. Ruby VM gets notified about IO blocked operations and can pass them through <tt>Fiber.scheduler</tt>.
1055
+ * So only <tt>async_*</tt> methods are compatible to event based schedulers like the async gem.
967
1056
  */
968
1057
  static VALUE
969
- pgconn_exec(int argc, VALUE *argv, VALUE self)
1058
+ pgconn_sync_exec(int argc, VALUE *argv, VALUE self)
970
1059
  {
971
1060
  t_pg_connection *this = pg_get_connection_safe( self );
972
1061
  PGresult *result = NULL;
@@ -987,7 +1076,7 @@ pgconn_exec(int argc, VALUE *argv, VALUE self)
987
1076
  pg_deprecated(0, ("forwarding exec to exec_params is deprecated"));
988
1077
 
989
1078
  /* Otherwise, just call #exec_params instead for backward-compatibility */
990
- return pgconn_exec_params( argc, argv, self );
1079
+ return pgconn_sync_exec_params( argc, argv, self );
991
1080
 
992
1081
  }
993
1082
 
@@ -1019,7 +1108,7 @@ struct query_params_data {
1019
1108
  * Filled by alloc_query_params()
1020
1109
  */
1021
1110
 
1022
- /* Wraps the pointer of allocated memory, if function parameters dont't
1111
+ /* Wraps the pointer of allocated memory, if function parameters don't
1023
1112
  * fit in the memory_pool below.
1024
1113
  */
1025
1114
  VALUE heap_pool;
@@ -1037,7 +1126,7 @@ struct query_params_data {
1037
1126
  Oid *types;
1038
1127
 
1039
1128
  /* This array takes the string values for the timeframe of the query,
1040
- * if param value convertion is required
1129
+ * if param value conversion is required
1041
1130
  */
1042
1131
  VALUE gc_array;
1043
1132
 
@@ -1051,8 +1140,9 @@ struct query_params_data {
1051
1140
  };
1052
1141
 
1053
1142
  static void
1054
- free_typecast_heap_chain(struct linked_typecast_data *chain_entry)
1143
+ free_typecast_heap_chain(void *_chain_entry)
1055
1144
  {
1145
+ struct linked_typecast_data *chain_entry = (struct linked_typecast_data *)_chain_entry;
1056
1146
  while(chain_entry){
1057
1147
  struct linked_typecast_data *next = chain_entry->next;
1058
1148
  xfree(chain_entry);
@@ -1060,6 +1150,18 @@ free_typecast_heap_chain(struct linked_typecast_data *chain_entry)
1060
1150
  }
1061
1151
  }
1062
1152
 
1153
+ static const rb_data_type_t pg_typecast_buffer_type = {
1154
+ "PG::Connection typecast buffer chain",
1155
+ {
1156
+ (RUBY_DATA_FUNC) NULL,
1157
+ free_typecast_heap_chain,
1158
+ (size_t (*)(const void *))NULL,
1159
+ },
1160
+ 0,
1161
+ 0,
1162
+ RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
1163
+ };
1164
+
1063
1165
  static char *
1064
1166
  alloc_typecast_buf( VALUE *typecast_heap_chain, int len )
1065
1167
  {
@@ -1070,17 +1172,28 @@ alloc_typecast_buf( VALUE *typecast_heap_chain, int len )
1070
1172
  /* Did we already wrap a memory chain per T_DATA object? */
1071
1173
  if( NIL_P( *typecast_heap_chain ) ){
1072
1174
  /* 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 );
1175
+ *typecast_heap_chain = TypedData_Wrap_Struct( rb_cObject, &pg_typecast_buffer_type, allocated );
1074
1176
  allocated->next = NULL;
1075
1177
  } else {
1076
1178
  /* Append to the chain */
1077
- allocated->next = DATA_PTR( *typecast_heap_chain );
1078
- DATA_PTR( *typecast_heap_chain ) = allocated;
1179
+ allocated->next = RTYPEDDATA_DATA( *typecast_heap_chain );
1180
+ RTYPEDDATA_DATA( *typecast_heap_chain ) = allocated;
1079
1181
  }
1080
1182
 
1081
1183
  return &allocated->data[0];
1082
1184
  }
1083
1185
 
1186
+ static const rb_data_type_t pg_query_heap_pool_type = {
1187
+ "PG::Connection query heap pool",
1188
+ {
1189
+ (RUBY_DATA_FUNC) NULL,
1190
+ RUBY_TYPED_DEFAULT_FREE,
1191
+ (size_t (*)(const void *))NULL,
1192
+ },
1193
+ 0,
1194
+ 0,
1195
+ RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
1196
+ };
1084
1197
 
1085
1198
  static int
1086
1199
  alloc_query_params(struct query_params_data *paramsData)
@@ -1095,7 +1208,7 @@ alloc_query_params(struct query_params_data *paramsData)
1095
1208
 
1096
1209
  Check_Type(paramsData->params, T_ARRAY);
1097
1210
 
1098
- p_typemap = DATA_PTR( paramsData->typemap );
1211
+ p_typemap = RTYPEDDATA_DATA( paramsData->typemap );
1099
1212
  p_typemap->funcs.fit_to_query( paramsData->typemap, paramsData->params );
1100
1213
 
1101
1214
  paramsData->heap_pool = Qnil;
@@ -1114,7 +1227,7 @@ alloc_query_params(struct query_params_data *paramsData)
1114
1227
  /* Allocate one combined memory pool for all possible function parameters */
1115
1228
  memory_pool = (char*)xmalloc( required_pool_size );
1116
1229
  /* 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 );
1230
+ paramsData->heap_pool = TypedData_Wrap_Struct( rb_cObject, &pg_query_heap_pool_type, memory_pool );
1118
1231
  required_pool_size = 0;
1119
1232
  }else{
1120
1233
  /* Use stack memory for function parameters */
@@ -1227,12 +1340,11 @@ pgconn_query_assign_typemap( VALUE self, struct query_params_data *paramsData )
1227
1340
  /* Use default typemap for queries. It's type is checked when assigned. */
1228
1341
  paramsData->typemap = pg_get_connection(self)->type_map_for_queries;
1229
1342
  }else{
1343
+ t_typemap *tm;
1344
+ UNUSED(tm);
1345
+
1230
1346
  /* 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 );
1347
+ TypedData_Get_Struct(paramsData->typemap, t_typemap, &pg_typemap_type, tm);
1236
1348
  }
1237
1349
  }
1238
1350
 
@@ -1246,7 +1358,7 @@ pgconn_query_assign_typemap( VALUE self, struct query_params_data *paramsData )
1246
1358
  * 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
1359
  */
1248
1360
  static VALUE
1249
- pgconn_exec_params( int argc, VALUE *argv, VALUE self )
1361
+ pgconn_sync_exec_params( int argc, VALUE *argv, VALUE self )
1250
1362
  {
1251
1363
  t_pg_connection *this = pg_get_connection_safe( self );
1252
1364
  PGresult *result = NULL;
@@ -1266,7 +1378,7 @@ pgconn_exec_params( int argc, VALUE *argv, VALUE self )
1266
1378
  */
1267
1379
  if ( NIL_P(paramsData.params) ) {
1268
1380
  pg_deprecated(1, ("forwarding exec_params to exec is deprecated"));
1269
- return pgconn_exec( 1, argv, self );
1381
+ return pgconn_sync_exec( 1, argv, self );
1270
1382
  }
1271
1383
  pgconn_query_assign_typemap( self, &paramsData );
1272
1384
 
@@ -1297,7 +1409,7 @@ pgconn_exec_params( int argc, VALUE *argv, VALUE self )
1297
1409
  * It's not recommended to use explicit sync or async variants but #prepare instead, unless you have a good reason to do so.
1298
1410
  */
1299
1411
  static VALUE
1300
- pgconn_prepare(int argc, VALUE *argv, VALUE self)
1412
+ pgconn_sync_prepare(int argc, VALUE *argv, VALUE self)
1301
1413
  {
1302
1414
  t_pg_connection *this = pg_get_connection_safe( self );
1303
1415
  PGresult *result = NULL;
@@ -1346,7 +1458,7 @@ pgconn_prepare(int argc, VALUE *argv, VALUE self)
1346
1458
  * 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
1459
  */
1348
1460
  static VALUE
1349
- pgconn_exec_prepared(int argc, VALUE *argv, VALUE self)
1461
+ pgconn_sync_exec_prepared(int argc, VALUE *argv, VALUE self)
1350
1462
  {
1351
1463
  t_pg_connection *this = pg_get_connection_safe( self );
1352
1464
  PGresult *result = NULL;
@@ -1391,7 +1503,7 @@ pgconn_exec_prepared(int argc, VALUE *argv, VALUE self)
1391
1503
  * 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
1504
  */
1393
1505
  static VALUE
1394
- pgconn_describe_prepared(VALUE self, VALUE stmt_name)
1506
+ pgconn_sync_describe_prepared(VALUE self, VALUE stmt_name)
1395
1507
  {
1396
1508
  PGresult *result;
1397
1509
  VALUE rb_pgresult;
@@ -1419,8 +1531,7 @@ pgconn_describe_prepared(VALUE self, VALUE stmt_name)
1419
1531
  * 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
1532
  */
1421
1533
  static VALUE
1422
- pgconn_describe_portal(self, stmt_name)
1423
- VALUE self, stmt_name;
1534
+ pgconn_sync_describe_portal(VALUE self, VALUE stmt_name)
1424
1535
  {
1425
1536
  PGresult *result;
1426
1537
  VALUE rb_pgresult;
@@ -1454,6 +1565,9 @@ pgconn_describe_portal(self, stmt_name)
1454
1565
  * * +PGRES_NONFATAL_ERROR+
1455
1566
  * * +PGRES_FATAL_ERROR+
1456
1567
  * * +PGRES_COPY_BOTH+
1568
+ * * +PGRES_SINGLE_TUPLE+
1569
+ * * +PGRES_PIPELINE_SYNC+
1570
+ * * +PGRES_PIPELINE_ABORTED+
1457
1571
  */
1458
1572
  static VALUE
1459
1573
  pgconn_make_empty_pgresult(VALUE self, VALUE status)
@@ -1509,9 +1623,9 @@ pgconn_s_escape(VALUE self, VALUE string)
1509
1623
  if( !singleton ) {
1510
1624
  size = PQescapeStringConn(pg_get_pgconn(self), RSTRING_PTR(result),
1511
1625
  RSTRING_PTR(string), RSTRING_LEN(string), &error);
1512
- if(error) {
1513
- rb_raise(rb_ePGerror, "%s", PQerrorMessage(pg_get_pgconn(self)));
1514
- }
1626
+ if(error)
1627
+ pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(pg_get_pgconn(self)));
1628
+
1515
1629
  } else {
1516
1630
  size = PQescapeString(RSTRING_PTR(result), RSTRING_PTR(string), RSTRING_LEN(string));
1517
1631
  }
@@ -1607,7 +1721,6 @@ pgconn_escape_literal(VALUE self, VALUE string)
1607
1721
  {
1608
1722
  t_pg_connection *this = pg_get_connection_safe( self );
1609
1723
  char *escaped = NULL;
1610
- VALUE error;
1611
1724
  VALUE result = Qnil;
1612
1725
  int enc_idx = this->enc_idx;
1613
1726
 
@@ -1618,12 +1731,8 @@ pgconn_escape_literal(VALUE self, VALUE string)
1618
1731
 
1619
1732
  escaped = PQescapeLiteral(this->pgconn, RSTRING_PTR(string), RSTRING_LEN(string));
1620
1733
  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
- }
1734
+ pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(this->pgconn));
1735
+
1627
1736
  result = rb_str_new2(escaped);
1628
1737
  PQfreemem(escaped);
1629
1738
  PG_ENCODING_SET_NOCHECK(result, enc_idx);
@@ -1646,7 +1755,6 @@ pgconn_escape_identifier(VALUE self, VALUE string)
1646
1755
  {
1647
1756
  t_pg_connection *this = pg_get_connection_safe( self );
1648
1757
  char *escaped = NULL;
1649
- VALUE error;
1650
1758
  VALUE result = Qnil;
1651
1759
  int enc_idx = this->enc_idx;
1652
1760
 
@@ -1657,12 +1765,8 @@ pgconn_escape_identifier(VALUE self, VALUE string)
1657
1765
 
1658
1766
  escaped = PQescapeIdentifier(this->pgconn, RSTRING_PTR(string), RSTRING_LEN(string));
1659
1767
  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
- }
1768
+ pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(this->pgconn));
1769
+
1666
1770
  result = rb_str_new2(escaped);
1667
1771
  PQfreemem(escaped);
1668
1772
  PG_ENCODING_SET_NOCHECK(result, enc_idx);
@@ -1710,14 +1814,10 @@ static VALUE
1710
1814
  pgconn_set_single_row_mode(VALUE self)
1711
1815
  {
1712
1816
  PGconn *conn = pg_get_pgconn(self);
1713
- VALUE error;
1714
1817
 
1818
+ rb_check_frozen(self);
1715
1819
  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
- }
1820
+ pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(conn));
1721
1821
 
1722
1822
  return self;
1723
1823
  }
@@ -1741,15 +1841,13 @@ static VALUE
1741
1841
  pgconn_send_query(int argc, VALUE *argv, VALUE self)
1742
1842
  {
1743
1843
  t_pg_connection *this = pg_get_connection_safe( self );
1744
- VALUE error;
1745
1844
 
1746
1845
  /* If called with no or nil parameters, use PQexec for compatibility */
1747
1846
  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
- }
1847
+ if(gvl_PQsendQuery(this->pgconn, pg_cstr_enc(argv[0], this->enc_idx)) == 0)
1848
+ pg_raise_conn_error( rb_eUnableToSend, self, "%s", PQerrorMessage(this->pgconn));
1849
+
1850
+ pgconn_wait_for_flush( self );
1753
1851
  return Qnil;
1754
1852
  }
1755
1853
 
@@ -1779,7 +1877,7 @@ pgconn_send_query(int argc, VALUE *argv, VALUE self)
1779
1877
  * or, it may be a String. If it is a string, that is equivalent to the hash:
1780
1878
  * { :value => <string value>, :type => 0, :format => 0 }
1781
1879
  *
1782
- * PostgreSQL bind parameters are represented as $1, $1, $2, etc.,
1880
+ * PostgreSQL bind parameters are represented as $1, $2, $3, etc.,
1783
1881
  * inside the SQL query. The 0th element of the +params+ array is bound
1784
1882
  * to $1, the 1st element is bound to $2, etc. +nil+ is treated as +NULL+.
1785
1883
  *
@@ -1805,7 +1903,6 @@ pgconn_send_query_params(int argc, VALUE *argv, VALUE self)
1805
1903
  t_pg_connection *this = pg_get_connection_safe( self );
1806
1904
  int result;
1807
1905
  VALUE command, in_res_fmt;
1808
- VALUE error;
1809
1906
  int nParams;
1810
1907
  int resultFormat;
1811
1908
  struct query_params_data paramsData = { this->enc_idx };
@@ -1822,11 +1919,10 @@ pgconn_send_query_params(int argc, VALUE *argv, VALUE self)
1822
1919
 
1823
1920
  free_query_params( &paramsData );
1824
1921
 
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
- }
1922
+ if(result == 0)
1923
+ pg_raise_conn_error( rb_eUnableToSend, self, "%s", PQerrorMessage(this->pgconn));
1924
+
1925
+ pgconn_wait_for_flush( self );
1830
1926
  return Qnil;
1831
1927
  }
1832
1928
 
@@ -1847,7 +1943,7 @@ pgconn_send_query_params(int argc, VALUE *argv, VALUE self)
1847
1943
  *
1848
1944
  * For example: "SELECT $1::int"
1849
1945
  *
1850
- * PostgreSQL bind parameters are represented as $1, $1, $2, etc.,
1946
+ * PostgreSQL bind parameters are represented as $1, $2, $3, etc.,
1851
1947
  * inside the SQL query.
1852
1948
  */
1853
1949
  static VALUE
@@ -1857,7 +1953,6 @@ pgconn_send_prepare(int argc, VALUE *argv, VALUE self)
1857
1953
  int result;
1858
1954
  VALUE name, command, in_paramtypes;
1859
1955
  VALUE param;
1860
- VALUE error;
1861
1956
  int i = 0;
1862
1957
  int nParams = 0;
1863
1958
  Oid *paramTypes = NULL;
@@ -1886,10 +1981,9 @@ pgconn_send_prepare(int argc, VALUE *argv, VALUE self)
1886
1981
  xfree(paramTypes);
1887
1982
 
1888
1983
  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);
1984
+ pg_raise_conn_error( rb_eUnableToSend, self, "%s", PQerrorMessage(this->pgconn));
1892
1985
  }
1986
+ pgconn_wait_for_flush( self );
1893
1987
  return Qnil;
1894
1988
  }
1895
1989
 
@@ -1911,7 +2005,7 @@ pgconn_send_prepare(int argc, VALUE *argv, VALUE self)
1911
2005
  * or, it may be a String. If it is a string, that is equivalent to the hash:
1912
2006
  * { :value => <string value>, :format => 0 }
1913
2007
  *
1914
- * PostgreSQL bind parameters are represented as $1, $1, $2, etc.,
2008
+ * PostgreSQL bind parameters are represented as $1, $2, $3, etc.,
1915
2009
  * inside the SQL query. The 0th element of the +params+ array is bound
1916
2010
  * to $1, the 1st element is bound to $2, etc. +nil+ is treated as +NULL+.
1917
2011
  *
@@ -1931,7 +2025,6 @@ pgconn_send_query_prepared(int argc, VALUE *argv, VALUE self)
1931
2025
  t_pg_connection *this = pg_get_connection_safe( self );
1932
2026
  int result;
1933
2027
  VALUE name, in_res_fmt;
1934
- VALUE error;
1935
2028
  int nParams;
1936
2029
  int resultFormat;
1937
2030
  struct query_params_data paramsData = { this->enc_idx };
@@ -1941,7 +2034,6 @@ pgconn_send_query_prepared(int argc, VALUE *argv, VALUE self)
1941
2034
 
1942
2035
  if(NIL_P(paramsData.params)) {
1943
2036
  paramsData.params = rb_ary_new2(0);
1944
- resultFormat = 0;
1945
2037
  }
1946
2038
  pgconn_query_assign_typemap( self, &paramsData );
1947
2039
 
@@ -1954,11 +2046,10 @@ pgconn_send_query_prepared(int argc, VALUE *argv, VALUE self)
1954
2046
 
1955
2047
  free_query_params( &paramsData );
1956
2048
 
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
- }
2049
+ if(result == 0)
2050
+ pg_raise_conn_error( rb_eUnableToSend, self, "%s", PQerrorMessage(this->pgconn));
2051
+
2052
+ pgconn_wait_for_flush( self );
1962
2053
  return Qnil;
1963
2054
  }
1964
2055
 
@@ -1972,14 +2063,12 @@ pgconn_send_query_prepared(int argc, VALUE *argv, VALUE self)
1972
2063
  static VALUE
1973
2064
  pgconn_send_describe_prepared(VALUE self, VALUE stmt_name)
1974
2065
  {
1975
- VALUE error;
1976
2066
  t_pg_connection *this = pg_get_connection_safe( self );
1977
2067
  /* 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
- }
2068
+ if(gvl_PQsendDescribePrepared(this->pgconn, pg_cstr_enc(stmt_name, this->enc_idx)) == 0)
2069
+ pg_raise_conn_error( rb_eUnableToSend, self, "%s", PQerrorMessage(this->pgconn));
2070
+
2071
+ pgconn_wait_for_flush( self );
1983
2072
  return Qnil;
1984
2073
  }
1985
2074
 
@@ -1994,36 +2083,18 @@ pgconn_send_describe_prepared(VALUE self, VALUE stmt_name)
1994
2083
  static VALUE
1995
2084
  pgconn_send_describe_portal(VALUE self, VALUE portal)
1996
2085
  {
1997
- VALUE error;
1998
2086
  t_pg_connection *this = pg_get_connection_safe( self );
1999
2087
  /* 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
- }
2088
+ if(gvl_PQsendDescribePortal(this->pgconn, pg_cstr_enc(portal, this->enc_idx)) == 0)
2089
+ pg_raise_conn_error( rb_eUnableToSend, self, "%s", PQerrorMessage(this->pgconn));
2090
+
2091
+ pgconn_wait_for_flush( self );
2005
2092
  return Qnil;
2006
2093
  }
2007
2094
 
2008
2095
 
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
2096
  static VALUE
2026
- pgconn_get_result(VALUE self)
2097
+ pgconn_sync_get_result(VALUE self)
2027
2098
  {
2028
2099
  PGconn *conn = pg_get_pgconn(self);
2029
2100
  PGresult *result;
@@ -2049,17 +2120,15 @@ pgconn_get_result(VALUE self)
2049
2120
  * or *notifies* to see if the state has changed.
2050
2121
  */
2051
2122
  static VALUE
2052
- pgconn_consume_input(self)
2053
- VALUE self;
2123
+ pgconn_consume_input(VALUE self)
2054
2124
  {
2055
- VALUE error;
2056
2125
  PGconn *conn = pg_get_pgconn(self);
2057
2126
  /* returns 0 on error */
2058
2127
  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);
2128
+ pgconn_close_socket_io(self);
2129
+ pg_raise_conn_error( rb_eConnectionBad, self, "%s", PQerrorMessage(conn));
2062
2130
  }
2131
+
2063
2132
  return Qnil;
2064
2133
  }
2065
2134
 
@@ -2068,38 +2137,20 @@ pgconn_consume_input(self)
2068
2137
  * conn.is_busy() -> Boolean
2069
2138
  *
2070
2139
  * Returns +true+ if a command is busy, that is, if
2071
- * PQgetResult would block. Otherwise returns +false+.
2140
+ * #get_result would block. Otherwise returns +false+.
2072
2141
  */
2073
2142
  static VALUE
2074
- pgconn_is_busy(self)
2075
- VALUE self;
2143
+ pgconn_is_busy(VALUE self)
2076
2144
  {
2077
2145
  return gvl_PQisBusy(pg_get_pgconn(self)) ? Qtrue : Qfalse;
2078
2146
  }
2079
2147
 
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
2148
  static VALUE
2097
- pgconn_setnonblocking(self, state)
2098
- VALUE self, state;
2149
+ pgconn_sync_setnonblocking(VALUE self, VALUE state)
2099
2150
  {
2100
2151
  int arg;
2101
- VALUE error;
2102
2152
  PGconn *conn = pg_get_pgconn(self);
2153
+ rb_check_frozen(self);
2103
2154
  if(state == Qtrue)
2104
2155
  arg = 1;
2105
2156
  else if (state == Qfalse)
@@ -2107,67 +2158,32 @@ pgconn_setnonblocking(self, state)
2107
2158
  else
2108
2159
  rb_raise(rb_eArgError, "Boolean value expected");
2109
2160
 
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
- }
2161
+ if(PQsetnonblocking(conn, arg) == -1)
2162
+ pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(conn));
2163
+
2115
2164
  return Qnil;
2116
2165
  }
2117
2166
 
2118
2167
 
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
2168
  static VALUE
2127
- pgconn_isnonblocking(self)
2128
- VALUE self;
2169
+ pgconn_sync_isnonblocking(VALUE self)
2129
2170
  {
2130
2171
  return PQisnonblocking(pg_get_pgconn(self)) ? Qtrue : Qfalse;
2131
2172
  }
2132
2173
 
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
2174
  static VALUE
2144
- pgconn_flush(self)
2145
- VALUE self;
2175
+ pgconn_sync_flush(VALUE self)
2146
2176
  {
2147
2177
  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
- }
2178
+ int ret = PQflush(conn);
2179
+ if(ret == -1)
2180
+ pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(conn));
2181
+
2156
2182
  return (ret) ? Qfalse : Qtrue;
2157
2183
  }
2158
2184
 
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
2185
  static VALUE
2170
- pgconn_cancel(VALUE self)
2186
+ pgconn_sync_cancel(VALUE self)
2171
2187
  {
2172
2188
  char errbuf[256];
2173
2189
  PGcancel *cancel;
@@ -2176,9 +2192,9 @@ pgconn_cancel(VALUE self)
2176
2192
 
2177
2193
  cancel = PQgetCancel(pg_get_pgconn(self));
2178
2194
  if(cancel == NULL)
2179
- rb_raise(rb_ePGerror,"Invalid connection!");
2195
+ pg_raise_conn_error( rb_ePGerror, self, "Invalid connection!");
2180
2196
 
2181
- ret = gvl_PQcancel(cancel, errbuf, 256);
2197
+ ret = gvl_PQcancel(cancel, errbuf, sizeof(errbuf));
2182
2198
  if(ret == 1)
2183
2199
  retval = Qnil;
2184
2200
  else
@@ -2229,55 +2245,63 @@ pgconn_notifies(VALUE self)
2229
2245
  return hash;
2230
2246
  }
2231
2247
 
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().
2248
+ #if defined(_WIN32)
2249
+
2250
+ /* We use a specialized implementation of rb_io_wait() on Windows.
2251
+ * This is because rb_io_wait() and rb_wait_for_single_fd() are very slow on Windows.
2237
2252
  */
2238
2253
 
2254
+ #if defined(HAVE_RUBY_FIBER_SCHEDULER_H)
2255
+ #include <ruby/fiber/scheduler.h>
2256
+ #endif
2257
+
2258
+ typedef enum {
2259
+ PG_RUBY_IO_READABLE = RB_WAITFD_IN,
2260
+ PG_RUBY_IO_WRITABLE = RB_WAITFD_OUT,
2261
+ PG_RUBY_IO_PRIORITY = RB_WAITFD_PRI,
2262
+ } pg_rb_io_event_t;
2263
+
2239
2264
  int rb_w32_wait_events( HANDLE *events, int num, DWORD timeout );
2240
2265
 
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;
2266
+ static VALUE
2267
+ pg_rb_thread_io_wait(VALUE io, VALUE events, VALUE timeout) {
2268
+ rb_io_t *fptr;
2269
+ struct timeval ptimeout;
2270
+
2246
2271
  struct timeval aborttime={0,0}, currtime, waittime;
2247
2272
  DWORD timeout_milisec = INFINITE;
2248
- DWORD wait_ret;
2249
- WSAEVENT hEvent;
2273
+ HANDLE hEvent = WSACreateEvent();
2250
2274
 
2251
- if ( sd < 0 )
2252
- rb_raise(rb_eConnectionBad, "PQsocket() can't get socket descriptor");
2253
-
2254
- hEvent = WSACreateEvent();
2275
+ long rb_events = NUM2UINT(events);
2276
+ long w32_events = 0;
2277
+ DWORD wait_ret;
2255
2278
 
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
- }
2279
+ GetOpenFile((io), fptr);
2280
+ if( !NIL_P(timeout) ){
2281
+ ptimeout.tv_sec = (time_t)(NUM2DBL(timeout));
2282
+ ptimeout.tv_usec = (time_t)((NUM2DBL(timeout) - (double)ptimeout.tv_sec) * 1e6);
2261
2283
 
2262
- if ( ptimeout ) {
2263
2284
  gettimeofday(&currtime, NULL);
2264
- timeradd(&currtime, ptimeout, &aborttime);
2285
+ timeradd(&currtime, &ptimeout, &aborttime);
2265
2286
  }
2266
2287
 
2267
- while ( !(retval=is_readable(conn)) ) {
2268
- if ( WSAEventSelect(sd, hEvent, FD_READ|FD_CLOSE) == SOCKET_ERROR ) {
2288
+ if(rb_events & PG_RUBY_IO_READABLE) w32_events |= FD_READ | FD_ACCEPT | FD_CLOSE;
2289
+ if(rb_events & PG_RUBY_IO_WRITABLE) w32_events |= FD_WRITE | FD_CONNECT;
2290
+ if(rb_events & PG_RUBY_IO_PRIORITY) w32_events |= FD_OOB;
2291
+
2292
+ for(;;) {
2293
+ if ( WSAEventSelect(_get_osfhandle(fptr->fd), hEvent, w32_events) == SOCKET_ERROR ) {
2269
2294
  WSACloseEvent( hEvent );
2270
2295
  rb_raise( rb_eConnectionBad, "WSAEventSelect socket error: %d", WSAGetLastError() );
2271
2296
  }
2272
2297
 
2273
- if ( ptimeout ) {
2298
+ if ( !NIL_P(timeout) ) {
2274
2299
  gettimeofday(&currtime, NULL);
2275
2300
  timersub(&aborttime, &currtime, &waittime);
2276
2301
  timeout_milisec = (DWORD)( waittime.tv_sec * 1e3 + waittime.tv_usec / 1e3 );
2277
2302
  }
2278
2303
 
2279
- /* Is the given timeout valid? */
2280
- if( !ptimeout || (waittime.tv_sec >= 0 && waittime.tv_usec >= 0) ){
2304
+ if( NIL_P(timeout) || (waittime.tv_sec >= 0 && waittime.tv_usec >= 0) ){
2281
2305
  /* Wait for the socket to become readable before checking again */
2282
2306
  wait_ret = rb_w32_wait_events( &hEvent, 1, timeout_milisec );
2283
2307
  } else {
@@ -2286,9 +2310,11 @@ wait_socket_readable( PGconn *conn, struct timeval *ptimeout, void *(*is_readabl
2286
2310
 
2287
2311
  if ( wait_ret == WAIT_TIMEOUT ) {
2288
2312
  WSACloseEvent( hEvent );
2289
- return NULL;
2313
+ return UINT2NUM(0);
2290
2314
  } else if ( wait_ret == WAIT_OBJECT_0 ) {
2315
+ WSACloseEvent( hEvent );
2291
2316
  /* The event we were waiting for. */
2317
+ return UINT2NUM(rb_events);
2292
2318
  } else if ( wait_ret == WAIT_OBJECT_0 + 1) {
2293
2319
  /* This indicates interruption from timer thread, GC, exception
2294
2320
  * from other threads etc... */
@@ -2300,36 +2326,66 @@ wait_socket_readable( PGconn *conn, struct timeval *ptimeout, void *(*is_readabl
2300
2326
  WSACloseEvent( hEvent );
2301
2327
  rb_raise( rb_eConnectionBad, "Wait on socket abandoned (WaitForMultipleObjects)" );
2302
2328
  }
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
2329
  }
2330
+ }
2310
2331
 
2311
- WSACloseEvent( hEvent );
2312
- return retval;
2332
+ static VALUE
2333
+ pg_rb_io_wait(VALUE io, VALUE events, VALUE timeout) {
2334
+ #if defined(HAVE_RUBY_FIBER_SCHEDULER_H)
2335
+ /* We don't support Fiber.scheduler on Windows ruby-3.0 because there is no fast way to check whether a scheduler is active.
2336
+ * Fortunatelly ruby-3.1 offers a C-API for it.
2337
+ */
2338
+ VALUE scheduler = rb_fiber_scheduler_current();
2339
+
2340
+ if (!NIL_P(scheduler)) {
2341
+ return rb_io_wait(io, events, timeout);
2342
+ }
2343
+ #endif
2344
+ return pg_rb_thread_io_wait(io, events, timeout);
2313
2345
  }
2314
2346
 
2347
+ #elif defined(HAVE_RB_IO_WAIT)
2348
+
2349
+ /* Use our own function and constants names, to avoid conflicts with truffleruby-head on its road to ruby-3.0 compatibility. */
2350
+ #define pg_rb_io_wait rb_io_wait
2351
+ #define PG_RUBY_IO_READABLE RUBY_IO_READABLE
2352
+ #define PG_RUBY_IO_WRITABLE RUBY_IO_WRITABLE
2353
+ #define PG_RUBY_IO_PRIORITY RUBY_IO_PRIORITY
2354
+
2315
2355
  #else
2356
+ /* For compat with ruby < 3.0 */
2316
2357
 
2317
- /* non Win32 */
2358
+ typedef enum {
2359
+ PG_RUBY_IO_READABLE = RB_WAITFD_IN,
2360
+ PG_RUBY_IO_WRITABLE = RB_WAITFD_OUT,
2361
+ PG_RUBY_IO_PRIORITY = RB_WAITFD_PRI,
2362
+ } pg_rb_io_event_t;
2363
+
2364
+ static VALUE
2365
+ pg_rb_io_wait(VALUE io, VALUE events, VALUE timeout) {
2366
+ rb_io_t *fptr;
2367
+ struct timeval waittime;
2368
+ int res;
2369
+
2370
+ GetOpenFile((io), fptr);
2371
+ if( !NIL_P(timeout) ){
2372
+ waittime.tv_sec = (time_t)(NUM2DBL(timeout));
2373
+ waittime.tv_usec = (time_t)((NUM2DBL(timeout) - (double)waittime.tv_sec) * 1e6);
2374
+ }
2375
+ res = rb_wait_for_single_fd(fptr->fd, NUM2UINT(events), NIL_P(timeout) ? NULL : &waittime);
2376
+
2377
+ return UINT2NUM(res);
2378
+ }
2379
+ #endif
2318
2380
 
2319
2381
  static void *
2320
- wait_socket_readable( PGconn *conn, struct timeval *ptimeout, void *(*is_readable)(PGconn *))
2382
+ wait_socket_readable( VALUE self, struct timeval *ptimeout, void *(*is_readable)(PGconn *))
2321
2383
  {
2322
- int sd = PQsocket( conn );
2323
- int ret;
2384
+ VALUE ret;
2324
2385
  void *retval;
2325
2386
  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) );
2387
+ VALUE wait_timeout = Qnil;
2388
+ PGconn *conn = pg_get_pgconn(self);
2333
2389
 
2334
2390
  if ( ptimeout ) {
2335
2391
  gettimeofday(&currtime, NULL);
@@ -2340,36 +2396,81 @@ wait_socket_readable( PGconn *conn, struct timeval *ptimeout, void *(*is_readabl
2340
2396
  if ( ptimeout ) {
2341
2397
  gettimeofday(&currtime, NULL);
2342
2398
  timersub(&aborttime, &currtime, &waittime);
2399
+ wait_timeout = DBL2NUM((double)(waittime.tv_sec) + (double)(waittime.tv_usec) / 1000000.0);
2343
2400
  }
2344
2401
 
2345
2402
  /* Is the given timeout valid? */
2346
2403
  if( !ptimeout || (waittime.tv_sec >= 0 && waittime.tv_usec >= 0) ){
2404
+ VALUE socket_io;
2405
+
2406
+ /* before we wait for data, make sure everything has been sent */
2407
+ pgconn_async_flush(self);
2408
+ if ((retval=is_readable(conn)))
2409
+ return retval;
2410
+
2411
+ socket_io = pgconn_socket_io(self);
2347
2412
  /* Wait for the socket to become readable before checking again */
2348
- ret = rb_wait_for_single_fd( sd, RB_WAITFD_IN, ptimeout ? &waittime : NULL );
2413
+ ret = pg_rb_io_wait(socket_io, RB_INT2NUM(PG_RUBY_IO_READABLE), wait_timeout);
2349
2414
  } else {
2350
- ret = 0;
2351
- }
2352
-
2353
- if ( ret < 0 ){
2354
- rb_sys_fail( "rb_wait_for_single_fd()" );
2415
+ ret = Qfalse;
2355
2416
  }
2356
2417
 
2357
2418
  /* Return false if the select() timed out */
2358
- if ( ret == 0 ){
2419
+ if ( ret == Qfalse ){
2359
2420
  return NULL;
2360
2421
  }
2361
2422
 
2362
2423
  /* Check for connection errors (PQisBusy is true on connection errors) */
2363
2424
  if ( PQconsumeInput(conn) == 0 ){
2364
- rb_raise( rb_eConnectionBad, "PQconsumeInput() %s", PQerrorMessage(conn) );
2425
+ pgconn_close_socket_io(self);
2426
+ pg_raise_conn_error(rb_eConnectionBad, self, "PQconsumeInput() %s", PQerrorMessage(conn));
2365
2427
  }
2366
2428
  }
2367
2429
 
2368
2430
  return retval;
2369
2431
  }
2370
2432
 
2433
+ /*
2434
+ * call-seq:
2435
+ * conn.flush() -> Boolean
2436
+ *
2437
+ * Attempts to flush any queued output data to the server.
2438
+ * Returns +true+ if data is successfully flushed, +false+
2439
+ * if not. It can only return +false+ if connection is
2440
+ * in nonblocking mode.
2441
+ * Raises PG::Error if some other failure occurred.
2442
+ */
2443
+ static VALUE
2444
+ pgconn_async_flush(VALUE self)
2445
+ {
2446
+ while( pgconn_sync_flush(self) == Qfalse ){
2447
+ /* wait for the socket to become read- or write-ready */
2448
+ int events;
2449
+ VALUE socket_io = pgconn_socket_io(self);
2450
+ events = RB_NUM2INT(pg_rb_io_wait(socket_io, RB_INT2NUM(PG_RUBY_IO_READABLE | PG_RUBY_IO_WRITABLE), Qnil));
2451
+
2452
+ if (events & PG_RUBY_IO_READABLE){
2453
+ pgconn_consume_input(self);
2454
+ }
2455
+ }
2456
+ return Qtrue;
2457
+ }
2458
+
2459
+ static VALUE
2460
+ pgconn_wait_for_flush( VALUE self ){
2461
+ if( !pg_get_connection_safe(self)->flush_data )
2462
+ return Qnil;
2463
+
2464
+ return pgconn_async_flush(self);
2465
+ }
2371
2466
 
2372
- #endif
2467
+ static VALUE
2468
+ pgconn_flush_data_set( VALUE self, VALUE enabled ){
2469
+ t_pg_connection *conn = pg_get_connection(self);
2470
+ rb_check_frozen(self);
2471
+ conn->flush_data = RTEST(enabled);
2472
+ return enabled;
2473
+ }
2373
2474
 
2374
2475
  static void *
2375
2476
  notify_readable(PGconn *conn)
@@ -2408,7 +2509,7 @@ pgconn_wait_for_notify(int argc, VALUE *argv, VALUE self)
2408
2509
  ptimeout = &timeout;
2409
2510
  }
2410
2511
 
2411
- pnotification = (PGnotify*) wait_socket_readable( this->pgconn, ptimeout, notify_readable);
2512
+ pnotification = (PGnotify*) wait_socket_readable( self, ptimeout, notify_readable);
2412
2513
 
2413
2514
  /* Return nil if the select timed out */
2414
2515
  if ( !pnotification ) return Qnil;
@@ -2429,28 +2530,8 @@ pgconn_wait_for_notify(int argc, VALUE *argv, VALUE self)
2429
2530
  }
2430
2531
 
2431
2532
 
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
2533
  static VALUE
2453
- pgconn_put_copy_data(int argc, VALUE *argv, VALUE self)
2534
+ pgconn_sync_put_copy_data(int argc, VALUE *argv, VALUE self)
2454
2535
  {
2455
2536
  int ret;
2456
2537
  int len;
@@ -2467,13 +2548,11 @@ pgconn_put_copy_data(int argc, VALUE *argv, VALUE self)
2467
2548
  if( NIL_P(this->encoder_for_put_copy_data) ){
2468
2549
  buffer = value;
2469
2550
  } else {
2470
- p_coder = DATA_PTR( this->encoder_for_put_copy_data );
2551
+ p_coder = RTYPEDDATA_DATA( this->encoder_for_put_copy_data );
2471
2552
  }
2472
- } else if( rb_obj_is_kind_of(encoder, rb_cPG_Coder) ) {
2473
- Data_Get_Struct( encoder, t_pg_coder, p_coder );
2474
2553
  } else {
2475
- rb_raise( rb_eTypeError, "wrong encoder type %s (expected some kind of PG::Coder)",
2476
- rb_obj_classname( encoder ) );
2554
+ /* Check argument type and use argument encoder */
2555
+ TypedData_Get_Struct(encoder, t_pg_coder, &pg_coder_type, p_coder);
2477
2556
  }
2478
2557
 
2479
2558
  if( p_coder ){
@@ -2496,36 +2575,19 @@ pgconn_put_copy_data(int argc, VALUE *argv, VALUE self)
2496
2575
  Check_Type(buffer, T_STRING);
2497
2576
 
2498
2577
  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
- }
2578
+ if(ret == -1)
2579
+ pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(this->pgconn));
2580
+
2504
2581
  RB_GC_GUARD(intermediate);
2505
2582
  RB_GC_GUARD(buffer);
2506
2583
 
2507
2584
  return (ret) ? Qtrue : Qfalse;
2508
2585
  }
2509
2586
 
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
2587
  static VALUE
2525
- pgconn_put_copy_end(int argc, VALUE *argv, VALUE self)
2588
+ pgconn_sync_put_copy_end(int argc, VALUE *argv, VALUE self)
2526
2589
  {
2527
2590
  VALUE str;
2528
- VALUE error;
2529
2591
  int ret;
2530
2592
  const char *error_message = NULL;
2531
2593
  t_pg_connection *this = pg_get_connection_safe( self );
@@ -2536,38 +2598,16 @@ pgconn_put_copy_end(int argc, VALUE *argv, VALUE self)
2536
2598
  error_message = pg_cstr_enc(str, this->enc_idx);
2537
2599
 
2538
2600
  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
- }
2601
+ if(ret == -1)
2602
+ pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(this->pgconn));
2603
+
2544
2604
  return (ret) ? Qtrue : Qfalse;
2545
2605
  }
2546
2606
 
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
2607
  static VALUE
2567
- pgconn_get_copy_data(int argc, VALUE *argv, VALUE self )
2608
+ pgconn_sync_get_copy_data(int argc, VALUE *argv, VALUE self )
2568
2609
  {
2569
2610
  VALUE async_in;
2570
- VALUE error;
2571
2611
  VALUE result;
2572
2612
  int ret;
2573
2613
  char *buffer;
@@ -2579,20 +2619,16 @@ pgconn_get_copy_data(int argc, VALUE *argv, VALUE self )
2579
2619
 
2580
2620
  if( NIL_P(decoder) ){
2581
2621
  if( !NIL_P(this->decoder_for_get_copy_data) ){
2582
- p_coder = DATA_PTR( this->decoder_for_get_copy_data );
2622
+ p_coder = RTYPEDDATA_DATA( this->decoder_for_get_copy_data );
2583
2623
  }
2584
- } else if( rb_obj_is_kind_of(decoder, rb_cPG_Coder) ) {
2585
- Data_Get_Struct( decoder, t_pg_coder, p_coder );
2586
2624
  } else {
2587
- rb_raise( rb_eTypeError, "wrong decoder type %s (expected some kind of PG::Coder)",
2588
- rb_obj_classname( decoder ) );
2625
+ /* Check argument type and use argument decoder */
2626
+ TypedData_Get_Struct(decoder, t_pg_coder, &pg_coder_type, p_coder);
2589
2627
  }
2590
2628
 
2591
2629
  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);
2630
+ if(ret == -2){ /* error */
2631
+ pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(this->pgconn));
2596
2632
  }
2597
2633
  if(ret == -1) { /* No data left */
2598
2634
  return Qnil;
@@ -2686,6 +2722,7 @@ pgconn_trace(VALUE self, VALUE stream)
2686
2722
  VALUE new_file;
2687
2723
  t_pg_connection *this = pg_get_connection_safe( self );
2688
2724
 
2725
+ rb_check_frozen(self);
2689
2726
  if(!rb_respond_to(stream,rb_intern("fileno")))
2690
2727
  rb_raise(rb_eArgError, "stream does not respond to method: fileno");
2691
2728
 
@@ -2707,7 +2744,7 @@ pgconn_trace(VALUE self, VALUE stream)
2707
2744
  rb_raise(rb_eArgError, "stream is not writable");
2708
2745
 
2709
2746
  new_file = rb_funcall(rb_cIO, rb_intern("new"), 1, INT2NUM(new_fd));
2710
- this->trace_stream = new_file;
2747
+ RB_OBJ_WRITE(self, &this->trace_stream, new_file);
2711
2748
 
2712
2749
  PQtrace(this->pgconn, new_fp);
2713
2750
  return Qnil;
@@ -2726,7 +2763,7 @@ pgconn_untrace(VALUE self)
2726
2763
 
2727
2764
  PQuntrace(this->pgconn);
2728
2765
  rb_funcall(this->trace_stream, rb_intern("close"), 0);
2729
- this->trace_stream = Qnil;
2766
+ RB_OBJ_WRITE(self, &this->trace_stream, Qnil);
2730
2767
  return Qnil;
2731
2768
  }
2732
2769
 
@@ -2785,13 +2822,14 @@ pgconn_set_notice_receiver(VALUE self)
2785
2822
  VALUE proc, old_proc;
2786
2823
  t_pg_connection *this = pg_get_connection_safe( self );
2787
2824
 
2825
+ rb_check_frozen(self);
2788
2826
  /* If default_notice_receiver is unset, assume that the current
2789
2827
  * notice receiver is the default, and save it to a global variable.
2790
2828
  * This should not be a problem because the default receiver is
2791
2829
  * always the same, so won't vary among connections.
2792
2830
  */
2793
- if(default_notice_receiver == NULL)
2794
- default_notice_receiver = PQsetNoticeReceiver(this->pgconn, NULL, NULL);
2831
+ if(this->default_notice_receiver == NULL)
2832
+ this->default_notice_receiver = PQsetNoticeReceiver(this->pgconn, NULL, NULL);
2795
2833
 
2796
2834
  old_proc = this->notice_receiver;
2797
2835
  if( rb_block_given_p() ) {
@@ -2800,10 +2838,10 @@ pgconn_set_notice_receiver(VALUE self)
2800
2838
  } else {
2801
2839
  /* if no block is given, set back to default */
2802
2840
  proc = Qnil;
2803
- PQsetNoticeReceiver(this->pgconn, default_notice_receiver, NULL);
2841
+ PQsetNoticeReceiver(this->pgconn, this->default_notice_receiver, NULL);
2804
2842
  }
2805
2843
 
2806
- this->notice_receiver = proc;
2844
+ RB_OBJ_WRITE(self, &this->notice_receiver, proc);
2807
2845
  return old_proc;
2808
2846
  }
2809
2847
 
@@ -2818,10 +2856,10 @@ notice_processor_proxy(void *arg, const char *message)
2818
2856
  VALUE self = (VALUE)arg;
2819
2857
  t_pg_connection *this = pg_get_connection( self );
2820
2858
 
2821
- if (this->notice_receiver != Qnil) {
2859
+ if (this->notice_processor != Qnil) {
2822
2860
  VALUE message_str = rb_str_new2(message);
2823
2861
  PG_ENCODING_SET_NOCHECK( message_str, this->enc_idx );
2824
- rb_funcall(this->notice_receiver, rb_intern("call"), 1, message_str);
2862
+ rb_funcall(this->notice_processor, rb_intern("call"), 1, message_str);
2825
2863
  }
2826
2864
  return;
2827
2865
  }
@@ -2830,7 +2868,7 @@ notice_processor_proxy(void *arg, const char *message)
2830
2868
  * call-seq:
2831
2869
  * conn.set_notice_processor {|message| ... } -> Proc
2832
2870
  *
2833
- * See #set_notice_receiver for the desription of what this and the
2871
+ * See #set_notice_receiver for the description of what this and the
2834
2872
  * notice_processor methods do.
2835
2873
  *
2836
2874
  * This function takes a new block to act as the notice processor and returns
@@ -2845,25 +2883,26 @@ pgconn_set_notice_processor(VALUE self)
2845
2883
  VALUE proc, old_proc;
2846
2884
  t_pg_connection *this = pg_get_connection_safe( self );
2847
2885
 
2886
+ rb_check_frozen(self);
2848
2887
  /* If default_notice_processor is unset, assume that the current
2849
2888
  * notice processor is the default, and save it to a global variable.
2850
2889
  * This should not be a problem because the default processor is
2851
2890
  * always the same, so won't vary among connections.
2852
2891
  */
2853
- if(default_notice_processor == NULL)
2854
- default_notice_processor = PQsetNoticeProcessor(this->pgconn, NULL, NULL);
2892
+ if(this->default_notice_processor == NULL)
2893
+ this->default_notice_processor = PQsetNoticeProcessor(this->pgconn, NULL, NULL);
2855
2894
 
2856
- old_proc = this->notice_receiver;
2895
+ old_proc = this->notice_processor;
2857
2896
  if( rb_block_given_p() ) {
2858
2897
  proc = rb_block_proc();
2859
2898
  PQsetNoticeProcessor(this->pgconn, gvl_notice_processor_proxy, (void *)self);
2860
2899
  } else {
2861
2900
  /* if no block is given, set back to default */
2862
2901
  proc = Qnil;
2863
- PQsetNoticeProcessor(this->pgconn, default_notice_processor, NULL);
2902
+ PQsetNoticeProcessor(this->pgconn, this->default_notice_processor, NULL);
2864
2903
  }
2865
2904
 
2866
- this->notice_receiver = proc;
2905
+ RB_OBJ_WRITE(self, &this->notice_processor, proc);
2867
2906
  return old_proc;
2868
2907
  }
2869
2908
 
@@ -2884,68 +2923,28 @@ pgconn_get_client_encoding(VALUE self)
2884
2923
 
2885
2924
  /*
2886
2925
  * call-seq:
2887
- * conn.set_client_encoding( encoding )
2926
+ * conn.sync_set_client_encoding( encoding )
2888
2927
  *
2889
- * Sets the client encoding to the _encoding_ String.
2928
+ * This function has the same behavior as #async_set_client_encoding, but is implemented using the synchronous command processing API of libpq.
2929
+ * See #async_exec for the differences between the two API variants.
2930
+ * 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
2931
  */
2891
2932
  static VALUE
2892
- pgconn_set_client_encoding(VALUE self, VALUE str)
2933
+ pgconn_sync_set_client_encoding(VALUE self, VALUE str)
2893
2934
  {
2894
2935
  PGconn *conn = pg_get_pgconn( self );
2895
2936
 
2937
+ rb_check_frozen(self);
2896
2938
  Check_Type(str, T_STRING);
2897
2939
 
2898
- if ( (gvl_PQsetClientEncoding(conn, StringValueCStr(str))) == -1 ) {
2899
- rb_raise(rb_ePGerror, "%s", PQerrorMessage(conn));
2900
- }
2940
+ if ( (gvl_PQsetClientEncoding(conn, StringValueCStr(str))) == -1 )
2941
+ pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(conn));
2942
+
2901
2943
  pgconn_set_internal_encoding_index( self );
2902
2944
 
2903
2945
  return Qnil;
2904
2946
  }
2905
2947
 
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
2948
 
2950
2949
  /*
2951
2950
  * call-seq:
@@ -3020,10 +3019,8 @@ get_result_readable(PGconn *conn)
3020
3019
  * If +true+ is returned, +conn.is_busy+ will return +false+
3021
3020
  * and +conn.get_result+ will not block.
3022
3021
  */
3023
- static VALUE
3022
+ VALUE
3024
3023
  pgconn_block( int argc, VALUE *argv, VALUE self ) {
3025
- PGconn *conn = pg_get_pgconn( self );
3026
-
3027
3024
  struct timeval timeout;
3028
3025
  struct timeval *ptimeout = NULL;
3029
3026
  VALUE timeout_in;
@@ -3037,7 +3034,7 @@ pgconn_block( int argc, VALUE *argv, VALUE self ) {
3037
3034
  ptimeout = &timeout;
3038
3035
  }
3039
3036
 
3040
- ret = wait_socket_readable( conn, ptimeout, get_result_readable);
3037
+ ret = wait_socket_readable( self, ptimeout, get_result_readable);
3041
3038
 
3042
3039
  if( !ret )
3043
3040
  return Qfalse;
@@ -3046,6 +3043,42 @@ pgconn_block( int argc, VALUE *argv, VALUE self ) {
3046
3043
  }
3047
3044
 
3048
3045
 
3046
+ /*
3047
+ * call-seq:
3048
+ * conn.sync_get_last_result( ) -> PG::Result
3049
+ *
3050
+ * This function has the same behavior as #async_get_last_result, but is implemented using the synchronous command processing API of libpq.
3051
+ * See #async_exec for the differences between the two API variants.
3052
+ * 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.
3053
+ */
3054
+ static VALUE
3055
+ pgconn_sync_get_last_result(VALUE self)
3056
+ {
3057
+ PGconn *conn = pg_get_pgconn(self);
3058
+ VALUE rb_pgresult = Qnil;
3059
+ PGresult *cur, *prev;
3060
+
3061
+
3062
+ cur = prev = NULL;
3063
+ while ((cur = gvl_PQgetResult(conn)) != NULL) {
3064
+ int status;
3065
+
3066
+ if (prev) PQclear(prev);
3067
+ prev = cur;
3068
+
3069
+ status = PQresultStatus(cur);
3070
+ if (status == PGRES_COPY_OUT || status == PGRES_COPY_IN || status == PGRES_COPY_BOTH)
3071
+ break;
3072
+ }
3073
+
3074
+ if (prev) {
3075
+ rb_pgresult = pg_new_result( prev, self );
3076
+ pg_result_check(rb_pgresult);
3077
+ }
3078
+
3079
+ return rb_pgresult;
3080
+ }
3081
+
3049
3082
  /*
3050
3083
  * call-seq:
3051
3084
  * conn.get_last_result( ) -> PG::Result
@@ -3056,27 +3089,36 @@ pgconn_block( int argc, VALUE *argv, VALUE self ) {
3056
3089
  * returns the last non-NULL result, or +nil+ if no
3057
3090
  * results are available.
3058
3091
  *
3092
+ * If the last result contains a bad result_status, an
3093
+ * appropriate exception is raised.
3094
+ *
3059
3095
  * This function is similar to #get_result
3060
3096
  * except that it is designed to get one and only
3061
- * one result.
3097
+ * one result and that it checks the result state.
3062
3098
  */
3063
3099
  static VALUE
3064
- pgconn_get_last_result(VALUE self)
3100
+ pgconn_async_get_last_result(VALUE self)
3065
3101
  {
3066
3102
  PGconn *conn = pg_get_pgconn(self);
3067
3103
  VALUE rb_pgresult = Qnil;
3068
3104
  PGresult *cur, *prev;
3069
3105
 
3070
-
3071
3106
  cur = prev = NULL;
3072
- while ((cur = gvl_PQgetResult(conn)) != NULL) {
3107
+ for(;;) {
3073
3108
  int status;
3074
3109
 
3110
+ /* wait for input (without blocking) before reading each result */
3111
+ wait_socket_readable(self, NULL, get_result_readable);
3112
+
3113
+ cur = gvl_PQgetResult(conn);
3114
+ if (cur == NULL)
3115
+ break;
3116
+
3075
3117
  if (prev) PQclear(prev);
3076
3118
  prev = cur;
3077
3119
 
3078
3120
  status = PQresultStatus(cur);
3079
- if (status == PGRES_COPY_OUT || status == PGRES_COPY_IN)
3121
+ if (status == PGRES_COPY_OUT || status == PGRES_COPY_IN || status == PGRES_COPY_BOTH)
3080
3122
  break;
3081
3123
  }
3082
3124
 
@@ -3093,29 +3135,91 @@ pgconn_get_last_result(VALUE self)
3093
3135
  * conn.discard_results()
3094
3136
  *
3095
3137
  * 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.
3138
+ * This is internally used prior to Connection#exec and sibling methods.
3139
+ * It doesn't raise an exception on connection errors, but returns +false+ instead.
3140
+ *
3141
+ * Returns:
3142
+ * * +nil+ when the connection is already idle
3143
+ * * +true+ when some results have been discarded
3144
+ * * +false+ when a failure occured and the connection was closed
3145
+ *
3098
3146
  */
3099
3147
  static VALUE
3100
3148
  pgconn_discard_results(VALUE self)
3101
3149
  {
3102
3150
  PGconn *conn = pg_get_pgconn(self);
3151
+ VALUE socket_io;
3152
+
3153
+ switch( PQtransactionStatus(conn) ) {
3154
+ case PQTRANS_IDLE:
3155
+ case PQTRANS_INTRANS:
3156
+ case PQTRANS_INERROR:
3157
+ return Qnil;
3158
+ default:;
3159
+ }
3103
3160
 
3104
- PGresult *cur;
3105
- while ((cur = gvl_PQgetResult(conn)) != NULL) {
3106
- int status = PQresultStatus(cur);
3161
+ socket_io = pgconn_socket_io(self);
3162
+
3163
+ for(;;) {
3164
+ PGresult *cur;
3165
+ int status;
3166
+
3167
+ /* pgconn_block() raises an exception in case of errors.
3168
+ * To avoid this call pg_rb_io_wait() and PQconsumeInput() without rb_raise().
3169
+ */
3170
+ while( gvl_PQisBusy(conn) ){
3171
+ int events;
3172
+
3173
+ switch( PQflush(conn) ) {
3174
+ case 1:
3175
+ events = RB_NUM2INT(pg_rb_io_wait(socket_io, RB_INT2NUM(PG_RUBY_IO_READABLE | PG_RUBY_IO_WRITABLE), Qnil));
3176
+ if (events & PG_RUBY_IO_READABLE){
3177
+ if ( PQconsumeInput(conn) == 0 ) goto error;
3178
+ }
3179
+ break;
3180
+ case 0:
3181
+ pg_rb_io_wait(socket_io, RB_INT2NUM(PG_RUBY_IO_READABLE), Qnil);
3182
+ if ( PQconsumeInput(conn) == 0 ) goto error;
3183
+ break;
3184
+ default:
3185
+ goto error;
3186
+ }
3187
+ }
3188
+
3189
+ cur = gvl_PQgetResult(conn);
3190
+ if( cur == NULL) break;
3191
+
3192
+ status = PQresultStatus(cur);
3107
3193
  PQclear(cur);
3108
3194
  if (status == PGRES_COPY_IN){
3109
- gvl_PQputCopyEnd(conn, "COPY terminated by new PQexec");
3195
+ while( gvl_PQputCopyEnd(conn, "COPY terminated by new query or discard_results") == 0 ){
3196
+ pgconn_async_flush(self);
3197
+ }
3110
3198
  }
3111
3199
  if (status == PGRES_COPY_OUT){
3112
- char *buffer = NULL;
3113
- while( gvl_PQgetCopyData(conn, &buffer, 0) > 0)
3114
- PQfreemem(buffer);
3200
+ for(;;) {
3201
+ char *buffer = NULL;
3202
+ int st = gvl_PQgetCopyData(conn, &buffer, 1);
3203
+ if( st == 0 ) {
3204
+ /* would block -> wait for readable data */
3205
+ pg_rb_io_wait(socket_io, RB_INT2NUM(PG_RUBY_IO_READABLE), Qnil);
3206
+ if ( PQconsumeInput(conn) == 0 ) goto error;
3207
+ } else if( st > 0 ) {
3208
+ /* some data retrieved -> discard it */
3209
+ PQfreemem(buffer);
3210
+ } else {
3211
+ /* no more data */
3212
+ break;
3213
+ }
3214
+ }
3115
3215
  }
3116
3216
  }
3117
3217
 
3118
- return Qnil;
3218
+ return Qtrue;
3219
+
3220
+ error:
3221
+ pgconn_close_socket_io(self);
3222
+ return Qfalse;
3119
3223
  }
3120
3224
 
3121
3225
  /*
@@ -3138,6 +3242,7 @@ pgconn_discard_results(VALUE self)
3138
3242
  * #exec is an alias for #async_exec which is almost identical to #sync_exec .
3139
3243
  * #sync_exec is implemented on the simpler synchronous command processing API of libpq, whereas
3140
3244
  * #async_exec is implemented on the asynchronous API and on ruby's IO mechanisms.
3245
+ * Only #async_exec is compatible to <tt>Fiber.scheduler</tt> based asynchronous IO processing introduced in ruby-3.0.
3141
3246
  * Both methods ensure that other threads can process while waiting for the server to
3142
3247
  * complete the request, but #sync_exec blocks all signals to be processed until the query is finished.
3143
3248
  * This is most notably visible by a delayed reaction to Control+C.
@@ -3152,8 +3257,7 @@ pgconn_async_exec(int argc, VALUE *argv, VALUE self)
3152
3257
 
3153
3258
  pgconn_discard_results( self );
3154
3259
  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 );
3260
+ rb_pgresult = pgconn_async_get_last_result( self );
3157
3261
 
3158
3262
  if ( rb_block_given_p() ) {
3159
3263
  return rb_ensure( rb_yield, rb_pgresult, pg_result_clear, rb_pgresult );
@@ -3182,7 +3286,7 @@ pgconn_async_exec(int argc, VALUE *argv, VALUE self)
3182
3286
  * or, it may be a String. If it is a string, that is equivalent to the hash:
3183
3287
  * { :value => <string value>, :type => 0, :format => 0 }
3184
3288
  *
3185
- * PostgreSQL bind parameters are represented as $1, $1, $2, etc.,
3289
+ * PostgreSQL bind parameters are represented as $1, $2, $3, etc.,
3186
3290
  * inside the SQL query. The 0th element of the +params+ array is bound
3187
3291
  * to $1, the 1st element is bound to $2, etc. +nil+ is treated as +NULL+.
3188
3292
  *
@@ -3225,8 +3329,7 @@ pgconn_async_exec_params(int argc, VALUE *argv, VALUE self)
3225
3329
  } else {
3226
3330
  pgconn_send_query_params( argc, argv, self );
3227
3331
  }
3228
- pgconn_block( 0, NULL, self ); /* wait for input (without blocking) before reading the last result */
3229
- rb_pgresult = pgconn_get_last_result( self );
3332
+ rb_pgresult = pgconn_async_get_last_result( self );
3230
3333
 
3231
3334
  if ( rb_block_given_p() ) {
3232
3335
  return rb_ensure( rb_yield, rb_pgresult, pg_result_clear, rb_pgresult );
@@ -3252,7 +3355,7 @@ pgconn_async_exec_params(int argc, VALUE *argv, VALUE self)
3252
3355
  *
3253
3356
  * For example: "SELECT $1::int"
3254
3357
  *
3255
- * PostgreSQL bind parameters are represented as $1, $1, $2, etc.,
3358
+ * PostgreSQL bind parameters are represented as $1, $2, $3, etc.,
3256
3359
  * inside the SQL query.
3257
3360
  *
3258
3361
  * See also corresponding {libpq function}[https://www.postgresql.org/docs/current/libpq-exec.html#LIBPQ-PQPREPARE].
@@ -3264,8 +3367,7 @@ pgconn_async_prepare(int argc, VALUE *argv, VALUE self)
3264
3367
 
3265
3368
  pgconn_discard_results( self );
3266
3369
  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 );
3370
+ rb_pgresult = pgconn_async_get_last_result( self );
3269
3371
 
3270
3372
  if ( rb_block_given_p() ) {
3271
3373
  return rb_ensure( rb_yield, rb_pgresult, pg_result_clear, rb_pgresult );
@@ -3292,7 +3394,7 @@ pgconn_async_prepare(int argc, VALUE *argv, VALUE self)
3292
3394
  * or, it may be a String. If it is a string, that is equivalent to the hash:
3293
3395
  * { :value => <string value>, :format => 0 }
3294
3396
  *
3295
- * PostgreSQL bind parameters are represented as $1, $1, $2, etc.,
3397
+ * PostgreSQL bind parameters are represented as $1, $2, $3, etc.,
3296
3398
  * inside the SQL query. The 0th element of the +params+ array is bound
3297
3399
  * to $1, the 1st element is bound to $2, etc. +nil+ is treated as +NULL+.
3298
3400
  *
@@ -3318,8 +3420,7 @@ pgconn_async_exec_prepared(int argc, VALUE *argv, VALUE self)
3318
3420
 
3319
3421
  pgconn_discard_results( self );
3320
3422
  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 );
3423
+ rb_pgresult = pgconn_async_get_last_result( self );
3323
3424
 
3324
3425
  if ( rb_block_given_p() ) {
3325
3426
  return rb_ensure( rb_yield, rb_pgresult, pg_result_clear, rb_pgresult );
@@ -3343,8 +3444,7 @@ pgconn_async_describe_portal(VALUE self, VALUE portal)
3343
3444
 
3344
3445
  pgconn_discard_results( self );
3345
3446
  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 );
3447
+ rb_pgresult = pgconn_async_get_last_result( self );
3348
3448
 
3349
3449
  if ( rb_block_given_p() ) {
3350
3450
  return rb_ensure( rb_yield, rb_pgresult, pg_result_clear, rb_pgresult );
@@ -3368,8 +3468,7 @@ pgconn_async_describe_prepared(VALUE self, VALUE stmt_name)
3368
3468
 
3369
3469
  pgconn_discard_results( self );
3370
3470
  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 );
3471
+ rb_pgresult = pgconn_async_get_last_result( self );
3373
3472
 
3374
3473
  if ( rb_block_given_p() ) {
3375
3474
  return rb_ensure( rb_yield, rb_pgresult, pg_result_clear, rb_pgresult );
@@ -3457,10 +3556,134 @@ pgconn_ssl_attribute_names(VALUE self)
3457
3556
  #endif
3458
3557
 
3459
3558
 
3559
+ #ifdef HAVE_PQENTERPIPELINEMODE
3560
+ /*
3561
+ * call-seq:
3562
+ * conn.pipeline_status -> Integer
3563
+ *
3564
+ * Returns the current pipeline mode status of the libpq connection.
3565
+ *
3566
+ * PQpipelineStatus can return one of the following values:
3567
+ *
3568
+ * * PQ_PIPELINE_ON - The libpq connection is in pipeline mode.
3569
+ * * PQ_PIPELINE_OFF - The libpq connection is not in pipeline mode.
3570
+ * * PQ_PIPELINE_ABORTED - The libpq connection is in pipeline mode and an error occurred while processing the current pipeline.
3571
+ * The aborted flag is cleared when PQgetResult returns a result of type PGRES_PIPELINE_SYNC.
3572
+ *
3573
+ * Available since PostgreSQL-14
3574
+ */
3575
+ static VALUE
3576
+ pgconn_pipeline_status(VALUE self)
3577
+ {
3578
+ int res = PQpipelineStatus(pg_get_pgconn(self));
3579
+ return INT2FIX(res);
3580
+ }
3581
+
3582
+
3583
+ /*
3584
+ * call-seq:
3585
+ * conn.enter_pipeline_mode -> nil
3586
+ *
3587
+ * Causes a connection to enter pipeline mode if it is currently idle or already in pipeline mode.
3588
+ *
3589
+ * 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.
3590
+ * This function does not actually send anything to the server, it just changes the libpq connection state.
3591
+ *
3592
+ * Available since PostgreSQL-14
3593
+ */
3594
+ static VALUE
3595
+ pgconn_enter_pipeline_mode(VALUE self)
3596
+ {
3597
+ PGconn *conn = pg_get_pgconn(self);
3598
+ int res = PQenterPipelineMode(conn);
3599
+ if( res != 1 )
3600
+ pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(conn));
3601
+
3602
+ return Qnil;
3603
+ }
3604
+
3605
+ /*
3606
+ * call-seq:
3607
+ * conn.exit_pipeline_mode -> nil
3608
+ *
3609
+ * Causes a connection to exit pipeline mode if it is currently in pipeline mode with an empty queue and no pending results.
3610
+ *
3611
+ * Takes no action if not in pipeline mode.
3612
+ * 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.
3613
+ *
3614
+ * Available since PostgreSQL-14
3615
+ */
3616
+ static VALUE
3617
+ pgconn_exit_pipeline_mode(VALUE self)
3618
+ {
3619
+ PGconn *conn = pg_get_pgconn(self);
3620
+ int res = PQexitPipelineMode(conn);
3621
+ if( res != 1 )
3622
+ pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(conn));
3623
+
3624
+ return Qnil;
3625
+ }
3626
+
3627
+
3628
+ /*
3629
+ * call-seq:
3630
+ * conn.pipeline_sync -> nil
3631
+ *
3632
+ * Marks a synchronization point in a pipeline by sending a sync message and flushing the send buffer.
3633
+ * This serves as the delimiter of an implicit transaction and an error recovery point; see Section 34.5.1.3 of the PostgreSQL documentation.
3634
+ *
3635
+ * Raises PG::Error if the connection is not in pipeline mode or sending a sync message failed.
3636
+ *
3637
+ * Available since PostgreSQL-14
3638
+ */
3639
+ static VALUE
3640
+ pgconn_pipeline_sync(VALUE self)
3641
+ {
3642
+ PGconn *conn = pg_get_pgconn(self);
3643
+ int res = PQpipelineSync(conn);
3644
+ if( res != 1 )
3645
+ pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(conn));
3646
+
3647
+ return Qnil;
3648
+ }
3649
+
3650
+ /*
3651
+ * call-seq:
3652
+ * conn.pipeline_sync -> nil
3653
+ *
3654
+ * Sends a request for the server to flush its output buffer.
3655
+ *
3656
+ * 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.
3657
+ * This function is useful to cause the server to flush its output buffer in pipeline mode without establishing a synchronization point.
3658
+ * Note that the request is not itself flushed to the server automatically; use Connection#flush if necessary.
3659
+ *
3660
+ * Available since PostgreSQL-14
3661
+ */
3662
+ static VALUE
3663
+ pgconn_send_flush_request(VALUE self)
3664
+ {
3665
+ PGconn *conn = pg_get_pgconn(self);
3666
+ int res = PQsendFlushRequest(conn);
3667
+ if( res != 1 )
3668
+ pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(conn));
3669
+
3670
+ return Qnil;
3671
+ }
3672
+
3673
+ #endif
3674
+
3460
3675
  /**************************************************************************
3461
3676
  * LARGE OBJECT SUPPORT
3462
3677
  **************************************************************************/
3463
3678
 
3679
+ #define BLOCKING_BEGIN(conn) do { \
3680
+ int old_nonblocking = PQisnonblocking(conn); \
3681
+ PQsetnonblocking(conn, 0);
3682
+
3683
+ #define BLOCKING_END(th) \
3684
+ PQsetnonblocking(conn, old_nonblocking); \
3685
+ } while(0);
3686
+
3464
3687
  /*
3465
3688
  * call-seq:
3466
3689
  * conn.lo_creat( [mode] ) -> Integer
@@ -3481,9 +3704,12 @@ pgconn_locreat(int argc, VALUE *argv, VALUE self)
3481
3704
  else
3482
3705
  mode = NUM2INT(nmode);
3483
3706
 
3484
- lo_oid = lo_creat(conn, mode);
3707
+ BLOCKING_BEGIN(conn)
3708
+ lo_oid = lo_creat(conn, mode);
3709
+ BLOCKING_END(conn)
3710
+
3485
3711
  if (lo_oid == 0)
3486
- rb_raise(rb_ePGerror, "lo_creat failed");
3712
+ pg_raise_conn_error( rb_ePGerror, self, "lo_creat failed");
3487
3713
 
3488
3714
  return UINT2NUM(lo_oid);
3489
3715
  }
@@ -3504,7 +3730,7 @@ pgconn_locreate(VALUE self, VALUE in_lo_oid)
3504
3730
 
3505
3731
  ret = lo_create(conn, lo_oid);
3506
3732
  if (ret == InvalidOid)
3507
- rb_raise(rb_ePGerror, "lo_create failed");
3733
+ pg_raise_conn_error( rb_ePGerror, self, "lo_create failed");
3508
3734
 
3509
3735
  return UINT2NUM(ret);
3510
3736
  }
@@ -3526,9 +3752,12 @@ pgconn_loimport(VALUE self, VALUE filename)
3526
3752
 
3527
3753
  Check_Type(filename, T_STRING);
3528
3754
 
3529
- lo_oid = lo_import(conn, StringValueCStr(filename));
3755
+ BLOCKING_BEGIN(conn)
3756
+ lo_oid = lo_import(conn, StringValueCStr(filename));
3757
+ BLOCKING_END(conn)
3758
+
3530
3759
  if (lo_oid == 0) {
3531
- rb_raise(rb_ePGerror, "%s", PQerrorMessage(conn));
3760
+ pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(conn));
3532
3761
  }
3533
3762
  return UINT2NUM(lo_oid);
3534
3763
  }
@@ -3544,12 +3773,17 @@ pgconn_loexport(VALUE self, VALUE lo_oid, VALUE filename)
3544
3773
  {
3545
3774
  PGconn *conn = pg_get_pgconn(self);
3546
3775
  Oid oid;
3776
+ int ret;
3547
3777
  Check_Type(filename, T_STRING);
3548
3778
 
3549
3779
  oid = NUM2UINT(lo_oid);
3550
3780
 
3551
- if (lo_export(conn, oid, StringValueCStr(filename)) < 0) {
3552
- rb_raise(rb_ePGerror, "%s", PQerrorMessage(conn));
3781
+ BLOCKING_BEGIN(conn)
3782
+ ret = lo_export(conn, oid, StringValueCStr(filename));
3783
+ BLOCKING_END(conn)
3784
+
3785
+ if (ret < 0) {
3786
+ pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(conn));
3553
3787
  }
3554
3788
  return Qnil;
3555
3789
  }
@@ -3579,8 +3813,12 @@ pgconn_loopen(int argc, VALUE *argv, VALUE self)
3579
3813
  else
3580
3814
  mode = NUM2INT(nmode);
3581
3815
 
3582
- if((fd = lo_open(conn, lo_oid, mode)) < 0) {
3583
- rb_raise(rb_ePGerror, "can't open large object: %s", PQerrorMessage(conn));
3816
+ BLOCKING_BEGIN(conn)
3817
+ fd = lo_open(conn, lo_oid, mode);
3818
+ BLOCKING_END(conn)
3819
+
3820
+ if(fd < 0) {
3821
+ pg_raise_conn_error( rb_ePGerror, self, "can't open large object: %s", PQerrorMessage(conn));
3584
3822
  }
3585
3823
  return INT2FIX(fd);
3586
3824
  }
@@ -3602,11 +3840,15 @@ pgconn_lowrite(VALUE self, VALUE in_lo_desc, VALUE buffer)
3602
3840
  Check_Type(buffer, T_STRING);
3603
3841
 
3604
3842
  if( RSTRING_LEN(buffer) < 0) {
3605
- rb_raise(rb_ePGerror, "write buffer zero string");
3843
+ pg_raise_conn_error( rb_ePGerror, self, "write buffer zero string");
3606
3844
  }
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));
3845
+ BLOCKING_BEGIN(conn)
3846
+ n = lo_write(conn, fd, StringValuePtr(buffer),
3847
+ RSTRING_LEN(buffer));
3848
+ BLOCKING_END(conn)
3849
+
3850
+ if(n < 0) {
3851
+ pg_raise_conn_error( rb_ePGerror, self, "lo_write failed: %s", PQerrorMessage(conn));
3610
3852
  }
3611
3853
 
3612
3854
  return INT2FIX(n);
@@ -3629,16 +3871,17 @@ pgconn_loread(VALUE self, VALUE in_lo_desc, VALUE in_len)
3629
3871
  VALUE str;
3630
3872
  char *buffer;
3631
3873
 
3632
- buffer = ALLOC_N(char, len);
3633
- if(buffer == NULL)
3634
- rb_raise(rb_eNoMemError, "ALLOC failed!");
3874
+ if (len < 0)
3875
+ pg_raise_conn_error( rb_ePGerror, self, "negative length %d given", len);
3635
3876
 
3636
- if (len < 0){
3637
- rb_raise(rb_ePGerror,"nagative length %d given", len);
3638
- }
3877
+ buffer = ALLOC_N(char, len);
3639
3878
 
3640
- if((ret = lo_read(conn, lo_desc, buffer, len)) < 0)
3641
- rb_raise(rb_ePGerror, "lo_read failed");
3879
+ BLOCKING_BEGIN(conn)
3880
+ ret = lo_read(conn, lo_desc, buffer, len);
3881
+ BLOCKING_END(conn)
3882
+
3883
+ if(ret < 0)
3884
+ pg_raise_conn_error( rb_ePGerror, self, "lo_read failed");
3642
3885
 
3643
3886
  if(ret == 0) {
3644
3887
  xfree(buffer);
@@ -3667,8 +3910,12 @@ pgconn_lolseek(VALUE self, VALUE in_lo_desc, VALUE offset, VALUE whence)
3667
3910
  int lo_desc = NUM2INT(in_lo_desc);
3668
3911
  int ret;
3669
3912
 
3670
- if((ret = lo_lseek(conn, lo_desc, NUM2INT(offset), NUM2INT(whence))) < 0) {
3671
- rb_raise(rb_ePGerror, "lo_lseek failed");
3913
+ BLOCKING_BEGIN(conn)
3914
+ ret = lo_lseek(conn, lo_desc, NUM2INT(offset), NUM2INT(whence));
3915
+ BLOCKING_END(conn)
3916
+
3917
+ if(ret < 0) {
3918
+ pg_raise_conn_error( rb_ePGerror, self, "lo_lseek failed");
3672
3919
  }
3673
3920
 
3674
3921
  return INT2FIX(ret);
@@ -3687,8 +3934,12 @@ pgconn_lotell(VALUE self, VALUE in_lo_desc)
3687
3934
  PGconn *conn = pg_get_pgconn(self);
3688
3935
  int lo_desc = NUM2INT(in_lo_desc);
3689
3936
 
3690
- if((position = lo_tell(conn, lo_desc)) < 0)
3691
- rb_raise(rb_ePGerror,"lo_tell failed");
3937
+ BLOCKING_BEGIN(conn)
3938
+ position = lo_tell(conn, lo_desc);
3939
+ BLOCKING_END(conn)
3940
+
3941
+ if(position < 0)
3942
+ pg_raise_conn_error( rb_ePGerror, self, "lo_tell failed");
3692
3943
 
3693
3944
  return INT2FIX(position);
3694
3945
  }
@@ -3705,9 +3956,14 @@ pgconn_lotruncate(VALUE self, VALUE in_lo_desc, VALUE in_len)
3705
3956
  PGconn *conn = pg_get_pgconn(self);
3706
3957
  int lo_desc = NUM2INT(in_lo_desc);
3707
3958
  size_t len = NUM2INT(in_len);
3959
+ int ret;
3708
3960
 
3709
- if(lo_truncate(conn,lo_desc,len) < 0)
3710
- rb_raise(rb_ePGerror,"lo_truncate failed");
3961
+ BLOCKING_BEGIN(conn)
3962
+ ret = lo_truncate(conn,lo_desc,len);
3963
+ BLOCKING_END(conn)
3964
+
3965
+ if(ret < 0)
3966
+ pg_raise_conn_error( rb_ePGerror, self, "lo_truncate failed");
3711
3967
 
3712
3968
  return Qnil;
3713
3969
  }
@@ -3723,9 +3979,14 @@ pgconn_loclose(VALUE self, VALUE in_lo_desc)
3723
3979
  {
3724
3980
  PGconn *conn = pg_get_pgconn(self);
3725
3981
  int lo_desc = NUM2INT(in_lo_desc);
3982
+ int ret;
3983
+
3984
+ BLOCKING_BEGIN(conn)
3985
+ ret = lo_close(conn,lo_desc);
3986
+ BLOCKING_END(conn)
3726
3987
 
3727
- if(lo_close(conn,lo_desc) < 0)
3728
- rb_raise(rb_ePGerror,"lo_close failed");
3988
+ if(ret < 0)
3989
+ pg_raise_conn_error( rb_ePGerror, self, "lo_close failed");
3729
3990
 
3730
3991
  return Qnil;
3731
3992
  }
@@ -3741,9 +4002,14 @@ pgconn_lounlink(VALUE self, VALUE in_oid)
3741
4002
  {
3742
4003
  PGconn *conn = pg_get_pgconn(self);
3743
4004
  Oid oid = NUM2UINT(in_oid);
4005
+ int ret;
4006
+
4007
+ BLOCKING_BEGIN(conn)
4008
+ ret = lo_unlink(conn,oid);
4009
+ BLOCKING_END(conn)
3744
4010
 
3745
- if(lo_unlink(conn,oid) < 0)
3746
- rb_raise(rb_ePGerror,"lo_unlink failed");
4011
+ if(ret < 0)
4012
+ pg_raise_conn_error( rb_ePGerror, self, "lo_unlink failed");
3747
4013
 
3748
4014
  return Qnil;
3749
4015
  }
@@ -3800,12 +4066,13 @@ static VALUE pgconn_external_encoding(VALUE self);
3800
4066
  static VALUE
3801
4067
  pgconn_internal_encoding_set(VALUE self, VALUE enc)
3802
4068
  {
4069
+ rb_check_frozen(self);
3803
4070
  if (NIL_P(enc)) {
3804
- pgconn_set_client_encoding( self, rb_usascii_str_new_cstr("SQL_ASCII") );
4071
+ pgconn_sync_set_client_encoding( self, rb_usascii_str_new_cstr("SQL_ASCII") );
3805
4072
  return enc;
3806
4073
  }
3807
4074
  else if ( TYPE(enc) == T_STRING && strcasecmp("JOHAB", StringValueCStr(enc)) == 0 ) {
3808
- pgconn_set_client_encoding(self, rb_usascii_str_new_cstr("JOHAB"));
4075
+ pgconn_sync_set_client_encoding(self, rb_usascii_str_new_cstr("JOHAB"));
3809
4076
  return enc;
3810
4077
  }
3811
4078
  else {
@@ -3843,16 +4110,34 @@ pgconn_external_encoding(VALUE self)
3843
4110
  return rb_enc_from_encoding( enc );
3844
4111
  }
3845
4112
 
4113
+ /*
4114
+ * call-seq:
4115
+ * conn.set_client_encoding( encoding )
4116
+ *
4117
+ * Sets the client encoding to the _encoding_ String.
4118
+ */
4119
+ static VALUE
4120
+ pgconn_async_set_client_encoding(VALUE self, VALUE encname)
4121
+ {
4122
+ VALUE query_format, query;
4123
+
4124
+ rb_check_frozen(self);
4125
+ Check_Type(encname, T_STRING);
4126
+ query_format = rb_str_new_cstr("set client_encoding to '%s'");
4127
+ query = rb_funcall(query_format, rb_intern("%"), 1, encname);
4128
+
4129
+ pgconn_async_exec(1, &query, self);
4130
+ pgconn_set_internal_encoding_index( self );
4131
+
4132
+ return Qnil;
4133
+ }
3846
4134
 
3847
4135
  static VALUE
3848
4136
  pgconn_set_client_encoding_async1( VALUE args )
3849
4137
  {
3850
4138
  VALUE self = ((VALUE*)args)[0];
3851
4139
  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);
4140
+ pgconn_async_set_client_encoding(self, encname);
3856
4141
  return 0;
3857
4142
  }
3858
4143
 
@@ -3867,9 +4152,9 @@ pgconn_set_client_encoding_async2( VALUE arg, VALUE ex )
3867
4152
 
3868
4153
 
3869
4154
  static VALUE
3870
- pgconn_set_client_encoding_async( VALUE self, const char *encname )
4155
+ pgconn_set_client_encoding_async( VALUE self, VALUE encname )
3871
4156
  {
3872
- VALUE args[] = { self, rb_str_new_cstr(encname) };
4157
+ VALUE args[] = { self, encname };
3873
4158
  return rb_rescue(pgconn_set_client_encoding_async1, (VALUE)&args, pgconn_set_client_encoding_async2, Qnil);
3874
4159
  }
3875
4160
 
@@ -3889,12 +4174,12 @@ pgconn_set_default_encoding( VALUE self )
3889
4174
  rb_encoding *enc;
3890
4175
  const char *encname;
3891
4176
 
4177
+ rb_check_frozen(self);
3892
4178
  if (( enc = rb_default_internal_encoding() )) {
3893
4179
  encname = pg_get_rb_encoding_as_pg_encoding( enc );
3894
- if ( pgconn_set_client_encoding_async(self, encname) != 0 )
4180
+ if ( pgconn_set_client_encoding_async(self, rb_str_new_cstr(encname)) != 0 )
3895
4181
  rb_warning( "Failed to set the default_internal encoding to %s: '%s'",
3896
4182
  encname, PQerrorMessage(conn) );
3897
- pgconn_set_internal_encoding_index( self );
3898
4183
  return rb_enc_from_encoding( enc );
3899
4184
  } else {
3900
4185
  pgconn_set_internal_encoding_index( self );
@@ -3916,13 +4201,14 @@ static VALUE
3916
4201
  pgconn_type_map_for_queries_set(VALUE self, VALUE typemap)
3917
4202
  {
3918
4203
  t_pg_connection *this = pg_get_connection( self );
4204
+ t_typemap *tm;
4205
+ UNUSED(tm);
3919
4206
 
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;
4207
+ rb_check_frozen(self);
4208
+ /* Check type of method param */
4209
+ TypedData_Get_Struct(typemap, t_typemap, &pg_typemap_type, tm);
4210
+
4211
+ RB_OBJ_WRITE(self, &this->type_map_for_queries, typemap);
3926
4212
 
3927
4213
  return typemap;
3928
4214
  }
@@ -3956,13 +4242,12 @@ static VALUE
3956
4242
  pgconn_type_map_for_results_set(VALUE self, VALUE typemap)
3957
4243
  {
3958
4244
  t_pg_connection *this = pg_get_connection( self );
4245
+ t_typemap *tm;
4246
+ UNUSED(tm);
3959
4247
 
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;
4248
+ rb_check_frozen(self);
4249
+ TypedData_Get_Struct(typemap, t_typemap, &pg_typemap_type, tm);
4250
+ RB_OBJ_WRITE(self, &this->type_map_for_results, typemap);
3966
4251
 
3967
4252
  return typemap;
3968
4253
  }
@@ -3996,20 +4281,20 @@ pgconn_type_map_for_results_get(VALUE self)
3996
4281
  *
3997
4282
  */
3998
4283
  static VALUE
3999
- pgconn_encoder_for_put_copy_data_set(VALUE self, VALUE typemap)
4284
+ pgconn_encoder_for_put_copy_data_set(VALUE self, VALUE encoder)
4000
4285
  {
4001
4286
  t_pg_connection *this = pg_get_connection( self );
4002
4287
 
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);
4288
+ rb_check_frozen(self);
4289
+ if( encoder != Qnil ){
4290
+ t_pg_coder *co;
4291
+ UNUSED(co);
4292
+ /* Check argument type */
4293
+ TypedData_Get_Struct(encoder, t_pg_coder, &pg_coder_type, co);
4009
4294
  }
4010
- this->encoder_for_put_copy_data = typemap;
4295
+ RB_OBJ_WRITE(self, &this->encoder_for_put_copy_data, encoder);
4011
4296
 
4012
- return typemap;
4297
+ return encoder;
4013
4298
  }
4014
4299
 
4015
4300
  /*
@@ -4045,20 +4330,20 @@ pgconn_encoder_for_put_copy_data_get(VALUE self)
4045
4330
  *
4046
4331
  */
4047
4332
  static VALUE
4048
- pgconn_decoder_for_get_copy_data_set(VALUE self, VALUE typemap)
4333
+ pgconn_decoder_for_get_copy_data_set(VALUE self, VALUE decoder)
4049
4334
  {
4050
4335
  t_pg_connection *this = pg_get_connection( self );
4051
4336
 
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);
4337
+ rb_check_frozen(self);
4338
+ if( decoder != Qnil ){
4339
+ t_pg_coder *co;
4340
+ UNUSED(co);
4341
+ /* Check argument type */
4342
+ TypedData_Get_Struct(decoder, t_pg_coder, &pg_coder_type, co);
4058
4343
  }
4059
- this->decoder_for_get_copy_data = typemap;
4344
+ RB_OBJ_WRITE(self, &this->decoder_for_get_copy_data, decoder);
4060
4345
 
4061
- return typemap;
4346
+ return decoder;
4062
4347
  }
4063
4348
 
4064
4349
  /*
@@ -4102,6 +4387,7 @@ pgconn_field_name_type_set(VALUE self, VALUE sym)
4102
4387
  {
4103
4388
  t_pg_connection *this = pg_get_connection( self );
4104
4389
 
4390
+ rb_check_frozen(self);
4105
4391
  this->flags &= ~PG_RESULT_FIELD_NAMES_MASK;
4106
4392
  if( sym == sym_symbol ) this->flags |= PG_RESULT_FIELD_NAMES_SYMBOL;
4107
4393
  else if ( sym == sym_static_symbol ) this->flags |= PG_RESULT_FIELD_NAMES_STATIC_SYMBOL;
@@ -4138,9 +4424,10 @@ pgconn_field_name_type_get(VALUE self)
4138
4424
  * Document-class: PG::Connection
4139
4425
  */
4140
4426
  void
4141
- init_pg_connection()
4427
+ init_pg_connection(void)
4142
4428
  {
4143
4429
  s_id_encode = rb_intern("encode");
4430
+ s_id_autoclose_set = rb_intern("autoclose=");
4144
4431
  sym_type = ID2SYM(rb_intern("type"));
4145
4432
  sym_format = ID2SYM(rb_intern("format"));
4146
4433
  sym_value = ID2SYM(rb_intern("value"));
@@ -4156,10 +4443,6 @@ init_pg_connection()
4156
4443
  /****** PG::Connection CLASS METHODS ******/
4157
4444
  rb_define_alloc_func( rb_cPGconn, pgconn_s_allocate );
4158
4445
 
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
4446
  rb_define_singleton_method(rb_cPGconn, "escape_string", pgconn_s_escape, 1);
4164
4447
  SINGLETON_ALIAS(rb_cPGconn, "escape", "escape_string");
4165
4448
  rb_define_singleton_method(rb_cPGconn, "escape_bytea", pgconn_s_escape_bytea, 1);
@@ -4168,14 +4451,15 @@ init_pg_connection()
4168
4451
  rb_define_singleton_method(rb_cPGconn, "quote_ident", pgconn_s_quote_ident, 1);
4169
4452
  rb_define_singleton_method(rb_cPGconn, "connect_start", pgconn_s_connect_start, -1);
4170
4453
  rb_define_singleton_method(rb_cPGconn, "conndefaults", pgconn_s_conndefaults, 0);
4171
- rb_define_singleton_method(rb_cPGconn, "ping", pgconn_s_ping, -1);
4454
+ rb_define_singleton_method(rb_cPGconn, "conninfo_parse", pgconn_s_conninfo_parse, 1);
4455
+ rb_define_singleton_method(rb_cPGconn, "sync_ping", pgconn_s_sync_ping, -1);
4456
+ rb_define_singleton_method(rb_cPGconn, "sync_connect", pgconn_s_sync_connect, -1);
4172
4457
 
4173
4458
  /****** PG::Connection INSTANCE METHODS: Connection Control ******/
4174
- rb_define_method(rb_cPGconn, "initialize", pgconn_init, -1);
4175
4459
  rb_define_method(rb_cPGconn, "connect_poll", pgconn_connect_poll, 0);
4176
4460
  rb_define_method(rb_cPGconn, "finish", pgconn_finish, 0);
4177
4461
  rb_define_method(rb_cPGconn, "finished?", pgconn_finished_p, 0);
4178
- rb_define_method(rb_cPGconn, "reset", pgconn_reset, 0);
4462
+ rb_define_method(rb_cPGconn, "sync_reset", pgconn_sync_reset, 0);
4179
4463
  rb_define_method(rb_cPGconn, "reset_start", pgconn_reset_start, 0);
4180
4464
  rb_define_method(rb_cPGconn, "reset_poll", pgconn_reset_poll, 0);
4181
4465
  rb_define_alias(rb_cPGconn, "close", "finish");
@@ -4185,11 +4469,12 @@ init_pg_connection()
4185
4469
  rb_define_method(rb_cPGconn, "user", pgconn_user, 0);
4186
4470
  rb_define_method(rb_cPGconn, "pass", pgconn_pass, 0);
4187
4471
  rb_define_method(rb_cPGconn, "host", pgconn_host, 0);
4472
+ #if defined(HAVE_PQRESULTMEMORYSIZE)
4473
+ rb_define_method(rb_cPGconn, "hostaddr", pgconn_hostaddr, 0);
4474
+ #endif
4188
4475
  rb_define_method(rb_cPGconn, "port", pgconn_port, 0);
4189
4476
  rb_define_method(rb_cPGconn, "tty", pgconn_tty, 0);
4190
- #ifdef HAVE_PQCONNINFO
4191
4477
  rb_define_method(rb_cPGconn, "conninfo", pgconn_conninfo, 0);
4192
- #endif
4193
4478
  rb_define_method(rb_cPGconn, "options", pgconn_options, 0);
4194
4479
  rb_define_method(rb_cPGconn, "status", pgconn_status, 0);
4195
4480
  rb_define_method(rb_cPGconn, "transaction_status", pgconn_transaction_status, 0);
@@ -4200,17 +4485,18 @@ init_pg_connection()
4200
4485
  rb_define_method(rb_cPGconn, "socket", pgconn_socket, 0);
4201
4486
  rb_define_method(rb_cPGconn, "socket_io", pgconn_socket_io, 0);
4202
4487
  rb_define_method(rb_cPGconn, "backend_pid", pgconn_backend_pid, 0);
4488
+ rb_define_method(rb_cPGconn, "backend_key", pgconn_backend_key, 0);
4203
4489
  rb_define_method(rb_cPGconn, "connection_needs_password", pgconn_connection_needs_password, 0);
4204
4490
  rb_define_method(rb_cPGconn, "connection_used_password", pgconn_connection_used_password, 0);
4205
4491
  /* rb_define_method(rb_cPGconn, "getssl", pgconn_getssl, 0); */
4206
4492
 
4207
4493
  /****** 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);
4494
+ rb_define_method(rb_cPGconn, "sync_exec", pgconn_sync_exec, -1);
4495
+ rb_define_method(rb_cPGconn, "sync_exec_params", pgconn_sync_exec_params, -1);
4496
+ rb_define_method(rb_cPGconn, "sync_prepare", pgconn_sync_prepare, -1);
4497
+ rb_define_method(rb_cPGconn, "sync_exec_prepared", pgconn_sync_exec_prepared, -1);
4498
+ rb_define_method(rb_cPGconn, "sync_describe_prepared", pgconn_sync_describe_prepared, 1);
4499
+ rb_define_method(rb_cPGconn, "sync_describe_portal", pgconn_sync_describe_portal, 1);
4214
4500
 
4215
4501
  rb_define_method(rb_cPGconn, "exec", pgconn_async_exec, -1);
4216
4502
  rb_define_method(rb_cPGconn, "exec_params", pgconn_async_exec_params, -1);
@@ -4243,25 +4529,26 @@ init_pg_connection()
4243
4529
  rb_define_method(rb_cPGconn, "send_query_prepared", pgconn_send_query_prepared, -1);
4244
4530
  rb_define_method(rb_cPGconn, "send_describe_prepared", pgconn_send_describe_prepared, 1);
4245
4531
  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);
4532
+ rb_define_method(rb_cPGconn, "sync_get_result", pgconn_sync_get_result, 0);
4247
4533
  rb_define_method(rb_cPGconn, "consume_input", pgconn_consume_input, 0);
4248
4534
  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);
4535
+ rb_define_method(rb_cPGconn, "sync_setnonblocking", pgconn_sync_setnonblocking, 1);
4536
+ rb_define_method(rb_cPGconn, "sync_isnonblocking", pgconn_sync_isnonblocking, 0);
4537
+ rb_define_method(rb_cPGconn, "sync_flush", pgconn_sync_flush, 0);
4538
+ rb_define_method(rb_cPGconn, "flush", pgconn_async_flush, 0);
4539
+ rb_define_alias(rb_cPGconn, "async_flush", "flush");
4253
4540
  rb_define_method(rb_cPGconn, "discard_results", pgconn_discard_results, 0);
4254
4541
 
4255
4542
  /****** PG::Connection INSTANCE METHODS: Cancelling Queries in Progress ******/
4256
- rb_define_method(rb_cPGconn, "cancel", pgconn_cancel, 0);
4543
+ rb_define_method(rb_cPGconn, "sync_cancel", pgconn_sync_cancel, 0);
4257
4544
 
4258
4545
  /****** PG::Connection INSTANCE METHODS: NOTIFY ******/
4259
4546
  rb_define_method(rb_cPGconn, "notifies", pgconn_notifies, 0);
4260
4547
 
4261
4548
  /****** 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);
4549
+ rb_define_method(rb_cPGconn, "sync_put_copy_data", pgconn_sync_put_copy_data, -1);
4550
+ rb_define_method(rb_cPGconn, "sync_put_copy_end", pgconn_sync_put_copy_end, -1);
4551
+ rb_define_method(rb_cPGconn, "sync_get_copy_data", pgconn_sync_get_copy_data, -1);
4265
4552
 
4266
4553
  /****** PG::Connection INSTANCE METHODS: Control Functions ******/
4267
4554
  rb_define_method(rb_cPGconn, "set_error_verbosity", pgconn_set_error_verbosity, 1);
@@ -4277,16 +4564,20 @@ init_pg_connection()
4277
4564
 
4278
4565
  /****** PG::Connection INSTANCE METHODS: Other ******/
4279
4566
  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);
4567
+ rb_define_method(rb_cPGconn, "sync_set_client_encoding", pgconn_sync_set_client_encoding, 1);
4568
+ rb_define_method(rb_cPGconn, "set_client_encoding", pgconn_async_set_client_encoding, 1);
4569
+ rb_define_alias(rb_cPGconn, "async_set_client_encoding", "set_client_encoding");
4281
4570
  rb_define_alias(rb_cPGconn, "client_encoding=", "set_client_encoding");
4282
- rb_define_method(rb_cPGconn, "transaction", pgconn_transaction, 0);
4283
4571
  rb_define_method(rb_cPGconn, "block", pgconn_block, -1);
4572
+ rb_define_private_method(rb_cPGconn, "flush_data=", pgconn_flush_data_set, 1);
4284
4573
  rb_define_method(rb_cPGconn, "wait_for_notify", pgconn_wait_for_notify, -1);
4285
4574
  rb_define_alias(rb_cPGconn, "notifies_wait", "wait_for_notify");
4286
4575
  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);
4576
+ rb_define_method(rb_cPGconn, "sync_get_last_result", pgconn_sync_get_last_result, 0);
4577
+ rb_define_method(rb_cPGconn, "get_last_result", pgconn_async_get_last_result, 0);
4578
+ rb_define_alias(rb_cPGconn, "async_get_last_result", "get_last_result");
4288
4579
  #ifdef HAVE_PQENCRYPTPASSWORDCONN
4289
- rb_define_method(rb_cPGconn, "encrypt_password", pgconn_encrypt_password, -1);
4580
+ rb_define_method(rb_cPGconn, "sync_encrypt_password", pgconn_sync_encrypt_password, -1);
4290
4581
  #endif
4291
4582
 
4292
4583
  #ifdef HAVE_PQSSLATTRIBUTE
@@ -4295,6 +4586,14 @@ init_pg_connection()
4295
4586
  rb_define_method(rb_cPGconn, "ssl_attribute_names", pgconn_ssl_attribute_names, 0);
4296
4587
  #endif
4297
4588
 
4589
+ #ifdef HAVE_PQENTERPIPELINEMODE
4590
+ rb_define_method(rb_cPGconn, "pipeline_status", pgconn_pipeline_status, 0);
4591
+ rb_define_method(rb_cPGconn, "enter_pipeline_mode", pgconn_enter_pipeline_mode, 0);
4592
+ rb_define_method(rb_cPGconn, "exit_pipeline_mode", pgconn_exit_pipeline_mode, 0);
4593
+ rb_define_method(rb_cPGconn, "pipeline_sync", pgconn_pipeline_sync, 0);
4594
+ rb_define_method(rb_cPGconn, "send_flush_request", pgconn_send_flush_request, 0);
4595
+ #endif
4596
+
4298
4597
  /****** PG::Connection INSTANCE METHODS: Large Object Support ******/
4299
4598
  rb_define_method(rb_cPGconn, "lo_creat", pgconn_locreat, -1);
4300
4599
  rb_define_alias(rb_cPGconn, "locreat", "lo_creat");