pg 1.1.4 → 1.5.3

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