pg 1.0.0 → 1.5.9

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 (126) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data/Gemfile +20 -0
  4. data/History.md +932 -0
  5. data/Manifest.txt +8 -3
  6. data/README-Windows.rdoc +4 -4
  7. data/README.ja.md +300 -0
  8. data/README.md +286 -0
  9. data/Rakefile +41 -138
  10. data/Rakefile.cross +71 -66
  11. data/certs/ged.pem +24 -0
  12. data/certs/kanis@comcard.de.pem +20 -0
  13. data/certs/larskanis-2022.pem +26 -0
  14. data/certs/larskanis-2023.pem +24 -0
  15. data/certs/larskanis-2024.pem +24 -0
  16. data/ext/errorcodes.def +84 -5
  17. data/ext/errorcodes.rb +1 -1
  18. data/ext/errorcodes.txt +23 -6
  19. data/ext/extconf.rb +109 -25
  20. data/ext/gvl_wrappers.c +4 -0
  21. data/ext/gvl_wrappers.h +23 -0
  22. data/ext/pg.c +213 -155
  23. data/ext/pg.h +89 -23
  24. data/ext/pg_binary_decoder.c +164 -16
  25. data/ext/pg_binary_encoder.c +238 -13
  26. data/ext/pg_coder.c +159 -35
  27. data/ext/pg_connection.c +1584 -967
  28. data/ext/pg_copy_coder.c +373 -43
  29. data/ext/pg_errors.c +1 -1
  30. data/ext/pg_record_coder.c +522 -0
  31. data/ext/pg_result.c +710 -217
  32. data/ext/pg_text_decoder.c +630 -43
  33. data/ext/pg_text_encoder.c +222 -72
  34. data/ext/pg_tuple.c +572 -0
  35. data/ext/pg_type_map.c +45 -11
  36. data/ext/pg_type_map_all_strings.c +21 -7
  37. data/ext/pg_type_map_by_class.c +59 -27
  38. data/ext/pg_type_map_by_column.c +80 -37
  39. data/ext/pg_type_map_by_mri_type.c +49 -20
  40. data/ext/pg_type_map_by_oid.c +62 -29
  41. data/ext/pg_type_map_in_ruby.c +56 -22
  42. data/ext/{util.c → pg_util.c} +12 -12
  43. data/ext/{util.h → pg_util.h} +2 -2
  44. data/lib/pg/basic_type_map_based_on_result.rb +67 -0
  45. data/lib/pg/basic_type_map_for_queries.rb +202 -0
  46. data/lib/pg/basic_type_map_for_results.rb +104 -0
  47. data/lib/pg/basic_type_registry.rb +311 -0
  48. data/lib/pg/binary_decoder/date.rb +9 -0
  49. data/lib/pg/binary_decoder/timestamp.rb +26 -0
  50. data/lib/pg/binary_encoder/timestamp.rb +20 -0
  51. data/lib/pg/coder.rb +36 -13
  52. data/lib/pg/connection.rb +769 -70
  53. data/lib/pg/exceptions.rb +22 -2
  54. data/lib/pg/result.rb +14 -2
  55. data/lib/pg/text_decoder/date.rb +21 -0
  56. data/lib/pg/text_decoder/inet.rb +9 -0
  57. data/lib/pg/text_decoder/json.rb +17 -0
  58. data/lib/pg/text_decoder/numeric.rb +9 -0
  59. data/lib/pg/text_decoder/timestamp.rb +30 -0
  60. data/lib/pg/text_encoder/date.rb +13 -0
  61. data/lib/pg/text_encoder/inet.rb +31 -0
  62. data/lib/pg/text_encoder/json.rb +17 -0
  63. data/lib/pg/text_encoder/numeric.rb +9 -0
  64. data/lib/pg/text_encoder/timestamp.rb +24 -0
  65. data/lib/pg/tuple.rb +30 -0
  66. data/lib/pg/type_map_by_column.rb +3 -2
  67. data/lib/pg/version.rb +4 -0
  68. data/lib/pg.rb +106 -39
  69. data/misc/openssl-pg-segfault.rb +31 -0
  70. data/misc/postgres/History.txt +9 -0
  71. data/misc/postgres/Manifest.txt +5 -0
  72. data/misc/postgres/README.txt +21 -0
  73. data/misc/postgres/Rakefile +21 -0
  74. data/misc/postgres/lib/postgres.rb +16 -0
  75. data/misc/ruby-pg/History.txt +9 -0
  76. data/misc/ruby-pg/Manifest.txt +5 -0
  77. data/misc/ruby-pg/README.txt +21 -0
  78. data/misc/ruby-pg/Rakefile +21 -0
  79. data/misc/ruby-pg/lib/ruby/pg.rb +16 -0
  80. data/pg.gemspec +36 -0
  81. data/rakelib/task_extension.rb +46 -0
  82. data/sample/array_insert.rb +20 -0
  83. data/sample/async_api.rb +102 -0
  84. data/sample/async_copyto.rb +39 -0
  85. data/sample/async_mixed.rb +56 -0
  86. data/sample/check_conn.rb +21 -0
  87. data/sample/copydata.rb +71 -0
  88. data/sample/copyfrom.rb +81 -0
  89. data/sample/copyto.rb +19 -0
  90. data/sample/cursor.rb +21 -0
  91. data/sample/disk_usage_report.rb +177 -0
  92. data/sample/issue-119.rb +94 -0
  93. data/sample/losample.rb +69 -0
  94. data/sample/minimal-testcase.rb +17 -0
  95. data/sample/notify_wait.rb +72 -0
  96. data/sample/pg_statistics.rb +285 -0
  97. data/sample/replication_monitor.rb +222 -0
  98. data/sample/test_binary_values.rb +33 -0
  99. data/sample/wal_shipper.rb +434 -0
  100. data/sample/warehouse_partitions.rb +311 -0
  101. data.tar.gz.sig +0 -0
  102. metadata +138 -223
  103. metadata.gz.sig +0 -0
  104. data/.gemtest +0 -0
  105. data/ChangeLog +0 -6595
  106. data/History.rdoc +0 -422
  107. data/README.ja.rdoc +0 -14
  108. data/README.rdoc +0 -167
  109. data/lib/pg/basic_type_mapping.rb +0 -426
  110. data/lib/pg/constants.rb +0 -11
  111. data/lib/pg/text_decoder.rb +0 -51
  112. data/lib/pg/text_encoder.rb +0 -35
  113. data/spec/data/expected_trace.out +0 -26
  114. data/spec/data/random_binary_data +0 -0
  115. data/spec/helpers.rb +0 -348
  116. data/spec/pg/basic_type_mapping_spec.rb +0 -305
  117. data/spec/pg/connection_spec.rb +0 -1719
  118. data/spec/pg/result_spec.rb +0 -456
  119. data/spec/pg/type_map_by_class_spec.rb +0 -138
  120. data/spec/pg/type_map_by_column_spec.rb +0 -222
  121. data/spec/pg/type_map_by_mri_type_spec.rb +0 -136
  122. data/spec/pg/type_map_by_oid_spec.rb +0 -149
  123. data/spec/pg/type_map_in_ruby_spec.rb +0 -164
  124. data/spec/pg/type_map_spec.rb +0 -22
  125. data/spec/pg/type_spec.rb +0 -777
  126. data/spec/pg_spec.rb +0 -50
data/ext/pg_connection.c CHANGED
@@ -1,6 +1,6 @@
1
1
  /*
2
2
  * pg_connection.c - PG::Connection class extension
3
- * $Id: pg_connection.c,v 1f0926bfa9a5 2018/01/04 18:14:32 lars $
3
+ * $Id$
4
4
  *
5
5
  */
6
6
 
@@ -12,19 +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 PQnoticeReceiver default_notice_receiver = NULL;
18
- static PQnoticeProcessor default_notice_processor = NULL;
17
+ static VALUE sym_symbol, sym_string, sym_static_symbol;
19
18
 
20
19
  static VALUE pgconn_finish( VALUE );
21
20
  static VALUE pgconn_set_default_encoding( VALUE self );
22
- void pgconn_set_internal_encoding_index( VALUE );
21
+ static VALUE pgconn_wait_for_flush( VALUE self );
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);
23
25
 
24
26
  /*
25
27
  * Global functions
26
28
  */
27
29
 
30
+ /*
31
+ * Convenience function to raise connection errors
32
+ */
33
+ #ifdef __GNUC__
34
+ __attribute__((format(printf, 3, 4)))
35
+ #endif
36
+ NORETURN( 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
+
28
50
  /*
29
51
  * Fetch the PG::Connection object data pointer.
30
52
  */
@@ -32,7 +54,7 @@ t_pg_connection *
32
54
  pg_get_connection( VALUE self )
33
55
  {
34
56
  t_pg_connection *this;
35
- Data_Get_Struct( self, t_pg_connection, this);
57
+ TypedData_Get_Struct( self, t_pg_connection, &pg_connection_type, this);
36
58
 
37
59
  return this;
38
60
  }
@@ -45,10 +67,10 @@ static t_pg_connection *
45
67
  pg_get_connection_safe( VALUE self )
46
68
  {
47
69
  t_pg_connection *this;
48
- Data_Get_Struct( self, t_pg_connection, this);
70
+ TypedData_Get_Struct( self, t_pg_connection, &pg_connection_type, this);
49
71
 
50
72
  if ( !this->pgconn )
51
- rb_raise( rb_eConnectionBad, "connection is closed" );
73
+ pg_raise_conn_error( rb_eConnectionBad, self, "connection is closed");
52
74
 
53
75
  return this;
54
76
  }
@@ -64,10 +86,11 @@ PGconn *
64
86
  pg_get_pgconn( VALUE self )
65
87
  {
66
88
  t_pg_connection *this;
67
- Data_Get_Struct( self, t_pg_connection, this);
89
+ TypedData_Get_Struct( self, t_pg_connection, &pg_connection_type, this);
68
90
 
69
- if ( !this->pgconn )
70
- rb_raise( rb_eConnectionBad, "connection is closed" );
91
+ if ( !this->pgconn ){
92
+ pg_raise_conn_error( rb_eConnectionBad, self, "connection is closed");
93
+ }
71
94
 
72
95
  return this->pgconn;
73
96
  }
@@ -85,15 +108,13 @@ pgconn_close_socket_io( VALUE self )
85
108
 
86
109
  if ( RTEST(socket_io) ) {
87
110
  #if defined(_WIN32)
88
- int ruby_sd = NUM2INT(rb_funcall( socket_io, rb_intern("fileno"), 0 ));
89
- if( rb_w32_unwrap_io_handle(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,17 +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->external_encoding );
157
- rb_gc_mark( this->encoder_for_put_copy_data );
158
- 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 );
159
194
  }
160
195
 
161
196
 
@@ -163,14 +198,45 @@ pgconn_gc_mark( t_pg_connection *this )
163
198
  * GC Free function
164
199
  */
165
200
  static void
166
- pgconn_gc_free( t_pg_connection *this )
201
+ pgconn_gc_free( void *_this )
167
202
  {
203
+ t_pg_connection *this = (t_pg_connection *)_this;
204
+ #if defined(_WIN32)
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
+ }
210
+ #endif
168
211
  if (this->pgconn != NULL)
169
212
  PQfinish( this->pgconn );
170
213
 
171
214
  xfree(this);
172
215
  }
173
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
+
174
240
 
175
241
  /**************************************************************************
176
242
  * Class Methods
@@ -186,99 +252,39 @@ static VALUE
186
252
  pgconn_s_allocate( VALUE klass )
187
253
  {
188
254
  t_pg_connection *this;
189
- 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 );
190
256
 
191
257
  this->pgconn = NULL;
192
- this->socket_io = Qnil;
193
- this->notice_receiver = Qnil;
194
- this->notice_processor = Qnil;
195
- this->type_map_for_queries = pg_typemap_all_strings;
196
- this->type_map_for_results = pg_typemap_all_strings;
197
- this->encoder_for_put_copy_data = Qnil;
198
- this->decoder_for_get_copy_data = Qnil;
199
- this->trace_stream = Qnil;
200
- this->external_encoding = 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));
267
+ rb_ivar_set(self, rb_intern("@iopts_for_reset"), Qnil);
201
268
 
202
269
  return self;
203
270
  }
204
271
 
205
-
206
- /*
207
- * Document-method: new
208
- *
209
- * call-seq:
210
- * PG::Connection.new -> conn
211
- * PG::Connection.new(connection_hash) -> conn
212
- * PG::Connection.new(connection_string) -> conn
213
- * PG::Connection.new(host, port, options, tty, dbname, user, password) -> conn
214
- *
215
- * Create a connection to the specified server.
216
- *
217
- * [+host+]
218
- * server hostname
219
- * [+hostaddr+]
220
- * server address (avoids hostname lookup, overrides +host+)
221
- * [+port+]
222
- * server port number
223
- * [+dbname+]
224
- * connecting database name
225
- * [+user+]
226
- * login user name
227
- * [+password+]
228
- * login password
229
- * [+connect_timeout+]
230
- * maximum time to wait for connection to succeed
231
- * [+options+]
232
- * backend options
233
- * [+tty+]
234
- * (ignored in newer versions of PostgreSQL)
235
- * [+sslmode+]
236
- * (disable|allow|prefer|require)
237
- * [+krbsrvname+]
238
- * kerberos service name
239
- * [+gsslib+]
240
- * GSS library to use for GSSAPI authentication
241
- * [+service+]
242
- * service name to use for additional parameters
243
- *
244
- * Examples:
245
- *
246
- * # Connect using all defaults
247
- * PG::Connection.new
248
- *
249
- * # As a Hash
250
- * PG::Connection.new( :dbname => 'test', :port => 5432 )
251
- *
252
- * # As a String
253
- * PG::Connection.new( "dbname=test port=5432" )
254
- *
255
- * # As an Array
256
- * PG::Connection.new( nil, 5432, nil, nil, 'test', nil, nil )
257
- *
258
- * If the Ruby default internal encoding is set (i.e., Encoding.default_internal != nil), the
259
- * connection will have its +client_encoding+ set accordingly.
260
- *
261
- * Raises a PG::Error if the connection fails.
262
- */
263
272
  static VALUE
264
- pgconn_init(int argc, VALUE *argv, VALUE self)
273
+ pgconn_s_sync_connect(int argc, VALUE *argv, VALUE klass)
265
274
  {
266
275
  t_pg_connection *this;
267
276
  VALUE conninfo;
268
- VALUE error;
277
+ VALUE self = pgconn_s_allocate( klass );
269
278
 
270
279
  this = pg_get_connection( self );
271
280
  conninfo = rb_funcall2( rb_cPGconn, rb_intern("parse_connect_args"), argc, argv );
272
281
  this->pgconn = gvl_PQconnectdb(StringValueCStr(conninfo));
273
282
 
274
283
  if(this->pgconn == NULL)
275
- rb_raise(rb_ePGerror, "PQconnectdb() unable to allocate structure");
284
+ rb_raise(rb_ePGerror, "PQconnectdb() unable to allocate PGconn structure");
276
285
 
277
- if (PQstatus(this->pgconn) == CONNECTION_BAD) {
278
- error = rb_exc_new2(rb_eConnectionBad, PQerrorMessage(this->pgconn));
279
- rb_iv_set(error, "@connection", self);
280
- rb_exc_raise(error);
281
- }
286
+ if (PQstatus(this->pgconn) == CONNECTION_BAD)
287
+ pg_raise_conn_error( rb_eConnectionBad, self, "%s", PQerrorMessage(this->pgconn));
282
288
 
283
289
  pgconn_set_default_encoding( self );
284
290
 
@@ -294,14 +300,16 @@ pgconn_init(int argc, VALUE *argv, VALUE self)
294
300
  * PG::Connection.connect_start(connection_string) -> conn
295
301
  * PG::Connection.connect_start(host, port, options, tty, dbname, login, password) -> conn
296
302
  *
297
- * This is an asynchronous version of PG::Connection.connect().
303
+ * This is an asynchronous version of PG::Connection.new.
298
304
  *
299
305
  * Use #connect_poll to poll the status of the connection.
300
306
  *
301
307
  * NOTE: this does *not* set the connection's +client_encoding+ for you if
302
- * Encoding.default_internal is set. To set it after the connection is established,
308
+ * +Encoding.default_internal+ is set. To set it after the connection is established,
303
309
  * call #internal_encoding=. You can also set it automatically by setting
304
- * ENV['PGCLIENTENCODING'], or include the 'options' connection parameter.
310
+ * <code>ENV['PGCLIENTENCODING']</code>, or include the 'options' connection parameter.
311
+ *
312
+ * See also the 'sample' directory of this gem and the corresponding {libpq functions}[https://www.postgresql.org/docs/current/libpq-connect.html#LIBPQ-PQCONNECTSTARTPARAMS].
305
313
  *
306
314
  */
307
315
  static VALUE
@@ -309,7 +317,6 @@ pgconn_s_connect_start( int argc, VALUE *argv, VALUE klass )
309
317
  {
310
318
  VALUE rb_conn;
311
319
  VALUE conninfo;
312
- VALUE error;
313
320
  t_pg_connection *this;
314
321
 
315
322
  /*
@@ -322,13 +329,10 @@ pgconn_s_connect_start( int argc, VALUE *argv, VALUE klass )
322
329
  this->pgconn = gvl_PQconnectStart( StringValueCStr(conninfo) );
323
330
 
324
331
  if( this->pgconn == NULL )
325
- rb_raise(rb_ePGerror, "PQconnectStart() unable to allocate structure");
332
+ rb_raise(rb_ePGerror, "PQconnectStart() unable to allocate PGconn structure");
326
333
 
327
- if ( PQstatus(this->pgconn) == CONNECTION_BAD ) {
328
- error = rb_exc_new2(rb_eConnectionBad, PQerrorMessage(this->pgconn));
329
- rb_iv_set(error, "@connection", rb_conn);
330
- rb_exc_raise(error);
331
- }
334
+ if ( PQstatus(this->pgconn) == CONNECTION_BAD )
335
+ pg_raise_conn_error( rb_eConnectionBad, rb_conn, "%s", PQerrorMessage(this->pgconn));
332
336
 
333
337
  if ( rb_block_given_p() ) {
334
338
  return rb_ensure( rb_yield, rb_conn, pgconn_finish, rb_conn );
@@ -336,34 +340,14 @@ pgconn_s_connect_start( int argc, VALUE *argv, VALUE klass )
336
340
  return rb_conn;
337
341
  }
338
342
 
339
- /*
340
- * call-seq:
341
- * PG::Connection.ping(connection_hash) -> Integer
342
- * PG::Connection.ping(connection_string) -> Integer
343
- * PG::Connection.ping(host, port, options, tty, dbname, login, password) -> Integer
344
- *
345
- * Check server status.
346
- *
347
- * Returns one of:
348
- * [+PQPING_OK+]
349
- * server is accepting connections
350
- * [+PQPING_REJECT+]
351
- * server is alive but rejecting connections
352
- * [+PQPING_NO_RESPONSE+]
353
- * could not establish connection
354
- * [+PQPING_NO_ATTEMPT+]
355
- * connection not attempted (bad params)
356
- *
357
- * Available since PostgreSQL-9.1
358
- */
359
343
  static VALUE
360
- pgconn_s_ping( int argc, VALUE *argv, VALUE klass )
344
+ pgconn_s_sync_ping( int argc, VALUE *argv, VALUE klass )
361
345
  {
362
346
  PGPing ping;
363
347
  VALUE conninfo;
364
348
 
365
349
  conninfo = rb_funcall2( klass, rb_intern("parse_connect_args"), argc, argv );
366
- ping = PQping( StringValueCStr(conninfo) );
350
+ ping = gvl_PQping( StringValueCStr(conninfo) );
367
351
 
368
352
  return INT2FIX((int)ping);
369
353
  }
@@ -404,31 +388,40 @@ pgconn_s_conndefaults(VALUE self)
404
388
  return array;
405
389
  }
406
390
 
407
-
408
- #ifdef HAVE_PQENCRYPTPASSWORDCONN
409
391
  /*
410
- * call-seq:
411
- * conn.encrypt_password( password, username, algorithm=nil ) -> String
412
- *
413
- * This function is intended to be used by client applications that wish to send commands like <tt>ALTER USER joe PASSWORD 'pwd'</tt>.
414
- * 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.
415
- * Instead, use this function to convert the password to encrypted form before it is sent.
392
+ * Document-method: PG::Connection.conninfo_parse
416
393
  *
417
- * The +password+ and +username+ arguments are the cleartext password, and the SQL name of the user it is for.
418
- * +algorithm+ specifies the encryption algorithm to use to encrypt the password.
419
- * 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).
420
- * Note that support for +scram-sha-256+ was introduced in PostgreSQL version 10, and will not work correctly with older server versions.
421
- * If algorithm is omitted or +nil+, this function will query the server for the current value of the +password_encryption+ setting.
422
- * That can block, and will fail if the current transaction is aborted, or if the connection is busy executing another query.
423
- * 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.
424
- *
425
- * Return value is the encrypted password.
426
- * The caller can assume the string doesn't contain any special characters that would require escaping.
394
+ * call-seq:
395
+ * PG::Connection.conninfo_parse(conninfo_string) -> Array
427
396
  *
428
- * Available since PostgreSQL-10
397
+ * Returns parsed connection options from the provided connection string as an array of hashes.
398
+ * Each hash has the same keys as PG::Connection.conndefaults() .
399
+ * The values from the +conninfo_string+ are stored in the +:val+ key.
429
400
  */
430
401
  static VALUE
431
- pgconn_encrypt_password(int argc, VALUE *argv, VALUE self)
402
+ pgconn_s_conninfo_parse(VALUE self, VALUE conninfo)
403
+ {
404
+ VALUE array;
405
+ char *errmsg = NULL;
406
+ PQconninfoOption *options = PQconninfoParse(StringValueCStr(conninfo), &errmsg);
407
+ if(errmsg){
408
+ VALUE error = rb_str_new_cstr(errmsg);
409
+ PQfreemem(errmsg);
410
+ rb_raise(rb_ePGerror, "%"PRIsVALUE, error);
411
+ }
412
+ array = pgconn_make_conninfo_array( options );
413
+
414
+ PQconninfoFree(options);
415
+
416
+ UNUSED( self );
417
+
418
+ return array;
419
+ }
420
+
421
+
422
+ #ifdef HAVE_PQENCRYPTPASSWORDCONN
423
+ static VALUE
424
+ pgconn_sync_encrypt_password(int argc, VALUE *argv, VALUE self)
432
425
  {
433
426
  char *encrypted = NULL;
434
427
  VALUE rval = Qnil;
@@ -444,12 +437,8 @@ pgconn_encrypt_password(int argc, VALUE *argv, VALUE self)
444
437
  if ( encrypted ) {
445
438
  rval = rb_str_new2( encrypted );
446
439
  PQfreemem( encrypted );
447
-
448
- OBJ_INFECT( rval, password );
449
- OBJ_INFECT( rval, username );
450
- OBJ_INFECT( rval, algorithm );
451
440
  } else {
452
- rb_raise(rb_ePGerror, "%s", PQerrorMessage(conn));
441
+ pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(conn));
453
442
  }
454
443
 
455
444
  return rval;
@@ -480,9 +469,6 @@ pgconn_s_encrypt_password(VALUE self, VALUE password, VALUE username)
480
469
  rval = rb_str_new2( encrypted );
481
470
  PQfreemem( encrypted );
482
471
 
483
- OBJ_INFECT( rval, password );
484
- OBJ_INFECT( rval, username );
485
-
486
472
  return rval;
487
473
  }
488
474
 
@@ -506,17 +492,18 @@ pgconn_s_encrypt_password(VALUE self, VALUE password, VALUE username)
506
492
  * the asynchronous connection is ready
507
493
  *
508
494
  * Example:
509
- * conn = PG::Connection.connect_start("dbname=mydatabase")
510
- * socket = conn.socket_io
495
+ * require "io/wait"
496
+ *
497
+ * conn = PG::Connection.connect_start(dbname: 'mydatabase')
511
498
  * status = conn.connect_poll
512
499
  * while(status != PG::PGRES_POLLING_OK) do
513
500
  * # do some work while waiting for the connection to complete
514
501
  * if(status == PG::PGRES_POLLING_READING)
515
- * if(not select([socket], [], [], 10.0))
502
+ * unless conn.socket_io.wait_readable(10.0)
516
503
  * raise "Asynchronous connection timed out!"
517
504
  * end
518
505
  * elsif(status == PG::PGRES_POLLING_WRITING)
519
- * if(not select([], [socket], [], 10.0))
506
+ * unless conn.socket_io.wait_writable(10.0)
520
507
  * raise "Asynchronous connection timed out!"
521
508
  * end
522
509
  * end
@@ -529,7 +516,10 @@ static VALUE
529
516
  pgconn_connect_poll(VALUE self)
530
517
  {
531
518
  PostgresPollingStatusType status;
519
+
520
+ pgconn_close_socket_io(self);
532
521
  status = gvl_PQconnectPoll(pg_get_pgconn(self));
522
+
533
523
  return INT2FIX((int)status);
534
524
  }
535
525
 
@@ -566,21 +556,35 @@ pgconn_finished_p( VALUE self )
566
556
  }
567
557
 
568
558
 
569
- /*
570
- * call-seq:
571
- * conn.reset()
572
- *
573
- * Resets the backend connection. This method closes the
574
- * backend connection and tries to re-connect.
575
- */
576
559
  static VALUE
577
- pgconn_reset( VALUE self )
560
+ pgconn_sync_reset( VALUE self )
578
561
  {
579
562
  pgconn_close_socket_io( self );
580
563
  gvl_PQreset( pg_get_pgconn(self) );
581
564
  return self;
582
565
  }
583
566
 
567
+ static VALUE
568
+ pgconn_reset_start2( VALUE self, VALUE conninfo )
569
+ {
570
+ t_pg_connection *this = pg_get_connection( self );
571
+
572
+ /* Close old connection */
573
+ pgconn_close_socket_io( self );
574
+ PQfinish( this->pgconn );
575
+
576
+ /* Start new connection */
577
+ this->pgconn = gvl_PQconnectStart( StringValueCStr(conninfo) );
578
+
579
+ if( this->pgconn == NULL )
580
+ rb_raise(rb_ePGerror, "PQconnectStart() unable to allocate PGconn structure");
581
+
582
+ if ( PQstatus(this->pgconn) == CONNECTION_BAD )
583
+ pg_raise_conn_error( rb_eConnectionBad, self, "%s", PQerrorMessage(this->pgconn));
584
+
585
+ return Qnil;
586
+ }
587
+
584
588
  /*
585
589
  * call-seq:
586
590
  * conn.reset_start() -> nil
@@ -596,7 +600,7 @@ pgconn_reset_start(VALUE self)
596
600
  {
597
601
  pgconn_close_socket_io( self );
598
602
  if(gvl_PQresetStart(pg_get_pgconn(self)) == 0)
599
- rb_raise(rb_eUnableToSend, "reset has failed");
603
+ pg_raise_conn_error( rb_eUnableToSend, self, "reset has failed");
600
604
  return Qnil;
601
605
  }
602
606
 
@@ -612,7 +616,10 @@ static VALUE
612
616
  pgconn_reset_poll(VALUE self)
613
617
  {
614
618
  PostgresPollingStatusType status;
619
+
620
+ pgconn_close_socket_io(self);
615
621
  status = gvl_PQresetPoll(pg_get_pgconn(self));
622
+
616
623
  return INT2FIX((int)status);
617
624
  }
618
625
 
@@ -628,7 +635,7 @@ pgconn_db(VALUE self)
628
635
  {
629
636
  char *db = PQdb(pg_get_pgconn(self));
630
637
  if (!db) return Qnil;
631
- return rb_tainted_str_new2(db);
638
+ return rb_str_new2(db);
632
639
  }
633
640
 
634
641
  /*
@@ -642,7 +649,7 @@ pgconn_user(VALUE self)
642
649
  {
643
650
  char *user = PQuser(pg_get_pgconn(self));
644
651
  if (!user) return Qnil;
645
- return rb_tainted_str_new2(user);
652
+ return rb_str_new2(user);
646
653
  }
647
654
 
648
655
  /*
@@ -656,22 +663,53 @@ pgconn_pass(VALUE self)
656
663
  {
657
664
  char *user = PQpass(pg_get_pgconn(self));
658
665
  if (!user) return Qnil;
659
- return rb_tainted_str_new2(user);
666
+ return rb_str_new2(user);
660
667
  }
661
668
 
662
669
  /*
663
670
  * call-seq:
664
671
  * conn.host()
665
672
  *
666
- * Returns the connected server name.
673
+ * Returns the server host name of the active connection.
674
+ * This can be a host name, an IP address, or a directory path if the connection is via Unix socket.
675
+ * (The path case can be distinguished because it will always be an absolute path, beginning with +/+ .)
676
+ *
677
+ * If the connection parameters specified both host and hostaddr, then +host+ will return the host information.
678
+ * If only hostaddr was specified, then that is returned.
679
+ * If multiple hosts were specified in the connection parameters, +host+ returns the host actually connected to.
680
+ *
681
+ * 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.
682
+ *
683
+ * 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.
684
+ * The status of the connection can be checked using the function Connection#status .
667
685
  */
668
686
  static VALUE
669
687
  pgconn_host(VALUE self)
670
688
  {
671
689
  char *host = PQhost(pg_get_pgconn(self));
672
690
  if (!host) return Qnil;
673
- return rb_tainted_str_new2(host);
691
+ return rb_str_new2(host);
692
+ }
693
+
694
+ /* PQhostaddr() appeared in PostgreSQL-12 together with PQresultMemorySize() */
695
+ #if defined(HAVE_PQRESULTMEMORYSIZE)
696
+ /*
697
+ * call-seq:
698
+ * conn.hostaddr()
699
+ *
700
+ * Returns the server IP address of the active connection.
701
+ * This can be the address that a host name resolved to, or an IP address provided through the hostaddr parameter.
702
+ * 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.
703
+ *
704
+ */
705
+ static VALUE
706
+ pgconn_hostaddr(VALUE self)
707
+ {
708
+ char *host = PQhostaddr(pg_get_pgconn(self));
709
+ if (!host) return Qnil;
710
+ return rb_str_new2(host);
674
711
  }
712
+ #endif
675
713
 
676
714
  /*
677
715
  * call-seq:
@@ -683,21 +721,22 @@ static VALUE
683
721
  pgconn_port(VALUE self)
684
722
  {
685
723
  char* port = PQport(pg_get_pgconn(self));
686
- return INT2NUM(atol(port));
724
+ if (!port || port[0] == '\0')
725
+ return INT2NUM(DEF_PGPORT);
726
+ else
727
+ return INT2NUM(atoi(port));
687
728
  }
688
729
 
689
730
  /*
690
731
  * call-seq:
691
732
  * conn.tty()
692
733
  *
693
- * Returns the connected pgtty. (Obsolete)
734
+ * Obsolete function.
694
735
  */
695
736
  static VALUE
696
737
  pgconn_tty(VALUE self)
697
738
  {
698
- char *tty = PQtty(pg_get_pgconn(self));
699
- if (!tty) return Qnil;
700
- return rb_tainted_str_new2(tty);
739
+ return rb_str_new2("");
701
740
  }
702
741
 
703
742
  /*
@@ -711,11 +750,10 @@ pgconn_options(VALUE self)
711
750
  {
712
751
  char *options = PQoptions(pg_get_pgconn(self));
713
752
  if (!options) return Qnil;
714
- return rb_tainted_str_new2(options);
753
+ return rb_str_new2(options);
715
754
  }
716
755
 
717
756
 
718
- #ifdef HAVE_PQCONNINFO
719
757
  /*
720
758
  * call-seq:
721
759
  * conn.conninfo -> hash
@@ -735,14 +773,24 @@ pgconn_conninfo( VALUE self )
735
773
 
736
774
  return array;
737
775
  }
738
- #endif
739
776
 
740
777
 
741
778
  /*
742
779
  * call-seq:
743
780
  * conn.status()
744
781
  *
745
- * Returns status of connection : CONNECTION_OK or CONNECTION_BAD
782
+ * Returns the status of the connection, which is one:
783
+ * PG::Constants::CONNECTION_OK
784
+ * PG::Constants::CONNECTION_BAD
785
+ *
786
+ * ... and other constants of kind PG::Constants::CONNECTION_*
787
+ *
788
+ * This method returns the status of the last command from memory.
789
+ * It doesn't do any socket access hence is not suitable to test the connectivity.
790
+ * See check_socket for a way to verify the socket state.
791
+ *
792
+ * Example:
793
+ * PG.constants.grep(/CONNECTION_/).find{|c| PG.const_get(c) == conn.status} # => :CONNECTION_OK
746
794
  */
747
795
  static VALUE
748
796
  pgconn_status(VALUE self)
@@ -792,7 +840,7 @@ pgconn_parameter_status(VALUE self, VALUE param_name)
792
840
  if(ret == NULL)
793
841
  return Qnil;
794
842
  else
795
- return rb_tainted_str_new2(ret);
843
+ return rb_str_new2(ret);
796
844
  }
797
845
 
798
846
  /*
@@ -830,14 +878,17 @@ pgconn_server_version(VALUE self)
830
878
  * call-seq:
831
879
  * conn.error_message -> String
832
880
  *
833
- * Returns the error message about connection.
881
+ * Returns the error message most recently generated by an operation on the connection.
882
+ *
883
+ * Nearly all libpq functions will set a message for conn.error_message if they fail.
884
+ * Note that by libpq convention, a nonempty error_message result can consist of multiple lines, and will include a trailing newline.
834
885
  */
835
886
  static VALUE
836
887
  pgconn_error_message(VALUE self)
837
888
  {
838
889
  char *error = PQerrorMessage(pg_get_pgconn(self));
839
890
  if (!error) return Qnil;
840
- return rb_tainted_str_new2(error);
891
+ return rb_str_new2(error);
841
892
  }
842
893
 
843
894
  /*
@@ -861,8 +912,11 @@ static VALUE
861
912
  pgconn_socket(VALUE self)
862
913
  {
863
914
  int sd;
915
+ pg_deprecated(4, ("conn.socket is deprecated and should be replaced by conn.socket_io"));
916
+
864
917
  if( (sd = PQsocket(pg_get_pgconn(self))) < 0)
865
- rb_raise(rb_eConnectionBad, "PQsocket() can't get socket descriptor");
918
+ pg_raise_conn_error( rb_eConnectionBad, self, "PQsocket() can't get socket descriptor");
919
+
866
920
  return INT2NUM(sd);
867
921
  }
868
922
 
@@ -870,41 +924,47 @@ pgconn_socket(VALUE self)
870
924
  * call-seq:
871
925
  * conn.socket_io() -> IO
872
926
  *
873
- * Fetch a memorized IO object created from the Connection's underlying socket.
874
- * This object can be used for IO.select to wait for events while running
875
- * asynchronous API calls.
927
+ * Fetch an IO object created from the Connection's underlying socket.
928
+ * 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.
929
+ * <tt>IO#wait_*able</tt> is is <tt>Fiber.scheduler</tt> compatible in contrast to <tt>IO.select</tt>.
876
930
  *
877
- * Using this instead of #socket avoids the problem of the underlying connection
878
- * being closed by Ruby when an IO created using <tt>IO.for_fd(conn.socket)</tt>
879
- * goes out of scope. In contrast to #socket, it also works on Windows.
931
+ * The IO object can change while the connection is established, but is memorized afterwards.
932
+ * So be sure not to cache the IO object, but repeat calling <tt>conn.socket_io</tt> instead.
933
+ *
934
+ * Using this method also works on Windows in contrast to using #socket .
935
+ * 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.
880
936
  */
881
937
  static VALUE
882
938
  pgconn_socket_io(VALUE self)
883
939
  {
884
940
  int sd;
885
941
  int ruby_sd;
886
- ID id_autoclose = rb_intern("autoclose=");
887
942
  t_pg_connection *this = pg_get_connection_safe( self );
943
+ VALUE cSocket;
888
944
  VALUE socket_io = this->socket_io;
889
945
 
890
946
  if ( !RTEST(socket_io) ) {
891
- if( (sd = PQsocket(this->pgconn)) < 0)
892
- rb_raise(rb_eConnectionBad, "PQsocket() can't get socket descriptor");
947
+ if( (sd = PQsocket(this->pgconn)) < 0){
948
+ pg_raise_conn_error( rb_eConnectionBad, self, "PQsocket() can't get socket descriptor");
949
+ }
893
950
 
894
951
  #ifdef _WIN32
895
952
  ruby_sd = rb_w32_wrap_io_handle((HANDLE)(intptr_t)sd, O_RDWR|O_BINARY|O_NOINHERIT);
953
+ if( ruby_sd == -1 )
954
+ pg_raise_conn_error( rb_eConnectionBad, self, "Could not wrap win32 socket handle");
955
+
956
+ this->ruby_sd = ruby_sd;
896
957
  #else
897
958
  ruby_sd = sd;
898
959
  #endif
899
960
 
900
- socket_io = rb_funcall( rb_cIO, rb_intern("for_fd"), 1, INT2NUM(ruby_sd) );
961
+ cSocket = rb_const_get(rb_cObject, rb_intern("BasicSocket"));
962
+ socket_io = rb_funcall( cSocket, rb_intern("for_fd"), 1, INT2NUM(ruby_sd));
901
963
 
902
- /* Disable autoclose feature, when supported */
903
- if( rb_respond_to(socket_io, id_autoclose) ){
904
- rb_funcall( socket_io, id_autoclose, 1, Qfalse );
905
- }
964
+ /* Disable autoclose feature */
965
+ rb_funcall( socket_io, s_id_autoclose_set, 1, Qfalse );
906
966
 
907
- this->socket_io = socket_io;
967
+ RB_OBJ_WRITE(self, &this->socket_io, socket_io);
908
968
  }
909
969
 
910
970
  return socket_io;
@@ -924,6 +984,51 @@ pgconn_backend_pid(VALUE self)
924
984
  return INT2NUM(PQbackendPID(pg_get_pgconn(self)));
925
985
  }
926
986
 
987
+ typedef struct
988
+ {
989
+ struct sockaddr_storage addr;
990
+ socklen_t salen;
991
+ } SockAddr;
992
+
993
+ /* Copy of struct pg_cancel from libpq-int.h
994
+ *
995
+ * See https://github.com/postgres/postgres/blame/master/src/interfaces/libpq/libpq-int.h#L577-L586
996
+ */
997
+ struct pg_cancel
998
+ {
999
+ SockAddr raddr; /* Remote address */
1000
+ int be_pid; /* PID of backend --- needed for cancels */
1001
+ int be_key; /* key of backend --- needed for cancels */
1002
+ };
1003
+
1004
+ /*
1005
+ * call-seq:
1006
+ * conn.backend_key() -> Integer
1007
+ *
1008
+ * Returns the key of the backend server process for this connection.
1009
+ * This key can be used to cancel queries on the server.
1010
+ */
1011
+ static VALUE
1012
+ pgconn_backend_key(VALUE self)
1013
+ {
1014
+ int be_key;
1015
+ struct pg_cancel *cancel;
1016
+ PGconn *conn = pg_get_pgconn(self);
1017
+
1018
+ cancel = (struct pg_cancel*)PQgetCancel(conn);
1019
+ if(cancel == NULL)
1020
+ pg_raise_conn_error( rb_ePGerror, self, "Invalid connection!");
1021
+
1022
+ if( cancel->be_pid != PQbackendPID(conn) )
1023
+ rb_raise(rb_ePGerror,"Unexpected binary struct layout - please file a bug report at ruby-pg!");
1024
+
1025
+ be_key = cancel->be_key;
1026
+
1027
+ PQfreeCancel(cancel);
1028
+
1029
+ return INT2NUM(be_key);
1030
+ }
1031
+
927
1032
  /*
928
1033
  * call-seq:
929
1034
  * conn.connection_needs_password() -> Boolean
@@ -954,44 +1059,35 @@ pgconn_connection_used_password(VALUE self)
954
1059
  /* :TODO: get_ssl */
955
1060
 
956
1061
 
957
- static VALUE pgconn_exec_params( int, VALUE *, VALUE );
1062
+ static VALUE pgconn_sync_exec_params( int, VALUE *, VALUE );
958
1063
 
959
1064
  /*
960
1065
  * call-seq:
961
- * conn.exec(sql) -> PG::Result
962
- * conn.exec(sql) {|pg_result| block }
963
- *
964
- * Sends SQL query request specified by _sql_ to PostgreSQL.
965
- * Returns a PG::Result instance on success.
966
- * On failure, it raises a PG::Error.
1066
+ * conn.sync_exec(sql) -> PG::Result
1067
+ * conn.sync_exec(sql) {|pg_result| block }
967
1068
  *
968
- * For backward compatibility, if you pass more than one parameter to this method,
969
- * it will call #exec_params for you. New code should explicitly use #exec_params if
970
- * argument placeholders are used.
1069
+ * This function has the same behavior as #async_exec, but is implemented using the synchronous command processing API of libpq.
1070
+ * It's not recommended to use explicit sync or async variants but #exec instead, unless you have a good reason to do so.
971
1071
  *
972
- * If the optional code block is given, it will be passed <i>result</i> as an argument,
973
- * and the PG::Result object will automatically be cleared when the block terminates.
974
- * In this instance, <code>conn.exec</code> returns the value of the block.
1072
+ * Both #sync_exec and #async_exec release the GVL while waiting for server response, so that concurrent threads will get executed.
1073
+ * However #async_exec has two advantages:
975
1074
  *
976
- * #exec is implemented on the synchronous command processing API of libpq, whereas
977
- * #async_exec is implemented on the asynchronous API.
978
- * #exec is somewhat faster that #async_exec, but blocks any signals to be processed until
979
- * the query is finished. This is most notably visible by a delayed reaction to Control+C.
980
- * Both methods ensure that other threads can process while waiting for the server to
981
- * complete the request.
1075
+ * 1. #async_exec can be aborted by signals (like Ctrl-C), while #exec blocks signal processing until the query is answered.
1076
+ * 2. Ruby VM gets notified about IO blocked operations and can pass them through <tt>Fiber.scheduler</tt>.
1077
+ * So only <tt>async_*</tt> methods are compatible to event based schedulers like the async gem.
982
1078
  */
983
1079
  static VALUE
984
- pgconn_exec(int argc, VALUE *argv, VALUE self)
1080
+ pgconn_sync_exec(int argc, VALUE *argv, VALUE self)
985
1081
  {
986
- PGconn *conn = pg_get_pgconn(self);
1082
+ t_pg_connection *this = pg_get_connection_safe( self );
987
1083
  PGresult *result = NULL;
988
1084
  VALUE rb_pgresult;
989
1085
 
990
- /* If called with no parameters, use PQexec */
991
- if ( argc == 1 ) {
1086
+ /* If called with no or nil parameters, use PQexec for compatibility */
1087
+ if ( argc == 1 || (argc >= 2 && argc <= 4 && NIL_P(argv[1]) )) {
992
1088
  VALUE query_str = argv[0];
993
1089
 
994
- result = gvl_PQexec(conn, pg_cstr_enc(query_str, ENCODING_GET(self)));
1090
+ result = gvl_PQexec(this->pgconn, pg_cstr_enc(query_str, this->enc_idx));
995
1091
  rb_pgresult = pg_new_result(result, self);
996
1092
  pg_result_check(rb_pgresult);
997
1093
  if (rb_block_given_p()) {
@@ -999,11 +1095,10 @@ pgconn_exec(int argc, VALUE *argv, VALUE self)
999
1095
  }
1000
1096
  return rb_pgresult;
1001
1097
  }
1098
+ pg_deprecated(0, ("forwarding exec to exec_params is deprecated"));
1002
1099
 
1003
1100
  /* Otherwise, just call #exec_params instead for backward-compatibility */
1004
- else {
1005
- return pgconn_exec_params( argc, argv, self );
1006
- }
1101
+ return pgconn_sync_exec_params( argc, argv, self );
1007
1102
 
1008
1103
  }
1009
1104
 
@@ -1035,7 +1130,7 @@ struct query_params_data {
1035
1130
  * Filled by alloc_query_params()
1036
1131
  */
1037
1132
 
1038
- /* Wraps the pointer of allocated memory, if function parameters dont't
1133
+ /* Wraps the pointer of allocated memory, if function parameters don't
1039
1134
  * fit in the memory_pool below.
1040
1135
  */
1041
1136
  VALUE heap_pool;
@@ -1053,7 +1148,7 @@ struct query_params_data {
1053
1148
  Oid *types;
1054
1149
 
1055
1150
  /* This array takes the string values for the timeframe of the query,
1056
- * if param value convertion is required
1151
+ * if param value conversion is required
1057
1152
  */
1058
1153
  VALUE gc_array;
1059
1154
 
@@ -1067,8 +1162,9 @@ struct query_params_data {
1067
1162
  };
1068
1163
 
1069
1164
  static void
1070
- free_typecast_heap_chain(struct linked_typecast_data *chain_entry)
1165
+ free_typecast_heap_chain(void *_chain_entry)
1071
1166
  {
1167
+ struct linked_typecast_data *chain_entry = (struct linked_typecast_data *)_chain_entry;
1072
1168
  while(chain_entry){
1073
1169
  struct linked_typecast_data *next = chain_entry->next;
1074
1170
  xfree(chain_entry);
@@ -1076,6 +1172,18 @@ free_typecast_heap_chain(struct linked_typecast_data *chain_entry)
1076
1172
  }
1077
1173
  }
1078
1174
 
1175
+ static const rb_data_type_t pg_typecast_buffer_type = {
1176
+ "PG::Connection typecast buffer chain",
1177
+ {
1178
+ (RUBY_DATA_FUNC) NULL,
1179
+ free_typecast_heap_chain,
1180
+ (size_t (*)(const void *))NULL,
1181
+ },
1182
+ 0,
1183
+ 0,
1184
+ RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
1185
+ };
1186
+
1079
1187
  static char *
1080
1188
  alloc_typecast_buf( VALUE *typecast_heap_chain, int len )
1081
1189
  {
@@ -1086,17 +1194,28 @@ alloc_typecast_buf( VALUE *typecast_heap_chain, int len )
1086
1194
  /* Did we already wrap a memory chain per T_DATA object? */
1087
1195
  if( NIL_P( *typecast_heap_chain ) ){
1088
1196
  /* Leave free'ing of the buffer chain to the GC, when paramsData has left the stack */
1089
- *typecast_heap_chain = Data_Wrap_Struct( rb_cObject, NULL, free_typecast_heap_chain, allocated );
1197
+ *typecast_heap_chain = TypedData_Wrap_Struct( rb_cObject, &pg_typecast_buffer_type, allocated );
1090
1198
  allocated->next = NULL;
1091
1199
  } else {
1092
1200
  /* Append to the chain */
1093
- allocated->next = DATA_PTR( *typecast_heap_chain );
1094
- DATA_PTR( *typecast_heap_chain ) = allocated;
1201
+ allocated->next = RTYPEDDATA_DATA( *typecast_heap_chain );
1202
+ RTYPEDDATA_DATA( *typecast_heap_chain ) = allocated;
1095
1203
  }
1096
1204
 
1097
1205
  return &allocated->data[0];
1098
1206
  }
1099
1207
 
1208
+ static const rb_data_type_t pg_query_heap_pool_type = {
1209
+ "PG::Connection query heap pool",
1210
+ {
1211
+ (RUBY_DATA_FUNC) NULL,
1212
+ RUBY_TYPED_DEFAULT_FREE,
1213
+ (size_t (*)(const void *))NULL,
1214
+ },
1215
+ 0,
1216
+ 0,
1217
+ RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
1218
+ };
1100
1219
 
1101
1220
  static int
1102
1221
  alloc_query_params(struct query_params_data *paramsData)
@@ -1111,7 +1230,7 @@ alloc_query_params(struct query_params_data *paramsData)
1111
1230
 
1112
1231
  Check_Type(paramsData->params, T_ARRAY);
1113
1232
 
1114
- p_typemap = DATA_PTR( paramsData->typemap );
1233
+ p_typemap = RTYPEDDATA_DATA( paramsData->typemap );
1115
1234
  p_typemap->funcs.fit_to_query( paramsData->typemap, paramsData->params );
1116
1235
 
1117
1236
  paramsData->heap_pool = Qnil;
@@ -1130,7 +1249,7 @@ alloc_query_params(struct query_params_data *paramsData)
1130
1249
  /* Allocate one combined memory pool for all possible function parameters */
1131
1250
  memory_pool = (char*)xmalloc( required_pool_size );
1132
1251
  /* Leave free'ing of the buffer to the GC, when paramsData has left the stack */
1133
- paramsData->heap_pool = Data_Wrap_Struct( rb_cObject, NULL, -1, memory_pool );
1252
+ paramsData->heap_pool = TypedData_Wrap_Struct( rb_cObject, &pg_query_heap_pool_type, memory_pool );
1134
1253
  required_pool_size = 0;
1135
1254
  }else{
1136
1255
  /* Use stack memory for function parameters */
@@ -1243,85 +1362,52 @@ pgconn_query_assign_typemap( VALUE self, struct query_params_data *paramsData )
1243
1362
  /* Use default typemap for queries. It's type is checked when assigned. */
1244
1363
  paramsData->typemap = pg_get_connection(self)->type_map_for_queries;
1245
1364
  }else{
1365
+ t_typemap *tm;
1366
+ UNUSED(tm);
1367
+
1246
1368
  /* Check type of method param */
1247
- if ( !rb_obj_is_kind_of(paramsData->typemap, rb_cTypeMap) ) {
1248
- rb_raise( rb_eTypeError, "wrong argument type %s (expected kind of PG::TypeMap)",
1249
- rb_obj_classname( paramsData->typemap ) );
1250
- }
1251
- Check_Type( paramsData->typemap, T_DATA );
1369
+ TypedData_Get_Struct(paramsData->typemap, t_typemap, &pg_typemap_type, tm);
1252
1370
  }
1253
1371
  }
1254
1372
 
1255
1373
  /*
1256
1374
  * call-seq:
1257
- * conn.exec_params(sql, params[, result_format[, type_map]] ) -> PG::Result
1258
- * conn.exec_params(sql, params[, result_format[, type_map]] ) {|pg_result| block }
1259
- *
1260
- * Sends SQL query request specified by +sql+ to PostgreSQL using placeholders
1261
- * for parameters.
1262
- *
1263
- * Returns a PG::Result instance on success. On failure, it raises a PG::Error.
1264
- *
1265
- * +params+ is an array of the bind parameters for the SQL query.
1266
- * Each element of the +params+ array may be either:
1267
- * a hash of the form:
1268
- * {:value => String (value of bind parameter)
1269
- * :type => Integer (oid of type of bind parameter)
1270
- * :format => Integer (0 for text, 1 for binary)
1271
- * }
1272
- * or, it may be a String. If it is a string, that is equivalent to the hash:
1273
- * { :value => <string value>, :type => 0, :format => 0 }
1274
- *
1275
- * PostgreSQL bind parameters are represented as $1, $1, $2, etc.,
1276
- * inside the SQL query. The 0th element of the +params+ array is bound
1277
- * to $1, the 1st element is bound to $2, etc. +nil+ is treated as +NULL+.
1278
- *
1279
- * If the types are not specified, they will be inferred by PostgreSQL.
1280
- * Instead of specifying type oids, it's recommended to simply add
1281
- * explicit casts in the query to ensure that the right type is used.
1282
- *
1283
- * For example: "SELECT $1::int"
1284
- *
1285
- * The optional +result_format+ should be 0 for text results, 1
1286
- * for binary.
1287
- *
1288
- * type_map can be a PG::TypeMap derivation (such as PG::BasicTypeMapForQueries).
1289
- * This will type cast the params from various Ruby types before transmission
1290
- * based on the encoders defined by the type map. When a type encoder is used
1291
- * the format and oid of a given bind parameter are retrieved from the encoder
1292
- * instead out of the hash form described above.
1375
+ * conn.sync_exec_params(sql, params[, result_format[, type_map]] ) -> PG::Result
1376
+ * conn.sync_exec_params(sql, params[, result_format[, type_map]] ) {|pg_result| block }
1293
1377
  *
1294
- * If the optional code block is given, it will be passed <i>result</i> as an argument,
1295
- * and the PG::Result object will automatically be cleared when the block terminates.
1296
- * In this instance, <code>conn.exec</code> returns the value of the block.
1378
+ * This function has the same behavior as #async_exec_params, but is implemented using the synchronous command processing API of libpq.
1379
+ * See #async_exec for the differences between the two API variants.
1380
+ * It's not recommended to use explicit sync or async variants but #exec_params instead, unless you have a good reason to do so.
1297
1381
  */
1298
1382
  static VALUE
1299
- pgconn_exec_params( int argc, VALUE *argv, VALUE self )
1383
+ pgconn_sync_exec_params( int argc, VALUE *argv, VALUE self )
1300
1384
  {
1301
- PGconn *conn = pg_get_pgconn(self);
1385
+ t_pg_connection *this = pg_get_connection_safe( self );
1302
1386
  PGresult *result = NULL;
1303
1387
  VALUE rb_pgresult;
1304
1388
  VALUE command, in_res_fmt;
1305
1389
  int nParams;
1306
1390
  int resultFormat;
1307
- struct query_params_data paramsData = { ENCODING_GET(self) };
1391
+ struct query_params_data paramsData = { this->enc_idx };
1308
1392
 
1393
+ /* For compatibility we accept 1 to 4 parameters */
1309
1394
  rb_scan_args(argc, argv, "13", &command, &paramsData.params, &in_res_fmt, &paramsData.typemap);
1310
1395
  paramsData.with_types = 1;
1311
1396
 
1312
1397
  /*
1313
- * Handle the edge-case where the caller is coming from #exec, but passed an explict +nil+
1314
- * for the second parameter.
1398
+ * For backward compatibility no or +nil+ for the second parameter
1399
+ * is passed to #exec
1315
1400
  */
1316
1401
  if ( NIL_P(paramsData.params) ) {
1317
- return pgconn_exec( 1, argv, self );
1402
+ pg_deprecated(1, ("forwarding exec_params to exec is deprecated"));
1403
+ return pgconn_sync_exec( 1, argv, self );
1318
1404
  }
1319
1405
  pgconn_query_assign_typemap( self, &paramsData );
1320
1406
 
1321
1407
  resultFormat = NIL_P(in_res_fmt) ? 0 : NUM2INT(in_res_fmt);
1322
1408
  nParams = alloc_query_params( &paramsData );
1323
1409
 
1324
- result = gvl_PQexecParams(conn, pg_cstr_enc(command, paramsData.enc_idx), nParams, paramsData.types,
1410
+ result = gvl_PQexecParams(this->pgconn, pg_cstr_enc(command, paramsData.enc_idx), nParams, paramsData.types,
1325
1411
  (const char * const *)paramsData.values, paramsData.lengths, paramsData.formats, resultFormat);
1326
1412
 
1327
1413
  free_query_params( &paramsData );
@@ -1338,28 +1424,16 @@ pgconn_exec_params( int argc, VALUE *argv, VALUE self )
1338
1424
 
1339
1425
  /*
1340
1426
  * call-seq:
1341
- * conn.prepare(stmt_name, sql [, param_types ] ) -> PG::Result
1342
- *
1343
- * Prepares statement _sql_ with name _name_ to be executed later.
1344
- * Returns a PG::Result instance on success.
1345
- * On failure, it raises a PG::Error.
1346
- *
1347
- * +param_types+ is an optional parameter to specify the Oids of the
1348
- * types of the parameters.
1349
- *
1350
- * If the types are not specified, they will be inferred by PostgreSQL.
1351
- * Instead of specifying type oids, it's recommended to simply add
1352
- * explicit casts in the query to ensure that the right type is used.
1353
- *
1354
- * For example: "SELECT $1::int"
1427
+ * conn.sync_prepare(stmt_name, sql [, param_types ] ) -> PG::Result
1355
1428
  *
1356
- * PostgreSQL bind parameters are represented as $1, $1, $2, etc.,
1357
- * inside the SQL query.
1429
+ * This function has the same behavior as #async_prepare, but is implemented using the synchronous command processing API of libpq.
1430
+ * See #async_exec for the differences between the two API variants.
1431
+ * It's not recommended to use explicit sync or async variants but #prepare instead, unless you have a good reason to do so.
1358
1432
  */
1359
1433
  static VALUE
1360
- pgconn_prepare(int argc, VALUE *argv, VALUE self)
1434
+ pgconn_sync_prepare(int argc, VALUE *argv, VALUE self)
1361
1435
  {
1362
- PGconn *conn = pg_get_pgconn(self);
1436
+ t_pg_connection *this = pg_get_connection_safe( self );
1363
1437
  PGresult *result = NULL;
1364
1438
  VALUE rb_pgresult;
1365
1439
  VALUE name, command, in_paramtypes;
@@ -1369,7 +1443,7 @@ pgconn_prepare(int argc, VALUE *argv, VALUE self)
1369
1443
  Oid *paramTypes = NULL;
1370
1444
  const char *name_cstr;
1371
1445
  const char *command_cstr;
1372
- int enc_idx = ENCODING_GET(self);
1446
+ int enc_idx = this->enc_idx;
1373
1447
 
1374
1448
  rb_scan_args(argc, argv, "21", &name, &command, &in_paramtypes);
1375
1449
  name_cstr = pg_cstr_enc(name, enc_idx);
@@ -1387,7 +1461,7 @@ pgconn_prepare(int argc, VALUE *argv, VALUE self)
1387
1461
  paramTypes[i] = NUM2UINT(param);
1388
1462
  }
1389
1463
  }
1390
- result = gvl_PQprepare(conn, name_cstr, command_cstr, nParams, paramTypes);
1464
+ result = gvl_PQprepare(this->pgconn, name_cstr, command_cstr, nParams, paramTypes);
1391
1465
 
1392
1466
  xfree(paramTypes);
1393
1467
 
@@ -1398,49 +1472,23 @@ pgconn_prepare(int argc, VALUE *argv, VALUE self)
1398
1472
 
1399
1473
  /*
1400
1474
  * call-seq:
1401
- * conn.exec_prepared(statement_name [, params, result_format[, type_map]] ) -> PG::Result
1402
- * conn.exec_prepared(statement_name [, params, result_format[, type_map]] ) {|pg_result| block }
1403
- *
1404
- * Execute prepared named statement specified by _statement_name_.
1405
- * Returns a PG::Result instance on success.
1406
- * On failure, it raises a PG::Error.
1407
- *
1408
- * +params+ is an array of the optional bind parameters for the
1409
- * SQL query. Each element of the +params+ array may be either:
1410
- * a hash of the form:
1411
- * {:value => String (value of bind parameter)
1412
- * :format => Integer (0 for text, 1 for binary)
1413
- * }
1414
- * or, it may be a String. If it is a string, that is equivalent to the hash:
1415
- * { :value => <string value>, :format => 0 }
1416
- *
1417
- * PostgreSQL bind parameters are represented as $1, $1, $2, etc.,
1418
- * inside the SQL query. The 0th element of the +params+ array is bound
1419
- * to $1, the 1st element is bound to $2, etc. +nil+ is treated as +NULL+.
1420
- *
1421
- * The optional +result_format+ should be 0 for text results, 1
1422
- * for binary.
1423
- *
1424
- * type_map can be a PG::TypeMap derivation (such as PG::BasicTypeMapForQueries).
1425
- * This will type cast the params from various Ruby types before transmission
1426
- * based on the encoders defined by the type map. When a type encoder is used
1427
- * the format and oid of a given bind parameter are retrieved from the encoder
1428
- * instead out of the hash form described above.
1475
+ * conn.sync_exec_prepared(statement_name [, params, result_format[, type_map]] ) -> PG::Result
1476
+ * conn.sync_exec_prepared(statement_name [, params, result_format[, type_map]] ) {|pg_result| block }
1429
1477
  *
1430
- * If the optional code block is given, it will be passed <i>result</i> as an argument,
1431
- * and the PG::Result object will automatically be cleared when the block terminates.
1432
- * In this instance, <code>conn.exec_prepared</code> returns the value of the block.
1478
+ * This function has the same behavior as #async_exec_prepared, but is implemented using the synchronous command processing API of libpq.
1479
+ * See #async_exec for the differences between the two API variants.
1480
+ * It's not recommended to use explicit sync or async variants but #exec_prepared instead, unless you have a good reason to do so.
1433
1481
  */
1434
1482
  static VALUE
1435
- pgconn_exec_prepared(int argc, VALUE *argv, VALUE self)
1483
+ pgconn_sync_exec_prepared(int argc, VALUE *argv, VALUE self)
1436
1484
  {
1437
- PGconn *conn = pg_get_pgconn(self);
1485
+ t_pg_connection *this = pg_get_connection_safe( self );
1438
1486
  PGresult *result = NULL;
1439
1487
  VALUE rb_pgresult;
1440
1488
  VALUE name, in_res_fmt;
1441
1489
  int nParams;
1442
1490
  int resultFormat;
1443
- struct query_params_data paramsData = { ENCODING_GET(self) };
1491
+ struct query_params_data paramsData = { this->enc_idx };
1444
1492
 
1445
1493
  rb_scan_args(argc, argv, "13", &name, &paramsData.params, &in_res_fmt, &paramsData.typemap);
1446
1494
  paramsData.with_types = 0;
@@ -1453,7 +1501,7 @@ pgconn_exec_prepared(int argc, VALUE *argv, VALUE self)
1453
1501
  resultFormat = NIL_P(in_res_fmt) ? 0 : NUM2INT(in_res_fmt);
1454
1502
  nParams = alloc_query_params( &paramsData );
1455
1503
 
1456
- result = gvl_PQexecPrepared(conn, pg_cstr_enc(name, paramsData.enc_idx), nParams,
1504
+ result = gvl_PQexecPrepared(this->pgconn, pg_cstr_enc(name, paramsData.enc_idx), nParams,
1457
1505
  (const char * const *)paramsData.values, paramsData.lengths, paramsData.formats,
1458
1506
  resultFormat);
1459
1507
 
@@ -1470,25 +1518,26 @@ pgconn_exec_prepared(int argc, VALUE *argv, VALUE self)
1470
1518
 
1471
1519
  /*
1472
1520
  * call-seq:
1473
- * conn.describe_prepared( statement_name ) -> PG::Result
1521
+ * conn.sync_describe_prepared( statement_name ) -> PG::Result
1474
1522
  *
1475
- * Retrieve information about the prepared statement
1476
- * _statement_name_.
1523
+ * This function has the same behavior as #async_describe_prepared, but is implemented using the synchronous command processing API of libpq.
1524
+ * See #async_exec for the differences between the two API variants.
1525
+ * It's not recommended to use explicit sync or async variants but #describe_prepared instead, unless you have a good reason to do so.
1477
1526
  */
1478
1527
  static VALUE
1479
- pgconn_describe_prepared(VALUE self, VALUE stmt_name)
1528
+ pgconn_sync_describe_prepared(VALUE self, VALUE stmt_name)
1480
1529
  {
1481
1530
  PGresult *result;
1482
1531
  VALUE rb_pgresult;
1483
- PGconn *conn = pg_get_pgconn(self);
1532
+ t_pg_connection *this = pg_get_connection_safe( self );
1484
1533
  const char *stmt;
1485
1534
  if(NIL_P(stmt_name)) {
1486
1535
  stmt = NULL;
1487
1536
  }
1488
1537
  else {
1489
- stmt = pg_cstr_enc(stmt_name, ENCODING_GET(self));
1538
+ stmt = pg_cstr_enc(stmt_name, this->enc_idx);
1490
1539
  }
1491
- result = gvl_PQdescribePrepared(conn, stmt);
1540
+ result = gvl_PQdescribePrepared(this->pgconn, stmt);
1492
1541
  rb_pgresult = pg_new_result(result, self);
1493
1542
  pg_result_check(rb_pgresult);
1494
1543
  return rb_pgresult;
@@ -1497,25 +1546,26 @@ pgconn_describe_prepared(VALUE self, VALUE stmt_name)
1497
1546
 
1498
1547
  /*
1499
1548
  * call-seq:
1500
- * conn.describe_portal( portal_name ) -> PG::Result
1549
+ * conn.sync_describe_portal( portal_name ) -> PG::Result
1501
1550
  *
1502
- * Retrieve information about the portal _portal_name_.
1551
+ * This function has the same behavior as #async_describe_portal, but is implemented using the synchronous command processing API of libpq.
1552
+ * See #async_exec for the differences between the two API variants.
1553
+ * It's not recommended to use explicit sync or async variants but #describe_portal instead, unless you have a good reason to do so.
1503
1554
  */
1504
1555
  static VALUE
1505
- pgconn_describe_portal(self, stmt_name)
1506
- VALUE self, stmt_name;
1556
+ pgconn_sync_describe_portal(VALUE self, VALUE stmt_name)
1507
1557
  {
1508
1558
  PGresult *result;
1509
1559
  VALUE rb_pgresult;
1510
- PGconn *conn = pg_get_pgconn(self);
1560
+ t_pg_connection *this = pg_get_connection_safe( self );
1511
1561
  const char *stmt;
1512
1562
  if(NIL_P(stmt_name)) {
1513
1563
  stmt = NULL;
1514
1564
  }
1515
1565
  else {
1516
- stmt = pg_cstr_enc(stmt_name, ENCODING_GET(self));
1566
+ stmt = pg_cstr_enc(stmt_name, this->enc_idx);
1517
1567
  }
1518
- result = gvl_PQdescribePortal(conn, stmt);
1568
+ result = gvl_PQdescribePortal(this->pgconn, stmt);
1519
1569
  rb_pgresult = pg_new_result(result, self);
1520
1570
  pg_result_check(rb_pgresult);
1521
1571
  return rb_pgresult;
@@ -1537,6 +1587,9 @@ pgconn_describe_portal(self, stmt_name)
1537
1587
  * * +PGRES_NONFATAL_ERROR+
1538
1588
  * * +PGRES_FATAL_ERROR+
1539
1589
  * * +PGRES_COPY_BOTH+
1590
+ * * +PGRES_SINGLE_TUPLE+
1591
+ * * +PGRES_PIPELINE_SYNC+
1592
+ * * +PGRES_PIPELINE_ABORTED+
1540
1593
  */
1541
1594
  static VALUE
1542
1595
  pgconn_make_empty_pgresult(VALUE self, VALUE status)
@@ -1562,13 +1615,15 @@ pgconn_make_empty_pgresult(VALUE self, VALUE status)
1562
1615
  * Consider using exec_params, which avoids the need for passing values
1563
1616
  * inside of SQL commands.
1564
1617
  *
1565
- * Encoding of escaped string will be equal to client encoding of connection.
1618
+ * Character encoding of escaped string will be equal to client encoding of connection.
1566
1619
  *
1567
1620
  * NOTE: This class version of this method can only be used safely in client
1568
1621
  * programs that use a single PostgreSQL connection at a time (in this case it can
1569
1622
  * find out what it needs to know "behind the scenes"). It might give the wrong
1570
1623
  * results if used in programs that use multiple database connections; use the
1571
1624
  * same method on the connection object in such cases.
1625
+ *
1626
+ * See also convenience functions #escape_literal and #escape_identifier which also add proper quotes around the string.
1572
1627
  */
1573
1628
  static VALUE
1574
1629
  pgconn_s_escape(VALUE self, VALUE string)
@@ -1579,8 +1634,8 @@ pgconn_s_escape(VALUE self, VALUE string)
1579
1634
  int enc_idx;
1580
1635
  int singleton = !rb_obj_is_kind_of(self, rb_cPGconn);
1581
1636
 
1582
- Check_Type(string, T_STRING);
1583
- enc_idx = ENCODING_GET( singleton ? string : self );
1637
+ StringValueCStr(string);
1638
+ enc_idx = singleton ? ENCODING_GET(string) : pg_get_connection(self)->enc_idx;
1584
1639
  if( ENCODING_GET(string) != enc_idx ){
1585
1640
  string = rb_str_export_to_enc(string, rb_enc_from_index(enc_idx));
1586
1641
  }
@@ -1590,14 +1645,13 @@ pgconn_s_escape(VALUE self, VALUE string)
1590
1645
  if( !singleton ) {
1591
1646
  size = PQescapeStringConn(pg_get_pgconn(self), RSTRING_PTR(result),
1592
1647
  RSTRING_PTR(string), RSTRING_LEN(string), &error);
1593
- if(error) {
1594
- rb_raise(rb_ePGerror, "%s", PQerrorMessage(pg_get_pgconn(self)));
1595
- }
1648
+ if(error)
1649
+ pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(pg_get_pgconn(self)));
1650
+
1596
1651
  } else {
1597
1652
  size = PQescapeString(RSTRING_PTR(result), RSTRING_PTR(string), RSTRING_LEN(string));
1598
1653
  }
1599
1654
  rb_str_set_len(result, size);
1600
- OBJ_INFECT(result, string);
1601
1655
 
1602
1656
  return result;
1603
1657
  }
@@ -1643,7 +1697,6 @@ pgconn_s_escape_bytea(VALUE self, VALUE str)
1643
1697
  }
1644
1698
 
1645
1699
  ret = rb_str_new((char*)to, to_len - 1);
1646
- OBJ_INFECT(ret, str);
1647
1700
  PQfreemem(to);
1648
1701
  return ret;
1649
1702
  }
@@ -1673,7 +1726,6 @@ pgconn_s_unescape_bytea(VALUE self, VALUE str)
1673
1726
  to = PQunescapeBytea(from, &to_len);
1674
1727
 
1675
1728
  ret = rb_str_new((char*)to, to_len);
1676
- OBJ_INFECT(ret, str);
1677
1729
  PQfreemem(to);
1678
1730
  return ret;
1679
1731
  }
@@ -1684,33 +1736,27 @@ pgconn_s_unescape_bytea(VALUE self, VALUE str)
1684
1736
  *
1685
1737
  * Escape an arbitrary String +str+ as a literal.
1686
1738
  *
1687
- * Available since PostgreSQL-9.0
1739
+ * See also PG::TextEncoder::QuotedLiteral for a type cast integrated version of this function.
1688
1740
  */
1689
1741
  static VALUE
1690
1742
  pgconn_escape_literal(VALUE self, VALUE string)
1691
1743
  {
1692
- PGconn *conn = pg_get_pgconn(self);
1744
+ t_pg_connection *this = pg_get_connection_safe( self );
1693
1745
  char *escaped = NULL;
1694
- VALUE error;
1695
1746
  VALUE result = Qnil;
1696
- int enc_idx = ENCODING_GET(self);
1747
+ int enc_idx = this->enc_idx;
1697
1748
 
1698
- Check_Type(string, T_STRING);
1749
+ StringValueCStr(string);
1699
1750
  if( ENCODING_GET(string) != enc_idx ){
1700
1751
  string = rb_str_export_to_enc(string, rb_enc_from_index(enc_idx));
1701
1752
  }
1702
1753
 
1703
- escaped = PQescapeLiteral(conn, RSTRING_PTR(string), RSTRING_LEN(string));
1754
+ escaped = PQescapeLiteral(this->pgconn, RSTRING_PTR(string), RSTRING_LEN(string));
1704
1755
  if (escaped == NULL)
1705
- {
1706
- error = rb_exc_new2(rb_ePGerror, PQerrorMessage(conn));
1707
- rb_iv_set(error, "@connection", self);
1708
- rb_exc_raise(error);
1709
- return Qnil;
1710
- }
1756
+ pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(this->pgconn));
1757
+
1711
1758
  result = rb_str_new2(escaped);
1712
1759
  PQfreemem(escaped);
1713
- OBJ_INFECT(result, string);
1714
1760
  PG_ENCODING_SET_NOCHECK(result, enc_idx);
1715
1761
 
1716
1762
  return result;
@@ -1725,34 +1771,26 @@ pgconn_escape_literal(VALUE self, VALUE string)
1725
1771
  * This method does the same as #quote_ident with a String argument,
1726
1772
  * but it doesn't support an Array argument and it makes use of libpq
1727
1773
  * to process the string.
1728
- *
1729
- * Available since PostgreSQL-9.0
1730
1774
  */
1731
1775
  static VALUE
1732
1776
  pgconn_escape_identifier(VALUE self, VALUE string)
1733
1777
  {
1734
- PGconn *conn = pg_get_pgconn(self);
1778
+ t_pg_connection *this = pg_get_connection_safe( self );
1735
1779
  char *escaped = NULL;
1736
- VALUE error;
1737
1780
  VALUE result = Qnil;
1738
- int enc_idx = ENCODING_GET(self);
1781
+ int enc_idx = this->enc_idx;
1739
1782
 
1740
- Check_Type(string, T_STRING);
1783
+ StringValueCStr(string);
1741
1784
  if( ENCODING_GET(string) != enc_idx ){
1742
1785
  string = rb_str_export_to_enc(string, rb_enc_from_index(enc_idx));
1743
1786
  }
1744
1787
 
1745
- escaped = PQescapeIdentifier(conn, RSTRING_PTR(string), RSTRING_LEN(string));
1788
+ escaped = PQescapeIdentifier(this->pgconn, RSTRING_PTR(string), RSTRING_LEN(string));
1746
1789
  if (escaped == NULL)
1747
- {
1748
- error = rb_exc_new2(rb_ePGerror, PQerrorMessage(conn));
1749
- rb_iv_set(error, "@connection", self);
1750
- rb_exc_raise(error);
1751
- return Qnil;
1752
- }
1790
+ pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(this->pgconn));
1791
+
1753
1792
  result = rb_str_new2(escaped);
1754
1793
  PQfreemem(escaped);
1755
- OBJ_INFECT(result, string);
1756
1794
  PG_ENCODING_SET_NOCHECK(result, enc_idx);
1757
1795
 
1758
1796
  return result;
@@ -1793,34 +1831,65 @@ pgconn_escape_identifier(VALUE self, VALUE string)
1793
1831
  * # do something with the received row
1794
1832
  * end
1795
1833
  * end
1796
- *
1797
- * Available since PostgreSQL-9.2
1798
1834
  */
1799
1835
  static VALUE
1800
1836
  pgconn_set_single_row_mode(VALUE self)
1801
1837
  {
1802
1838
  PGconn *conn = pg_get_pgconn(self);
1803
- VALUE error;
1804
1839
 
1840
+ rb_check_frozen(self);
1805
1841
  if( PQsetSingleRowMode(conn) == 0 )
1806
- {
1807
- error = rb_exc_new2(rb_ePGerror, PQerrorMessage(conn));
1808
- rb_iv_set(error, "@connection", self);
1809
- rb_exc_raise(error);
1810
- }
1842
+ pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(conn));
1811
1843
 
1812
1844
  return self;
1813
1845
  }
1814
1846
 
1847
+ static VALUE pgconn_send_query_params(int argc, VALUE *argv, VALUE self);
1848
+
1849
+ /*
1850
+ * call-seq:
1851
+ * conn.send_query(sql) -> nil
1852
+ *
1853
+ * Sends SQL query request specified by _sql_ to PostgreSQL for
1854
+ * asynchronous processing, and immediately returns.
1855
+ * On failure, it raises a PG::Error.
1856
+ *
1857
+ * For backward compatibility, if you pass more than one parameter to this method,
1858
+ * it will call #send_query_params for you. New code should explicitly use #send_query_params if
1859
+ * argument placeholders are used.
1860
+ *
1861
+ */
1862
+ static VALUE
1863
+ pgconn_send_query(int argc, VALUE *argv, VALUE self)
1864
+ {
1865
+ t_pg_connection *this = pg_get_connection_safe( self );
1866
+
1867
+ /* If called with no or nil parameters, use PQexec for compatibility */
1868
+ if ( argc == 1 || (argc >= 2 && argc <= 4 && NIL_P(argv[1]) )) {
1869
+ if(gvl_PQsendQuery(this->pgconn, pg_cstr_enc(argv[0], this->enc_idx)) == 0)
1870
+ pg_raise_conn_error( rb_eUnableToSend, self, "%s", PQerrorMessage(this->pgconn));
1871
+
1872
+ pgconn_wait_for_flush( self );
1873
+ return Qnil;
1874
+ }
1875
+
1876
+ pg_deprecated(2, ("forwarding async_exec to async_exec_params and send_query to send_query_params is deprecated"));
1877
+
1878
+ /* If called with parameters, and optionally result_format,
1879
+ * use PQsendQueryParams
1880
+ */
1881
+ return pgconn_send_query_params( argc, argv, self);
1882
+ }
1883
+
1815
1884
  /*
1816
1885
  * call-seq:
1817
- * conn.send_query(sql [, params, result_format[, type_map ]] ) -> nil
1886
+ * conn.send_query_params(sql, params [, result_format [, type_map ]] ) -> nil
1818
1887
  *
1819
1888
  * Sends SQL query request specified by _sql_ to PostgreSQL for
1820
1889
  * asynchronous processing, and immediately returns.
1821
1890
  * On failure, it raises a PG::Error.
1822
1891
  *
1823
- * +params+ is an optional array of the bind parameters for the SQL query.
1892
+ * +params+ is an array of the bind parameters for the SQL query.
1824
1893
  * Each element of the +params+ array may be either:
1825
1894
  * a hash of the form:
1826
1895
  * {:value => String (value of bind parameter)
@@ -1830,7 +1899,7 @@ pgconn_set_single_row_mode(VALUE self)
1830
1899
  * or, it may be a String. If it is a string, that is equivalent to the hash:
1831
1900
  * { :value => <string value>, :type => 0, :format => 0 }
1832
1901
  *
1833
- * PostgreSQL bind parameters are represented as $1, $1, $2, etc.,
1902
+ * PostgreSQL bind parameters are represented as $1, $2, $3, etc.,
1834
1903
  * inside the SQL query. The 0th element of the +params+ array is bound
1835
1904
  * to $1, the 1st element is bound to $2, etc. +nil+ is treated as +NULL+.
1836
1905
  *
@@ -1843,7 +1912,7 @@ pgconn_set_single_row_mode(VALUE self)
1843
1912
  * The optional +result_format+ should be 0 for text results, 1
1844
1913
  * for binary.
1845
1914
  *
1846
- * type_map can be a PG::TypeMap derivation (such as PG::BasicTypeMapForQueries).
1915
+ * +type_map+ can be a PG::TypeMap derivation (such as PG::BasicTypeMapForQueries).
1847
1916
  * This will type cast the params from various Ruby types before transmission
1848
1917
  * based on the encoders defined by the type map. When a type encoder is used
1849
1918
  * the format and oid of a given bind parameter are retrieved from the encoder
@@ -1851,47 +1920,31 @@ pgconn_set_single_row_mode(VALUE self)
1851
1920
  *
1852
1921
  */
1853
1922
  static VALUE
1854
- pgconn_send_query(int argc, VALUE *argv, VALUE self)
1923
+ pgconn_send_query_params(int argc, VALUE *argv, VALUE self)
1855
1924
  {
1856
- PGconn *conn = pg_get_pgconn(self);
1925
+ t_pg_connection *this = pg_get_connection_safe( self );
1857
1926
  int result;
1858
1927
  VALUE command, in_res_fmt;
1859
- VALUE error;
1860
1928
  int nParams;
1861
1929
  int resultFormat;
1862
- struct query_params_data paramsData = { ENCODING_GET(self) };
1930
+ struct query_params_data paramsData = { this->enc_idx };
1863
1931
 
1864
- rb_scan_args(argc, argv, "13", &command, &paramsData.params, &in_res_fmt, &paramsData.typemap);
1932
+ rb_scan_args(argc, argv, "22", &command, &paramsData.params, &in_res_fmt, &paramsData.typemap);
1865
1933
  paramsData.with_types = 1;
1866
1934
 
1867
- /* If called with no parameters, use PQsendQuery */
1868
- if(NIL_P(paramsData.params)) {
1869
- if(gvl_PQsendQuery(conn, pg_cstr_enc(command, paramsData.enc_idx)) == 0) {
1870
- error = rb_exc_new2(rb_eUnableToSend, PQerrorMessage(conn));
1871
- rb_iv_set(error, "@connection", self);
1872
- rb_exc_raise(error);
1873
- }
1874
- return Qnil;
1875
- }
1876
-
1877
- /* If called with parameters, and optionally result_format,
1878
- * use PQsendQueryParams
1879
- */
1880
-
1881
1935
  pgconn_query_assign_typemap( self, &paramsData );
1882
1936
  resultFormat = NIL_P(in_res_fmt) ? 0 : NUM2INT(in_res_fmt);
1883
1937
  nParams = alloc_query_params( &paramsData );
1884
1938
 
1885
- result = gvl_PQsendQueryParams(conn, pg_cstr_enc(command, paramsData.enc_idx), nParams, paramsData.types,
1939
+ result = gvl_PQsendQueryParams(this->pgconn, pg_cstr_enc(command, paramsData.enc_idx), nParams, paramsData.types,
1886
1940
  (const char * const *)paramsData.values, paramsData.lengths, paramsData.formats, resultFormat);
1887
1941
 
1888
1942
  free_query_params( &paramsData );
1889
1943
 
1890
- if(result == 0) {
1891
- error = rb_exc_new2(rb_eUnableToSend, PQerrorMessage(conn));
1892
- rb_iv_set(error, "@connection", self);
1893
- rb_exc_raise(error);
1894
- }
1944
+ if(result == 0)
1945
+ pg_raise_conn_error( rb_eUnableToSend, self, "%s", PQerrorMessage(this->pgconn));
1946
+
1947
+ pgconn_wait_for_flush( self );
1895
1948
  return Qnil;
1896
1949
  }
1897
1950
 
@@ -1912,23 +1965,22 @@ pgconn_send_query(int argc, VALUE *argv, VALUE self)
1912
1965
  *
1913
1966
  * For example: "SELECT $1::int"
1914
1967
  *
1915
- * PostgreSQL bind parameters are represented as $1, $1, $2, etc.,
1968
+ * PostgreSQL bind parameters are represented as $1, $2, $3, etc.,
1916
1969
  * inside the SQL query.
1917
1970
  */
1918
1971
  static VALUE
1919
1972
  pgconn_send_prepare(int argc, VALUE *argv, VALUE self)
1920
1973
  {
1921
- PGconn *conn = pg_get_pgconn(self);
1974
+ t_pg_connection *this = pg_get_connection_safe( self );
1922
1975
  int result;
1923
1976
  VALUE name, command, in_paramtypes;
1924
1977
  VALUE param;
1925
- VALUE error;
1926
1978
  int i = 0;
1927
1979
  int nParams = 0;
1928
1980
  Oid *paramTypes = NULL;
1929
1981
  const char *name_cstr;
1930
1982
  const char *command_cstr;
1931
- int enc_idx = ENCODING_GET(self);
1983
+ int enc_idx = this->enc_idx;
1932
1984
 
1933
1985
  rb_scan_args(argc, argv, "21", &name, &command, &in_paramtypes);
1934
1986
  name_cstr = pg_cstr_enc(name, enc_idx);
@@ -1946,15 +1998,14 @@ pgconn_send_prepare(int argc, VALUE *argv, VALUE self)
1946
1998
  paramTypes[i] = NUM2UINT(param);
1947
1999
  }
1948
2000
  }
1949
- result = gvl_PQsendPrepare(conn, name_cstr, command_cstr, nParams, paramTypes);
2001
+ result = gvl_PQsendPrepare(this->pgconn, name_cstr, command_cstr, nParams, paramTypes);
1950
2002
 
1951
2003
  xfree(paramTypes);
1952
2004
 
1953
2005
  if(result == 0) {
1954
- error = rb_exc_new2(rb_eUnableToSend, PQerrorMessage(conn));
1955
- rb_iv_set(error, "@connection", self);
1956
- rb_exc_raise(error);
2006
+ pg_raise_conn_error( rb_eUnableToSend, self, "%s", PQerrorMessage(this->pgconn));
1957
2007
  }
2008
+ pgconn_wait_for_flush( self );
1958
2009
  return Qnil;
1959
2010
  }
1960
2011
 
@@ -1976,14 +2027,14 @@ pgconn_send_prepare(int argc, VALUE *argv, VALUE self)
1976
2027
  * or, it may be a String. If it is a string, that is equivalent to the hash:
1977
2028
  * { :value => <string value>, :format => 0 }
1978
2029
  *
1979
- * PostgreSQL bind parameters are represented as $1, $1, $2, etc.,
2030
+ * PostgreSQL bind parameters are represented as $1, $2, $3, etc.,
1980
2031
  * inside the SQL query. The 0th element of the +params+ array is bound
1981
2032
  * to $1, the 1st element is bound to $2, etc. +nil+ is treated as +NULL+.
1982
2033
  *
1983
2034
  * The optional +result_format+ should be 0 for text results, 1
1984
2035
  * for binary.
1985
2036
  *
1986
- * type_map can be a PG::TypeMap derivation (such as PG::BasicTypeMapForQueries).
2037
+ * +type_map+ can be a PG::TypeMap derivation (such as PG::BasicTypeMapForQueries).
1987
2038
  * This will type cast the params from various Ruby types before transmission
1988
2039
  * based on the encoders defined by the type map. When a type encoder is used
1989
2040
  * the format and oid of a given bind parameter are retrieved from the encoder
@@ -1993,37 +2044,34 @@ pgconn_send_prepare(int argc, VALUE *argv, VALUE self)
1993
2044
  static VALUE
1994
2045
  pgconn_send_query_prepared(int argc, VALUE *argv, VALUE self)
1995
2046
  {
1996
- PGconn *conn = pg_get_pgconn(self);
2047
+ t_pg_connection *this = pg_get_connection_safe( self );
1997
2048
  int result;
1998
2049
  VALUE name, in_res_fmt;
1999
- VALUE error;
2000
2050
  int nParams;
2001
2051
  int resultFormat;
2002
- struct query_params_data paramsData = { ENCODING_GET(self) };
2052
+ struct query_params_data paramsData = { this->enc_idx };
2003
2053
 
2004
2054
  rb_scan_args(argc, argv, "13", &name, &paramsData.params, &in_res_fmt, &paramsData.typemap);
2005
2055
  paramsData.with_types = 0;
2006
2056
 
2007
2057
  if(NIL_P(paramsData.params)) {
2008
2058
  paramsData.params = rb_ary_new2(0);
2009
- resultFormat = 0;
2010
2059
  }
2011
2060
  pgconn_query_assign_typemap( self, &paramsData );
2012
2061
 
2013
2062
  resultFormat = NIL_P(in_res_fmt) ? 0 : NUM2INT(in_res_fmt);
2014
2063
  nParams = alloc_query_params( &paramsData );
2015
2064
 
2016
- result = gvl_PQsendQueryPrepared(conn, pg_cstr_enc(name, paramsData.enc_idx), nParams,
2065
+ result = gvl_PQsendQueryPrepared(this->pgconn, pg_cstr_enc(name, paramsData.enc_idx), nParams,
2017
2066
  (const char * const *)paramsData.values, paramsData.lengths, paramsData.formats,
2018
2067
  resultFormat);
2019
2068
 
2020
2069
  free_query_params( &paramsData );
2021
2070
 
2022
- if(result == 0) {
2023
- error = rb_exc_new2(rb_eUnableToSend, PQerrorMessage(conn));
2024
- rb_iv_set(error, "@connection", self);
2025
- rb_exc_raise(error);
2026
- }
2071
+ if(result == 0)
2072
+ pg_raise_conn_error( rb_eUnableToSend, self, "%s", PQerrorMessage(this->pgconn));
2073
+
2074
+ pgconn_wait_for_flush( self );
2027
2075
  return Qnil;
2028
2076
  }
2029
2077
 
@@ -2037,14 +2085,12 @@ pgconn_send_query_prepared(int argc, VALUE *argv, VALUE self)
2037
2085
  static VALUE
2038
2086
  pgconn_send_describe_prepared(VALUE self, VALUE stmt_name)
2039
2087
  {
2040
- VALUE error;
2041
- PGconn *conn = pg_get_pgconn(self);
2088
+ t_pg_connection *this = pg_get_connection_safe( self );
2042
2089
  /* returns 0 on failure */
2043
- if(gvl_PQsendDescribePrepared(conn, pg_cstr_enc(stmt_name, ENCODING_GET(self))) == 0) {
2044
- error = rb_exc_new2(rb_eUnableToSend, PQerrorMessage(conn));
2045
- rb_iv_set(error, "@connection", self);
2046
- rb_exc_raise(error);
2047
- }
2090
+ if(gvl_PQsendDescribePrepared(this->pgconn, pg_cstr_enc(stmt_name, this->enc_idx)) == 0)
2091
+ pg_raise_conn_error( rb_eUnableToSend, self, "%s", PQerrorMessage(this->pgconn));
2092
+
2093
+ pgconn_wait_for_flush( self );
2048
2094
  return Qnil;
2049
2095
  }
2050
2096
 
@@ -2059,36 +2105,18 @@ pgconn_send_describe_prepared(VALUE self, VALUE stmt_name)
2059
2105
  static VALUE
2060
2106
  pgconn_send_describe_portal(VALUE self, VALUE portal)
2061
2107
  {
2062
- VALUE error;
2063
- PGconn *conn = pg_get_pgconn(self);
2108
+ t_pg_connection *this = pg_get_connection_safe( self );
2064
2109
  /* returns 0 on failure */
2065
- if(gvl_PQsendDescribePortal(conn, pg_cstr_enc(portal, ENCODING_GET(self))) == 0) {
2066
- error = rb_exc_new2(rb_eUnableToSend, PQerrorMessage(conn));
2067
- rb_iv_set(error, "@connection", self);
2068
- rb_exc_raise(error);
2069
- }
2110
+ if(gvl_PQsendDescribePortal(this->pgconn, pg_cstr_enc(portal, this->enc_idx)) == 0)
2111
+ pg_raise_conn_error( rb_eUnableToSend, self, "%s", PQerrorMessage(this->pgconn));
2112
+
2113
+ pgconn_wait_for_flush( self );
2070
2114
  return Qnil;
2071
2115
  }
2072
2116
 
2073
2117
 
2074
- /*
2075
- * call-seq:
2076
- * conn.get_result() -> PG::Result
2077
- * conn.get_result() {|pg_result| block }
2078
- *
2079
- * Blocks waiting for the next result from a call to
2080
- * #send_query (or another asynchronous command), and returns
2081
- * it. Returns +nil+ if no more results are available.
2082
- *
2083
- * Note: call this function repeatedly until it returns +nil+, or else
2084
- * you will not be able to issue further commands.
2085
- *
2086
- * If the optional code block is given, it will be passed <i>result</i> as an argument,
2087
- * and the PG::Result object will automatically be cleared when the block terminates.
2088
- * In this instance, <code>conn.exec</code> returns the value of the block.
2089
- */
2090
2118
  static VALUE
2091
- pgconn_get_result(VALUE self)
2119
+ pgconn_sync_get_result(VALUE self)
2092
2120
  {
2093
2121
  PGconn *conn = pg_get_pgconn(self);
2094
2122
  PGresult *result;
@@ -2114,17 +2142,15 @@ pgconn_get_result(VALUE self)
2114
2142
  * or *notifies* to see if the state has changed.
2115
2143
  */
2116
2144
  static VALUE
2117
- pgconn_consume_input(self)
2118
- VALUE self;
2145
+ pgconn_consume_input(VALUE self)
2119
2146
  {
2120
- VALUE error;
2121
2147
  PGconn *conn = pg_get_pgconn(self);
2122
2148
  /* returns 0 on error */
2123
2149
  if(PQconsumeInput(conn) == 0) {
2124
- error = rb_exc_new2(rb_eConnectionBad, PQerrorMessage(conn));
2125
- rb_iv_set(error, "@connection", self);
2126
- rb_exc_raise(error);
2150
+ pgconn_close_socket_io(self);
2151
+ pg_raise_conn_error( rb_eConnectionBad, self, "%s", PQerrorMessage(conn));
2127
2152
  }
2153
+
2128
2154
  return Qnil;
2129
2155
  }
2130
2156
 
@@ -2133,38 +2159,20 @@ pgconn_consume_input(self)
2133
2159
  * conn.is_busy() -> Boolean
2134
2160
  *
2135
2161
  * Returns +true+ if a command is busy, that is, if
2136
- * PQgetResult would block. Otherwise returns +false+.
2162
+ * #get_result would block. Otherwise returns +false+.
2137
2163
  */
2138
2164
  static VALUE
2139
- pgconn_is_busy(self)
2140
- VALUE self;
2165
+ pgconn_is_busy(VALUE self)
2141
2166
  {
2142
2167
  return gvl_PQisBusy(pg_get_pgconn(self)) ? Qtrue : Qfalse;
2143
2168
  }
2144
2169
 
2145
- /*
2146
- * call-seq:
2147
- * conn.setnonblocking(Boolean) -> nil
2148
- *
2149
- * Sets the nonblocking status of the connection.
2150
- * In the blocking state, calls to #send_query
2151
- * will block until the message is sent to the server,
2152
- * but will not wait for the query results.
2153
- * In the nonblocking state, calls to #send_query
2154
- * will return an error if the socket is not ready for
2155
- * writing.
2156
- * Note: This function does not affect #exec, because
2157
- * that function doesn't return until the server has
2158
- * processed the query and returned the results.
2159
- * Returns +nil+.
2160
- */
2161
2170
  static VALUE
2162
- pgconn_setnonblocking(self, state)
2163
- VALUE self, state;
2171
+ pgconn_sync_setnonblocking(VALUE self, VALUE state)
2164
2172
  {
2165
2173
  int arg;
2166
- VALUE error;
2167
2174
  PGconn *conn = pg_get_pgconn(self);
2175
+ rb_check_frozen(self);
2168
2176
  if(state == Qtrue)
2169
2177
  arg = 1;
2170
2178
  else if (state == Qfalse)
@@ -2172,67 +2180,32 @@ pgconn_setnonblocking(self, state)
2172
2180
  else
2173
2181
  rb_raise(rb_eArgError, "Boolean value expected");
2174
2182
 
2175
- if(PQsetnonblocking(conn, arg) == -1) {
2176
- error = rb_exc_new2(rb_ePGerror, PQerrorMessage(conn));
2177
- rb_iv_set(error, "@connection", self);
2178
- rb_exc_raise(error);
2179
- }
2183
+ if(PQsetnonblocking(conn, arg) == -1)
2184
+ pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(conn));
2185
+
2180
2186
  return Qnil;
2181
2187
  }
2182
2188
 
2183
2189
 
2184
- /*
2185
- * call-seq:
2186
- * conn.isnonblocking() -> Boolean
2187
- *
2188
- * Returns +true+ if a command is busy, that is, if
2189
- * PQgetResult would block. Otherwise returns +false+.
2190
- */
2191
2190
  static VALUE
2192
- pgconn_isnonblocking(self)
2193
- VALUE self;
2191
+ pgconn_sync_isnonblocking(VALUE self)
2194
2192
  {
2195
2193
  return PQisnonblocking(pg_get_pgconn(self)) ? Qtrue : Qfalse;
2196
2194
  }
2197
2195
 
2198
- /*
2199
- * call-seq:
2200
- * conn.flush() -> Boolean
2201
- *
2202
- * Attempts to flush any queued output data to the server.
2203
- * Returns +true+ if data is successfully flushed, +false+
2204
- * if not (can only return +false+ if connection is
2205
- * nonblocking.
2206
- * Raises PG::Error if some other failure occurred.
2207
- */
2208
2196
  static VALUE
2209
- pgconn_flush(self)
2210
- VALUE self;
2197
+ pgconn_sync_flush(VALUE self)
2211
2198
  {
2212
2199
  PGconn *conn = pg_get_pgconn(self);
2213
- int ret;
2214
- VALUE error;
2215
- ret = PQflush(conn);
2216
- if(ret == -1) {
2217
- error = rb_exc_new2(rb_ePGerror, PQerrorMessage(conn));
2218
- rb_iv_set(error, "@connection", self);
2219
- rb_exc_raise(error);
2220
- }
2200
+ int ret = PQflush(conn);
2201
+ if(ret == -1)
2202
+ pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(conn));
2203
+
2221
2204
  return (ret) ? Qfalse : Qtrue;
2222
2205
  }
2223
2206
 
2224
- /*
2225
- * call-seq:
2226
- * conn.cancel() -> String
2227
- *
2228
- * Requests cancellation of the command currently being
2229
- * processed. (Only implemented in PostgreSQL >= 8.0)
2230
- *
2231
- * Returns +nil+ on success, or a string containing the
2232
- * error message if a failure occurs.
2233
- */
2234
2207
  static VALUE
2235
- pgconn_cancel(VALUE self)
2208
+ pgconn_sync_cancel(VALUE self)
2236
2209
  {
2237
2210
  char errbuf[256];
2238
2211
  PGcancel *cancel;
@@ -2241,9 +2214,9 @@ pgconn_cancel(VALUE self)
2241
2214
 
2242
2215
  cancel = PQgetCancel(pg_get_pgconn(self));
2243
2216
  if(cancel == NULL)
2244
- rb_raise(rb_ePGerror,"Invalid connection!");
2217
+ pg_raise_conn_error( rb_ePGerror, self, "Invalid connection!");
2245
2218
 
2246
- ret = gvl_PQcancel(cancel, errbuf, 256);
2219
+ ret = gvl_PQcancel(cancel, errbuf, sizeof(errbuf));
2247
2220
  if(ret == 1)
2248
2221
  retval = Qnil;
2249
2222
  else
@@ -2264,7 +2237,7 @@ pgconn_cancel(VALUE self)
2264
2237
  static VALUE
2265
2238
  pgconn_notifies(VALUE self)
2266
2239
  {
2267
- PGconn* conn = pg_get_pgconn(self);
2240
+ t_pg_connection *this = pg_get_connection_safe( self );
2268
2241
  PGnotify *notification;
2269
2242
  VALUE hash;
2270
2243
  VALUE sym_relname, sym_be_pid, sym_extra;
@@ -2274,17 +2247,17 @@ pgconn_notifies(VALUE self)
2274
2247
  sym_be_pid = ID2SYM(rb_intern("be_pid"));
2275
2248
  sym_extra = ID2SYM(rb_intern("extra"));
2276
2249
 
2277
- notification = gvl_PQnotifies(conn);
2250
+ notification = gvl_PQnotifies(this->pgconn);
2278
2251
  if (notification == NULL) {
2279
2252
  return Qnil;
2280
2253
  }
2281
2254
 
2282
2255
  hash = rb_hash_new();
2283
- relname = rb_tainted_str_new2(notification->relname);
2256
+ relname = rb_str_new2(notification->relname);
2284
2257
  be_pid = INT2NUM(notification->be_pid);
2285
- extra = rb_tainted_str_new2(notification->extra);
2286
- PG_ENCODING_SET_NOCHECK( relname, ENCODING_GET(self) );
2287
- PG_ENCODING_SET_NOCHECK( extra, ENCODING_GET(self) );
2258
+ extra = rb_str_new2(notification->extra);
2259
+ PG_ENCODING_SET_NOCHECK( relname, this->enc_idx );
2260
+ PG_ENCODING_SET_NOCHECK( extra, this->enc_idx );
2288
2261
 
2289
2262
  rb_hash_aset(hash, sym_relname, relname);
2290
2263
  rb_hash_aset(hash, sym_be_pid, be_pid);
@@ -2294,59 +2267,72 @@ pgconn_notifies(VALUE self)
2294
2267
  return hash;
2295
2268
  }
2296
2269
 
2297
- /* Win32 + Ruby 1.9+ */
2298
- #if defined( _WIN32 )
2299
- /*
2300
- * On Windows, use platform-specific strategies to wait for the socket
2301
- * instead of rb_thread_select().
2270
+ #ifndef HAVE_RB_IO_DESCRIPTOR
2271
+ static int
2272
+ rb_io_descriptor(VALUE io)
2273
+ {
2274
+ Check_Type(io, T_FILE);
2275
+ rb_io_t *fptr = RFILE(io)->fptr;
2276
+ rb_io_check_closed(fptr);
2277
+ return fptr->fd;
2278
+ }
2279
+ #endif
2280
+
2281
+ #if defined(_WIN32)
2282
+
2283
+ /* We use a specialized implementation of rb_io_wait() on Windows.
2284
+ * This is because rb_io_wait() and rb_wait_for_single_fd() are very slow on Windows.
2302
2285
  */
2303
2286
 
2287
+ #if defined(HAVE_RUBY_FIBER_SCHEDULER_H)
2288
+ #include <ruby/fiber/scheduler.h>
2289
+ #endif
2290
+
2291
+ typedef enum {
2292
+ PG_RUBY_IO_READABLE = RB_WAITFD_IN,
2293
+ PG_RUBY_IO_WRITABLE = RB_WAITFD_OUT,
2294
+ PG_RUBY_IO_PRIORITY = RB_WAITFD_PRI,
2295
+ } pg_rb_io_event_t;
2296
+
2304
2297
  int rb_w32_wait_events( HANDLE *events, int num, DWORD timeout );
2305
2298
 
2306
- /* If WIN32 and Ruby 1.9 do not use rb_thread_select() which sometimes hangs
2307
- * and does not wait (nor sleep) any time even if timeout is given.
2308
- * Instead use the Winsock events and rb_w32_wait_events(). */
2299
+ static VALUE
2300
+ pg_rb_thread_io_wait(VALUE io, VALUE events, VALUE timeout) {
2301
+ struct timeval ptimeout;
2309
2302
 
2310
- static void *
2311
- wait_socket_readable( PGconn *conn, struct timeval *ptimeout, void *(*is_readable)(PGconn *) )
2312
- {
2313
- int sd = PQsocket( conn );
2314
- void *retval;
2315
2303
  struct timeval aborttime={0,0}, currtime, waittime;
2316
2304
  DWORD timeout_milisec = INFINITE;
2317
- DWORD wait_ret;
2318
- WSAEVENT hEvent;
2319
-
2320
- if ( sd < 0 )
2321
- rb_raise(rb_eConnectionBad, "PQsocket() can't get socket descriptor");
2305
+ HANDLE hEvent = WSACreateEvent();
2322
2306
 
2323
- hEvent = WSACreateEvent();
2307
+ long rb_events = NUM2UINT(events);
2308
+ long w32_events = 0;
2309
+ DWORD wait_ret;
2324
2310
 
2325
- /* Check for connection errors (PQisBusy is true on connection errors) */
2326
- if( PQconsumeInput(conn) == 0 ) {
2327
- WSACloseEvent( hEvent );
2328
- rb_raise( rb_eConnectionBad, "PQconsumeInput() %s", PQerrorMessage(conn) );
2329
- }
2311
+ if( !NIL_P(timeout) ){
2312
+ ptimeout.tv_sec = (time_t)(NUM2DBL(timeout));
2313
+ ptimeout.tv_usec = (time_t)((NUM2DBL(timeout) - (double)ptimeout.tv_sec) * 1e6);
2330
2314
 
2331
- if ( ptimeout ) {
2332
2315
  gettimeofday(&currtime, NULL);
2333
- timeradd(&currtime, ptimeout, &aborttime);
2316
+ timeradd(&currtime, &ptimeout, &aborttime);
2334
2317
  }
2335
2318
 
2336
- while ( !(retval=is_readable(conn)) ) {
2337
- if ( WSAEventSelect(sd, hEvent, FD_READ|FD_CLOSE) == SOCKET_ERROR ) {
2319
+ if(rb_events & PG_RUBY_IO_READABLE) w32_events |= FD_READ | FD_ACCEPT | FD_CLOSE;
2320
+ if(rb_events & PG_RUBY_IO_WRITABLE) w32_events |= FD_WRITE | FD_CONNECT;
2321
+ if(rb_events & PG_RUBY_IO_PRIORITY) w32_events |= FD_OOB;
2322
+
2323
+ for(;;) {
2324
+ if ( WSAEventSelect(_get_osfhandle(rb_io_descriptor(io)), hEvent, w32_events) == SOCKET_ERROR ) {
2338
2325
  WSACloseEvent( hEvent );
2339
2326
  rb_raise( rb_eConnectionBad, "WSAEventSelect socket error: %d", WSAGetLastError() );
2340
2327
  }
2341
2328
 
2342
- if ( ptimeout ) {
2329
+ if ( !NIL_P(timeout) ) {
2343
2330
  gettimeofday(&currtime, NULL);
2344
2331
  timersub(&aborttime, &currtime, &waittime);
2345
2332
  timeout_milisec = (DWORD)( waittime.tv_sec * 1e3 + waittime.tv_usec / 1e3 );
2346
2333
  }
2347
2334
 
2348
- /* Is the given timeout valid? */
2349
- if( !ptimeout || (waittime.tv_sec >= 0 && waittime.tv_usec >= 0) ){
2335
+ if( NIL_P(timeout) || (waittime.tv_sec >= 0 && waittime.tv_usec >= 0) ){
2350
2336
  /* Wait for the socket to become readable before checking again */
2351
2337
  wait_ret = rb_w32_wait_events( &hEvent, 1, timeout_milisec );
2352
2338
  } else {
@@ -2355,9 +2341,11 @@ wait_socket_readable( PGconn *conn, struct timeval *ptimeout, void *(*is_readabl
2355
2341
 
2356
2342
  if ( wait_ret == WAIT_TIMEOUT ) {
2357
2343
  WSACloseEvent( hEvent );
2358
- return NULL;
2344
+ return UINT2NUM(0);
2359
2345
  } else if ( wait_ret == WAIT_OBJECT_0 ) {
2346
+ WSACloseEvent( hEvent );
2360
2347
  /* The event we were waiting for. */
2348
+ return UINT2NUM(rb_events);
2361
2349
  } else if ( wait_ret == WAIT_OBJECT_0 + 1) {
2362
2350
  /* This indicates interruption from timer thread, GC, exception
2363
2351
  * from other threads etc... */
@@ -2369,39 +2357,64 @@ wait_socket_readable( PGconn *conn, struct timeval *ptimeout, void *(*is_readabl
2369
2357
  WSACloseEvent( hEvent );
2370
2358
  rb_raise( rb_eConnectionBad, "Wait on socket abandoned (WaitForMultipleObjects)" );
2371
2359
  }
2372
-
2373
- /* Check for connection errors (PQisBusy is true on connection errors) */
2374
- if ( PQconsumeInput(conn) == 0 ) {
2375
- WSACloseEvent( hEvent );
2376
- rb_raise( rb_eConnectionBad, "PQconsumeInput() %s", PQerrorMessage(conn) );
2377
- }
2378
2360
  }
2361
+ }
2379
2362
 
2380
- WSACloseEvent( hEvent );
2381
- return retval;
2363
+ static VALUE
2364
+ pg_rb_io_wait(VALUE io, VALUE events, VALUE timeout) {
2365
+ #if defined(HAVE_RUBY_FIBER_SCHEDULER_H)
2366
+ /* We don't support Fiber.scheduler on Windows ruby-3.0 because there is no fast way to check whether a scheduler is active.
2367
+ * Fortunately ruby-3.1 offers a C-API for it.
2368
+ */
2369
+ VALUE scheduler = rb_fiber_scheduler_current();
2370
+
2371
+ if (!NIL_P(scheduler)) {
2372
+ return rb_io_wait(io, events, timeout);
2373
+ }
2374
+ #endif
2375
+ return pg_rb_thread_io_wait(io, events, timeout);
2382
2376
  }
2383
2377
 
2378
+ #elif defined(HAVE_RB_IO_WAIT)
2379
+
2380
+ /* Use our own function and constants names, to avoid conflicts with truffleruby-head on its road to ruby-3.0 compatibility. */
2381
+ #define pg_rb_io_wait rb_io_wait
2382
+ #define PG_RUBY_IO_READABLE RUBY_IO_READABLE
2383
+ #define PG_RUBY_IO_WRITABLE RUBY_IO_WRITABLE
2384
+ #define PG_RUBY_IO_PRIORITY RUBY_IO_PRIORITY
2385
+
2384
2386
  #else
2387
+ /* For compat with ruby < 3.0 */
2388
+
2389
+ typedef enum {
2390
+ PG_RUBY_IO_READABLE = RB_WAITFD_IN,
2391
+ PG_RUBY_IO_WRITABLE = RB_WAITFD_OUT,
2392
+ PG_RUBY_IO_PRIORITY = RB_WAITFD_PRI,
2393
+ } pg_rb_io_event_t;
2394
+
2395
+ static VALUE
2396
+ pg_rb_io_wait(VALUE io, VALUE events, VALUE timeout) {
2397
+ struct timeval waittime;
2398
+ int res;
2399
+
2400
+ if( !NIL_P(timeout) ){
2401
+ waittime.tv_sec = (time_t)(NUM2DBL(timeout));
2402
+ waittime.tv_usec = (time_t)((NUM2DBL(timeout) - (double)waittime.tv_sec) * 1e6);
2403
+ }
2404
+ res = rb_wait_for_single_fd(rb_io_descriptor(io), NUM2UINT(events), NIL_P(timeout) ? NULL : &waittime);
2385
2405
 
2386
- /* non Win32 */
2406
+ return UINT2NUM(res);
2407
+ }
2408
+ #endif
2387
2409
 
2388
2410
  static void *
2389
- wait_socket_readable( PGconn *conn, struct timeval *ptimeout, void *(*is_readable)(PGconn *))
2411
+ wait_socket_readable( VALUE self, struct timeval *ptimeout, void *(*is_readable)(PGconn *))
2390
2412
  {
2391
- int sd = PQsocket( conn );
2392
- int ret;
2413
+ VALUE ret;
2393
2414
  void *retval;
2394
- rb_fdset_t sd_rset;
2395
2415
  struct timeval aborttime={0,0}, currtime, waittime;
2396
-
2397
- if ( sd < 0 )
2398
- rb_raise(rb_eConnectionBad, "PQsocket() can't get socket descriptor");
2399
-
2400
- /* Check for connection errors (PQisBusy is true on connection errors) */
2401
- if ( PQconsumeInput(conn) == 0 )
2402
- rb_raise( rb_eConnectionBad, "PQconsumeInput() %s", PQerrorMessage(conn) );
2403
-
2404
- rb_fd_init( &sd_rset );
2416
+ VALUE wait_timeout = Qnil;
2417
+ PGconn *conn = pg_get_pgconn(self);
2405
2418
 
2406
2419
  if ( ptimeout ) {
2407
2420
  gettimeofday(&currtime, NULL);
@@ -2409,46 +2422,84 @@ wait_socket_readable( PGconn *conn, struct timeval *ptimeout, void *(*is_readabl
2409
2422
  }
2410
2423
 
2411
2424
  while ( !(retval=is_readable(conn)) ) {
2412
- rb_fd_zero( &sd_rset );
2413
- rb_fd_set( sd, &sd_rset );
2414
-
2415
2425
  if ( ptimeout ) {
2416
2426
  gettimeofday(&currtime, NULL);
2417
2427
  timersub(&aborttime, &currtime, &waittime);
2428
+ wait_timeout = DBL2NUM((double)(waittime.tv_sec) + (double)(waittime.tv_usec) / 1000000.0);
2418
2429
  }
2419
2430
 
2420
2431
  /* Is the given timeout valid? */
2421
2432
  if( !ptimeout || (waittime.tv_sec >= 0 && waittime.tv_usec >= 0) ){
2433
+ VALUE socket_io;
2434
+
2435
+ /* before we wait for data, make sure everything has been sent */
2436
+ pgconn_async_flush(self);
2437
+ if ((retval=is_readable(conn)))
2438
+ return retval;
2439
+
2440
+ socket_io = pgconn_socket_io(self);
2422
2441
  /* Wait for the socket to become readable before checking again */
2423
- ret = rb_thread_fd_select( sd+1, &sd_rset, NULL, NULL, ptimeout ? &waittime : NULL );
2442
+ ret = pg_rb_io_wait(socket_io, RB_INT2NUM(PG_RUBY_IO_READABLE), wait_timeout);
2424
2443
  } else {
2425
- ret = 0;
2426
- }
2427
-
2428
- if ( ret < 0 ){
2429
- rb_fd_term( &sd_rset );
2430
- rb_sys_fail( "rb_thread_select()" );
2444
+ ret = Qfalse;
2431
2445
  }
2432
2446
 
2433
2447
  /* Return false if the select() timed out */
2434
- if ( ret == 0 ){
2435
- rb_fd_term( &sd_rset );
2448
+ if ( ret == Qfalse ){
2436
2449
  return NULL;
2437
2450
  }
2438
2451
 
2439
2452
  /* Check for connection errors (PQisBusy is true on connection errors) */
2440
2453
  if ( PQconsumeInput(conn) == 0 ){
2441
- rb_fd_term( &sd_rset );
2442
- rb_raise( rb_eConnectionBad, "PQconsumeInput() %s", PQerrorMessage(conn) );
2454
+ pgconn_close_socket_io(self);
2455
+ pg_raise_conn_error(rb_eConnectionBad, self, "PQconsumeInput() %s", PQerrorMessage(conn));
2443
2456
  }
2444
2457
  }
2445
2458
 
2446
- rb_fd_term( &sd_rset );
2447
2459
  return retval;
2448
2460
  }
2449
2461
 
2462
+ /*
2463
+ * call-seq:
2464
+ * conn.flush() -> Boolean
2465
+ *
2466
+ * Attempts to flush any queued output data to the server.
2467
+ * Returns +true+ if data is successfully flushed, +false+
2468
+ * if not. It can only return +false+ if connection is
2469
+ * in nonblocking mode.
2470
+ * Raises PG::Error if some other failure occurred.
2471
+ */
2472
+ static VALUE
2473
+ pgconn_async_flush(VALUE self)
2474
+ {
2475
+ while( pgconn_sync_flush(self) == Qfalse ){
2476
+ /* wait for the socket to become read- or write-ready */
2477
+ int events;
2478
+ VALUE socket_io = pgconn_socket_io(self);
2479
+ events = RB_NUM2INT(pg_rb_io_wait(socket_io, RB_INT2NUM(PG_RUBY_IO_READABLE | PG_RUBY_IO_WRITABLE), Qnil));
2480
+
2481
+ if (events & PG_RUBY_IO_READABLE){
2482
+ pgconn_consume_input(self);
2483
+ }
2484
+ }
2485
+ return Qtrue;
2486
+ }
2487
+
2488
+ static VALUE
2489
+ pgconn_wait_for_flush( VALUE self ){
2490
+ if( !pg_get_connection_safe(self)->flush_data )
2491
+ return Qnil;
2492
+
2493
+ return pgconn_async_flush(self);
2494
+ }
2450
2495
 
2451
- #endif
2496
+ static VALUE
2497
+ pgconn_flush_data_set( VALUE self, VALUE enabled ){
2498
+ t_pg_connection *conn = pg_get_connection(self);
2499
+ rb_check_frozen(self);
2500
+ conn->flush_data = RTEST(enabled);
2501
+ return enabled;
2502
+ }
2452
2503
 
2453
2504
  static void *
2454
2505
  notify_readable(PGconn *conn)
@@ -2458,27 +2509,20 @@ notify_readable(PGconn *conn)
2458
2509
 
2459
2510
  /*
2460
2511
  * call-seq:
2461
- * conn.wait_for_notify( [ timeout ] ) -> String
2462
- * conn.wait_for_notify( [ timeout ] ) { |event, pid| block }
2463
- * conn.wait_for_notify( [ timeout ] ) { |event, pid, payload| block } # PostgreSQL 9.0
2512
+ * conn.wait_for_notify( [ timeout ] ) { |event, pid, payload| block } -> String
2464
2513
  *
2465
2514
  * Blocks while waiting for notification(s), or until the optional
2466
2515
  * _timeout_ is reached, whichever comes first. _timeout_ is
2467
2516
  * measured in seconds and can be fractional.
2468
2517
  *
2469
- * Returns +nil+ if _timeout_ is reached, the name of the NOTIFY
2470
- * event otherwise. If used in block form, passes the name of the
2471
- * NOTIFY +event+ and the generating +pid+ into the block.
2472
- *
2473
- * Under PostgreSQL 9.0 and later, if the notification is sent with
2474
- * the optional +payload+ string, it will be given to the block as the
2475
- * third argument.
2476
- *
2518
+ * Returns +nil+ if _timeout_ is reached, the name of the NOTIFY event otherwise.
2519
+ * If used in block form, passes the name of the NOTIFY +event+, the generating
2520
+ * +pid+ and the optional +payload+ string into the block.
2477
2521
  */
2478
2522
  static VALUE
2479
2523
  pgconn_wait_for_notify(int argc, VALUE *argv, VALUE self)
2480
2524
  {
2481
- PGconn *conn = pg_get_pgconn( self );
2525
+ t_pg_connection *this = pg_get_connection_safe( self );
2482
2526
  PGnotify *pnotification;
2483
2527
  struct timeval timeout;
2484
2528
  struct timeval *ptimeout = NULL;
@@ -2494,17 +2538,17 @@ pgconn_wait_for_notify(int argc, VALUE *argv, VALUE self)
2494
2538
  ptimeout = &timeout;
2495
2539
  }
2496
2540
 
2497
- pnotification = (PGnotify*) wait_socket_readable( conn, ptimeout, notify_readable);
2541
+ pnotification = (PGnotify*) wait_socket_readable( self, ptimeout, notify_readable);
2498
2542
 
2499
2543
  /* Return nil if the select timed out */
2500
2544
  if ( !pnotification ) return Qnil;
2501
2545
 
2502
- relname = rb_tainted_str_new2( pnotification->relname );
2503
- PG_ENCODING_SET_NOCHECK( relname, ENCODING_GET(self) );
2546
+ relname = rb_str_new2( pnotification->relname );
2547
+ PG_ENCODING_SET_NOCHECK( relname, this->enc_idx );
2504
2548
  be_pid = INT2NUM( pnotification->be_pid );
2505
2549
  if ( *pnotification->extra ) {
2506
- extra = rb_tainted_str_new2( pnotification->extra );
2507
- PG_ENCODING_SET_NOCHECK( extra, ENCODING_GET(self) );
2550
+ extra = rb_str_new2( pnotification->extra );
2551
+ PG_ENCODING_SET_NOCHECK( extra, this->enc_idx );
2508
2552
  }
2509
2553
  PQfreemem( pnotification );
2510
2554
 
@@ -2515,28 +2559,8 @@ pgconn_wait_for_notify(int argc, VALUE *argv, VALUE self)
2515
2559
  }
2516
2560
 
2517
2561
 
2518
- /*
2519
- * call-seq:
2520
- * conn.put_copy_data( buffer [, encoder] ) -> Boolean
2521
- *
2522
- * Transmits _buffer_ as copy data to the server.
2523
- * Returns true if the data was sent, false if it was
2524
- * not sent (false is only possible if the connection
2525
- * is in nonblocking mode, and this command would block).
2526
- *
2527
- * _encoder_ can be a PG::Coder derivation (typically PG::TextEncoder::CopyRow).
2528
- * This encodes the data fields given as _buffer_ from an Array of Strings to
2529
- * PostgreSQL's COPY text format inclusive proper escaping. Optionally
2530
- * the encoder can type cast the fields from various Ruby types in one step,
2531
- * if PG::TextEncoder::CopyRow#type_map is set accordingly.
2532
- *
2533
- * Raises an exception if an error occurs.
2534
- *
2535
- * See also #copy_data.
2536
- *
2537
- */
2538
2562
  static VALUE
2539
- pgconn_put_copy_data(int argc, VALUE *argv, VALUE self)
2563
+ pgconn_sync_put_copy_data(int argc, VALUE *argv, VALUE self)
2540
2564
  {
2541
2565
  int ret;
2542
2566
  int len;
@@ -2553,18 +2577,16 @@ pgconn_put_copy_data(int argc, VALUE *argv, VALUE self)
2553
2577
  if( NIL_P(this->encoder_for_put_copy_data) ){
2554
2578
  buffer = value;
2555
2579
  } else {
2556
- p_coder = DATA_PTR( this->encoder_for_put_copy_data );
2580
+ p_coder = RTYPEDDATA_DATA( this->encoder_for_put_copy_data );
2557
2581
  }
2558
- } else if( rb_obj_is_kind_of(encoder, rb_cPG_Coder) ) {
2559
- Data_Get_Struct( encoder, t_pg_coder, p_coder );
2560
2582
  } else {
2561
- rb_raise( rb_eTypeError, "wrong encoder type %s (expected some kind of PG::Coder)",
2562
- rb_obj_classname( encoder ) );
2583
+ /* Check argument type and use argument encoder */
2584
+ TypedData_Get_Struct(encoder, t_pg_coder, &pg_coder_type, p_coder);
2563
2585
  }
2564
2586
 
2565
2587
  if( p_coder ){
2566
2588
  t_pg_coder_enc_func enc_func;
2567
- int enc_idx = ENCODING_GET(self);
2589
+ int enc_idx = this->enc_idx;
2568
2590
 
2569
2591
  enc_func = pg_coder_enc_func( p_coder );
2570
2592
  len = enc_func( p_coder, value, NULL, &intermediate, enc_idx);
@@ -2582,76 +2604,39 @@ pgconn_put_copy_data(int argc, VALUE *argv, VALUE self)
2582
2604
  Check_Type(buffer, T_STRING);
2583
2605
 
2584
2606
  ret = gvl_PQputCopyData(this->pgconn, RSTRING_PTR(buffer), RSTRING_LENINT(buffer));
2585
- if(ret == -1) {
2586
- VALUE error = rb_exc_new2(rb_ePGerror, PQerrorMessage(this->pgconn));
2587
- rb_iv_set(error, "@connection", self);
2588
- rb_exc_raise(error);
2589
- }
2607
+ if(ret == -1)
2608
+ pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(this->pgconn));
2609
+
2590
2610
  RB_GC_GUARD(intermediate);
2591
2611
  RB_GC_GUARD(buffer);
2592
2612
 
2593
2613
  return (ret) ? Qtrue : Qfalse;
2594
2614
  }
2595
2615
 
2596
- /*
2597
- * call-seq:
2598
- * conn.put_copy_end( [ error_message ] ) -> Boolean
2599
- *
2600
- * Sends end-of-data indication to the server.
2601
- *
2602
- * _error_message_ is an optional parameter, and if set,
2603
- * forces the COPY command to fail with the string
2604
- * _error_message_.
2605
- *
2606
- * Returns true if the end-of-data was sent, false if it was
2607
- * not sent (false is only possible if the connection
2608
- * is in nonblocking mode, and this command would block).
2609
- */
2610
2616
  static VALUE
2611
- pgconn_put_copy_end(int argc, VALUE *argv, VALUE self)
2617
+ pgconn_sync_put_copy_end(int argc, VALUE *argv, VALUE self)
2612
2618
  {
2613
2619
  VALUE str;
2614
- VALUE error;
2615
2620
  int ret;
2616
2621
  const char *error_message = NULL;
2617
- PGconn *conn = pg_get_pgconn(self);
2622
+ t_pg_connection *this = pg_get_connection_safe( self );
2618
2623
 
2619
2624
  if (rb_scan_args(argc, argv, "01", &str) == 0)
2620
2625
  error_message = NULL;
2621
2626
  else
2622
- error_message = pg_cstr_enc(str, ENCODING_GET(self));
2627
+ error_message = pg_cstr_enc(str, this->enc_idx);
2628
+
2629
+ ret = gvl_PQputCopyEnd(this->pgconn, error_message);
2630
+ if(ret == -1)
2631
+ pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(this->pgconn));
2623
2632
 
2624
- ret = gvl_PQputCopyEnd(conn, error_message);
2625
- if(ret == -1) {
2626
- error = rb_exc_new2(rb_ePGerror, PQerrorMessage(conn));
2627
- rb_iv_set(error, "@connection", self);
2628
- rb_exc_raise(error);
2629
- }
2630
2633
  return (ret) ? Qtrue : Qfalse;
2631
2634
  }
2632
2635
 
2633
- /*
2634
- * call-seq:
2635
- * conn.get_copy_data( [ async = false [, decoder = nil ]] ) -> String
2636
- *
2637
- * Return a string containing one row of data, +nil+
2638
- * if the copy is done, or +false+ if the call would
2639
- * block (only possible if _async_ is true).
2640
- *
2641
- * _decoder_ can be a PG::Coder derivation (typically PG::TextDecoder::CopyRow).
2642
- * This decodes the received data fields from PostgreSQL's COPY text format to an
2643
- * Array of Strings. Optionally
2644
- * the decoder can type cast the fields to various Ruby types in one step,
2645
- * if PG::TextDecoder::CopyRow#type_map is set accordingly.
2646
- *
2647
- * See also #copy_data.
2648
- *
2649
- */
2650
2636
  static VALUE
2651
- pgconn_get_copy_data(int argc, VALUE *argv, VALUE self )
2637
+ pgconn_sync_get_copy_data(int argc, VALUE *argv, VALUE self )
2652
2638
  {
2653
2639
  VALUE async_in;
2654
- VALUE error;
2655
2640
  VALUE result;
2656
2641
  int ret;
2657
2642
  char *buffer;
@@ -2663,20 +2648,16 @@ pgconn_get_copy_data(int argc, VALUE *argv, VALUE self )
2663
2648
 
2664
2649
  if( NIL_P(decoder) ){
2665
2650
  if( !NIL_P(this->decoder_for_get_copy_data) ){
2666
- p_coder = DATA_PTR( this->decoder_for_get_copy_data );
2651
+ p_coder = RTYPEDDATA_DATA( this->decoder_for_get_copy_data );
2667
2652
  }
2668
- } else if( rb_obj_is_kind_of(decoder, rb_cPG_Coder) ) {
2669
- Data_Get_Struct( decoder, t_pg_coder, p_coder );
2670
2653
  } else {
2671
- rb_raise( rb_eTypeError, "wrong decoder type %s (expected some kind of PG::Coder)",
2672
- rb_obj_classname( decoder ) );
2654
+ /* Check argument type and use argument decoder */
2655
+ TypedData_Get_Struct(decoder, t_pg_coder, &pg_coder_type, p_coder);
2673
2656
  }
2674
2657
 
2675
2658
  ret = gvl_PQgetCopyData(this->pgconn, &buffer, RTEST(async_in));
2676
- if(ret == -2) { /* error */
2677
- error = rb_exc_new2(rb_ePGerror, PQerrorMessage(this->pgconn));
2678
- rb_iv_set(error, "@connection", self);
2679
- rb_exc_raise(error);
2659
+ if(ret == -2){ /* error */
2660
+ pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(this->pgconn));
2680
2661
  }
2681
2662
  if(ret == -1) { /* No data left */
2682
2663
  return Qnil;
@@ -2687,9 +2668,9 @@ pgconn_get_copy_data(int argc, VALUE *argv, VALUE self )
2687
2668
 
2688
2669
  if( p_coder ){
2689
2670
  t_pg_coder_dec_func dec_func = pg_coder_dec_func( p_coder, p_coder->format );
2690
- result = dec_func( p_coder, buffer, ret, 0, 0, ENCODING_GET(self) );
2671
+ result = dec_func( p_coder, buffer, ret, 0, 0, this->enc_idx );
2691
2672
  } else {
2692
- result = rb_tainted_str_new(buffer, ret);
2673
+ result = rb_str_new(buffer, ret);
2693
2674
  }
2694
2675
 
2695
2676
  PQfreemem(buffer);
@@ -2702,9 +2683,16 @@ pgconn_get_copy_data(int argc, VALUE *argv, VALUE self )
2702
2683
  *
2703
2684
  * Sets connection's verbosity to _verbosity_ and returns
2704
2685
  * the previous setting. Available settings are:
2686
+ *
2705
2687
  * * PQERRORS_TERSE
2706
2688
  * * PQERRORS_DEFAULT
2707
2689
  * * PQERRORS_VERBOSE
2690
+ * * PQERRORS_SQLSTATE
2691
+ *
2692
+ * Changing the verbosity does not affect the messages available from already-existing PG::Result objects, only subsequently-created ones.
2693
+ * (But see PG::Result#verbose_error_message if you want to print a previous error with a different verbosity.)
2694
+ *
2695
+ * See also corresponding {libpq function}[https://www.postgresql.org/docs/current/libpq-control.html#LIBPQ-PQSETERRORVERBOSITY].
2708
2696
  */
2709
2697
  static VALUE
2710
2698
  pgconn_set_error_verbosity(VALUE self, VALUE in_verbosity)
@@ -2714,6 +2702,37 @@ pgconn_set_error_verbosity(VALUE self, VALUE in_verbosity)
2714
2702
  return INT2FIX(PQsetErrorVerbosity(conn, verbosity));
2715
2703
  }
2716
2704
 
2705
+ #ifdef HAVE_PQRESULTVERBOSEERRORMESSAGE
2706
+ /*
2707
+ * call-seq:
2708
+ * conn.set_error_context_visibility( context_visibility ) -> Integer
2709
+ *
2710
+ * Sets connection's context display mode to _context_visibility_ and returns
2711
+ * the previous setting. Available settings are:
2712
+ * * PQSHOW_CONTEXT_NEVER
2713
+ * * PQSHOW_CONTEXT_ERRORS
2714
+ * * PQSHOW_CONTEXT_ALWAYS
2715
+ *
2716
+ * This mode controls whether the CONTEXT field is included in messages (unless the verbosity setting is TERSE, in which case CONTEXT is never shown).
2717
+ * The NEVER mode never includes CONTEXT, while ALWAYS always includes it if available.
2718
+ * In ERRORS mode (the default), CONTEXT fields are included only for error messages, not for notices and warnings.
2719
+ *
2720
+ * Changing this mode does not affect the messages available from already-existing PG::Result objects, only subsequently-created ones.
2721
+ * (But see PG::Result#verbose_error_message if you want to print a previous error with a different display mode.)
2722
+ *
2723
+ * See also corresponding {libpq function}[https://www.postgresql.org/docs/current/libpq-control.html#LIBPQ-PQSETERRORCONTEXTVISIBILITY].
2724
+ *
2725
+ * Available since PostgreSQL-9.6
2726
+ */
2727
+ static VALUE
2728
+ pgconn_set_error_context_visibility(VALUE self, VALUE in_context_visibility)
2729
+ {
2730
+ PGconn *conn = pg_get_pgconn(self);
2731
+ PGContextVisibility context_visibility = NUM2INT(in_context_visibility);
2732
+ return INT2FIX(PQsetErrorContextVisibility(conn, context_visibility));
2733
+ }
2734
+ #endif
2735
+
2717
2736
  /*
2718
2737
  * call-seq:
2719
2738
  * conn.trace( stream ) -> nil
@@ -2732,7 +2751,8 @@ pgconn_trace(VALUE self, VALUE stream)
2732
2751
  VALUE new_file;
2733
2752
  t_pg_connection *this = pg_get_connection_safe( self );
2734
2753
 
2735
- if(rb_respond_to(stream,rb_intern("fileno")) == Qfalse)
2754
+ rb_check_frozen(self);
2755
+ if(!rb_respond_to(stream,rb_intern("fileno")))
2736
2756
  rb_raise(rb_eArgError, "stream does not respond to method: fileno");
2737
2757
 
2738
2758
  fileno = rb_funcall(stream, rb_intern("fileno"), 0);
@@ -2753,7 +2773,7 @@ pgconn_trace(VALUE self, VALUE stream)
2753
2773
  rb_raise(rb_eArgError, "stream is not writable");
2754
2774
 
2755
2775
  new_file = rb_funcall(rb_cIO, rb_intern("new"), 1, INT2NUM(new_fd));
2756
- this->trace_stream = new_file;
2776
+ RB_OBJ_WRITE(self, &this->trace_stream, new_file);
2757
2777
 
2758
2778
  PQtrace(this->pgconn, new_fp);
2759
2779
  return Qnil;
@@ -2772,7 +2792,7 @@ pgconn_untrace(VALUE self)
2772
2792
 
2773
2793
  PQuntrace(this->pgconn);
2774
2794
  rb_funcall(this->trace_stream, rb_intern("close"), 0);
2775
- this->trace_stream = Qnil;
2795
+ RB_OBJ_WRITE(self, &this->trace_stream, Qnil);
2776
2796
  return Qnil;
2777
2797
  }
2778
2798
 
@@ -2831,13 +2851,14 @@ pgconn_set_notice_receiver(VALUE self)
2831
2851
  VALUE proc, old_proc;
2832
2852
  t_pg_connection *this = pg_get_connection_safe( self );
2833
2853
 
2854
+ rb_check_frozen(self);
2834
2855
  /* If default_notice_receiver is unset, assume that the current
2835
2856
  * notice receiver is the default, and save it to a global variable.
2836
2857
  * This should not be a problem because the default receiver is
2837
2858
  * always the same, so won't vary among connections.
2838
2859
  */
2839
- if(default_notice_receiver == NULL)
2840
- default_notice_receiver = PQsetNoticeReceiver(this->pgconn, NULL, NULL);
2860
+ if(this->default_notice_receiver == NULL)
2861
+ this->default_notice_receiver = PQsetNoticeReceiver(this->pgconn, NULL, NULL);
2841
2862
 
2842
2863
  old_proc = this->notice_receiver;
2843
2864
  if( rb_block_given_p() ) {
@@ -2846,10 +2867,10 @@ pgconn_set_notice_receiver(VALUE self)
2846
2867
  } else {
2847
2868
  /* if no block is given, set back to default */
2848
2869
  proc = Qnil;
2849
- PQsetNoticeReceiver(this->pgconn, default_notice_receiver, NULL);
2870
+ PQsetNoticeReceiver(this->pgconn, this->default_notice_receiver, NULL);
2850
2871
  }
2851
2872
 
2852
- this->notice_receiver = proc;
2873
+ RB_OBJ_WRITE(self, &this->notice_receiver, proc);
2853
2874
  return old_proc;
2854
2875
  }
2855
2876
 
@@ -2864,10 +2885,10 @@ notice_processor_proxy(void *arg, const char *message)
2864
2885
  VALUE self = (VALUE)arg;
2865
2886
  t_pg_connection *this = pg_get_connection( self );
2866
2887
 
2867
- if (this->notice_receiver != Qnil) {
2868
- VALUE message_str = rb_tainted_str_new2(message);
2869
- PG_ENCODING_SET_NOCHECK( message_str, ENCODING_GET(self) );
2870
- rb_funcall(this->notice_receiver, rb_intern("call"), 1, message_str);
2888
+ if (this->notice_processor != Qnil) {
2889
+ VALUE message_str = rb_str_new2(message);
2890
+ PG_ENCODING_SET_NOCHECK( message_str, this->enc_idx );
2891
+ rb_funcall(this->notice_processor, rb_intern("call"), 1, message_str);
2871
2892
  }
2872
2893
  return;
2873
2894
  }
@@ -2876,7 +2897,7 @@ notice_processor_proxy(void *arg, const char *message)
2876
2897
  * call-seq:
2877
2898
  * conn.set_notice_processor {|message| ... } -> Proc
2878
2899
  *
2879
- * See #set_notice_receiver for the desription of what this and the
2900
+ * See #set_notice_receiver for the description of what this and the
2880
2901
  * notice_processor methods do.
2881
2902
  *
2882
2903
  * This function takes a new block to act as the notice processor and returns
@@ -2891,25 +2912,26 @@ pgconn_set_notice_processor(VALUE self)
2891
2912
  VALUE proc, old_proc;
2892
2913
  t_pg_connection *this = pg_get_connection_safe( self );
2893
2914
 
2915
+ rb_check_frozen(self);
2894
2916
  /* If default_notice_processor is unset, assume that the current
2895
2917
  * notice processor is the default, and save it to a global variable.
2896
2918
  * This should not be a problem because the default processor is
2897
2919
  * always the same, so won't vary among connections.
2898
2920
  */
2899
- if(default_notice_processor == NULL)
2900
- default_notice_processor = PQsetNoticeProcessor(this->pgconn, NULL, NULL);
2921
+ if(this->default_notice_processor == NULL)
2922
+ this->default_notice_processor = PQsetNoticeProcessor(this->pgconn, NULL, NULL);
2901
2923
 
2902
- old_proc = this->notice_receiver;
2924
+ old_proc = this->notice_processor;
2903
2925
  if( rb_block_given_p() ) {
2904
2926
  proc = rb_block_proc();
2905
2927
  PQsetNoticeProcessor(this->pgconn, gvl_notice_processor_proxy, (void *)self);
2906
2928
  } else {
2907
2929
  /* if no block is given, set back to default */
2908
2930
  proc = Qnil;
2909
- PQsetNoticeProcessor(this->pgconn, default_notice_processor, NULL);
2931
+ PQsetNoticeProcessor(this->pgconn, this->default_notice_processor, NULL);
2910
2932
  }
2911
2933
 
2912
- this->notice_receiver = proc;
2934
+ RB_OBJ_WRITE(self, &this->notice_processor, proc);
2913
2935
  return old_proc;
2914
2936
  }
2915
2937
 
@@ -2924,74 +2946,34 @@ static VALUE
2924
2946
  pgconn_get_client_encoding(VALUE self)
2925
2947
  {
2926
2948
  char *encoding = (char *)pg_encoding_to_char(PQclientEncoding(pg_get_pgconn(self)));
2927
- return rb_tainted_str_new2(encoding);
2949
+ return rb_str_new2(encoding);
2928
2950
  }
2929
2951
 
2930
2952
 
2931
2953
  /*
2932
2954
  * call-seq:
2933
- * conn.set_client_encoding( encoding )
2955
+ * conn.sync_set_client_encoding( encoding )
2934
2956
  *
2935
- * Sets the client encoding to the _encoding_ String.
2957
+ * This function has the same behavior as #async_set_client_encoding, but is implemented using the synchronous command processing API of libpq.
2958
+ * See #async_exec for the differences between the two API variants.
2959
+ * 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.
2936
2960
  */
2937
2961
  static VALUE
2938
- pgconn_set_client_encoding(VALUE self, VALUE str)
2962
+ pgconn_sync_set_client_encoding(VALUE self, VALUE str)
2939
2963
  {
2940
2964
  PGconn *conn = pg_get_pgconn( self );
2941
2965
 
2966
+ rb_check_frozen(self);
2942
2967
  Check_Type(str, T_STRING);
2943
2968
 
2944
- if ( (gvl_PQsetClientEncoding(conn, StringValueCStr(str))) == -1 ) {
2945
- rb_raise(rb_ePGerror, "%s", PQerrorMessage(conn));
2946
- }
2969
+ if ( (gvl_PQsetClientEncoding(conn, StringValueCStr(str))) == -1 )
2970
+ pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(conn));
2971
+
2947
2972
  pgconn_set_internal_encoding_index( self );
2948
2973
 
2949
2974
  return Qnil;
2950
2975
  }
2951
2976
 
2952
- /*
2953
- * call-seq:
2954
- * conn.transaction { |conn| ... } -> result of the block
2955
- *
2956
- * Executes a +BEGIN+ at the start of the block,
2957
- * and a +COMMIT+ at the end of the block, or
2958
- * +ROLLBACK+ if any exception occurs.
2959
- */
2960
- static VALUE
2961
- pgconn_transaction(VALUE self)
2962
- {
2963
- PGconn *conn = pg_get_pgconn(self);
2964
- PGresult *result;
2965
- VALUE rb_pgresult;
2966
- VALUE block_result = Qnil;
2967
- int status;
2968
-
2969
- if (rb_block_given_p()) {
2970
- result = gvl_PQexec(conn, "BEGIN");
2971
- rb_pgresult = pg_new_result(result, self);
2972
- pg_result_check(rb_pgresult);
2973
- block_result = rb_protect(rb_yield, self, &status);
2974
- if(status == 0) {
2975
- result = gvl_PQexec(conn, "COMMIT");
2976
- rb_pgresult = pg_new_result(result, self);
2977
- pg_result_check(rb_pgresult);
2978
- }
2979
- else {
2980
- /* exception occurred, ROLLBACK and re-raise */
2981
- result = gvl_PQexec(conn, "ROLLBACK");
2982
- rb_pgresult = pg_new_result(result, self);
2983
- pg_result_check(rb_pgresult);
2984
- rb_jump_tag(status);
2985
- }
2986
-
2987
- }
2988
- else {
2989
- /* no block supplied? */
2990
- rb_raise(rb_eArgError, "Must supply block for PG::Connection#transaction");
2991
- }
2992
- return block_result;
2993
- }
2994
-
2995
2977
 
2996
2978
  /*
2997
2979
  * call-seq:
@@ -3036,14 +3018,12 @@ pgconn_s_quote_ident(VALUE self, VALUE str_or_array)
3036
3018
  int enc_idx;
3037
3019
 
3038
3020
  if( rb_obj_is_kind_of(self, rb_cPGconn) ){
3039
- enc_idx = ENCODING_GET( self );
3021
+ enc_idx = pg_get_connection(self)->enc_idx;
3040
3022
  }else{
3041
3023
  enc_idx = RB_TYPE_P(str_or_array, T_STRING) ? ENCODING_GET( str_or_array ) : rb_ascii8bit_encindex();
3042
3024
  }
3043
3025
  pg_text_enc_identifier(NULL, str_or_array, NULL, &ret, enc_idx);
3044
3026
 
3045
- OBJ_INFECT(ret, str_or_array);
3046
-
3047
3027
  return ret;
3048
3028
  }
3049
3029
 
@@ -3068,14 +3048,8 @@ get_result_readable(PGconn *conn)
3068
3048
  * If +true+ is returned, +conn.is_busy+ will return +false+
3069
3049
  * and +conn.get_result+ will not block.
3070
3050
  */
3071
- static VALUE
3051
+ VALUE
3072
3052
  pgconn_block( int argc, VALUE *argv, VALUE self ) {
3073
- PGconn *conn = pg_get_pgconn( self );
3074
-
3075
- /* If WIN32 and Ruby 1.9 do not use rb_thread_select() which sometimes hangs
3076
- * and does not wait (nor sleep) any time even if timeout is given.
3077
- * Instead use the Winsock events and rb_w32_wait_events(). */
3078
-
3079
3053
  struct timeval timeout;
3080
3054
  struct timeval *ptimeout = NULL;
3081
3055
  VALUE timeout_in;
@@ -3089,7 +3063,7 @@ pgconn_block( int argc, VALUE *argv, VALUE self ) {
3089
3063
  ptimeout = &timeout;
3090
3064
  }
3091
3065
 
3092
- ret = wait_socket_readable( conn, ptimeout, get_result_readable);
3066
+ ret = wait_socket_readable( self, ptimeout, get_result_readable);
3093
3067
 
3094
3068
  if( !ret )
3095
3069
  return Qfalse;
@@ -3098,6 +3072,42 @@ pgconn_block( int argc, VALUE *argv, VALUE self ) {
3098
3072
  }
3099
3073
 
3100
3074
 
3075
+ /*
3076
+ * call-seq:
3077
+ * conn.sync_get_last_result( ) -> PG::Result
3078
+ *
3079
+ * This function has the same behavior as #async_get_last_result, but is implemented using the synchronous command processing API of libpq.
3080
+ * See #async_exec for the differences between the two API variants.
3081
+ * 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.
3082
+ */
3083
+ static VALUE
3084
+ pgconn_sync_get_last_result(VALUE self)
3085
+ {
3086
+ PGconn *conn = pg_get_pgconn(self);
3087
+ VALUE rb_pgresult = Qnil;
3088
+ PGresult *cur, *prev;
3089
+
3090
+
3091
+ cur = prev = NULL;
3092
+ while ((cur = gvl_PQgetResult(conn)) != NULL) {
3093
+ int status;
3094
+
3095
+ if (prev) PQclear(prev);
3096
+ prev = cur;
3097
+
3098
+ status = PQresultStatus(cur);
3099
+ if (status == PGRES_COPY_OUT || status == PGRES_COPY_IN || status == PGRES_COPY_BOTH)
3100
+ break;
3101
+ }
3102
+
3103
+ if (prev) {
3104
+ rb_pgresult = pg_new_result( prev, self );
3105
+ pg_result_check(rb_pgresult);
3106
+ }
3107
+
3108
+ return rb_pgresult;
3109
+ }
3110
+
3101
3111
  /*
3102
3112
  * call-seq:
3103
3113
  * conn.get_last_result( ) -> PG::Result
@@ -3108,27 +3118,38 @@ pgconn_block( int argc, VALUE *argv, VALUE self ) {
3108
3118
  * returns the last non-NULL result, or +nil+ if no
3109
3119
  * results are available.
3110
3120
  *
3121
+ * If the last result contains a bad result_status, an
3122
+ * appropriate exception is raised.
3123
+ *
3111
3124
  * This function is similar to #get_result
3112
3125
  * except that it is designed to get one and only
3113
- * one result.
3126
+ * one result and that it checks the result state.
3114
3127
  */
3115
3128
  static VALUE
3116
- pgconn_get_last_result(VALUE self)
3129
+ pgconn_async_get_last_result(VALUE self)
3117
3130
  {
3118
3131
  PGconn *conn = pg_get_pgconn(self);
3119
3132
  VALUE rb_pgresult = Qnil;
3120
3133
  PGresult *cur, *prev;
3121
3134
 
3122
-
3123
3135
  cur = prev = NULL;
3124
- while ((cur = gvl_PQgetResult(conn)) != NULL) {
3136
+ for(;;) {
3125
3137
  int status;
3126
3138
 
3139
+ /* Wait for input before reading each result.
3140
+ * That way we support the ruby-3.x IO scheduler and don't block other ruby threads.
3141
+ */
3142
+ wait_socket_readable(self, NULL, get_result_readable);
3143
+
3144
+ cur = gvl_PQgetResult(conn);
3145
+ if (cur == NULL)
3146
+ break;
3147
+
3127
3148
  if (prev) PQclear(prev);
3128
3149
  prev = cur;
3129
3150
 
3130
3151
  status = PQresultStatus(cur);
3131
- if (status == PGRES_COPY_OUT || status == PGRES_COPY_IN)
3152
+ if (status == PGRES_COPY_OUT || status == PGRES_COPY_IN || status == PGRES_COPY_BOTH)
3132
3153
  break;
3133
3154
  }
3134
3155
 
@@ -3142,25 +3163,343 @@ pgconn_get_last_result(VALUE self)
3142
3163
 
3143
3164
  /*
3144
3165
  * call-seq:
3145
- * conn.async_exec(sql [, params, result_format ] ) -> PG::Result
3146
- * conn.async_exec(sql [, params, result_format ] ) {|pg_result| block }
3166
+ * conn.discard_results()
3167
+ *
3168
+ * Silently discard any prior query result that application didn't eat.
3169
+ * This is internally used prior to Connection#exec and sibling methods.
3170
+ * It doesn't raise an exception on connection errors, but returns +false+ instead.
3171
+ *
3172
+ * Returns:
3173
+ * * +nil+ when the connection is already idle
3174
+ * * +true+ when some results have been discarded
3175
+ * * +false+ when a failure occurred and the connection was closed
3176
+ *
3177
+ */
3178
+ static VALUE
3179
+ pgconn_discard_results(VALUE self)
3180
+ {
3181
+ PGconn *conn = pg_get_pgconn(self);
3182
+ VALUE socket_io;
3183
+
3184
+ switch( PQtransactionStatus(conn) ) {
3185
+ case PQTRANS_IDLE:
3186
+ case PQTRANS_INTRANS:
3187
+ case PQTRANS_INERROR:
3188
+ return Qnil;
3189
+ default:;
3190
+ }
3191
+
3192
+ socket_io = pgconn_socket_io(self);
3193
+
3194
+ for(;;) {
3195
+ PGresult *cur;
3196
+ int status;
3197
+
3198
+ /* pgconn_block() raises an exception in case of errors.
3199
+ * To avoid this call pg_rb_io_wait() and PQconsumeInput() without rb_raise().
3200
+ */
3201
+ while( gvl_PQisBusy(conn) ){
3202
+ int events;
3203
+
3204
+ switch( PQflush(conn) ) {
3205
+ case 1:
3206
+ events = RB_NUM2INT(pg_rb_io_wait(socket_io, RB_INT2NUM(PG_RUBY_IO_READABLE | PG_RUBY_IO_WRITABLE), Qnil));
3207
+ if (events & PG_RUBY_IO_READABLE){
3208
+ if ( PQconsumeInput(conn) == 0 ) goto error;
3209
+ }
3210
+ break;
3211
+ case 0:
3212
+ pg_rb_io_wait(socket_io, RB_INT2NUM(PG_RUBY_IO_READABLE), Qnil);
3213
+ if ( PQconsumeInput(conn) == 0 ) goto error;
3214
+ break;
3215
+ default:
3216
+ goto error;
3217
+ }
3218
+ }
3219
+
3220
+ cur = gvl_PQgetResult(conn);
3221
+ if( cur == NULL) break;
3222
+
3223
+ status = PQresultStatus(cur);
3224
+ PQclear(cur);
3225
+ if (status == PGRES_COPY_IN){
3226
+ while( gvl_PQputCopyEnd(conn, "COPY terminated by new query or discard_results") == 0 ){
3227
+ pgconn_async_flush(self);
3228
+ }
3229
+ }
3230
+ if (status == PGRES_COPY_OUT){
3231
+ for(;;) {
3232
+ char *buffer = NULL;
3233
+ int st = gvl_PQgetCopyData(conn, &buffer, 1);
3234
+ if( st == 0 ) {
3235
+ /* would block -> wait for readable data */
3236
+ pg_rb_io_wait(socket_io, RB_INT2NUM(PG_RUBY_IO_READABLE), Qnil);
3237
+ if ( PQconsumeInput(conn) == 0 ) goto error;
3238
+ } else if( st > 0 ) {
3239
+ /* some data retrieved -> discard it */
3240
+ PQfreemem(buffer);
3241
+ } else {
3242
+ /* no more data */
3243
+ break;
3244
+ }
3245
+ }
3246
+ }
3247
+ }
3248
+
3249
+ return Qtrue;
3250
+
3251
+ error:
3252
+ pgconn_close_socket_io(self);
3253
+ return Qfalse;
3254
+ }
3255
+
3256
+ /*
3257
+ * call-seq:
3258
+ * conn.exec(sql) -> PG::Result
3259
+ * conn.exec(sql) {|pg_result| block }
3260
+ *
3261
+ * Sends SQL query request specified by _sql_ to PostgreSQL.
3262
+ * On success, it returns a PG::Result instance with all result rows and columns.
3263
+ * On failure, it raises a PG::Error.
3264
+ *
3265
+ * For backward compatibility, if you pass more than one parameter to this method,
3266
+ * it will call #exec_params for you. New code should explicitly use #exec_params if
3267
+ * argument placeholders are used.
3268
+ *
3269
+ * If the optional code block is given, it will be passed <i>result</i> as an argument,
3270
+ * and the PG::Result object will automatically be cleared when the block terminates.
3271
+ * In this instance, <code>conn.exec</code> returns the value of the block.
3272
+ *
3273
+ * #exec is an alias for #async_exec which is almost identical to #sync_exec .
3274
+ * #sync_exec is implemented on the simpler synchronous command processing API of libpq, whereas
3275
+ * #async_exec is implemented on the asynchronous API and on ruby's IO mechanisms.
3276
+ * Only #async_exec is compatible to <tt>Fiber.scheduler</tt> based asynchronous IO processing introduced in ruby-3.0.
3277
+ * Both methods ensure that other threads can process while waiting for the server to
3278
+ * complete the request, but #sync_exec blocks all signals to be processed until the query is finished.
3279
+ * This is most notably visible by a delayed reaction to Control+C.
3280
+ * It's not recommended to use explicit sync or async variants but #exec instead, unless you have a good reason to do so.
3147
3281
  *
3148
- * This function has the same behavior as #exec,
3149
- * but is implemented using the asynchronous command
3150
- * processing API of libpq.
3282
+ * See also corresponding {libpq function}[https://www.postgresql.org/docs/current/libpq-exec.html#LIBPQ-PQEXEC].
3151
3283
  */
3152
3284
  static VALUE
3153
3285
  pgconn_async_exec(int argc, VALUE *argv, VALUE self)
3154
3286
  {
3155
3287
  VALUE rb_pgresult = Qnil;
3156
3288
 
3157
- /* remove any remaining results from the queue */
3158
- pgconn_block( 0, NULL, self ); /* wait for input (without blocking) before reading the last result */
3159
- pgconn_get_last_result( self );
3160
-
3289
+ pgconn_discard_results( self );
3161
3290
  pgconn_send_query( argc, argv, self );
3162
- pgconn_block( 0, NULL, self );
3163
- rb_pgresult = pgconn_get_last_result( self );
3291
+ rb_pgresult = pgconn_async_get_last_result( self );
3292
+
3293
+ if ( rb_block_given_p() ) {
3294
+ return rb_ensure( rb_yield, rb_pgresult, pg_result_clear, rb_pgresult );
3295
+ }
3296
+ return rb_pgresult;
3297
+ }
3298
+
3299
+
3300
+ /*
3301
+ * call-seq:
3302
+ * conn.exec_params(sql, params [, result_format [, type_map ]] ) -> nil
3303
+ * conn.exec_params(sql, params [, result_format [, type_map ]] ) {|pg_result| block }
3304
+ *
3305
+ * Sends SQL query request specified by +sql+ to PostgreSQL using placeholders
3306
+ * for parameters.
3307
+ *
3308
+ * Returns a PG::Result instance on success. On failure, it raises a PG::Error.
3309
+ *
3310
+ * +params+ is an array of the bind parameters for the SQL query.
3311
+ * Each element of the +params+ array may be either:
3312
+ * a hash of the form:
3313
+ * {:value => String (value of bind parameter)
3314
+ * :type => Integer (oid of type of bind parameter)
3315
+ * :format => Integer (0 for text, 1 for binary)
3316
+ * }
3317
+ * or, it may be a String. If it is a string, that is equivalent to the hash:
3318
+ * { :value => <string value>, :type => 0, :format => 0 }
3319
+ *
3320
+ * PostgreSQL bind parameters are represented as $1, $2, $3, etc.,
3321
+ * inside the SQL query. The 0th element of the +params+ array is bound
3322
+ * to $1, the 1st element is bound to $2, etc. +nil+ is treated as +NULL+.
3323
+ *
3324
+ * If the types are not specified, they will be inferred by PostgreSQL.
3325
+ * Instead of specifying type oids, it's recommended to simply add
3326
+ * explicit casts in the query to ensure that the right type is used.
3327
+ *
3328
+ * For example: "SELECT $1::int"
3329
+ *
3330
+ * The optional +result_format+ should be 0 for text results, 1
3331
+ * for binary.
3332
+ *
3333
+ * +type_map+ can be a PG::TypeMap derivation (such as PG::BasicTypeMapForQueries).
3334
+ * This will type cast the params from various Ruby types before transmission
3335
+ * based on the encoders defined by the type map. When a type encoder is used
3336
+ * the format and oid of a given bind parameter are retrieved from the encoder
3337
+ * instead out of the hash form described above.
3338
+ *
3339
+ * If the optional code block is given, it will be passed <i>result</i> as an argument,
3340
+ * and the PG::Result object will automatically be cleared when the block terminates.
3341
+ * In this instance, <code>conn.exec</code> returns the value of the block.
3342
+ *
3343
+ * The primary advantage of #exec_params over #exec is that parameter values can be separated from the command string, thus avoiding the need for tedious and error-prone quoting and escaping.
3344
+ * Unlike #exec, #exec_params allows at most one SQL command in the given string.
3345
+ * (There can be semicolons in it, but not more than one nonempty command.)
3346
+ * This is a limitation of the underlying protocol, but has some usefulness as an extra defense against SQL-injection attacks.
3347
+ *
3348
+ * See also corresponding {libpq function}[https://www.postgresql.org/docs/current/libpq-exec.html#LIBPQ-PQEXECPARAMS].
3349
+ */
3350
+ static VALUE
3351
+ pgconn_async_exec_params(int argc, VALUE *argv, VALUE self)
3352
+ {
3353
+ VALUE rb_pgresult = Qnil;
3354
+
3355
+ pgconn_discard_results( self );
3356
+ /* If called with no or nil parameters, use PQsendQuery for compatibility */
3357
+ if ( argc == 1 || (argc >= 2 && argc <= 4 && NIL_P(argv[1]) )) {
3358
+ pg_deprecated(3, ("forwarding async_exec_params to async_exec is deprecated"));
3359
+ pgconn_send_query( argc, argv, self );
3360
+ } else {
3361
+ pgconn_send_query_params( argc, argv, self );
3362
+ }
3363
+ rb_pgresult = pgconn_async_get_last_result( self );
3364
+
3365
+ if ( rb_block_given_p() ) {
3366
+ return rb_ensure( rb_yield, rb_pgresult, pg_result_clear, rb_pgresult );
3367
+ }
3368
+ return rb_pgresult;
3369
+ }
3370
+
3371
+
3372
+ /*
3373
+ * call-seq:
3374
+ * conn.prepare(stmt_name, sql [, param_types ] ) -> PG::Result
3375
+ *
3376
+ * Prepares statement _sql_ with name _name_ to be executed later.
3377
+ * Returns a PG::Result instance on success.
3378
+ * On failure, it raises a PG::Error.
3379
+ *
3380
+ * +param_types+ is an optional parameter to specify the Oids of the
3381
+ * types of the parameters.
3382
+ *
3383
+ * If the types are not specified, they will be inferred by PostgreSQL.
3384
+ * Instead of specifying type oids, it's recommended to simply add
3385
+ * explicit casts in the query to ensure that the right type is used.
3386
+ *
3387
+ * For example: "SELECT $1::int"
3388
+ *
3389
+ * PostgreSQL bind parameters are represented as $1, $2, $3, etc.,
3390
+ * inside the SQL query.
3391
+ *
3392
+ * See also corresponding {libpq function}[https://www.postgresql.org/docs/current/libpq-exec.html#LIBPQ-PQPREPARE].
3393
+ */
3394
+ static VALUE
3395
+ pgconn_async_prepare(int argc, VALUE *argv, VALUE self)
3396
+ {
3397
+ VALUE rb_pgresult = Qnil;
3398
+
3399
+ pgconn_discard_results( self );
3400
+ pgconn_send_prepare( argc, argv, self );
3401
+ rb_pgresult = pgconn_async_get_last_result( self );
3402
+
3403
+ if ( rb_block_given_p() ) {
3404
+ return rb_ensure( rb_yield, rb_pgresult, pg_result_clear, rb_pgresult );
3405
+ }
3406
+ return rb_pgresult;
3407
+ }
3408
+
3409
+
3410
+ /*
3411
+ * call-seq:
3412
+ * conn.exec_prepared(statement_name [, params, result_format[, type_map]] ) -> PG::Result
3413
+ * conn.exec_prepared(statement_name [, params, result_format[, type_map]] ) {|pg_result| block }
3414
+ *
3415
+ * Execute prepared named statement specified by _statement_name_.
3416
+ * Returns a PG::Result instance on success.
3417
+ * On failure, it raises a PG::Error.
3418
+ *
3419
+ * +params+ is an array of the optional bind parameters for the
3420
+ * SQL query. Each element of the +params+ array may be either:
3421
+ * a hash of the form:
3422
+ * {:value => String (value of bind parameter)
3423
+ * :format => Integer (0 for text, 1 for binary)
3424
+ * }
3425
+ * or, it may be a String. If it is a string, that is equivalent to the hash:
3426
+ * { :value => <string value>, :format => 0 }
3427
+ *
3428
+ * PostgreSQL bind parameters are represented as $1, $2, $3, etc.,
3429
+ * inside the SQL query. The 0th element of the +params+ array is bound
3430
+ * to $1, the 1st element is bound to $2, etc. +nil+ is treated as +NULL+.
3431
+ *
3432
+ * The optional +result_format+ should be 0 for text results, 1
3433
+ * for binary.
3434
+ *
3435
+ * +type_map+ can be a PG::TypeMap derivation (such as PG::BasicTypeMapForQueries).
3436
+ * This will type cast the params from various Ruby types before transmission
3437
+ * based on the encoders defined by the type map. When a type encoder is used
3438
+ * the format and oid of a given bind parameter are retrieved from the encoder
3439
+ * instead out of the hash form described above.
3440
+ *
3441
+ * If the optional code block is given, it will be passed <i>result</i> as an argument,
3442
+ * and the PG::Result object will automatically be cleared when the block terminates.
3443
+ * In this instance, <code>conn.exec_prepared</code> returns the value of the block.
3444
+ *
3445
+ * See also corresponding {libpq function}[https://www.postgresql.org/docs/current/libpq-exec.html#LIBPQ-PQEXECPREPARED].
3446
+ */
3447
+ static VALUE
3448
+ pgconn_async_exec_prepared(int argc, VALUE *argv, VALUE self)
3449
+ {
3450
+ VALUE rb_pgresult = Qnil;
3451
+
3452
+ pgconn_discard_results( self );
3453
+ pgconn_send_query_prepared( argc, argv, self );
3454
+ rb_pgresult = pgconn_async_get_last_result( self );
3455
+
3456
+ if ( rb_block_given_p() ) {
3457
+ return rb_ensure( rb_yield, rb_pgresult, pg_result_clear, rb_pgresult );
3458
+ }
3459
+ return rb_pgresult;
3460
+ }
3461
+
3462
+
3463
+ /*
3464
+ * call-seq:
3465
+ * conn.describe_portal( portal_name ) -> PG::Result
3466
+ *
3467
+ * Retrieve information about the portal _portal_name_.
3468
+ *
3469
+ * See also corresponding {libpq function}[https://www.postgresql.org/docs/current/libpq-exec.html#LIBPQ-PQDESCRIBEPORTAL].
3470
+ */
3471
+ static VALUE
3472
+ pgconn_async_describe_portal(VALUE self, VALUE portal)
3473
+ {
3474
+ VALUE rb_pgresult = Qnil;
3475
+
3476
+ pgconn_discard_results( self );
3477
+ pgconn_send_describe_portal( self, portal );
3478
+ rb_pgresult = pgconn_async_get_last_result( self );
3479
+
3480
+ if ( rb_block_given_p() ) {
3481
+ return rb_ensure( rb_yield, rb_pgresult, pg_result_clear, rb_pgresult );
3482
+ }
3483
+ return rb_pgresult;
3484
+ }
3485
+
3486
+
3487
+ /*
3488
+ * call-seq:
3489
+ * conn.describe_prepared( statement_name ) -> PG::Result
3490
+ *
3491
+ * Retrieve information about the prepared statement _statement_name_.
3492
+ *
3493
+ * See also corresponding {libpq function}[https://www.postgresql.org/docs/current/libpq-exec.html#LIBPQ-PQDESCRIBEPREPARED].
3494
+ */
3495
+ static VALUE
3496
+ pgconn_async_describe_prepared(VALUE self, VALUE stmt_name)
3497
+ {
3498
+ VALUE rb_pgresult = Qnil;
3499
+
3500
+ pgconn_discard_results( self );
3501
+ pgconn_send_describe_prepared( self, stmt_name );
3502
+ rb_pgresult = pgconn_async_get_last_result( self );
3164
3503
 
3165
3504
  if ( rb_block_given_p() ) {
3166
3505
  return rb_ensure( rb_yield, rb_pgresult, pg_result_clear, rb_pgresult );
@@ -3174,7 +3513,7 @@ pgconn_async_exec(int argc, VALUE *argv, VALUE self)
3174
3513
  * call-seq:
3175
3514
  * conn.ssl_in_use? -> Boolean
3176
3515
  *
3177
- * Returns +true+ if the connection uses SSL, +false+ if not.
3516
+ * Returns +true+ if the connection uses SSL/TLS, +false+ if not.
3178
3517
  *
3179
3518
  * Available since PostgreSQL-9.5
3180
3519
  */
@@ -3208,7 +3547,7 @@ pgconn_ssl_in_use(VALUE self)
3208
3547
  * If SSL compression is in use, returns the name of the compression algorithm, or "on" if compression is used but the algorithm is not known. If compression is not in use, returns "off".
3209
3548
  *
3210
3549
  *
3211
- * See also #ssl_attribute_names and http://www.postgresql.org/docs/current/interactive/libpq-status.html#LIBPQ-PQSSLATTRIBUTE
3550
+ * See also #ssl_attribute_names and the {corresponding libpq function}[https://www.postgresql.org/docs/current/libpq-status.html#LIBPQ-PQSSLATTRIBUTE].
3212
3551
  *
3213
3552
  * Available since PostgreSQL-9.5
3214
3553
  */
@@ -3248,10 +3587,134 @@ pgconn_ssl_attribute_names(VALUE self)
3248
3587
  #endif
3249
3588
 
3250
3589
 
3590
+ #ifdef HAVE_PQENTERPIPELINEMODE
3591
+ /*
3592
+ * call-seq:
3593
+ * conn.pipeline_status -> Integer
3594
+ *
3595
+ * Returns the current pipeline mode status of the libpq connection.
3596
+ *
3597
+ * PQpipelineStatus can return one of the following values:
3598
+ *
3599
+ * * PQ_PIPELINE_ON - The libpq connection is in pipeline mode.
3600
+ * * PQ_PIPELINE_OFF - The libpq connection is not in pipeline mode.
3601
+ * * PQ_PIPELINE_ABORTED - The libpq connection is in pipeline mode and an error occurred while processing the current pipeline.
3602
+ * The aborted flag is cleared when PQgetResult returns a result of type PGRES_PIPELINE_SYNC.
3603
+ *
3604
+ * Available since PostgreSQL-14
3605
+ */
3606
+ static VALUE
3607
+ pgconn_pipeline_status(VALUE self)
3608
+ {
3609
+ int res = PQpipelineStatus(pg_get_pgconn(self));
3610
+ return INT2FIX(res);
3611
+ }
3612
+
3613
+
3614
+ /*
3615
+ * call-seq:
3616
+ * conn.enter_pipeline_mode -> nil
3617
+ *
3618
+ * Causes a connection to enter pipeline mode if it is currently idle or already in pipeline mode.
3619
+ *
3620
+ * 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.
3621
+ * This function does not actually send anything to the server, it just changes the libpq connection state.
3622
+ *
3623
+ * Available since PostgreSQL-14
3624
+ */
3625
+ static VALUE
3626
+ pgconn_enter_pipeline_mode(VALUE self)
3627
+ {
3628
+ PGconn *conn = pg_get_pgconn(self);
3629
+ int res = PQenterPipelineMode(conn);
3630
+ if( res != 1 )
3631
+ pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(conn));
3632
+
3633
+ return Qnil;
3634
+ }
3635
+
3636
+ /*
3637
+ * call-seq:
3638
+ * conn.exit_pipeline_mode -> nil
3639
+ *
3640
+ * Causes a connection to exit pipeline mode if it is currently in pipeline mode with an empty queue and no pending results.
3641
+ *
3642
+ * Takes no action if not in pipeline mode.
3643
+ * 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.
3644
+ *
3645
+ * Available since PostgreSQL-14
3646
+ */
3647
+ static VALUE
3648
+ pgconn_exit_pipeline_mode(VALUE self)
3649
+ {
3650
+ PGconn *conn = pg_get_pgconn(self);
3651
+ int res = PQexitPipelineMode(conn);
3652
+ if( res != 1 )
3653
+ pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(conn));
3654
+
3655
+ return Qnil;
3656
+ }
3657
+
3658
+
3659
+ /*
3660
+ * call-seq:
3661
+ * conn.pipeline_sync -> nil
3662
+ *
3663
+ * Marks a synchronization point in a pipeline by sending a sync message and flushing the send buffer.
3664
+ * This serves as the delimiter of an implicit transaction and an error recovery point; see Section 34.5.1.3 of the PostgreSQL documentation.
3665
+ *
3666
+ * Raises PG::Error if the connection is not in pipeline mode or sending a sync message failed.
3667
+ *
3668
+ * Available since PostgreSQL-14
3669
+ */
3670
+ static VALUE
3671
+ pgconn_pipeline_sync(VALUE self)
3672
+ {
3673
+ PGconn *conn = pg_get_pgconn(self);
3674
+ int res = PQpipelineSync(conn);
3675
+ if( res != 1 )
3676
+ pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(conn));
3677
+
3678
+ return Qnil;
3679
+ }
3680
+
3681
+ /*
3682
+ * call-seq:
3683
+ * conn.pipeline_sync -> nil
3684
+ *
3685
+ * Sends a request for the server to flush its output buffer.
3686
+ *
3687
+ * 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.
3688
+ * This function is useful to cause the server to flush its output buffer in pipeline mode without establishing a synchronization point.
3689
+ * Note that the request is not itself flushed to the server automatically; use Connection#flush if necessary.
3690
+ *
3691
+ * Available since PostgreSQL-14
3692
+ */
3693
+ static VALUE
3694
+ pgconn_send_flush_request(VALUE self)
3695
+ {
3696
+ PGconn *conn = pg_get_pgconn(self);
3697
+ int res = PQsendFlushRequest(conn);
3698
+ if( res != 1 )
3699
+ pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(conn));
3700
+
3701
+ return Qnil;
3702
+ }
3703
+
3704
+ #endif
3705
+
3251
3706
  /**************************************************************************
3252
3707
  * LARGE OBJECT SUPPORT
3253
3708
  **************************************************************************/
3254
3709
 
3710
+ #define BLOCKING_BEGIN(conn) do { \
3711
+ int old_nonblocking = PQisnonblocking(conn); \
3712
+ PQsetnonblocking(conn, 0);
3713
+
3714
+ #define BLOCKING_END(th) \
3715
+ PQsetnonblocking(conn, old_nonblocking); \
3716
+ } while(0);
3717
+
3255
3718
  /*
3256
3719
  * call-seq:
3257
3720
  * conn.lo_creat( [mode] ) -> Integer
@@ -3272,9 +3735,12 @@ pgconn_locreat(int argc, VALUE *argv, VALUE self)
3272
3735
  else
3273
3736
  mode = NUM2INT(nmode);
3274
3737
 
3275
- lo_oid = lo_creat(conn, mode);
3738
+ BLOCKING_BEGIN(conn)
3739
+ lo_oid = lo_creat(conn, mode);
3740
+ BLOCKING_END(conn)
3741
+
3276
3742
  if (lo_oid == 0)
3277
- rb_raise(rb_ePGerror, "lo_creat failed");
3743
+ pg_raise_conn_error( rb_ePGerror, self, "lo_creat failed");
3278
3744
 
3279
3745
  return UINT2NUM(lo_oid);
3280
3746
  }
@@ -3295,7 +3761,7 @@ pgconn_locreate(VALUE self, VALUE in_lo_oid)
3295
3761
 
3296
3762
  ret = lo_create(conn, lo_oid);
3297
3763
  if (ret == InvalidOid)
3298
- rb_raise(rb_ePGerror, "lo_create failed");
3764
+ pg_raise_conn_error( rb_ePGerror, self, "lo_create failed");
3299
3765
 
3300
3766
  return UINT2NUM(ret);
3301
3767
  }
@@ -3317,9 +3783,12 @@ pgconn_loimport(VALUE self, VALUE filename)
3317
3783
 
3318
3784
  Check_Type(filename, T_STRING);
3319
3785
 
3320
- lo_oid = lo_import(conn, StringValueCStr(filename));
3786
+ BLOCKING_BEGIN(conn)
3787
+ lo_oid = lo_import(conn, StringValueCStr(filename));
3788
+ BLOCKING_END(conn)
3789
+
3321
3790
  if (lo_oid == 0) {
3322
- rb_raise(rb_ePGerror, "%s", PQerrorMessage(conn));
3791
+ pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(conn));
3323
3792
  }
3324
3793
  return UINT2NUM(lo_oid);
3325
3794
  }
@@ -3335,12 +3804,17 @@ pgconn_loexport(VALUE self, VALUE lo_oid, VALUE filename)
3335
3804
  {
3336
3805
  PGconn *conn = pg_get_pgconn(self);
3337
3806
  Oid oid;
3807
+ int ret;
3338
3808
  Check_Type(filename, T_STRING);
3339
3809
 
3340
3810
  oid = NUM2UINT(lo_oid);
3341
3811
 
3342
- if (lo_export(conn, oid, StringValueCStr(filename)) < 0) {
3343
- rb_raise(rb_ePGerror, "%s", PQerrorMessage(conn));
3812
+ BLOCKING_BEGIN(conn)
3813
+ ret = lo_export(conn, oid, StringValueCStr(filename));
3814
+ BLOCKING_END(conn)
3815
+
3816
+ if (ret < 0) {
3817
+ pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(conn));
3344
3818
  }
3345
3819
  return Qnil;
3346
3820
  }
@@ -3370,8 +3844,12 @@ pgconn_loopen(int argc, VALUE *argv, VALUE self)
3370
3844
  else
3371
3845
  mode = NUM2INT(nmode);
3372
3846
 
3373
- if((fd = lo_open(conn, lo_oid, mode)) < 0) {
3374
- rb_raise(rb_ePGerror, "can't open large object: %s", PQerrorMessage(conn));
3847
+ BLOCKING_BEGIN(conn)
3848
+ fd = lo_open(conn, lo_oid, mode);
3849
+ BLOCKING_END(conn)
3850
+
3851
+ if(fd < 0) {
3852
+ pg_raise_conn_error( rb_ePGerror, self, "can't open large object: %s", PQerrorMessage(conn));
3375
3853
  }
3376
3854
  return INT2FIX(fd);
3377
3855
  }
@@ -3393,11 +3871,15 @@ pgconn_lowrite(VALUE self, VALUE in_lo_desc, VALUE buffer)
3393
3871
  Check_Type(buffer, T_STRING);
3394
3872
 
3395
3873
  if( RSTRING_LEN(buffer) < 0) {
3396
- rb_raise(rb_ePGerror, "write buffer zero string");
3874
+ pg_raise_conn_error( rb_ePGerror, self, "write buffer zero string");
3397
3875
  }
3398
- if((n = lo_write(conn, fd, StringValuePtr(buffer),
3399
- RSTRING_LEN(buffer))) < 0) {
3400
- rb_raise(rb_ePGerror, "lo_write failed: %s", PQerrorMessage(conn));
3876
+ BLOCKING_BEGIN(conn)
3877
+ n = lo_write(conn, fd, StringValuePtr(buffer),
3878
+ RSTRING_LEN(buffer));
3879
+ BLOCKING_END(conn)
3880
+
3881
+ if(n < 0) {
3882
+ pg_raise_conn_error( rb_ePGerror, self, "lo_write failed: %s", PQerrorMessage(conn));
3401
3883
  }
3402
3884
 
3403
3885
  return INT2FIX(n);
@@ -3420,23 +3902,24 @@ pgconn_loread(VALUE self, VALUE in_lo_desc, VALUE in_len)
3420
3902
  VALUE str;
3421
3903
  char *buffer;
3422
3904
 
3423
- buffer = ALLOC_N(char, len);
3424
- if(buffer == NULL)
3425
- rb_raise(rb_eNoMemError, "ALLOC failed!");
3905
+ if (len < 0)
3906
+ pg_raise_conn_error( rb_ePGerror, self, "negative length %d given", len);
3426
3907
 
3427
- if (len < 0){
3428
- rb_raise(rb_ePGerror,"nagative length %d given", len);
3429
- }
3908
+ buffer = ALLOC_N(char, len);
3909
+
3910
+ BLOCKING_BEGIN(conn)
3911
+ ret = lo_read(conn, lo_desc, buffer, len);
3912
+ BLOCKING_END(conn)
3430
3913
 
3431
- if((ret = lo_read(conn, lo_desc, buffer, len)) < 0)
3432
- rb_raise(rb_ePGerror, "lo_read failed");
3914
+ if(ret < 0)
3915
+ pg_raise_conn_error( rb_ePGerror, self, "lo_read failed");
3433
3916
 
3434
3917
  if(ret == 0) {
3435
3918
  xfree(buffer);
3436
3919
  return Qnil;
3437
3920
  }
3438
3921
 
3439
- str = rb_tainted_str_new(buffer, ret);
3922
+ str = rb_str_new(buffer, ret);
3440
3923
  xfree(buffer);
3441
3924
 
3442
3925
  return str;
@@ -3458,8 +3941,12 @@ pgconn_lolseek(VALUE self, VALUE in_lo_desc, VALUE offset, VALUE whence)
3458
3941
  int lo_desc = NUM2INT(in_lo_desc);
3459
3942
  int ret;
3460
3943
 
3461
- if((ret = lo_lseek(conn, lo_desc, NUM2INT(offset), NUM2INT(whence))) < 0) {
3462
- rb_raise(rb_ePGerror, "lo_lseek failed");
3944
+ BLOCKING_BEGIN(conn)
3945
+ ret = lo_lseek(conn, lo_desc, NUM2INT(offset), NUM2INT(whence));
3946
+ BLOCKING_END(conn)
3947
+
3948
+ if(ret < 0) {
3949
+ pg_raise_conn_error( rb_ePGerror, self, "lo_lseek failed");
3463
3950
  }
3464
3951
 
3465
3952
  return INT2FIX(ret);
@@ -3478,8 +3965,12 @@ pgconn_lotell(VALUE self, VALUE in_lo_desc)
3478
3965
  PGconn *conn = pg_get_pgconn(self);
3479
3966
  int lo_desc = NUM2INT(in_lo_desc);
3480
3967
 
3481
- if((position = lo_tell(conn, lo_desc)) < 0)
3482
- rb_raise(rb_ePGerror,"lo_tell failed");
3968
+ BLOCKING_BEGIN(conn)
3969
+ position = lo_tell(conn, lo_desc);
3970
+ BLOCKING_END(conn)
3971
+
3972
+ if(position < 0)
3973
+ pg_raise_conn_error( rb_ePGerror, self, "lo_tell failed");
3483
3974
 
3484
3975
  return INT2FIX(position);
3485
3976
  }
@@ -3496,9 +3987,14 @@ pgconn_lotruncate(VALUE self, VALUE in_lo_desc, VALUE in_len)
3496
3987
  PGconn *conn = pg_get_pgconn(self);
3497
3988
  int lo_desc = NUM2INT(in_lo_desc);
3498
3989
  size_t len = NUM2INT(in_len);
3990
+ int ret;
3499
3991
 
3500
- if(lo_truncate(conn,lo_desc,len) < 0)
3501
- rb_raise(rb_ePGerror,"lo_truncate failed");
3992
+ BLOCKING_BEGIN(conn)
3993
+ ret = lo_truncate(conn,lo_desc,len);
3994
+ BLOCKING_END(conn)
3995
+
3996
+ if(ret < 0)
3997
+ pg_raise_conn_error( rb_ePGerror, self, "lo_truncate failed");
3502
3998
 
3503
3999
  return Qnil;
3504
4000
  }
@@ -3514,9 +4010,14 @@ pgconn_loclose(VALUE self, VALUE in_lo_desc)
3514
4010
  {
3515
4011
  PGconn *conn = pg_get_pgconn(self);
3516
4012
  int lo_desc = NUM2INT(in_lo_desc);
4013
+ int ret;
3517
4014
 
3518
- if(lo_close(conn,lo_desc) < 0)
3519
- rb_raise(rb_ePGerror,"lo_close failed");
4015
+ BLOCKING_BEGIN(conn)
4016
+ ret = lo_close(conn,lo_desc);
4017
+ BLOCKING_END(conn)
4018
+
4019
+ if(ret < 0)
4020
+ pg_raise_conn_error( rb_ePGerror, self, "lo_close failed");
3520
4021
 
3521
4022
  return Qnil;
3522
4023
  }
@@ -3532,20 +4033,28 @@ pgconn_lounlink(VALUE self, VALUE in_oid)
3532
4033
  {
3533
4034
  PGconn *conn = pg_get_pgconn(self);
3534
4035
  Oid oid = NUM2UINT(in_oid);
4036
+ int ret;
4037
+
4038
+ BLOCKING_BEGIN(conn)
4039
+ ret = lo_unlink(conn,oid);
4040
+ BLOCKING_END(conn)
3535
4041
 
3536
- if(lo_unlink(conn,oid) < 0)
3537
- rb_raise(rb_ePGerror,"lo_unlink failed");
4042
+ if(ret < 0)
4043
+ pg_raise_conn_error( rb_ePGerror, self, "lo_unlink failed");
3538
4044
 
3539
4045
  return Qnil;
3540
4046
  }
3541
4047
 
3542
4048
 
3543
- void
4049
+ static void
3544
4050
  pgconn_set_internal_encoding_index( VALUE self )
3545
4051
  {
3546
- PGconn *conn = pg_get_pgconn(self);
3547
- rb_encoding *enc = pg_conn_enc_get( conn );
3548
- PG_ENCODING_SET_NOCHECK( self, rb_enc_to_index(enc));
4052
+ int enc_idx;
4053
+ t_pg_connection *this = pg_get_connection_safe( self );
4054
+ rb_encoding *enc = pg_conn_enc_get( this->pgconn );
4055
+ enc_idx = rb_enc_to_index(enc);
4056
+ if( enc_idx >= (1<<(PG_ENC_IDX_BITS-1)) ) rb_raise(rb_eArgError, "unsupported encoding index %d", enc_idx);
4057
+ this->enc_idx = enc_idx;
3549
4058
  }
3550
4059
 
3551
4060
  /*
@@ -3588,13 +4097,13 @@ static VALUE pgconn_external_encoding(VALUE self);
3588
4097
  static VALUE
3589
4098
  pgconn_internal_encoding_set(VALUE self, VALUE enc)
3590
4099
  {
3591
- VALUE enc_inspect;
4100
+ rb_check_frozen(self);
3592
4101
  if (NIL_P(enc)) {
3593
- pgconn_set_client_encoding( self, rb_usascii_str_new_cstr("SQL_ASCII") );
4102
+ pgconn_sync_set_client_encoding( self, rb_usascii_str_new_cstr("SQL_ASCII") );
3594
4103
  return enc;
3595
4104
  }
3596
4105
  else if ( TYPE(enc) == T_STRING && strcasecmp("JOHAB", StringValueCStr(enc)) == 0 ) {
3597
- pgconn_set_client_encoding(self, rb_usascii_str_new_cstr("JOHAB"));
4106
+ pgconn_sync_set_client_encoding(self, rb_usascii_str_new_cstr("JOHAB"));
3598
4107
  return enc;
3599
4108
  }
3600
4109
  else {
@@ -3609,11 +4118,6 @@ pgconn_internal_encoding_set(VALUE self, VALUE enc)
3609
4118
  pgconn_set_internal_encoding_index( self );
3610
4119
  return enc;
3611
4120
  }
3612
-
3613
- enc_inspect = rb_inspect(enc);
3614
- rb_raise( rb_ePGerror, "unknown encoding: %s", StringValueCStr(enc_inspect) );
3615
-
3616
- return Qnil;
3617
4121
  }
3618
4122
 
3619
4123
 
@@ -3632,42 +4136,56 @@ pgconn_external_encoding(VALUE self)
3632
4136
  rb_encoding *enc = NULL;
3633
4137
  const char *pg_encname = NULL;
3634
4138
 
3635
- /* Use cached value if found */
3636
- if ( RTEST(this->external_encoding) ) return this->external_encoding;
3637
-
3638
4139
  pg_encname = PQparameterStatus( this->pgconn, "server_encoding" );
3639
4140
  enc = pg_get_pg_encname_as_rb_encoding( pg_encname );
3640
- this->external_encoding = rb_enc_from_encoding( enc );
3641
-
3642
- return this->external_encoding;
4141
+ return rb_enc_from_encoding( enc );
3643
4142
  }
3644
4143
 
4144
+ /*
4145
+ * call-seq:
4146
+ * conn.set_client_encoding( encoding )
4147
+ *
4148
+ * Sets the client encoding to the _encoding_ String.
4149
+ */
4150
+ static VALUE
4151
+ pgconn_async_set_client_encoding(VALUE self, VALUE encname)
4152
+ {
4153
+ VALUE query_format, query;
4154
+
4155
+ rb_check_frozen(self);
4156
+ Check_Type(encname, T_STRING);
4157
+ query_format = rb_str_new_cstr("set client_encoding to '%s'");
4158
+ query = rb_funcall(query_format, rb_intern("%"), 1, encname);
4159
+
4160
+ pgconn_async_exec(1, &query, self);
4161
+ pgconn_set_internal_encoding_index( self );
4162
+
4163
+ return Qnil;
4164
+ }
3645
4165
 
3646
4166
  static VALUE
3647
4167
  pgconn_set_client_encoding_async1( VALUE args )
3648
4168
  {
3649
4169
  VALUE self = ((VALUE*)args)[0];
3650
4170
  VALUE encname = ((VALUE*)args)[1];
3651
- VALUE query_format = rb_str_new_cstr("set client_encoding to '%s'");
3652
- VALUE query = rb_funcall(query_format, rb_intern("%"), 1, encname);
3653
-
3654
- pgconn_async_exec(1, &query, self);
4171
+ pgconn_async_set_client_encoding(self, encname);
3655
4172
  return 0;
3656
4173
  }
3657
4174
 
3658
4175
 
3659
4176
  static VALUE
3660
- pgconn_set_client_encoding_async2( VALUE arg )
4177
+ pgconn_set_client_encoding_async2( VALUE arg, VALUE ex )
3661
4178
  {
3662
4179
  UNUSED(arg);
4180
+ UNUSED(ex);
3663
4181
  return 1;
3664
4182
  }
3665
4183
 
3666
4184
 
3667
4185
  static VALUE
3668
- pgconn_set_client_encoding_async( VALUE self, const char *encname )
4186
+ pgconn_set_client_encoding_async( VALUE self, VALUE encname )
3669
4187
  {
3670
- VALUE args[] = { self, rb_str_new_cstr(encname) };
4188
+ VALUE args[] = { self, encname };
3671
4189
  return rb_rescue(pgconn_set_client_encoding_async1, (VALUE)&args, pgconn_set_client_encoding_async2, Qnil);
3672
4190
  }
3673
4191
 
@@ -3684,16 +4202,23 @@ static VALUE
3684
4202
  pgconn_set_default_encoding( VALUE self )
3685
4203
  {
3686
4204
  PGconn *conn = pg_get_pgconn( self );
3687
- rb_encoding *enc;
3688
- const char *encname;
3689
-
3690
- if (( enc = rb_default_internal_encoding() )) {
3691
- encname = pg_get_rb_encoding_as_pg_encoding( enc );
3692
- if ( pgconn_set_client_encoding_async(self, encname) != 0 )
3693
- rb_warn( "Failed to set the default_internal encoding to %s: '%s'",
3694
- encname, PQerrorMessage(conn) );
4205
+ rb_encoding *rb_enc;
4206
+
4207
+ rb_check_frozen(self);
4208
+ if (( rb_enc = rb_default_internal_encoding() )) {
4209
+ rb_encoding * conn_encoding = pg_conn_enc_get( conn );
4210
+
4211
+ /* Don't set the server encoding, if it's unnecessary.
4212
+ * This is important for connection proxies, who disallow configuration settings.
4213
+ */
4214
+ if ( conn_encoding != rb_enc ) {
4215
+ const char *encname = pg_get_rb_encoding_as_pg_encoding( rb_enc );
4216
+ if ( pgconn_set_client_encoding_async(self, rb_str_new_cstr(encname)) != 0 )
4217
+ rb_warning( "Failed to set the default_internal encoding to %s: '%s'",
4218
+ encname, PQerrorMessage(conn) );
4219
+ }
3695
4220
  pgconn_set_internal_encoding_index( self );
3696
- return rb_enc_from_encoding( enc );
4221
+ return rb_enc_from_encoding( rb_enc );
3697
4222
  } else {
3698
4223
  pgconn_set_internal_encoding_index( self );
3699
4224
  return Qnil;
@@ -3714,13 +4239,14 @@ static VALUE
3714
4239
  pgconn_type_map_for_queries_set(VALUE self, VALUE typemap)
3715
4240
  {
3716
4241
  t_pg_connection *this = pg_get_connection( self );
4242
+ t_typemap *tm;
4243
+ UNUSED(tm);
3717
4244
 
3718
- if ( !rb_obj_is_kind_of(typemap, rb_cTypeMap) ) {
3719
- rb_raise( rb_eTypeError, "wrong argument type %s (expected kind of PG::TypeMap)",
3720
- rb_obj_classname( typemap ) );
3721
- }
3722
- Check_Type(typemap, T_DATA);
3723
- this->type_map_for_queries = typemap;
4245
+ rb_check_frozen(self);
4246
+ /* Check type of method param */
4247
+ TypedData_Get_Struct(typemap, t_typemap, &pg_typemap_type, tm);
4248
+
4249
+ RB_OBJ_WRITE(self, &this->type_map_for_queries, typemap);
3724
4250
 
3725
4251
  return typemap;
3726
4252
  }
@@ -3754,13 +4280,12 @@ static VALUE
3754
4280
  pgconn_type_map_for_results_set(VALUE self, VALUE typemap)
3755
4281
  {
3756
4282
  t_pg_connection *this = pg_get_connection( self );
4283
+ t_typemap *tm;
4284
+ UNUSED(tm);
3757
4285
 
3758
- if ( !rb_obj_is_kind_of(typemap, rb_cTypeMap) ) {
3759
- rb_raise( rb_eTypeError, "wrong argument type %s (expected kind of PG::TypeMap)",
3760
- rb_obj_classname( typemap ) );
3761
- }
3762
- Check_Type(typemap, T_DATA);
3763
- this->type_map_for_results = typemap;
4286
+ rb_check_frozen(self);
4287
+ TypedData_Get_Struct(typemap, t_typemap, &pg_typemap_type, tm);
4288
+ RB_OBJ_WRITE(self, &this->type_map_for_results, typemap);
3764
4289
 
3765
4290
  return typemap;
3766
4291
  }
@@ -3794,20 +4319,20 @@ pgconn_type_map_for_results_get(VALUE self)
3794
4319
  *
3795
4320
  */
3796
4321
  static VALUE
3797
- pgconn_encoder_for_put_copy_data_set(VALUE self, VALUE typemap)
4322
+ pgconn_encoder_for_put_copy_data_set(VALUE self, VALUE encoder)
3798
4323
  {
3799
4324
  t_pg_connection *this = pg_get_connection( self );
3800
4325
 
3801
- if( typemap != Qnil ){
3802
- if ( !rb_obj_is_kind_of(typemap, rb_cPG_Coder) ) {
3803
- rb_raise( rb_eTypeError, "wrong argument type %s (expected kind of PG::Coder)",
3804
- rb_obj_classname( typemap ) );
3805
- }
3806
- Check_Type(typemap, T_DATA);
4326
+ rb_check_frozen(self);
4327
+ if( encoder != Qnil ){
4328
+ t_pg_coder *co;
4329
+ UNUSED(co);
4330
+ /* Check argument type */
4331
+ TypedData_Get_Struct(encoder, t_pg_coder, &pg_coder_type, co);
3807
4332
  }
3808
- this->encoder_for_put_copy_data = typemap;
4333
+ RB_OBJ_WRITE(self, &this->encoder_for_put_copy_data, encoder);
3809
4334
 
3810
- return typemap;
4335
+ return encoder;
3811
4336
  }
3812
4337
 
3813
4338
  /*
@@ -3843,20 +4368,20 @@ pgconn_encoder_for_put_copy_data_get(VALUE self)
3843
4368
  *
3844
4369
  */
3845
4370
  static VALUE
3846
- pgconn_decoder_for_get_copy_data_set(VALUE self, VALUE typemap)
4371
+ pgconn_decoder_for_get_copy_data_set(VALUE self, VALUE decoder)
3847
4372
  {
3848
4373
  t_pg_connection *this = pg_get_connection( self );
3849
4374
 
3850
- if( typemap != Qnil ){
3851
- if ( !rb_obj_is_kind_of(typemap, rb_cPG_Coder) ) {
3852
- rb_raise( rb_eTypeError, "wrong argument type %s (expected kind of PG::Coder)",
3853
- rb_obj_classname( typemap ) );
3854
- }
3855
- Check_Type(typemap, T_DATA);
4375
+ rb_check_frozen(self);
4376
+ if( decoder != Qnil ){
4377
+ t_pg_coder *co;
4378
+ UNUSED(co);
4379
+ /* Check argument type */
4380
+ TypedData_Get_Struct(decoder, t_pg_coder, &pg_coder_type, co);
3856
4381
  }
3857
- this->decoder_for_get_copy_data = typemap;
4382
+ RB_OBJ_WRITE(self, &this->decoder_for_get_copy_data, decoder);
3858
4383
 
3859
- return typemap;
4384
+ return decoder;
3860
4385
  }
3861
4386
 
3862
4387
  /*
@@ -3879,28 +4404,83 @@ pgconn_decoder_for_get_copy_data_get(VALUE self)
3879
4404
  return this->decoder_for_get_copy_data;
3880
4405
  }
3881
4406
 
4407
+ /*
4408
+ * call-seq:
4409
+ * conn.field_name_type = Symbol
4410
+ *
4411
+ * Set default type of field names of results retrieved by this connection.
4412
+ * It can be set to one of:
4413
+ * * +:string+ to use String based field names
4414
+ * * +:symbol+ to use Symbol based field names
4415
+ *
4416
+ * The default is +:string+ .
4417
+ *
4418
+ * Settings the type of field names affects only future results.
4419
+ *
4420
+ * See further description at PG::Result#field_name_type=
4421
+ *
4422
+ */
4423
+ static VALUE
4424
+ pgconn_field_name_type_set(VALUE self, VALUE sym)
4425
+ {
4426
+ t_pg_connection *this = pg_get_connection( self );
4427
+
4428
+ rb_check_frozen(self);
4429
+ this->flags &= ~PG_RESULT_FIELD_NAMES_MASK;
4430
+ if( sym == sym_symbol ) this->flags |= PG_RESULT_FIELD_NAMES_SYMBOL;
4431
+ else if ( sym == sym_static_symbol ) this->flags |= PG_RESULT_FIELD_NAMES_STATIC_SYMBOL;
4432
+ else if ( sym == sym_string );
4433
+ else rb_raise(rb_eArgError, "invalid argument %+"PRIsVALUE, sym);
4434
+
4435
+ return sym;
4436
+ }
4437
+
4438
+ /*
4439
+ * call-seq:
4440
+ * conn.field_name_type -> Symbol
4441
+ *
4442
+ * Get type of field names.
4443
+ *
4444
+ * See description at #field_name_type=
4445
+ */
4446
+ static VALUE
4447
+ pgconn_field_name_type_get(VALUE self)
4448
+ {
4449
+ t_pg_connection *this = pg_get_connection( self );
4450
+
4451
+ if( this->flags & PG_RESULT_FIELD_NAMES_SYMBOL ){
4452
+ return sym_symbol;
4453
+ } else if( this->flags & PG_RESULT_FIELD_NAMES_STATIC_SYMBOL ){
4454
+ return sym_static_symbol;
4455
+ } else {
4456
+ return sym_string;
4457
+ }
4458
+ }
4459
+
3882
4460
 
3883
4461
  /*
3884
4462
  * Document-class: PG::Connection
3885
4463
  */
3886
4464
  void
3887
- init_pg_connection()
4465
+ init_pg_connection(void)
3888
4466
  {
3889
4467
  s_id_encode = rb_intern("encode");
4468
+ s_id_autoclose_set = rb_intern("autoclose=");
3890
4469
  sym_type = ID2SYM(rb_intern("type"));
3891
4470
  sym_format = ID2SYM(rb_intern("format"));
3892
4471
  sym_value = ID2SYM(rb_intern("value"));
4472
+ sym_string = ID2SYM(rb_intern("string"));
4473
+ sym_symbol = ID2SYM(rb_intern("symbol"));
4474
+ sym_static_symbol = ID2SYM(rb_intern("static_symbol"));
3893
4475
 
3894
4476
  rb_cPGconn = rb_define_class_under( rb_mPG, "Connection", rb_cObject );
4477
+ /* Help rdoc to known the Constants module */
4478
+ /* rb_mPGconstants = rb_define_module_under( rb_mPG, "Constants" ); */
3895
4479
  rb_include_module(rb_cPGconn, rb_mPGconstants);
3896
4480
 
3897
4481
  /****** PG::Connection CLASS METHODS ******/
3898
4482
  rb_define_alloc_func( rb_cPGconn, pgconn_s_allocate );
3899
4483
 
3900
- SINGLETON_ALIAS(rb_cPGconn, "connect", "new");
3901
- SINGLETON_ALIAS(rb_cPGconn, "open", "new");
3902
- SINGLETON_ALIAS(rb_cPGconn, "setdb", "new");
3903
- SINGLETON_ALIAS(rb_cPGconn, "setdblogin", "new");
3904
4484
  rb_define_singleton_method(rb_cPGconn, "escape_string", pgconn_s_escape, 1);
3905
4485
  SINGLETON_ALIAS(rb_cPGconn, "escape", "escape_string");
3906
4486
  rb_define_singleton_method(rb_cPGconn, "escape_bytea", pgconn_s_escape_bytea, 1);
@@ -3909,15 +4489,17 @@ init_pg_connection()
3909
4489
  rb_define_singleton_method(rb_cPGconn, "quote_ident", pgconn_s_quote_ident, 1);
3910
4490
  rb_define_singleton_method(rb_cPGconn, "connect_start", pgconn_s_connect_start, -1);
3911
4491
  rb_define_singleton_method(rb_cPGconn, "conndefaults", pgconn_s_conndefaults, 0);
3912
- rb_define_singleton_method(rb_cPGconn, "ping", pgconn_s_ping, -1);
4492
+ rb_define_singleton_method(rb_cPGconn, "conninfo_parse", pgconn_s_conninfo_parse, 1);
4493
+ rb_define_singleton_method(rb_cPGconn, "sync_ping", pgconn_s_sync_ping, -1);
4494
+ rb_define_singleton_method(rb_cPGconn, "sync_connect", pgconn_s_sync_connect, -1);
3913
4495
 
3914
4496
  /****** PG::Connection INSTANCE METHODS: Connection Control ******/
3915
- rb_define_method(rb_cPGconn, "initialize", pgconn_init, -1);
3916
4497
  rb_define_method(rb_cPGconn, "connect_poll", pgconn_connect_poll, 0);
3917
4498
  rb_define_method(rb_cPGconn, "finish", pgconn_finish, 0);
3918
4499
  rb_define_method(rb_cPGconn, "finished?", pgconn_finished_p, 0);
3919
- rb_define_method(rb_cPGconn, "reset", pgconn_reset, 0);
4500
+ rb_define_method(rb_cPGconn, "sync_reset", pgconn_sync_reset, 0);
3920
4501
  rb_define_method(rb_cPGconn, "reset_start", pgconn_reset_start, 0);
4502
+ rb_define_private_method(rb_cPGconn, "reset_start2", pgconn_reset_start2, 1);
3921
4503
  rb_define_method(rb_cPGconn, "reset_poll", pgconn_reset_poll, 0);
3922
4504
  rb_define_alias(rb_cPGconn, "close", "finish");
3923
4505
 
@@ -3926,11 +4508,12 @@ init_pg_connection()
3926
4508
  rb_define_method(rb_cPGconn, "user", pgconn_user, 0);
3927
4509
  rb_define_method(rb_cPGconn, "pass", pgconn_pass, 0);
3928
4510
  rb_define_method(rb_cPGconn, "host", pgconn_host, 0);
4511
+ #if defined(HAVE_PQRESULTMEMORYSIZE)
4512
+ rb_define_method(rb_cPGconn, "hostaddr", pgconn_hostaddr, 0);
4513
+ #endif
3929
4514
  rb_define_method(rb_cPGconn, "port", pgconn_port, 0);
3930
4515
  rb_define_method(rb_cPGconn, "tty", pgconn_tty, 0);
3931
- #ifdef HAVE_PQCONNINFO
3932
4516
  rb_define_method(rb_cPGconn, "conninfo", pgconn_conninfo, 0);
3933
- #endif
3934
4517
  rb_define_method(rb_cPGconn, "options", pgconn_options, 0);
3935
4518
  rb_define_method(rb_cPGconn, "status", pgconn_status, 0);
3936
4519
  rb_define_method(rb_cPGconn, "transaction_status", pgconn_transaction_status, 0);
@@ -3941,18 +4524,34 @@ init_pg_connection()
3941
4524
  rb_define_method(rb_cPGconn, "socket", pgconn_socket, 0);
3942
4525
  rb_define_method(rb_cPGconn, "socket_io", pgconn_socket_io, 0);
3943
4526
  rb_define_method(rb_cPGconn, "backend_pid", pgconn_backend_pid, 0);
4527
+ rb_define_method(rb_cPGconn, "backend_key", pgconn_backend_key, 0);
3944
4528
  rb_define_method(rb_cPGconn, "connection_needs_password", pgconn_connection_needs_password, 0);
3945
4529
  rb_define_method(rb_cPGconn, "connection_used_password", pgconn_connection_used_password, 0);
3946
4530
  /* rb_define_method(rb_cPGconn, "getssl", pgconn_getssl, 0); */
3947
4531
 
3948
4532
  /****** PG::Connection INSTANCE METHODS: Command Execution ******/
3949
- rb_define_method(rb_cPGconn, "exec", pgconn_exec, -1);
3950
- rb_define_alias(rb_cPGconn, "query", "exec");
3951
- rb_define_method(rb_cPGconn, "exec_params", pgconn_exec_params, -1);
3952
- rb_define_method(rb_cPGconn, "prepare", pgconn_prepare, -1);
3953
- rb_define_method(rb_cPGconn, "exec_prepared", pgconn_exec_prepared, -1);
3954
- rb_define_method(rb_cPGconn, "describe_prepared", pgconn_describe_prepared, 1);
3955
- rb_define_method(rb_cPGconn, "describe_portal", pgconn_describe_portal, 1);
4533
+ rb_define_method(rb_cPGconn, "sync_exec", pgconn_sync_exec, -1);
4534
+ rb_define_method(rb_cPGconn, "sync_exec_params", pgconn_sync_exec_params, -1);
4535
+ rb_define_method(rb_cPGconn, "sync_prepare", pgconn_sync_prepare, -1);
4536
+ rb_define_method(rb_cPGconn, "sync_exec_prepared", pgconn_sync_exec_prepared, -1);
4537
+ rb_define_method(rb_cPGconn, "sync_describe_prepared", pgconn_sync_describe_prepared, 1);
4538
+ rb_define_method(rb_cPGconn, "sync_describe_portal", pgconn_sync_describe_portal, 1);
4539
+
4540
+ rb_define_method(rb_cPGconn, "exec", pgconn_async_exec, -1);
4541
+ rb_define_method(rb_cPGconn, "exec_params", pgconn_async_exec_params, -1);
4542
+ rb_define_method(rb_cPGconn, "prepare", pgconn_async_prepare, -1);
4543
+ rb_define_method(rb_cPGconn, "exec_prepared", pgconn_async_exec_prepared, -1);
4544
+ rb_define_method(rb_cPGconn, "describe_prepared", pgconn_async_describe_prepared, 1);
4545
+ rb_define_method(rb_cPGconn, "describe_portal", pgconn_async_describe_portal, 1);
4546
+
4547
+ rb_define_alias(rb_cPGconn, "async_exec", "exec");
4548
+ rb_define_alias(rb_cPGconn, "async_query", "async_exec");
4549
+ rb_define_alias(rb_cPGconn, "async_exec_params", "exec_params");
4550
+ rb_define_alias(rb_cPGconn, "async_prepare", "prepare");
4551
+ rb_define_alias(rb_cPGconn, "async_exec_prepared", "exec_prepared");
4552
+ rb_define_alias(rb_cPGconn, "async_describe_prepared", "describe_prepared");
4553
+ rb_define_alias(rb_cPGconn, "async_describe_portal", "describe_portal");
4554
+
3956
4555
  rb_define_method(rb_cPGconn, "make_empty_pgresult", pgconn_make_empty_pgresult, 1);
3957
4556
  rb_define_method(rb_cPGconn, "escape_string", pgconn_s_escape, 1);
3958
4557
  rb_define_alias(rb_cPGconn, "escape", "escape_string");
@@ -3964,31 +4563,37 @@ init_pg_connection()
3964
4563
 
3965
4564
  /****** PG::Connection INSTANCE METHODS: Asynchronous Command Processing ******/
3966
4565
  rb_define_method(rb_cPGconn, "send_query", pgconn_send_query, -1);
4566
+ rb_define_method(rb_cPGconn, "send_query_params", pgconn_send_query_params, -1);
3967
4567
  rb_define_method(rb_cPGconn, "send_prepare", pgconn_send_prepare, -1);
3968
4568
  rb_define_method(rb_cPGconn, "send_query_prepared", pgconn_send_query_prepared, -1);
3969
4569
  rb_define_method(rb_cPGconn, "send_describe_prepared", pgconn_send_describe_prepared, 1);
3970
4570
  rb_define_method(rb_cPGconn, "send_describe_portal", pgconn_send_describe_portal, 1);
3971
- rb_define_method(rb_cPGconn, "get_result", pgconn_get_result, 0);
4571
+ rb_define_method(rb_cPGconn, "sync_get_result", pgconn_sync_get_result, 0);
3972
4572
  rb_define_method(rb_cPGconn, "consume_input", pgconn_consume_input, 0);
3973
4573
  rb_define_method(rb_cPGconn, "is_busy", pgconn_is_busy, 0);
3974
- rb_define_method(rb_cPGconn, "setnonblocking", pgconn_setnonblocking, 1);
3975
- rb_define_method(rb_cPGconn, "isnonblocking", pgconn_isnonblocking, 0);
3976
- rb_define_alias(rb_cPGconn, "nonblocking?", "isnonblocking");
3977
- rb_define_method(rb_cPGconn, "flush", pgconn_flush, 0);
4574
+ rb_define_method(rb_cPGconn, "sync_setnonblocking", pgconn_sync_setnonblocking, 1);
4575
+ rb_define_method(rb_cPGconn, "sync_isnonblocking", pgconn_sync_isnonblocking, 0);
4576
+ rb_define_method(rb_cPGconn, "sync_flush", pgconn_sync_flush, 0);
4577
+ rb_define_method(rb_cPGconn, "flush", pgconn_async_flush, 0);
4578
+ rb_define_alias(rb_cPGconn, "async_flush", "flush");
4579
+ rb_define_method(rb_cPGconn, "discard_results", pgconn_discard_results, 0);
3978
4580
 
3979
4581
  /****** PG::Connection INSTANCE METHODS: Cancelling Queries in Progress ******/
3980
- rb_define_method(rb_cPGconn, "cancel", pgconn_cancel, 0);
4582
+ rb_define_method(rb_cPGconn, "sync_cancel", pgconn_sync_cancel, 0);
3981
4583
 
3982
4584
  /****** PG::Connection INSTANCE METHODS: NOTIFY ******/
3983
4585
  rb_define_method(rb_cPGconn, "notifies", pgconn_notifies, 0);
3984
4586
 
3985
4587
  /****** PG::Connection INSTANCE METHODS: COPY ******/
3986
- rb_define_method(rb_cPGconn, "put_copy_data", pgconn_put_copy_data, -1);
3987
- rb_define_method(rb_cPGconn, "put_copy_end", pgconn_put_copy_end, -1);
3988
- rb_define_method(rb_cPGconn, "get_copy_data", pgconn_get_copy_data, -1);
4588
+ rb_define_method(rb_cPGconn, "sync_put_copy_data", pgconn_sync_put_copy_data, -1);
4589
+ rb_define_method(rb_cPGconn, "sync_put_copy_end", pgconn_sync_put_copy_end, -1);
4590
+ rb_define_method(rb_cPGconn, "sync_get_copy_data", pgconn_sync_get_copy_data, -1);
3989
4591
 
3990
4592
  /****** PG::Connection INSTANCE METHODS: Control Functions ******/
3991
4593
  rb_define_method(rb_cPGconn, "set_error_verbosity", pgconn_set_error_verbosity, 1);
4594
+ #ifdef HAVE_PQRESULTVERBOSEERRORMESSAGE
4595
+ rb_define_method(rb_cPGconn, "set_error_context_visibility", pgconn_set_error_context_visibility, 1 );
4596
+ #endif
3992
4597
  rb_define_method(rb_cPGconn, "trace", pgconn_trace, 1);
3993
4598
  rb_define_method(rb_cPGconn, "untrace", pgconn_untrace, 0);
3994
4599
 
@@ -3998,18 +4603,20 @@ init_pg_connection()
3998
4603
 
3999
4604
  /****** PG::Connection INSTANCE METHODS: Other ******/
4000
4605
  rb_define_method(rb_cPGconn, "get_client_encoding", pgconn_get_client_encoding, 0);
4001
- rb_define_method(rb_cPGconn, "set_client_encoding", pgconn_set_client_encoding, 1);
4606
+ rb_define_method(rb_cPGconn, "sync_set_client_encoding", pgconn_sync_set_client_encoding, 1);
4607
+ rb_define_method(rb_cPGconn, "set_client_encoding", pgconn_async_set_client_encoding, 1);
4608
+ rb_define_alias(rb_cPGconn, "async_set_client_encoding", "set_client_encoding");
4002
4609
  rb_define_alias(rb_cPGconn, "client_encoding=", "set_client_encoding");
4003
- rb_define_method(rb_cPGconn, "transaction", pgconn_transaction, 0);
4004
4610
  rb_define_method(rb_cPGconn, "block", pgconn_block, -1);
4611
+ rb_define_private_method(rb_cPGconn, "flush_data=", pgconn_flush_data_set, 1);
4005
4612
  rb_define_method(rb_cPGconn, "wait_for_notify", pgconn_wait_for_notify, -1);
4006
4613
  rb_define_alias(rb_cPGconn, "notifies_wait", "wait_for_notify");
4007
4614
  rb_define_method(rb_cPGconn, "quote_ident", pgconn_s_quote_ident, 1);
4008
- rb_define_method(rb_cPGconn, "async_exec", pgconn_async_exec, -1);
4009
- rb_define_alias(rb_cPGconn, "async_query", "async_exec");
4010
- rb_define_method(rb_cPGconn, "get_last_result", pgconn_get_last_result, 0);
4615
+ rb_define_method(rb_cPGconn, "sync_get_last_result", pgconn_sync_get_last_result, 0);
4616
+ rb_define_method(rb_cPGconn, "get_last_result", pgconn_async_get_last_result, 0);
4617
+ rb_define_alias(rb_cPGconn, "async_get_last_result", "get_last_result");
4011
4618
  #ifdef HAVE_PQENCRYPTPASSWORDCONN
4012
- rb_define_method(rb_cPGconn, "encrypt_password", pgconn_encrypt_password, -1);
4619
+ rb_define_method(rb_cPGconn, "sync_encrypt_password", pgconn_sync_encrypt_password, -1);
4013
4620
  #endif
4014
4621
 
4015
4622
  #ifdef HAVE_PQSSLATTRIBUTE
@@ -4018,6 +4625,14 @@ init_pg_connection()
4018
4625
  rb_define_method(rb_cPGconn, "ssl_attribute_names", pgconn_ssl_attribute_names, 0);
4019
4626
  #endif
4020
4627
 
4628
+ #ifdef HAVE_PQENTERPIPELINEMODE
4629
+ rb_define_method(rb_cPGconn, "pipeline_status", pgconn_pipeline_status, 0);
4630
+ rb_define_method(rb_cPGconn, "enter_pipeline_mode", pgconn_enter_pipeline_mode, 0);
4631
+ rb_define_method(rb_cPGconn, "exit_pipeline_mode", pgconn_exit_pipeline_mode, 0);
4632
+ rb_define_method(rb_cPGconn, "pipeline_sync", pgconn_pipeline_sync, 0);
4633
+ rb_define_method(rb_cPGconn, "send_flush_request", pgconn_send_flush_request, 0);
4634
+ #endif
4635
+
4021
4636
  /****** PG::Connection INSTANCE METHODS: Large Object Support ******/
4022
4637
  rb_define_method(rb_cPGconn, "lo_creat", pgconn_locreat, -1);
4023
4638
  rb_define_alias(rb_cPGconn, "locreat", "lo_creat");
@@ -4059,5 +4674,7 @@ init_pg_connection()
4059
4674
  rb_define_method(rb_cPGconn, "encoder_for_put_copy_data", pgconn_encoder_for_put_copy_data_get, 0);
4060
4675
  rb_define_method(rb_cPGconn, "decoder_for_get_copy_data=", pgconn_decoder_for_get_copy_data_set, 1);
4061
4676
  rb_define_method(rb_cPGconn, "decoder_for_get_copy_data", pgconn_decoder_for_get_copy_data_get, 0);
4062
- }
4063
4677
 
4678
+ rb_define_method(rb_cPGconn, "field_name_type=", pgconn_field_name_type_set, 1 );
4679
+ rb_define_method(rb_cPGconn, "field_name_type", pgconn_field_name_type_get, 0 );
4680
+ }