pg 0.21.0 → 1.4.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (119) hide show
  1. checksums.yaml +5 -5
  2. checksums.yaml.gz.sig +0 -0
  3. data/.appveyor.yml +36 -0
  4. data/.gems +6 -0
  5. data/.github/workflows/binary-gems.yml +86 -0
  6. data/.github/workflows/source-gem.yml +131 -0
  7. data/.gitignore +13 -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.rdoc +399 -4
  16. data/Manifest.txt +8 -4
  17. data/README-Windows.rdoc +4 -4
  18. data/README.ja.rdoc +1 -2
  19. data/README.rdoc +85 -20
  20. data/Rakefile +32 -142
  21. data/Rakefile.cross +71 -71
  22. data/certs/ged.pem +24 -0
  23. data/certs/larskanis-2022.pem +26 -0
  24. data/ext/errorcodes.def +88 -0
  25. data/ext/errorcodes.rb +1 -1
  26. data/ext/errorcodes.txt +24 -2
  27. data/ext/extconf.rb +111 -54
  28. data/ext/gvl_wrappers.c +8 -0
  29. data/ext/gvl_wrappers.h +40 -33
  30. data/ext/pg.c +214 -171
  31. data/ext/pg.h +87 -95
  32. data/ext/pg_binary_decoder.c +83 -16
  33. data/ext/pg_binary_encoder.c +14 -13
  34. data/ext/pg_coder.c +146 -31
  35. data/ext/pg_connection.c +1444 -1001
  36. data/ext/pg_copy_coder.c +61 -24
  37. data/ext/pg_errors.c +1 -1
  38. data/ext/pg_record_coder.c +521 -0
  39. data/ext/pg_result.c +623 -208
  40. data/ext/pg_text_decoder.c +607 -41
  41. data/ext/pg_text_encoder.c +191 -60
  42. data/ext/pg_tuple.c +569 -0
  43. data/ext/pg_type_map.c +43 -10
  44. data/ext/pg_type_map_all_strings.c +20 -6
  45. data/ext/pg_type_map_by_class.c +55 -25
  46. data/ext/pg_type_map_by_column.c +75 -36
  47. data/ext/pg_type_map_by_mri_type.c +49 -20
  48. data/ext/pg_type_map_by_oid.c +56 -26
  49. data/ext/pg_type_map_in_ruby.c +52 -21
  50. data/ext/{util.c → pg_util.c} +12 -12
  51. data/ext/{util.h → pg_util.h} +2 -2
  52. data/lib/pg/basic_type_map_based_on_result.rb +47 -0
  53. data/lib/pg/basic_type_map_for_queries.rb +193 -0
  54. data/lib/pg/basic_type_map_for_results.rb +81 -0
  55. data/lib/pg/basic_type_registry.rb +301 -0
  56. data/lib/pg/binary_decoder.rb +23 -0
  57. data/lib/pg/coder.rb +24 -3
  58. data/lib/pg/connection.rb +668 -57
  59. data/lib/pg/constants.rb +2 -1
  60. data/lib/pg/exceptions.rb +9 -2
  61. data/lib/pg/result.rb +14 -2
  62. data/lib/pg/text_decoder.rb +21 -26
  63. data/lib/pg/text_encoder.rb +32 -8
  64. data/lib/pg/tuple.rb +30 -0
  65. data/lib/pg/type_map_by_column.rb +3 -2
  66. data/lib/pg/version.rb +4 -0
  67. data/lib/pg.rb +51 -38
  68. data/misc/openssl-pg-segfault.rb +31 -0
  69. data/misc/postgres/History.txt +9 -0
  70. data/misc/postgres/Manifest.txt +5 -0
  71. data/misc/postgres/README.txt +21 -0
  72. data/misc/postgres/Rakefile +21 -0
  73. data/misc/postgres/lib/postgres.rb +16 -0
  74. data/misc/ruby-pg/History.txt +9 -0
  75. data/misc/ruby-pg/Manifest.txt +5 -0
  76. data/misc/ruby-pg/README.txt +21 -0
  77. data/misc/ruby-pg/Rakefile +21 -0
  78. data/misc/ruby-pg/lib/ruby/pg.rb +16 -0
  79. data/pg.gemspec +32 -0
  80. data/rakelib/task_extension.rb +46 -0
  81. data/sample/array_insert.rb +20 -0
  82. data/sample/async_api.rb +102 -0
  83. data/sample/async_copyto.rb +39 -0
  84. data/sample/async_mixed.rb +56 -0
  85. data/sample/check_conn.rb +21 -0
  86. data/sample/copydata.rb +71 -0
  87. data/sample/copyfrom.rb +81 -0
  88. data/sample/copyto.rb +19 -0
  89. data/sample/cursor.rb +21 -0
  90. data/sample/disk_usage_report.rb +177 -0
  91. data/sample/issue-119.rb +94 -0
  92. data/sample/losample.rb +69 -0
  93. data/sample/minimal-testcase.rb +17 -0
  94. data/sample/notify_wait.rb +72 -0
  95. data/sample/pg_statistics.rb +285 -0
  96. data/sample/replication_monitor.rb +222 -0
  97. data/sample/test_binary_values.rb +33 -0
  98. data/sample/wal_shipper.rb +434 -0
  99. data/sample/warehouse_partitions.rb +311 -0
  100. data.tar.gz.sig +0 -0
  101. metadata +91 -229
  102. metadata.gz.sig +0 -0
  103. data/ChangeLog +0 -6595
  104. data/lib/pg/basic_type_mapping.rb +0 -426
  105. data/lib/pg/deprecated_constants.rb +0 -21
  106. data/spec/data/expected_trace.out +0 -26
  107. data/spec/data/random_binary_data +0 -0
  108. data/spec/helpers.rb +0 -352
  109. data/spec/pg/basic_type_mapping_spec.rb +0 -305
  110. data/spec/pg/connection_spec.rb +0 -1676
  111. data/spec/pg/result_spec.rb +0 -456
  112. data/spec/pg/type_map_by_class_spec.rb +0 -138
  113. data/spec/pg/type_map_by_column_spec.rb +0 -222
  114. data/spec/pg/type_map_by_mri_type_spec.rb +0 -136
  115. data/spec/pg/type_map_by_oid_spec.rb +0 -149
  116. data/spec/pg/type_map_in_ruby_spec.rb +0 -164
  117. data/spec/pg/type_map_spec.rb +0 -22
  118. data/spec/pg/type_spec.rb +0 -777
  119. data/spec/pg_spec.rb +0 -50
data/ext/pg_connection.c CHANGED
@@ -1,6 +1,6 @@
1
1
  /*
2
2
  * pg_connection.c - PG::Connection class extension
3
- * $Id: pg_connection.c,v 2e17f315848e 2017/01/14 20:05:06 lars $
3
+ * $Id$
4
4
  *
5
5
  */
6
6
 
@@ -12,30 +12,44 @@
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;
17
+ static VALUE sym_symbol, sym_string, sym_static_symbol;
16
18
 
17
19
  static PQnoticeReceiver default_notice_receiver = NULL;
18
20
  static PQnoticeProcessor default_notice_processor = NULL;
19
21
 
20
22
  static VALUE pgconn_finish( VALUE );
21
- #ifdef M17N_SUPPORTED
22
23
  static VALUE pgconn_set_default_encoding( VALUE self );
23
- void pgconn_set_internal_encoding_index( VALUE );
24
- #endif
25
-
26
- #ifndef HAVE_RB_THREAD_FD_SELECT
27
- #define rb_fdset_t fd_set
28
- #define rb_fd_init(f)
29
- #define rb_fd_zero(f) FD_ZERO(f)
30
- #define rb_fd_set(n, f) FD_SET(n, f)
31
- #define rb_fd_term(f)
32
- #define rb_thread_fd_select rb_thread_select
33
- #endif
24
+ static VALUE pgconn_wait_for_flush( VALUE self );
25
+ static void pgconn_set_internal_encoding_index( VALUE );
26
+ static const rb_data_type_t pg_connection_type;
27
+ static VALUE pgconn_async_flush(VALUE self);
34
28
 
35
29
  /*
36
30
  * Global functions
37
31
  */
38
32
 
33
+ /*
34
+ * Convenience function to raise connection errors
35
+ */
36
+ #ifdef __GNUC__
37
+ __attribute__((format(printf, 3, 4)))
38
+ #endif
39
+ static void
40
+ pg_raise_conn_error( VALUE klass, VALUE self, const char *format, ...)
41
+ {
42
+ VALUE msg, error;
43
+ va_list ap;
44
+
45
+ va_start(ap, format);
46
+ msg = rb_vsprintf(format, ap);
47
+ va_end(ap);
48
+ error = rb_exc_new_str(klass, msg);
49
+ rb_iv_set(error, "@connection", self);
50
+ rb_exc_raise(error);
51
+ }
52
+
39
53
  /*
40
54
  * Fetch the PG::Connection object data pointer.
41
55
  */
@@ -43,7 +57,7 @@ t_pg_connection *
43
57
  pg_get_connection( VALUE self )
44
58
  {
45
59
  t_pg_connection *this;
46
- Data_Get_Struct( self, t_pg_connection, this);
60
+ TypedData_Get_Struct( self, t_pg_connection, &pg_connection_type, this);
47
61
 
48
62
  return this;
49
63
  }
@@ -56,10 +70,10 @@ static t_pg_connection *
56
70
  pg_get_connection_safe( VALUE self )
57
71
  {
58
72
  t_pg_connection *this;
59
- Data_Get_Struct( self, t_pg_connection, this);
73
+ TypedData_Get_Struct( self, t_pg_connection, &pg_connection_type, this);
60
74
 
61
75
  if ( !this->pgconn )
62
- rb_raise( rb_eConnectionBad, "connection is closed" );
76
+ pg_raise_conn_error( rb_eConnectionBad, self, "connection is closed");
63
77
 
64
78
  return this;
65
79
  }
@@ -75,10 +89,11 @@ PGconn *
75
89
  pg_get_pgconn( VALUE self )
76
90
  {
77
91
  t_pg_connection *this;
78
- Data_Get_Struct( self, t_pg_connection, this);
92
+ TypedData_Get_Struct( self, t_pg_connection, &pg_connection_type, this);
79
93
 
80
- if ( !this->pgconn )
81
- rb_raise( rb_eConnectionBad, "connection is closed" );
94
+ if ( !this->pgconn ){
95
+ pg_raise_conn_error( rb_eConnectionBad, self, "connection is closed");
96
+ }
82
97
 
83
98
  return this->pgconn;
84
99
  }
@@ -95,11 +110,9 @@ pgconn_close_socket_io( VALUE self )
95
110
  VALUE socket_io = this->socket_io;
96
111
 
97
112
  if ( RTEST(socket_io) ) {
98
- #if defined(_WIN32) && defined(HAVE_RB_W32_WRAP_IO_HANDLE)
99
- int ruby_sd = NUM2INT(rb_funcall( socket_io, rb_intern("fileno"), 0 ));
100
- if( rb_w32_unwrap_io_handle(ruby_sd) ){
101
- rb_raise(rb_eConnectionBad, "Could not unwrap win32 socket handle");
102
- }
113
+ #if defined(_WIN32)
114
+ if( rb_w32_unwrap_io_handle(this->ruby_sd) )
115
+ pg_raise_conn_error( rb_eConnectionBad, self, "Could not unwrap win32 socket handle");
103
116
  #endif
104
117
  rb_funcall( socket_io, rb_intern("close"), 0 );
105
118
  }
@@ -156,17 +169,31 @@ static const char *pg_cstr_enc(VALUE str, int enc_idx){
156
169
  * GC Mark function
157
170
  */
158
171
  static void
159
- pgconn_gc_mark( t_pg_connection *this )
172
+ pgconn_gc_mark( void *_this )
173
+ {
174
+ t_pg_connection *this = (t_pg_connection *)_this;
175
+ rb_gc_mark_movable( this->socket_io );
176
+ rb_gc_mark_movable( this->notice_receiver );
177
+ rb_gc_mark_movable( this->notice_processor );
178
+ rb_gc_mark_movable( this->type_map_for_queries );
179
+ rb_gc_mark_movable( this->type_map_for_results );
180
+ rb_gc_mark_movable( this->trace_stream );
181
+ rb_gc_mark_movable( this->encoder_for_put_copy_data );
182
+ rb_gc_mark_movable( this->decoder_for_get_copy_data );
183
+ }
184
+
185
+ static void
186
+ pgconn_gc_compact( void *_this )
160
187
  {
161
- rb_gc_mark( this->socket_io );
162
- rb_gc_mark( this->notice_receiver );
163
- rb_gc_mark( this->notice_processor );
164
- rb_gc_mark( this->type_map_for_queries );
165
- rb_gc_mark( this->type_map_for_results );
166
- rb_gc_mark( this->trace_stream );
167
- rb_gc_mark( this->external_encoding );
168
- rb_gc_mark( this->encoder_for_put_copy_data );
169
- rb_gc_mark( this->decoder_for_get_copy_data );
188
+ t_pg_connection *this = (t_pg_connection *)_this;
189
+ pg_gc_location( this->socket_io );
190
+ pg_gc_location( this->notice_receiver );
191
+ pg_gc_location( this->notice_processor );
192
+ pg_gc_location( this->type_map_for_queries );
193
+ pg_gc_location( this->type_map_for_results );
194
+ pg_gc_location( this->trace_stream );
195
+ pg_gc_location( this->encoder_for_put_copy_data );
196
+ pg_gc_location( this->decoder_for_get_copy_data );
170
197
  }
171
198
 
172
199
 
@@ -174,14 +201,45 @@ pgconn_gc_mark( t_pg_connection *this )
174
201
  * GC Free function
175
202
  */
176
203
  static void
177
- pgconn_gc_free( t_pg_connection *this )
204
+ pgconn_gc_free( void *_this )
178
205
  {
206
+ t_pg_connection *this = (t_pg_connection *)_this;
207
+ #if defined(_WIN32)
208
+ if ( RTEST(this->socket_io) ) {
209
+ if( rb_w32_unwrap_io_handle(this->ruby_sd) ){
210
+ rb_warn("pg: Could not unwrap win32 socket handle by garbage collector");
211
+ }
212
+ }
213
+ #endif
179
214
  if (this->pgconn != NULL)
180
215
  PQfinish( this->pgconn );
181
216
 
182
217
  xfree(this);
183
218
  }
184
219
 
220
+ /*
221
+ * Object Size function
222
+ */
223
+ static size_t
224
+ pgconn_memsize( const void *_this )
225
+ {
226
+ const t_pg_connection *this = (const t_pg_connection *)_this;
227
+ return sizeof(*this);
228
+ }
229
+
230
+ static const rb_data_type_t pg_connection_type = {
231
+ "PG::Connection",
232
+ {
233
+ pgconn_gc_mark,
234
+ pgconn_gc_free,
235
+ pgconn_memsize,
236
+ pg_compact_callback(pgconn_gc_compact),
237
+ },
238
+ 0,
239
+ 0,
240
+ 0,
241
+ };
242
+
185
243
 
186
244
  /**************************************************************************
187
245
  * Class Methods
@@ -197,7 +255,7 @@ static VALUE
197
255
  pgconn_s_allocate( VALUE klass )
198
256
  {
199
257
  t_pg_connection *this;
200
- VALUE self = Data_Make_Struct( klass, t_pg_connection, pgconn_gc_mark, pgconn_gc_free, this );
258
+ VALUE self = TypedData_Make_Struct( klass, t_pg_connection, &pg_connection_type, this );
201
259
 
202
260
  this->pgconn = NULL;
203
261
  this->socket_io = Qnil;
@@ -208,92 +266,29 @@ pgconn_s_allocate( VALUE klass )
208
266
  this->encoder_for_put_copy_data = Qnil;
209
267
  this->decoder_for_get_copy_data = Qnil;
210
268
  this->trace_stream = Qnil;
211
- this->external_encoding = Qnil;
269
+ rb_ivar_set(self, rb_intern("@calls_to_put_copy_data"), INT2FIX(0));
212
270
 
213
271
  return self;
214
272
  }
215
273
 
216
-
217
- /*
218
- * Document-method: new
219
- *
220
- * call-seq:
221
- * PG::Connection.new -> conn
222
- * PG::Connection.new(connection_hash) -> conn
223
- * PG::Connection.new(connection_string) -> conn
224
- * PG::Connection.new(host, port, options, tty, dbname, user, password) -> conn
225
- *
226
- * Create a connection to the specified server.
227
- *
228
- * [+host+]
229
- * server hostname
230
- * [+hostaddr+]
231
- * server address (avoids hostname lookup, overrides +host+)
232
- * [+port+]
233
- * server port number
234
- * [+dbname+]
235
- * connecting database name
236
- * [+user+]
237
- * login user name
238
- * [+password+]
239
- * login password
240
- * [+connect_timeout+]
241
- * maximum time to wait for connection to succeed
242
- * [+options+]
243
- * backend options
244
- * [+tty+]
245
- * (ignored in newer versions of PostgreSQL)
246
- * [+sslmode+]
247
- * (disable|allow|prefer|require)
248
- * [+krbsrvname+]
249
- * kerberos service name
250
- * [+gsslib+]
251
- * GSS library to use for GSSAPI authentication
252
- * [+service+]
253
- * service name to use for additional parameters
254
- *
255
- * Examples:
256
- *
257
- * # Connect using all defaults
258
- * PG::Connection.new
259
- *
260
- * # As a Hash
261
- * PG::Connection.new( :dbname => 'test', :port => 5432 )
262
- *
263
- * # As a String
264
- * PG::Connection.new( "dbname=test port=5432" )
265
- *
266
- * # As an Array
267
- * PG::Connection.new( nil, 5432, nil, nil, 'test', nil, nil )
268
- *
269
- * If the Ruby default internal encoding is set (i.e., Encoding.default_internal != nil), the
270
- * connection will have its +client_encoding+ set accordingly.
271
- *
272
- * Raises a PG::Error if the connection fails.
273
- */
274
274
  static VALUE
275
- pgconn_init(int argc, VALUE *argv, VALUE self)
275
+ pgconn_s_sync_connect(int argc, VALUE *argv, VALUE klass)
276
276
  {
277
277
  t_pg_connection *this;
278
278
  VALUE conninfo;
279
- VALUE error;
279
+ VALUE self = pgconn_s_allocate( klass );
280
280
 
281
281
  this = pg_get_connection( self );
282
282
  conninfo = rb_funcall2( rb_cPGconn, rb_intern("parse_connect_args"), argc, argv );
283
283
  this->pgconn = gvl_PQconnectdb(StringValueCStr(conninfo));
284
284
 
285
285
  if(this->pgconn == NULL)
286
- rb_raise(rb_ePGerror, "PQconnectdb() unable to allocate structure");
286
+ rb_raise(rb_ePGerror, "PQconnectdb() unable to allocate PGconn structure");
287
287
 
288
- if (PQstatus(this->pgconn) == CONNECTION_BAD) {
289
- error = rb_exc_new2(rb_eConnectionBad, PQerrorMessage(this->pgconn));
290
- rb_iv_set(error, "@connection", self);
291
- rb_exc_raise(error);
292
- }
288
+ if (PQstatus(this->pgconn) == CONNECTION_BAD)
289
+ pg_raise_conn_error( rb_eConnectionBad, self, "%s", PQerrorMessage(this->pgconn));
293
290
 
294
- #ifdef M17N_SUPPORTED
295
291
  pgconn_set_default_encoding( self );
296
- #endif
297
292
 
298
293
  if (rb_block_given_p()) {
299
294
  return rb_ensure(rb_yield, self, pgconn_finish, self);
@@ -307,14 +302,16 @@ pgconn_init(int argc, VALUE *argv, VALUE self)
307
302
  * PG::Connection.connect_start(connection_string) -> conn
308
303
  * PG::Connection.connect_start(host, port, options, tty, dbname, login, password) -> conn
309
304
  *
310
- * This is an asynchronous version of PG::Connection.connect().
305
+ * This is an asynchronous version of PG::Connection.new.
311
306
  *
312
307
  * Use #connect_poll to poll the status of the connection.
313
308
  *
314
309
  * NOTE: this does *not* set the connection's +client_encoding+ for you if
315
- * Encoding.default_internal is set. To set it after the connection is established,
310
+ * +Encoding.default_internal+ is set. To set it after the connection is established,
316
311
  * call #internal_encoding=. You can also set it automatically by setting
317
- * ENV['PGCLIENTENCODING'], or include the 'options' connection parameter.
312
+ * <code>ENV['PGCLIENTENCODING']</code>, or include the 'options' connection parameter.
313
+ *
314
+ * See also the 'sample' directory of this gem and the corresponding {libpq functions}[https://www.postgresql.org/docs/current/libpq-connect.html#LIBPQ-PQCONNECTSTARTPARAMS].
318
315
  *
319
316
  */
320
317
  static VALUE
@@ -322,7 +319,6 @@ pgconn_s_connect_start( int argc, VALUE *argv, VALUE klass )
322
319
  {
323
320
  VALUE rb_conn;
324
321
  VALUE conninfo;
325
- VALUE error;
326
322
  t_pg_connection *this;
327
323
 
328
324
  /*
@@ -335,13 +331,10 @@ pgconn_s_connect_start( int argc, VALUE *argv, VALUE klass )
335
331
  this->pgconn = gvl_PQconnectStart( StringValueCStr(conninfo) );
336
332
 
337
333
  if( this->pgconn == NULL )
338
- rb_raise(rb_ePGerror, "PQconnectStart() unable to allocate structure");
334
+ rb_raise(rb_ePGerror, "PQconnectStart() unable to allocate PGconn structure");
339
335
 
340
- if ( PQstatus(this->pgconn) == CONNECTION_BAD ) {
341
- error = rb_exc_new2(rb_eConnectionBad, PQerrorMessage(this->pgconn));
342
- rb_iv_set(error, "@connection", rb_conn);
343
- rb_exc_raise(error);
344
- }
336
+ if ( PQstatus(this->pgconn) == CONNECTION_BAD )
337
+ pg_raise_conn_error( rb_eConnectionBad, rb_conn, "%s", PQerrorMessage(this->pgconn));
345
338
 
346
339
  if ( rb_block_given_p() ) {
347
340
  return rb_ensure( rb_yield, rb_conn, pgconn_finish, rb_conn );
@@ -349,37 +342,17 @@ pgconn_s_connect_start( int argc, VALUE *argv, VALUE klass )
349
342
  return rb_conn;
350
343
  }
351
344
 
352
- #ifdef HAVE_PQPING
353
- /*
354
- * call-seq:
355
- * PG::Connection.ping(connection_hash) -> Integer
356
- * PG::Connection.ping(connection_string) -> Integer
357
- * PG::Connection.ping(host, port, options, tty, dbname, login, password) -> Integer
358
- *
359
- * Check server status.
360
- *
361
- * Returns one of:
362
- * [+PQPING_OK+]
363
- * server is accepting connections
364
- * [+PQPING_REJECT+]
365
- * server is alive but rejecting connections
366
- * [+PQPING_NO_RESPONSE+]
367
- * could not establish connection
368
- * [+PQPING_NO_ATTEMPT+]
369
- * connection not attempted (bad params)
370
- */
371
345
  static VALUE
372
- pgconn_s_ping( int argc, VALUE *argv, VALUE klass )
346
+ pgconn_s_sync_ping( int argc, VALUE *argv, VALUE klass )
373
347
  {
374
348
  PGPing ping;
375
349
  VALUE conninfo;
376
350
 
377
351
  conninfo = rb_funcall2( klass, rb_intern("parse_connect_args"), argc, argv );
378
- ping = PQping( StringValueCStr(conninfo) );
352
+ ping = gvl_PQping( StringValueCStr(conninfo) );
379
353
 
380
354
  return INT2FIX((int)ping);
381
355
  }
382
- #endif
383
356
 
384
357
 
385
358
  /*
@@ -417,17 +390,71 @@ pgconn_s_conndefaults(VALUE self)
417
390
  return array;
418
391
  }
419
392
 
393
+ /*
394
+ * Document-method: PG::Connection.conninfo_parse
395
+ *
396
+ * call-seq:
397
+ * PG::Connection.conninfo_parse(conninfo_string) -> Array
398
+ *
399
+ * Returns parsed connection options from the provided connection string as an array of hashes.
400
+ * Each hash has the same keys as PG::Connection.conndefaults() .
401
+ * The values from the +conninfo_string+ are stored in the +:val+ key.
402
+ */
403
+ static VALUE
404
+ pgconn_s_conninfo_parse(VALUE self, VALUE conninfo)
405
+ {
406
+ VALUE array;
407
+ char *errmsg = NULL;
408
+ PQconninfoOption *options = PQconninfoParse(StringValueCStr(conninfo), &errmsg);
409
+ if(errmsg){
410
+ VALUE error = rb_str_new_cstr(errmsg);
411
+ PQfreemem(errmsg);
412
+ rb_raise(rb_ePGerror, "%"PRIsVALUE, error);
413
+ }
414
+ array = pgconn_make_conninfo_array( options );
415
+
416
+ PQconninfoFree(options);
417
+
418
+ UNUSED( self );
419
+
420
+ return array;
421
+ }
422
+
423
+
424
+ #ifdef HAVE_PQENCRYPTPASSWORDCONN
425
+ static VALUE
426
+ pgconn_sync_encrypt_password(int argc, VALUE *argv, VALUE self)
427
+ {
428
+ char *encrypted = NULL;
429
+ VALUE rval = Qnil;
430
+ VALUE password, username, algorithm;
431
+ PGconn *conn = pg_get_pgconn(self);
432
+
433
+ rb_scan_args( argc, argv, "21", &password, &username, &algorithm );
434
+
435
+ Check_Type(password, T_STRING);
436
+ Check_Type(username, T_STRING);
437
+
438
+ encrypted = gvl_PQencryptPasswordConn(conn, StringValueCStr(password), StringValueCStr(username), RTEST(algorithm) ? StringValueCStr(algorithm) : NULL);
439
+ if ( encrypted ) {
440
+ rval = rb_str_new2( encrypted );
441
+ PQfreemem( encrypted );
442
+ } else {
443
+ pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(conn));
444
+ }
445
+
446
+ return rval;
447
+ }
448
+ #endif
449
+
420
450
 
421
451
  /*
422
452
  * call-seq:
423
453
  * PG::Connection.encrypt_password( password, username ) -> String
424
454
  *
425
- * This function is intended to be used by client applications that
426
- * send commands like: +ALTER USER joe PASSWORD 'pwd'+.
427
- * The arguments are the cleartext password, and the SQL name
428
- * of the user it is for.
455
+ * This is an older, deprecated version of #encrypt_password.
456
+ * The difference is that this function always uses +md5+ as the encryption algorithm.
429
457
  *
430
- * Return value is the encrypted password.
431
458
  */
432
459
  static VALUE
433
460
  pgconn_s_encrypt_password(VALUE self, VALUE password, VALUE username)
@@ -444,9 +471,6 @@ pgconn_s_encrypt_password(VALUE self, VALUE password, VALUE username)
444
471
  rval = rb_str_new2( encrypted );
445
472
  PQfreemem( encrypted );
446
473
 
447
- OBJ_INFECT( rval, password );
448
- OBJ_INFECT( rval, username );
449
-
450
474
  return rval;
451
475
  }
452
476
 
@@ -470,17 +494,18 @@ pgconn_s_encrypt_password(VALUE self, VALUE password, VALUE username)
470
494
  * the asynchronous connection is ready
471
495
  *
472
496
  * Example:
473
- * conn = PG::Connection.connect_start("dbname=mydatabase")
474
- * socket = conn.socket_io
497
+ * require "io/wait"
498
+ *
499
+ * conn = PG::Connection.connect_start(dbname: 'mydatabase')
475
500
  * status = conn.connect_poll
476
501
  * while(status != PG::PGRES_POLLING_OK) do
477
502
  * # do some work while waiting for the connection to complete
478
503
  * if(status == PG::PGRES_POLLING_READING)
479
- * if(not select([socket], [], [], 10.0))
504
+ * unless conn.socket_io.wait_readable(10.0)
480
505
  * raise "Asynchronous connection timed out!"
481
506
  * end
482
507
  * elsif(status == PG::PGRES_POLLING_WRITING)
483
- * if(not select([], [socket], [], 10.0))
508
+ * unless conn.socket_io.wait_writable(10.0)
484
509
  * raise "Asynchronous connection timed out!"
485
510
  * end
486
511
  * end
@@ -494,6 +519,9 @@ pgconn_connect_poll(VALUE self)
494
519
  {
495
520
  PostgresPollingStatusType status;
496
521
  status = gvl_PQconnectPoll(pg_get_pgconn(self));
522
+
523
+ pgconn_close_socket_io(self);
524
+
497
525
  return INT2FIX((int)status);
498
526
  }
499
527
 
@@ -530,15 +558,8 @@ pgconn_finished_p( VALUE self )
530
558
  }
531
559
 
532
560
 
533
- /*
534
- * call-seq:
535
- * conn.reset()
536
- *
537
- * Resets the backend connection. This method closes the
538
- * backend connection and tries to re-connect.
539
- */
540
561
  static VALUE
541
- pgconn_reset( VALUE self )
562
+ pgconn_sync_reset( VALUE self )
542
563
  {
543
564
  pgconn_close_socket_io( self );
544
565
  gvl_PQreset( pg_get_pgconn(self) );
@@ -560,7 +581,7 @@ pgconn_reset_start(VALUE self)
560
581
  {
561
582
  pgconn_close_socket_io( self );
562
583
  if(gvl_PQresetStart(pg_get_pgconn(self)) == 0)
563
- rb_raise(rb_eUnableToSend, "reset has failed");
584
+ pg_raise_conn_error( rb_eUnableToSend, self, "reset has failed");
564
585
  return Qnil;
565
586
  }
566
587
 
@@ -577,6 +598,9 @@ pgconn_reset_poll(VALUE self)
577
598
  {
578
599
  PostgresPollingStatusType status;
579
600
  status = gvl_PQresetPoll(pg_get_pgconn(self));
601
+
602
+ pgconn_close_socket_io(self);
603
+
580
604
  return INT2FIX((int)status);
581
605
  }
582
606
 
@@ -592,7 +616,7 @@ pgconn_db(VALUE self)
592
616
  {
593
617
  char *db = PQdb(pg_get_pgconn(self));
594
618
  if (!db) return Qnil;
595
- return rb_tainted_str_new2(db);
619
+ return rb_str_new2(db);
596
620
  }
597
621
 
598
622
  /*
@@ -606,36 +630,67 @@ pgconn_user(VALUE self)
606
630
  {
607
631
  char *user = PQuser(pg_get_pgconn(self));
608
632
  if (!user) return Qnil;
609
- return rb_tainted_str_new2(user);
633
+ return rb_str_new2(user);
610
634
  }
611
635
 
612
636
  /*
613
637
  * call-seq:
614
638
  * conn.pass()
615
639
  *
616
- * Returns the authenticated user name.
640
+ * Returns the authenticated password.
617
641
  */
618
642
  static VALUE
619
643
  pgconn_pass(VALUE self)
620
644
  {
621
645
  char *user = PQpass(pg_get_pgconn(self));
622
646
  if (!user) return Qnil;
623
- return rb_tainted_str_new2(user);
647
+ return rb_str_new2(user);
624
648
  }
625
649
 
626
650
  /*
627
651
  * call-seq:
628
652
  * conn.host()
629
653
  *
630
- * Returns the connected server name.
654
+ * Returns the server host name of the active connection.
655
+ * This can be a host name, an IP address, or a directory path if the connection is via Unix socket.
656
+ * (The path case can be distinguished because it will always be an absolute path, beginning with +/+ .)
657
+ *
658
+ * If the connection parameters specified both host and hostaddr, then +host+ will return the host information.
659
+ * If only hostaddr was specified, then that is returned.
660
+ * If multiple hosts were specified in the connection parameters, +host+ returns the host actually connected to.
661
+ *
662
+ * 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.
663
+ *
664
+ * 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.
665
+ * The status of the connection can be checked using the function Connection#status .
631
666
  */
632
667
  static VALUE
633
668
  pgconn_host(VALUE self)
634
669
  {
635
670
  char *host = PQhost(pg_get_pgconn(self));
636
671
  if (!host) return Qnil;
637
- return rb_tainted_str_new2(host);
672
+ return rb_str_new2(host);
673
+ }
674
+
675
+ /* PQhostaddr() appeared in PostgreSQL-12 together with PQresultMemorySize() */
676
+ #if defined(HAVE_PQRESULTMEMORYSIZE)
677
+ /*
678
+ * call-seq:
679
+ * conn.hostaddr()
680
+ *
681
+ * Returns the server IP address of the active connection.
682
+ * This can be the address that a host name resolved to, or an IP address provided through the hostaddr parameter.
683
+ * 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.
684
+ *
685
+ */
686
+ static VALUE
687
+ pgconn_hostaddr(VALUE self)
688
+ {
689
+ char *host = PQhostaddr(pg_get_pgconn(self));
690
+ if (!host) return Qnil;
691
+ return rb_str_new2(host);
638
692
  }
693
+ #endif
639
694
 
640
695
  /*
641
696
  * call-seq:
@@ -647,21 +702,22 @@ static VALUE
647
702
  pgconn_port(VALUE self)
648
703
  {
649
704
  char* port = PQport(pg_get_pgconn(self));
650
- return INT2NUM(atol(port));
705
+ if (!port || port[0] == '\0')
706
+ return INT2NUM(DEF_PGPORT);
707
+ else
708
+ return INT2NUM(atoi(port));
651
709
  }
652
710
 
653
711
  /*
654
712
  * call-seq:
655
713
  * conn.tty()
656
714
  *
657
- * Returns the connected pgtty. (Obsolete)
715
+ * Obsolete function.
658
716
  */
659
717
  static VALUE
660
718
  pgconn_tty(VALUE self)
661
719
  {
662
- char *tty = PQtty(pg_get_pgconn(self));
663
- if (!tty) return Qnil;
664
- return rb_tainted_str_new2(tty);
720
+ return rb_str_new2("");
665
721
  }
666
722
 
667
723
  /*
@@ -675,17 +731,17 @@ pgconn_options(VALUE self)
675
731
  {
676
732
  char *options = PQoptions(pg_get_pgconn(self));
677
733
  if (!options) return Qnil;
678
- return rb_tainted_str_new2(options);
734
+ return rb_str_new2(options);
679
735
  }
680
736
 
681
737
 
682
- #ifdef HAVE_PQCONNINFO
683
738
  /*
684
739
  * call-seq:
685
740
  * conn.conninfo -> hash
686
741
  *
687
742
  * Returns the connection options used by a live connection.
688
743
  *
744
+ * Available since PostgreSQL-9.3
689
745
  */
690
746
  static VALUE
691
747
  pgconn_conninfo( VALUE self )
@@ -698,14 +754,20 @@ pgconn_conninfo( VALUE self )
698
754
 
699
755
  return array;
700
756
  }
701
- #endif
702
757
 
703
758
 
704
759
  /*
705
760
  * call-seq:
706
761
  * conn.status()
707
762
  *
708
- * Returns status of connection : CONNECTION_OK or CONNECTION_BAD
763
+ * Returns the status of the connection, which is one:
764
+ * PG::Constants::CONNECTION_OK
765
+ * PG::Constants::CONNECTION_BAD
766
+ *
767
+ * ... and other constants of kind PG::Constants::CONNECTION_*
768
+ *
769
+ * Example:
770
+ * PG.constants.grep(/CONNECTION_/).find{|c| PG.const_get(c) == conn.status} # => :CONNECTION_OK
709
771
  */
710
772
  static VALUE
711
773
  pgconn_status(VALUE self)
@@ -755,7 +817,7 @@ pgconn_parameter_status(VALUE self, VALUE param_name)
755
817
  if(ret == NULL)
756
818
  return Qnil;
757
819
  else
758
- return rb_tainted_str_new2(ret);
820
+ return rb_str_new2(ret);
759
821
  }
760
822
 
761
823
  /*
@@ -793,20 +855,25 @@ pgconn_server_version(VALUE self)
793
855
  * call-seq:
794
856
  * conn.error_message -> String
795
857
  *
796
- * Returns the error message about connection.
858
+ * Returns the error message most recently generated by an operation on the connection.
859
+ *
860
+ * Nearly all libpq functions will set a message for conn.error_message if they fail.
861
+ * Note that by libpq convention, a nonempty error_message result can consist of multiple lines, and will include a trailing newline.
797
862
  */
798
863
  static VALUE
799
864
  pgconn_error_message(VALUE self)
800
865
  {
801
866
  char *error = PQerrorMessage(pg_get_pgconn(self));
802
867
  if (!error) return Qnil;
803
- return rb_tainted_str_new2(error);
868
+ return rb_str_new2(error);
804
869
  }
805
870
 
806
871
  /*
807
872
  * call-seq:
808
873
  * conn.socket() -> Integer
809
874
  *
875
+ * This method is deprecated. Please use the more portable method #socket_io .
876
+ *
810
877
  * Returns the socket's file descriptor for this connection.
811
878
  * <tt>IO.for_fd()</tt> can be used to build a proper IO object to the socket.
812
879
  * If you do so, you will likely also want to set <tt>autoclose=false</tt>
@@ -815,60 +882,64 @@ pgconn_error_message(VALUE self)
815
882
  * creates an IO that's associated with the connection object itself,
816
883
  * and so won't go out of scope until the connection does.
817
884
  *
818
- * *Note:* On Windows the file descriptor is not really usable,
885
+ * *Note:* On Windows the file descriptor is not usable,
819
886
  * since it can not be used to build a Ruby IO object.
820
887
  */
821
888
  static VALUE
822
889
  pgconn_socket(VALUE self)
823
890
  {
824
891
  int sd;
892
+ pg_deprecated(4, ("conn.socket is deprecated and should be replaced by conn.socket_io"));
893
+
825
894
  if( (sd = PQsocket(pg_get_pgconn(self))) < 0)
826
- rb_raise(rb_eConnectionBad, "PQsocket() can't get socket descriptor");
895
+ pg_raise_conn_error( rb_eConnectionBad, self, "PQsocket() can't get socket descriptor");
896
+
827
897
  return INT2NUM(sd);
828
898
  }
829
899
 
830
-
831
- #if !defined(_WIN32) || defined(HAVE_RB_W32_WRAP_IO_HANDLE)
832
-
833
900
  /*
834
901
  * call-seq:
835
902
  * conn.socket_io() -> IO
836
903
  *
837
- * Fetch a memoized IO object created from the Connection's underlying socket.
838
- * This object can be used for IO.select to wait for events while running
839
- * asynchronous API calls.
904
+ * Fetch an IO object created from the Connection's underlying socket.
905
+ * 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.
906
+ * <tt>IO#wait_*able</tt> is is <tt>Fiber.scheduler</tt> compatible in contrast to <tt>IO.select</tt>.
840
907
  *
841
- * Using this instead of #socket avoids the problem of the underlying connection
842
- * being closed by Ruby when an IO created using <tt>IO.for_fd(conn.socket)</tt>
843
- * goes out of scope.
908
+ * The IO object can change while the connection is established, but is memorized afterwards.
909
+ * So be sure not to cache the IO object, but repeat calling <tt>conn.socket_io</tt> instead.
844
910
  *
845
- * This method can also be used on Windows but requires Ruby-2.0+.
911
+ * Using this method also works on Windows in contrast to using #socket .
912
+ * 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.
846
913
  */
847
914
  static VALUE
848
915
  pgconn_socket_io(VALUE self)
849
916
  {
850
917
  int sd;
851
918
  int ruby_sd;
852
- ID id_autoclose = rb_intern("autoclose=");
853
919
  t_pg_connection *this = pg_get_connection_safe( self );
920
+ VALUE cSocket;
854
921
  VALUE socket_io = this->socket_io;
855
922
 
856
923
  if ( !RTEST(socket_io) ) {
857
- if( (sd = PQsocket(this->pgconn)) < 0)
858
- rb_raise(rb_eConnectionBad, "PQsocket() can't get socket descriptor");
924
+ if( (sd = PQsocket(this->pgconn)) < 0){
925
+ pg_raise_conn_error( rb_eConnectionBad, self, "PQsocket() can't get socket descriptor");
926
+ }
859
927
 
860
928
  #ifdef _WIN32
861
929
  ruby_sd = rb_w32_wrap_io_handle((HANDLE)(intptr_t)sd, O_RDWR|O_BINARY|O_NOINHERIT);
930
+ if( ruby_sd == -1 )
931
+ pg_raise_conn_error( rb_eConnectionBad, self, "Could not wrap win32 socket handle");
932
+
933
+ this->ruby_sd = ruby_sd;
862
934
  #else
863
935
  ruby_sd = sd;
864
936
  #endif
865
937
 
866
- socket_io = rb_funcall( rb_cIO, rb_intern("for_fd"), 1, INT2NUM(ruby_sd) );
938
+ cSocket = rb_const_get(rb_cObject, rb_intern("BasicSocket"));
939
+ socket_io = rb_funcall( cSocket, rb_intern("for_fd"), 1, INT2NUM(ruby_sd));
867
940
 
868
- /* Disable autoclose feature, when supported */
869
- if( rb_respond_to(socket_io, id_autoclose) ){
870
- rb_funcall( socket_io, id_autoclose, 1, Qfalse );
871
- }
941
+ /* Disable autoclose feature */
942
+ rb_funcall( socket_io, s_id_autoclose_set, 1, Qfalse );
872
943
 
873
944
  this->socket_io = socket_io;
874
945
  }
@@ -876,8 +947,6 @@ pgconn_socket_io(VALUE self)
876
947
  return socket_io;
877
948
  }
878
949
 
879
- #endif
880
-
881
950
  /*
882
951
  * call-seq:
883
952
  * conn.backend_pid() -> Integer
@@ -892,6 +961,51 @@ pgconn_backend_pid(VALUE self)
892
961
  return INT2NUM(PQbackendPID(pg_get_pgconn(self)));
893
962
  }
894
963
 
964
+ typedef struct
965
+ {
966
+ struct sockaddr_storage addr;
967
+ socklen_t salen;
968
+ } SockAddr;
969
+
970
+ /* Copy of struct pg_cancel from libpq-int.h
971
+ *
972
+ * See https://github.com/postgres/postgres/blame/master/src/interfaces/libpq/libpq-int.h#L577-L586
973
+ */
974
+ struct pg_cancel
975
+ {
976
+ SockAddr raddr; /* Remote address */
977
+ int be_pid; /* PID of backend --- needed for cancels */
978
+ int be_key; /* key of backend --- needed for cancels */
979
+ };
980
+
981
+ /*
982
+ * call-seq:
983
+ * conn.backend_key() -> Integer
984
+ *
985
+ * Returns the key of the backend server process for this connection.
986
+ * This key can be used to cancel queries on the server.
987
+ */
988
+ static VALUE
989
+ pgconn_backend_key(VALUE self)
990
+ {
991
+ int be_key;
992
+ struct pg_cancel *cancel;
993
+ PGconn *conn = pg_get_pgconn(self);
994
+
995
+ cancel = (struct pg_cancel*)PQgetCancel(conn);
996
+ if(cancel == NULL)
997
+ pg_raise_conn_error( rb_ePGerror, self, "Invalid connection!");
998
+
999
+ if( cancel->be_pid != PQbackendPID(conn) )
1000
+ rb_raise(rb_ePGerror,"Unexpected binary struct layout - please file a bug report at ruby-pg!");
1001
+
1002
+ be_key = cancel->be_key;
1003
+
1004
+ PQfreeCancel(cancel);
1005
+
1006
+ return INT2NUM(be_key);
1007
+ }
1008
+
895
1009
  /*
896
1010
  * call-seq:
897
1011
  * conn.connection_needs_password() -> Boolean
@@ -922,44 +1036,35 @@ pgconn_connection_used_password(VALUE self)
922
1036
  /* :TODO: get_ssl */
923
1037
 
924
1038
 
925
- static VALUE pgconn_exec_params( int, VALUE *, VALUE );
1039
+ static VALUE pgconn_sync_exec_params( int, VALUE *, VALUE );
926
1040
 
927
1041
  /*
928
1042
  * call-seq:
929
- * conn.exec(sql) -> PG::Result
930
- * conn.exec(sql) {|pg_result| block }
1043
+ * conn.sync_exec(sql) -> PG::Result
1044
+ * conn.sync_exec(sql) {|pg_result| block }
931
1045
  *
932
- * Sends SQL query request specified by _sql_ to PostgreSQL.
933
- * Returns a PG::Result instance on success.
934
- * On failure, it raises a PG::Error.
935
- *
936
- * For backward compatibility, if you pass more than one parameter to this method,
937
- * it will call #exec_params for you. New code should explicitly use #exec_params if
938
- * argument placeholders are used.
1046
+ * This function has the same behavior as #async_exec, but is implemented using the synchronous command processing API of libpq.
1047
+ * It's not recommended to use explicit sync or async variants but #exec instead, unless you have a good reason to do so.
939
1048
  *
940
- * If the optional code block is given, it will be passed <i>result</i> as an argument,
941
- * and the PG::Result object will automatically be cleared when the block terminates.
942
- * In this instance, <code>conn.exec</code> returns the value of the block.
1049
+ * Both #sync_exec and #async_exec release the GVL while waiting for server response, so that concurrent threads will get executed.
1050
+ * However #async_exec has two advantages:
943
1051
  *
944
- * #exec is implemented on the synchronous command processing API of libpq, whereas
945
- * #async_exec is implemented on the asynchronous API.
946
- * #exec is somewhat faster that #async_exec, but blocks any signals to be processed until
947
- * the query is finished. This is most notably visible by a delayed reaction to Control+C.
948
- * Both methods ensure that other threads can process while waiting for the server to
949
- * complete the request.
1052
+ * 1. #async_exec can be aborted by signals (like Ctrl-C), while #exec blocks signal processing until the query is answered.
1053
+ * 2. Ruby VM gets notified about IO blocked operations and can pass them through <tt>Fiber.scheduler</tt>.
1054
+ * So only <tt>async_*</tt> methods are compatible to event based schedulers like the async gem.
950
1055
  */
951
1056
  static VALUE
952
- pgconn_exec(int argc, VALUE *argv, VALUE self)
1057
+ pgconn_sync_exec(int argc, VALUE *argv, VALUE self)
953
1058
  {
954
- PGconn *conn = pg_get_pgconn(self);
1059
+ t_pg_connection *this = pg_get_connection_safe( self );
955
1060
  PGresult *result = NULL;
956
1061
  VALUE rb_pgresult;
957
1062
 
958
- /* If called with no parameters, use PQexec */
959
- if ( argc == 1 ) {
1063
+ /* If called with no or nil parameters, use PQexec for compatibility */
1064
+ if ( argc == 1 || (argc >= 2 && argc <= 4 && NIL_P(argv[1]) )) {
960
1065
  VALUE query_str = argv[0];
961
1066
 
962
- result = gvl_PQexec(conn, pg_cstr_enc(query_str, ENCODING_GET(self)));
1067
+ result = gvl_PQexec(this->pgconn, pg_cstr_enc(query_str, this->enc_idx));
963
1068
  rb_pgresult = pg_new_result(result, self);
964
1069
  pg_result_check(rb_pgresult);
965
1070
  if (rb_block_given_p()) {
@@ -967,11 +1072,10 @@ pgconn_exec(int argc, VALUE *argv, VALUE self)
967
1072
  }
968
1073
  return rb_pgresult;
969
1074
  }
1075
+ pg_deprecated(0, ("forwarding exec to exec_params is deprecated"));
970
1076
 
971
1077
  /* Otherwise, just call #exec_params instead for backward-compatibility */
972
- else {
973
- return pgconn_exec_params( argc, argv, self );
974
- }
1078
+ return pgconn_sync_exec_params( argc, argv, self );
975
1079
 
976
1080
  }
977
1081
 
@@ -1003,7 +1107,7 @@ struct query_params_data {
1003
1107
  * Filled by alloc_query_params()
1004
1108
  */
1005
1109
 
1006
- /* Wraps the pointer of allocated memory, if function parameters dont't
1110
+ /* Wraps the pointer of allocated memory, if function parameters don't
1007
1111
  * fit in the memory_pool below.
1008
1112
  */
1009
1113
  VALUE heap_pool;
@@ -1021,7 +1125,7 @@ struct query_params_data {
1021
1125
  Oid *types;
1022
1126
 
1023
1127
  /* This array takes the string values for the timeframe of the query,
1024
- * if param value convertion is required
1128
+ * if param value conversion is required
1025
1129
  */
1026
1130
  VALUE gc_array;
1027
1131
 
@@ -1035,8 +1139,9 @@ struct query_params_data {
1035
1139
  };
1036
1140
 
1037
1141
  static void
1038
- free_typecast_heap_chain(struct linked_typecast_data *chain_entry)
1142
+ free_typecast_heap_chain(void *_chain_entry)
1039
1143
  {
1144
+ struct linked_typecast_data *chain_entry = (struct linked_typecast_data *)_chain_entry;
1040
1145
  while(chain_entry){
1041
1146
  struct linked_typecast_data *next = chain_entry->next;
1042
1147
  xfree(chain_entry);
@@ -1044,6 +1149,18 @@ free_typecast_heap_chain(struct linked_typecast_data *chain_entry)
1044
1149
  }
1045
1150
  }
1046
1151
 
1152
+ static const rb_data_type_t pg_typecast_buffer_type = {
1153
+ "PG::Connection typecast buffer chain",
1154
+ {
1155
+ (RUBY_DATA_FUNC) NULL,
1156
+ free_typecast_heap_chain,
1157
+ (size_t (*)(const void *))NULL,
1158
+ },
1159
+ 0,
1160
+ 0,
1161
+ RUBY_TYPED_FREE_IMMEDIATELY,
1162
+ };
1163
+
1047
1164
  static char *
1048
1165
  alloc_typecast_buf( VALUE *typecast_heap_chain, int len )
1049
1166
  {
@@ -1054,17 +1171,28 @@ alloc_typecast_buf( VALUE *typecast_heap_chain, int len )
1054
1171
  /* Did we already wrap a memory chain per T_DATA object? */
1055
1172
  if( NIL_P( *typecast_heap_chain ) ){
1056
1173
  /* Leave free'ing of the buffer chain to the GC, when paramsData has left the stack */
1057
- *typecast_heap_chain = Data_Wrap_Struct( rb_cObject, NULL, free_typecast_heap_chain, allocated );
1174
+ *typecast_heap_chain = TypedData_Wrap_Struct( rb_cObject, &pg_typecast_buffer_type, allocated );
1058
1175
  allocated->next = NULL;
1059
1176
  } else {
1060
1177
  /* Append to the chain */
1061
- allocated->next = DATA_PTR( *typecast_heap_chain );
1062
- DATA_PTR( *typecast_heap_chain ) = allocated;
1178
+ allocated->next = RTYPEDDATA_DATA( *typecast_heap_chain );
1179
+ RTYPEDDATA_DATA( *typecast_heap_chain ) = allocated;
1063
1180
  }
1064
1181
 
1065
1182
  return &allocated->data[0];
1066
1183
  }
1067
1184
 
1185
+ static const rb_data_type_t pg_query_heap_pool_type = {
1186
+ "PG::Connection query heap pool",
1187
+ {
1188
+ (RUBY_DATA_FUNC) NULL,
1189
+ RUBY_TYPED_DEFAULT_FREE,
1190
+ (size_t (*)(const void *))NULL,
1191
+ },
1192
+ 0,
1193
+ 0,
1194
+ RUBY_TYPED_FREE_IMMEDIATELY,
1195
+ };
1068
1196
 
1069
1197
  static int
1070
1198
  alloc_query_params(struct query_params_data *paramsData)
@@ -1079,7 +1207,7 @@ alloc_query_params(struct query_params_data *paramsData)
1079
1207
 
1080
1208
  Check_Type(paramsData->params, T_ARRAY);
1081
1209
 
1082
- p_typemap = DATA_PTR( paramsData->typemap );
1210
+ p_typemap = RTYPEDDATA_DATA( paramsData->typemap );
1083
1211
  p_typemap->funcs.fit_to_query( paramsData->typemap, paramsData->params );
1084
1212
 
1085
1213
  paramsData->heap_pool = Qnil;
@@ -1098,7 +1226,7 @@ alloc_query_params(struct query_params_data *paramsData)
1098
1226
  /* Allocate one combined memory pool for all possible function parameters */
1099
1227
  memory_pool = (char*)xmalloc( required_pool_size );
1100
1228
  /* Leave free'ing of the buffer to the GC, when paramsData has left the stack */
1101
- paramsData->heap_pool = Data_Wrap_Struct( rb_cObject, NULL, -1, memory_pool );
1229
+ paramsData->heap_pool = TypedData_Wrap_Struct( rb_cObject, &pg_query_heap_pool_type, memory_pool );
1102
1230
  required_pool_size = 0;
1103
1231
  }else{
1104
1232
  /* Use stack memory for function parameters */
@@ -1211,85 +1339,52 @@ pgconn_query_assign_typemap( VALUE self, struct query_params_data *paramsData )
1211
1339
  /* Use default typemap for queries. It's type is checked when assigned. */
1212
1340
  paramsData->typemap = pg_get_connection(self)->type_map_for_queries;
1213
1341
  }else{
1342
+ t_typemap *tm;
1343
+ UNUSED(tm);
1344
+
1214
1345
  /* Check type of method param */
1215
- if ( !rb_obj_is_kind_of(paramsData->typemap, rb_cTypeMap) ) {
1216
- rb_raise( rb_eTypeError, "wrong argument type %s (expected kind of PG::TypeMap)",
1217
- rb_obj_classname( paramsData->typemap ) );
1218
- }
1219
- Check_Type( paramsData->typemap, T_DATA );
1346
+ TypedData_Get_Struct(paramsData->typemap, t_typemap, &pg_typemap_type, tm);
1220
1347
  }
1221
1348
  }
1222
1349
 
1223
1350
  /*
1224
1351
  * call-seq:
1225
- * conn.exec_params(sql, params[, result_format[, type_map]] ) -> PG::Result
1226
- * conn.exec_params(sql, params[, result_format[, type_map]] ) {|pg_result| block }
1227
- *
1228
- * Sends SQL query request specified by +sql+ to PostgreSQL using placeholders
1229
- * for parameters.
1230
- *
1231
- * Returns a PG::Result instance on success. On failure, it raises a PG::Error.
1232
- *
1233
- * +params+ is an array of the bind parameters for the SQL query.
1234
- * Each element of the +params+ array may be either:
1235
- * a hash of the form:
1236
- * {:value => String (value of bind parameter)
1237
- * :type => Integer (oid of type of bind parameter)
1238
- * :format => Integer (0 for text, 1 for binary)
1239
- * }
1240
- * or, it may be a String. If it is a string, that is equivalent to the hash:
1241
- * { :value => <string value>, :type => 0, :format => 0 }
1242
- *
1243
- * PostgreSQL bind parameters are represented as $1, $1, $2, etc.,
1244
- * inside the SQL query. The 0th element of the +params+ array is bound
1245
- * to $1, the 1st element is bound to $2, etc. +nil+ is treated as +NULL+.
1246
- *
1247
- * If the types are not specified, they will be inferred by PostgreSQL.
1248
- * Instead of specifying type oids, it's recommended to simply add
1249
- * explicit casts in the query to ensure that the right type is used.
1250
- *
1251
- * For example: "SELECT $1::int"
1252
- *
1253
- * The optional +result_format+ should be 0 for text results, 1
1254
- * for binary.
1255
- *
1256
- * type_map can be a PG::TypeMap derivation (such as PG::BasicTypeMapForQueries).
1257
- * This will type cast the params form various Ruby types before transmission
1258
- * based on the encoders defined by the type map. When a type encoder is used
1259
- * the format and oid of a given bind parameter are retrieved from the encoder
1260
- * instead out of the hash form described above.
1352
+ * conn.sync_exec_params(sql, params[, result_format[, type_map]] ) -> PG::Result
1353
+ * conn.sync_exec_params(sql, params[, result_format[, type_map]] ) {|pg_result| block }
1261
1354
  *
1262
- * If the optional code block is given, it will be passed <i>result</i> as an argument,
1263
- * and the PG::Result object will automatically be cleared when the block terminates.
1264
- * In this instance, <code>conn.exec</code> returns the value of the block.
1355
+ * This function has the same behavior as #async_exec_params, but is implemented using the synchronous command processing API of libpq.
1356
+ * See #async_exec for the differences between the two API variants.
1357
+ * It's not recommended to use explicit sync or async variants but #exec_params instead, unless you have a good reason to do so.
1265
1358
  */
1266
1359
  static VALUE
1267
- pgconn_exec_params( int argc, VALUE *argv, VALUE self )
1360
+ pgconn_sync_exec_params( int argc, VALUE *argv, VALUE self )
1268
1361
  {
1269
- PGconn *conn = pg_get_pgconn(self);
1362
+ t_pg_connection *this = pg_get_connection_safe( self );
1270
1363
  PGresult *result = NULL;
1271
1364
  VALUE rb_pgresult;
1272
1365
  VALUE command, in_res_fmt;
1273
1366
  int nParams;
1274
1367
  int resultFormat;
1275
- struct query_params_data paramsData = { ENCODING_GET(self) };
1368
+ struct query_params_data paramsData = { this->enc_idx };
1276
1369
 
1370
+ /* For compatibility we accept 1 to 4 parameters */
1277
1371
  rb_scan_args(argc, argv, "13", &command, &paramsData.params, &in_res_fmt, &paramsData.typemap);
1278
1372
  paramsData.with_types = 1;
1279
1373
 
1280
1374
  /*
1281
- * Handle the edge-case where the caller is coming from #exec, but passed an explict +nil+
1282
- * for the second parameter.
1375
+ * For backward compatibility no or +nil+ for the second parameter
1376
+ * is passed to #exec
1283
1377
  */
1284
1378
  if ( NIL_P(paramsData.params) ) {
1285
- return pgconn_exec( 1, argv, self );
1379
+ pg_deprecated(1, ("forwarding exec_params to exec is deprecated"));
1380
+ return pgconn_sync_exec( 1, argv, self );
1286
1381
  }
1287
1382
  pgconn_query_assign_typemap( self, &paramsData );
1288
1383
 
1289
1384
  resultFormat = NIL_P(in_res_fmt) ? 0 : NUM2INT(in_res_fmt);
1290
1385
  nParams = alloc_query_params( &paramsData );
1291
1386
 
1292
- result = gvl_PQexecParams(conn, pg_cstr_enc(command, paramsData.enc_idx), nParams, paramsData.types,
1387
+ result = gvl_PQexecParams(this->pgconn, pg_cstr_enc(command, paramsData.enc_idx), nParams, paramsData.types,
1293
1388
  (const char * const *)paramsData.values, paramsData.lengths, paramsData.formats, resultFormat);
1294
1389
 
1295
1390
  free_query_params( &paramsData );
@@ -1306,28 +1401,16 @@ pgconn_exec_params( int argc, VALUE *argv, VALUE self )
1306
1401
 
1307
1402
  /*
1308
1403
  * call-seq:
1309
- * conn.prepare(stmt_name, sql [, param_types ] ) -> PG::Result
1310
- *
1311
- * Prepares statement _sql_ with name _name_ to be executed later.
1312
- * Returns a PG::Result instance on success.
1313
- * On failure, it raises a PG::Error.
1314
- *
1315
- * +param_types+ is an optional parameter to specify the Oids of the
1316
- * types of the parameters.
1317
- *
1318
- * If the types are not specified, they will be inferred by PostgreSQL.
1319
- * Instead of specifying type oids, it's recommended to simply add
1320
- * explicit casts in the query to ensure that the right type is used.
1321
- *
1322
- * For example: "SELECT $1::int"
1404
+ * conn.sync_prepare(stmt_name, sql [, param_types ] ) -> PG::Result
1323
1405
  *
1324
- * PostgreSQL bind parameters are represented as $1, $1, $2, etc.,
1325
- * inside the SQL query.
1406
+ * This function has the same behavior as #async_prepare, but is implemented using the synchronous command processing API of libpq.
1407
+ * See #async_exec for the differences between the two API variants.
1408
+ * It's not recommended to use explicit sync or async variants but #prepare instead, unless you have a good reason to do so.
1326
1409
  */
1327
1410
  static VALUE
1328
- pgconn_prepare(int argc, VALUE *argv, VALUE self)
1411
+ pgconn_sync_prepare(int argc, VALUE *argv, VALUE self)
1329
1412
  {
1330
- PGconn *conn = pg_get_pgconn(self);
1413
+ t_pg_connection *this = pg_get_connection_safe( self );
1331
1414
  PGresult *result = NULL;
1332
1415
  VALUE rb_pgresult;
1333
1416
  VALUE name, command, in_paramtypes;
@@ -1337,7 +1420,7 @@ pgconn_prepare(int argc, VALUE *argv, VALUE self)
1337
1420
  Oid *paramTypes = NULL;
1338
1421
  const char *name_cstr;
1339
1422
  const char *command_cstr;
1340
- int enc_idx = ENCODING_GET(self);
1423
+ int enc_idx = this->enc_idx;
1341
1424
 
1342
1425
  rb_scan_args(argc, argv, "21", &name, &command, &in_paramtypes);
1343
1426
  name_cstr = pg_cstr_enc(name, enc_idx);
@@ -1355,7 +1438,7 @@ pgconn_prepare(int argc, VALUE *argv, VALUE self)
1355
1438
  paramTypes[i] = NUM2UINT(param);
1356
1439
  }
1357
1440
  }
1358
- result = gvl_PQprepare(conn, name_cstr, command_cstr, nParams, paramTypes);
1441
+ result = gvl_PQprepare(this->pgconn, name_cstr, command_cstr, nParams, paramTypes);
1359
1442
 
1360
1443
  xfree(paramTypes);
1361
1444
 
@@ -1366,49 +1449,23 @@ pgconn_prepare(int argc, VALUE *argv, VALUE self)
1366
1449
 
1367
1450
  /*
1368
1451
  * call-seq:
1369
- * conn.exec_prepared(statement_name [, params, result_format[, type_map]] ) -> PG::Result
1370
- * conn.exec_prepared(statement_name [, params, result_format[, type_map]] ) {|pg_result| block }
1371
- *
1372
- * Execute prepared named statement specified by _statement_name_.
1373
- * Returns a PG::Result instance on success.
1374
- * On failure, it raises a PG::Error.
1375
- *
1376
- * +params+ is an array of the optional bind parameters for the
1377
- * SQL query. Each element of the +params+ array may be either:
1378
- * a hash of the form:
1379
- * {:value => String (value of bind parameter)
1380
- * :format => Integer (0 for text, 1 for binary)
1381
- * }
1382
- * or, it may be a String. If it is a string, that is equivalent to the hash:
1383
- * { :value => <string value>, :format => 0 }
1384
- *
1385
- * PostgreSQL bind parameters are represented as $1, $1, $2, etc.,
1386
- * inside the SQL query. The 0th element of the +params+ array is bound
1387
- * to $1, the 1st element is bound to $2, etc. +nil+ is treated as +NULL+.
1388
- *
1389
- * The optional +result_format+ should be 0 for text results, 1
1390
- * for binary.
1452
+ * conn.sync_exec_prepared(statement_name [, params, result_format[, type_map]] ) -> PG::Result
1453
+ * conn.sync_exec_prepared(statement_name [, params, result_format[, type_map]] ) {|pg_result| block }
1391
1454
  *
1392
- * type_map can be a PG::TypeMap derivation (such as PG::BasicTypeMapForQueries).
1393
- * This will type cast the params form various Ruby types before transmission
1394
- * based on the encoders defined by the type map. When a type encoder is used
1395
- * the format and oid of a given bind parameter are retrieved from the encoder
1396
- * instead out of the hash form described above.
1397
- *
1398
- * If the optional code block is given, it will be passed <i>result</i> as an argument,
1399
- * and the PG::Result object will automatically be cleared when the block terminates.
1400
- * In this instance, <code>conn.exec_prepared</code> returns the value of the block.
1455
+ * This function has the same behavior as #async_exec_prepared, but is implemented using the synchronous command processing API of libpq.
1456
+ * See #async_exec for the differences between the two API variants.
1457
+ * It's not recommended to use explicit sync or async variants but #exec_prepared instead, unless you have a good reason to do so.
1401
1458
  */
1402
1459
  static VALUE
1403
- pgconn_exec_prepared(int argc, VALUE *argv, VALUE self)
1460
+ pgconn_sync_exec_prepared(int argc, VALUE *argv, VALUE self)
1404
1461
  {
1405
- PGconn *conn = pg_get_pgconn(self);
1462
+ t_pg_connection *this = pg_get_connection_safe( self );
1406
1463
  PGresult *result = NULL;
1407
1464
  VALUE rb_pgresult;
1408
1465
  VALUE name, in_res_fmt;
1409
1466
  int nParams;
1410
1467
  int resultFormat;
1411
- struct query_params_data paramsData = { ENCODING_GET(self) };
1468
+ struct query_params_data paramsData = { this->enc_idx };
1412
1469
 
1413
1470
  rb_scan_args(argc, argv, "13", &name, &paramsData.params, &in_res_fmt, &paramsData.typemap);
1414
1471
  paramsData.with_types = 0;
@@ -1421,7 +1478,7 @@ pgconn_exec_prepared(int argc, VALUE *argv, VALUE self)
1421
1478
  resultFormat = NIL_P(in_res_fmt) ? 0 : NUM2INT(in_res_fmt);
1422
1479
  nParams = alloc_query_params( &paramsData );
1423
1480
 
1424
- result = gvl_PQexecPrepared(conn, pg_cstr_enc(name, paramsData.enc_idx), nParams,
1481
+ result = gvl_PQexecPrepared(this->pgconn, pg_cstr_enc(name, paramsData.enc_idx), nParams,
1425
1482
  (const char * const *)paramsData.values, paramsData.lengths, paramsData.formats,
1426
1483
  resultFormat);
1427
1484
 
@@ -1438,25 +1495,26 @@ pgconn_exec_prepared(int argc, VALUE *argv, VALUE self)
1438
1495
 
1439
1496
  /*
1440
1497
  * call-seq:
1441
- * conn.describe_prepared( statement_name ) -> PG::Result
1498
+ * conn.sync_describe_prepared( statement_name ) -> PG::Result
1442
1499
  *
1443
- * Retrieve information about the prepared statement
1444
- * _statement_name_.
1500
+ * This function has the same behavior as #async_describe_prepared, but is implemented using the synchronous command processing API of libpq.
1501
+ * See #async_exec for the differences between the two API variants.
1502
+ * It's not recommended to use explicit sync or async variants but #describe_prepared instead, unless you have a good reason to do so.
1445
1503
  */
1446
1504
  static VALUE
1447
- pgconn_describe_prepared(VALUE self, VALUE stmt_name)
1505
+ pgconn_sync_describe_prepared(VALUE self, VALUE stmt_name)
1448
1506
  {
1449
1507
  PGresult *result;
1450
1508
  VALUE rb_pgresult;
1451
- PGconn *conn = pg_get_pgconn(self);
1509
+ t_pg_connection *this = pg_get_connection_safe( self );
1452
1510
  const char *stmt;
1453
1511
  if(NIL_P(stmt_name)) {
1454
1512
  stmt = NULL;
1455
1513
  }
1456
1514
  else {
1457
- stmt = pg_cstr_enc(stmt_name, ENCODING_GET(self));
1515
+ stmt = pg_cstr_enc(stmt_name, this->enc_idx);
1458
1516
  }
1459
- result = gvl_PQdescribePrepared(conn, stmt);
1517
+ result = gvl_PQdescribePrepared(this->pgconn, stmt);
1460
1518
  rb_pgresult = pg_new_result(result, self);
1461
1519
  pg_result_check(rb_pgresult);
1462
1520
  return rb_pgresult;
@@ -1465,25 +1523,26 @@ pgconn_describe_prepared(VALUE self, VALUE stmt_name)
1465
1523
 
1466
1524
  /*
1467
1525
  * call-seq:
1468
- * conn.describe_portal( portal_name ) -> PG::Result
1526
+ * conn.sync_describe_portal( portal_name ) -> PG::Result
1469
1527
  *
1470
- * Retrieve information about the portal _portal_name_.
1528
+ * This function has the same behavior as #async_describe_portal, but is implemented using the synchronous command processing API of libpq.
1529
+ * See #async_exec for the differences between the two API variants.
1530
+ * It's not recommended to use explicit sync or async variants but #describe_portal instead, unless you have a good reason to do so.
1471
1531
  */
1472
1532
  static VALUE
1473
- pgconn_describe_portal(self, stmt_name)
1474
- VALUE self, stmt_name;
1533
+ pgconn_sync_describe_portal(VALUE self, VALUE stmt_name)
1475
1534
  {
1476
1535
  PGresult *result;
1477
1536
  VALUE rb_pgresult;
1478
- PGconn *conn = pg_get_pgconn(self);
1537
+ t_pg_connection *this = pg_get_connection_safe( self );
1479
1538
  const char *stmt;
1480
1539
  if(NIL_P(stmt_name)) {
1481
1540
  stmt = NULL;
1482
1541
  }
1483
1542
  else {
1484
- stmt = pg_cstr_enc(stmt_name, ENCODING_GET(self));
1543
+ stmt = pg_cstr_enc(stmt_name, this->enc_idx);
1485
1544
  }
1486
- result = gvl_PQdescribePortal(conn, stmt);
1545
+ result = gvl_PQdescribePortal(this->pgconn, stmt);
1487
1546
  rb_pgresult = pg_new_result(result, self);
1488
1547
  pg_result_check(rb_pgresult);
1489
1548
  return rb_pgresult;
@@ -1505,6 +1564,9 @@ pgconn_describe_portal(self, stmt_name)
1505
1564
  * * +PGRES_NONFATAL_ERROR+
1506
1565
  * * +PGRES_FATAL_ERROR+
1507
1566
  * * +PGRES_COPY_BOTH+
1567
+ * * +PGRES_SINGLE_TUPLE+
1568
+ * * +PGRES_PIPELINE_SYNC+
1569
+ * * +PGRES_PIPELINE_ABORTED+
1508
1570
  */
1509
1571
  static VALUE
1510
1572
  pgconn_make_empty_pgresult(VALUE self, VALUE status)
@@ -1530,13 +1592,15 @@ pgconn_make_empty_pgresult(VALUE self, VALUE status)
1530
1592
  * Consider using exec_params, which avoids the need for passing values
1531
1593
  * inside of SQL commands.
1532
1594
  *
1533
- * Encoding of escaped string will be equal to client encoding of connection.
1595
+ * Character encoding of escaped string will be equal to client encoding of connection.
1534
1596
  *
1535
1597
  * NOTE: This class version of this method can only be used safely in client
1536
1598
  * programs that use a single PostgreSQL connection at a time (in this case it can
1537
1599
  * find out what it needs to know "behind the scenes"). It might give the wrong
1538
1600
  * results if used in programs that use multiple database connections; use the
1539
1601
  * same method on the connection object in such cases.
1602
+ *
1603
+ * See also convenience functions #escape_literal and #escape_identifier which also add proper quotes around the string.
1540
1604
  */
1541
1605
  static VALUE
1542
1606
  pgconn_s_escape(VALUE self, VALUE string)
@@ -1547,8 +1611,8 @@ pgconn_s_escape(VALUE self, VALUE string)
1547
1611
  int enc_idx;
1548
1612
  int singleton = !rb_obj_is_kind_of(self, rb_cPGconn);
1549
1613
 
1550
- Check_Type(string, T_STRING);
1551
- enc_idx = ENCODING_GET( singleton ? string : self );
1614
+ StringValueCStr(string);
1615
+ enc_idx = singleton ? ENCODING_GET(string) : pg_get_connection(self)->enc_idx;
1552
1616
  if( ENCODING_GET(string) != enc_idx ){
1553
1617
  string = rb_str_export_to_enc(string, rb_enc_from_index(enc_idx));
1554
1618
  }
@@ -1558,14 +1622,13 @@ pgconn_s_escape(VALUE self, VALUE string)
1558
1622
  if( !singleton ) {
1559
1623
  size = PQescapeStringConn(pg_get_pgconn(self), RSTRING_PTR(result),
1560
1624
  RSTRING_PTR(string), RSTRING_LEN(string), &error);
1561
- if(error) {
1562
- rb_raise(rb_ePGerror, "%s", PQerrorMessage(pg_get_pgconn(self)));
1563
- }
1625
+ if(error)
1626
+ pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(pg_get_pgconn(self)));
1627
+
1564
1628
  } else {
1565
1629
  size = PQescapeString(RSTRING_PTR(result), RSTRING_PTR(string), RSTRING_LEN(string));
1566
1630
  }
1567
1631
  rb_str_set_len(result, size);
1568
- OBJ_INFECT(result, string);
1569
1632
 
1570
1633
  return result;
1571
1634
  }
@@ -1611,7 +1674,6 @@ pgconn_s_escape_bytea(VALUE self, VALUE str)
1611
1674
  }
1612
1675
 
1613
1676
  ret = rb_str_new((char*)to, to_len - 1);
1614
- OBJ_INFECT(ret, str);
1615
1677
  PQfreemem(to);
1616
1678
  return ret;
1617
1679
  }
@@ -1641,50 +1703,42 @@ pgconn_s_unescape_bytea(VALUE self, VALUE str)
1641
1703
  to = PQunescapeBytea(from, &to_len);
1642
1704
 
1643
1705
  ret = rb_str_new((char*)to, to_len);
1644
- OBJ_INFECT(ret, str);
1645
1706
  PQfreemem(to);
1646
1707
  return ret;
1647
1708
  }
1648
1709
 
1649
- #ifdef HAVE_PQESCAPELITERAL
1650
1710
  /*
1651
1711
  * call-seq:
1652
1712
  * conn.escape_literal( str ) -> String
1653
1713
  *
1654
1714
  * Escape an arbitrary String +str+ as a literal.
1715
+ *
1716
+ * See also PG::TextEncoder::QuotedLiteral for a type cast integrated version of this function.
1655
1717
  */
1656
1718
  static VALUE
1657
1719
  pgconn_escape_literal(VALUE self, VALUE string)
1658
1720
  {
1659
- PGconn *conn = pg_get_pgconn(self);
1721
+ t_pg_connection *this = pg_get_connection_safe( self );
1660
1722
  char *escaped = NULL;
1661
- VALUE error;
1662
1723
  VALUE result = Qnil;
1663
- int enc_idx = ENCODING_GET(self);
1724
+ int enc_idx = this->enc_idx;
1664
1725
 
1665
- Check_Type(string, T_STRING);
1726
+ StringValueCStr(string);
1666
1727
  if( ENCODING_GET(string) != enc_idx ){
1667
1728
  string = rb_str_export_to_enc(string, rb_enc_from_index(enc_idx));
1668
1729
  }
1669
1730
 
1670
- escaped = PQescapeLiteral(conn, RSTRING_PTR(string), RSTRING_LEN(string));
1731
+ escaped = PQescapeLiteral(this->pgconn, RSTRING_PTR(string), RSTRING_LEN(string));
1671
1732
  if (escaped == NULL)
1672
- {
1673
- error = rb_exc_new2(rb_ePGerror, PQerrorMessage(conn));
1674
- rb_iv_set(error, "@connection", self);
1675
- rb_exc_raise(error);
1676
- return Qnil;
1677
- }
1733
+ pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(this->pgconn));
1734
+
1678
1735
  result = rb_str_new2(escaped);
1679
1736
  PQfreemem(escaped);
1680
- OBJ_INFECT(result, string);
1681
1737
  PG_ENCODING_SET_NOCHECK(result, enc_idx);
1682
1738
 
1683
1739
  return result;
1684
1740
  }
1685
- #endif
1686
1741
 
1687
- #ifdef HAVE_PQESCAPEIDENTIFIER
1688
1742
  /*
1689
1743
  * call-seq:
1690
1744
  * conn.escape_identifier( str ) -> String
@@ -1698,35 +1752,27 @@ pgconn_escape_literal(VALUE self, VALUE string)
1698
1752
  static VALUE
1699
1753
  pgconn_escape_identifier(VALUE self, VALUE string)
1700
1754
  {
1701
- PGconn *conn = pg_get_pgconn(self);
1755
+ t_pg_connection *this = pg_get_connection_safe( self );
1702
1756
  char *escaped = NULL;
1703
- VALUE error;
1704
1757
  VALUE result = Qnil;
1705
- int enc_idx = ENCODING_GET(self);
1758
+ int enc_idx = this->enc_idx;
1706
1759
 
1707
- Check_Type(string, T_STRING);
1760
+ StringValueCStr(string);
1708
1761
  if( ENCODING_GET(string) != enc_idx ){
1709
1762
  string = rb_str_export_to_enc(string, rb_enc_from_index(enc_idx));
1710
1763
  }
1711
1764
 
1712
- escaped = PQescapeIdentifier(conn, RSTRING_PTR(string), RSTRING_LEN(string));
1765
+ escaped = PQescapeIdentifier(this->pgconn, RSTRING_PTR(string), RSTRING_LEN(string));
1713
1766
  if (escaped == NULL)
1714
- {
1715
- error = rb_exc_new2(rb_ePGerror, PQerrorMessage(conn));
1716
- rb_iv_set(error, "@connection", self);
1717
- rb_exc_raise(error);
1718
- return Qnil;
1719
- }
1767
+ pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(this->pgconn));
1768
+
1720
1769
  result = rb_str_new2(escaped);
1721
1770
  PQfreemem(escaped);
1722
- OBJ_INFECT(result, string);
1723
1771
  PG_ENCODING_SET_NOCHECK(result, enc_idx);
1724
1772
 
1725
1773
  return result;
1726
1774
  }
1727
- #endif
1728
1775
 
1729
- #ifdef HAVE_PQSETSINGLEROWMODE
1730
1776
  /*
1731
1777
  * call-seq:
1732
1778
  * conn.set_single_row_mode -> self
@@ -1762,34 +1808,64 @@ pgconn_escape_identifier(VALUE self, VALUE string)
1762
1808
  * # do something with the received row
1763
1809
  * end
1764
1810
  * end
1765
- *
1766
1811
  */
1767
1812
  static VALUE
1768
1813
  pgconn_set_single_row_mode(VALUE self)
1769
1814
  {
1770
1815
  PGconn *conn = pg_get_pgconn(self);
1771
- VALUE error;
1772
1816
 
1773
1817
  if( PQsetSingleRowMode(conn) == 0 )
1774
- {
1775
- error = rb_exc_new2(rb_ePGerror, PQerrorMessage(conn));
1776
- rb_iv_set(error, "@connection", self);
1777
- rb_exc_raise(error);
1778
- }
1818
+ pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(conn));
1779
1819
 
1780
1820
  return self;
1781
1821
  }
1782
- #endif
1822
+
1823
+ static VALUE pgconn_send_query_params(int argc, VALUE *argv, VALUE self);
1824
+
1825
+ /*
1826
+ * call-seq:
1827
+ * conn.send_query(sql) -> nil
1828
+ *
1829
+ * Sends SQL query request specified by _sql_ to PostgreSQL for
1830
+ * asynchronous processing, and immediately returns.
1831
+ * On failure, it raises a PG::Error.
1832
+ *
1833
+ * For backward compatibility, if you pass more than one parameter to this method,
1834
+ * it will call #send_query_params for you. New code should explicitly use #send_query_params if
1835
+ * argument placeholders are used.
1836
+ *
1837
+ */
1838
+ static VALUE
1839
+ pgconn_send_query(int argc, VALUE *argv, VALUE self)
1840
+ {
1841
+ t_pg_connection *this = pg_get_connection_safe( self );
1842
+
1843
+ /* If called with no or nil parameters, use PQexec for compatibility */
1844
+ if ( argc == 1 || (argc >= 2 && argc <= 4 && NIL_P(argv[1]) )) {
1845
+ if(gvl_PQsendQuery(this->pgconn, pg_cstr_enc(argv[0], this->enc_idx)) == 0)
1846
+ pg_raise_conn_error( rb_eUnableToSend, self, "%s", PQerrorMessage(this->pgconn));
1847
+
1848
+ pgconn_wait_for_flush( self );
1849
+ return Qnil;
1850
+ }
1851
+
1852
+ pg_deprecated(2, ("forwarding async_exec to async_exec_params and send_query to send_query_params is deprecated"));
1853
+
1854
+ /* If called with parameters, and optionally result_format,
1855
+ * use PQsendQueryParams
1856
+ */
1857
+ return pgconn_send_query_params( argc, argv, self);
1858
+ }
1783
1859
 
1784
1860
  /*
1785
1861
  * call-seq:
1786
- * conn.send_query(sql [, params, result_format[, type_map ]] ) -> nil
1862
+ * conn.send_query_params(sql, params [, result_format [, type_map ]] ) -> nil
1787
1863
  *
1788
1864
  * Sends SQL query request specified by _sql_ to PostgreSQL for
1789
1865
  * asynchronous processing, and immediately returns.
1790
1866
  * On failure, it raises a PG::Error.
1791
1867
  *
1792
- * +params+ is an optional array of the bind parameters for the SQL query.
1868
+ * +params+ is an array of the bind parameters for the SQL query.
1793
1869
  * Each element of the +params+ array may be either:
1794
1870
  * a hash of the form:
1795
1871
  * {:value => String (value of bind parameter)
@@ -1799,7 +1875,7 @@ pgconn_set_single_row_mode(VALUE self)
1799
1875
  * or, it may be a String. If it is a string, that is equivalent to the hash:
1800
1876
  * { :value => <string value>, :type => 0, :format => 0 }
1801
1877
  *
1802
- * PostgreSQL bind parameters are represented as $1, $1, $2, etc.,
1878
+ * PostgreSQL bind parameters are represented as $1, $2, $3, etc.,
1803
1879
  * inside the SQL query. The 0th element of the +params+ array is bound
1804
1880
  * to $1, the 1st element is bound to $2, etc. +nil+ is treated as +NULL+.
1805
1881
  *
@@ -1812,55 +1888,39 @@ pgconn_set_single_row_mode(VALUE self)
1812
1888
  * The optional +result_format+ should be 0 for text results, 1
1813
1889
  * for binary.
1814
1890
  *
1815
- * type_map can be a PG::TypeMap derivation (such as PG::BasicTypeMapForQueries).
1816
- * This will type cast the params form various Ruby types before transmission
1891
+ * +type_map+ can be a PG::TypeMap derivation (such as PG::BasicTypeMapForQueries).
1892
+ * This will type cast the params from various Ruby types before transmission
1817
1893
  * based on the encoders defined by the type map. When a type encoder is used
1818
1894
  * the format and oid of a given bind parameter are retrieved from the encoder
1819
1895
  * instead out of the hash form described above.
1820
1896
  *
1821
1897
  */
1822
1898
  static VALUE
1823
- pgconn_send_query(int argc, VALUE *argv, VALUE self)
1899
+ pgconn_send_query_params(int argc, VALUE *argv, VALUE self)
1824
1900
  {
1825
- PGconn *conn = pg_get_pgconn(self);
1901
+ t_pg_connection *this = pg_get_connection_safe( self );
1826
1902
  int result;
1827
1903
  VALUE command, in_res_fmt;
1828
- VALUE error;
1829
1904
  int nParams;
1830
1905
  int resultFormat;
1831
- struct query_params_data paramsData = { ENCODING_GET(self) };
1906
+ struct query_params_data paramsData = { this->enc_idx };
1832
1907
 
1833
- rb_scan_args(argc, argv, "13", &command, &paramsData.params, &in_res_fmt, &paramsData.typemap);
1908
+ rb_scan_args(argc, argv, "22", &command, &paramsData.params, &in_res_fmt, &paramsData.typemap);
1834
1909
  paramsData.with_types = 1;
1835
1910
 
1836
- /* If called with no parameters, use PQsendQuery */
1837
- if(NIL_P(paramsData.params)) {
1838
- if(gvl_PQsendQuery(conn, pg_cstr_enc(command, paramsData.enc_idx)) == 0) {
1839
- error = rb_exc_new2(rb_eUnableToSend, PQerrorMessage(conn));
1840
- rb_iv_set(error, "@connection", self);
1841
- rb_exc_raise(error);
1842
- }
1843
- return Qnil;
1844
- }
1845
-
1846
- /* If called with parameters, and optionally result_format,
1847
- * use PQsendQueryParams
1848
- */
1849
-
1850
1911
  pgconn_query_assign_typemap( self, &paramsData );
1851
1912
  resultFormat = NIL_P(in_res_fmt) ? 0 : NUM2INT(in_res_fmt);
1852
1913
  nParams = alloc_query_params( &paramsData );
1853
1914
 
1854
- result = gvl_PQsendQueryParams(conn, pg_cstr_enc(command, paramsData.enc_idx), nParams, paramsData.types,
1915
+ result = gvl_PQsendQueryParams(this->pgconn, pg_cstr_enc(command, paramsData.enc_idx), nParams, paramsData.types,
1855
1916
  (const char * const *)paramsData.values, paramsData.lengths, paramsData.formats, resultFormat);
1856
1917
 
1857
1918
  free_query_params( &paramsData );
1858
1919
 
1859
- if(result == 0) {
1860
- error = rb_exc_new2(rb_eUnableToSend, PQerrorMessage(conn));
1861
- rb_iv_set(error, "@connection", self);
1862
- rb_exc_raise(error);
1863
- }
1920
+ if(result == 0)
1921
+ pg_raise_conn_error( rb_eUnableToSend, self, "%s", PQerrorMessage(this->pgconn));
1922
+
1923
+ pgconn_wait_for_flush( self );
1864
1924
  return Qnil;
1865
1925
  }
1866
1926
 
@@ -1881,23 +1941,22 @@ pgconn_send_query(int argc, VALUE *argv, VALUE self)
1881
1941
  *
1882
1942
  * For example: "SELECT $1::int"
1883
1943
  *
1884
- * PostgreSQL bind parameters are represented as $1, $1, $2, etc.,
1944
+ * PostgreSQL bind parameters are represented as $1, $2, $3, etc.,
1885
1945
  * inside the SQL query.
1886
1946
  */
1887
1947
  static VALUE
1888
1948
  pgconn_send_prepare(int argc, VALUE *argv, VALUE self)
1889
1949
  {
1890
- PGconn *conn = pg_get_pgconn(self);
1950
+ t_pg_connection *this = pg_get_connection_safe( self );
1891
1951
  int result;
1892
1952
  VALUE name, command, in_paramtypes;
1893
1953
  VALUE param;
1894
- VALUE error;
1895
1954
  int i = 0;
1896
1955
  int nParams = 0;
1897
1956
  Oid *paramTypes = NULL;
1898
1957
  const char *name_cstr;
1899
1958
  const char *command_cstr;
1900
- int enc_idx = ENCODING_GET(self);
1959
+ int enc_idx = this->enc_idx;
1901
1960
 
1902
1961
  rb_scan_args(argc, argv, "21", &name, &command, &in_paramtypes);
1903
1962
  name_cstr = pg_cstr_enc(name, enc_idx);
@@ -1915,15 +1974,14 @@ pgconn_send_prepare(int argc, VALUE *argv, VALUE self)
1915
1974
  paramTypes[i] = NUM2UINT(param);
1916
1975
  }
1917
1976
  }
1918
- result = gvl_PQsendPrepare(conn, name_cstr, command_cstr, nParams, paramTypes);
1977
+ result = gvl_PQsendPrepare(this->pgconn, name_cstr, command_cstr, nParams, paramTypes);
1919
1978
 
1920
1979
  xfree(paramTypes);
1921
1980
 
1922
1981
  if(result == 0) {
1923
- error = rb_exc_new2(rb_eUnableToSend, PQerrorMessage(conn));
1924
- rb_iv_set(error, "@connection", self);
1925
- rb_exc_raise(error);
1982
+ pg_raise_conn_error( rb_eUnableToSend, self, "%s", PQerrorMessage(this->pgconn));
1926
1983
  }
1984
+ pgconn_wait_for_flush( self );
1927
1985
  return Qnil;
1928
1986
  }
1929
1987
 
@@ -1945,15 +2003,15 @@ pgconn_send_prepare(int argc, VALUE *argv, VALUE self)
1945
2003
  * or, it may be a String. If it is a string, that is equivalent to the hash:
1946
2004
  * { :value => <string value>, :format => 0 }
1947
2005
  *
1948
- * PostgreSQL bind parameters are represented as $1, $1, $2, etc.,
2006
+ * PostgreSQL bind parameters are represented as $1, $2, $3, etc.,
1949
2007
  * inside the SQL query. The 0th element of the +params+ array is bound
1950
2008
  * to $1, the 1st element is bound to $2, etc. +nil+ is treated as +NULL+.
1951
2009
  *
1952
2010
  * The optional +result_format+ should be 0 for text results, 1
1953
2011
  * for binary.
1954
2012
  *
1955
- * type_map can be a PG::TypeMap derivation (such as PG::BasicTypeMapForQueries).
1956
- * This will type cast the params form various Ruby types before transmission
2013
+ * +type_map+ can be a PG::TypeMap derivation (such as PG::BasicTypeMapForQueries).
2014
+ * This will type cast the params from various Ruby types before transmission
1957
2015
  * based on the encoders defined by the type map. When a type encoder is used
1958
2016
  * the format and oid of a given bind parameter are retrieved from the encoder
1959
2017
  * instead out of the hash form described above.
@@ -1962,37 +2020,34 @@ pgconn_send_prepare(int argc, VALUE *argv, VALUE self)
1962
2020
  static VALUE
1963
2021
  pgconn_send_query_prepared(int argc, VALUE *argv, VALUE self)
1964
2022
  {
1965
- PGconn *conn = pg_get_pgconn(self);
2023
+ t_pg_connection *this = pg_get_connection_safe( self );
1966
2024
  int result;
1967
2025
  VALUE name, in_res_fmt;
1968
- VALUE error;
1969
2026
  int nParams;
1970
2027
  int resultFormat;
1971
- struct query_params_data paramsData = { ENCODING_GET(self) };
2028
+ struct query_params_data paramsData = { this->enc_idx };
1972
2029
 
1973
2030
  rb_scan_args(argc, argv, "13", &name, &paramsData.params, &in_res_fmt, &paramsData.typemap);
1974
2031
  paramsData.with_types = 0;
1975
2032
 
1976
2033
  if(NIL_P(paramsData.params)) {
1977
2034
  paramsData.params = rb_ary_new2(0);
1978
- resultFormat = 0;
1979
2035
  }
1980
2036
  pgconn_query_assign_typemap( self, &paramsData );
1981
2037
 
1982
2038
  resultFormat = NIL_P(in_res_fmt) ? 0 : NUM2INT(in_res_fmt);
1983
2039
  nParams = alloc_query_params( &paramsData );
1984
2040
 
1985
- result = gvl_PQsendQueryPrepared(conn, pg_cstr_enc(name, paramsData.enc_idx), nParams,
2041
+ result = gvl_PQsendQueryPrepared(this->pgconn, pg_cstr_enc(name, paramsData.enc_idx), nParams,
1986
2042
  (const char * const *)paramsData.values, paramsData.lengths, paramsData.formats,
1987
2043
  resultFormat);
1988
2044
 
1989
2045
  free_query_params( &paramsData );
1990
2046
 
1991
- if(result == 0) {
1992
- error = rb_exc_new2(rb_eUnableToSend, PQerrorMessage(conn));
1993
- rb_iv_set(error, "@connection", self);
1994
- rb_exc_raise(error);
1995
- }
2047
+ if(result == 0)
2048
+ pg_raise_conn_error( rb_eUnableToSend, self, "%s", PQerrorMessage(this->pgconn));
2049
+
2050
+ pgconn_wait_for_flush( self );
1996
2051
  return Qnil;
1997
2052
  }
1998
2053
 
@@ -2006,14 +2061,12 @@ pgconn_send_query_prepared(int argc, VALUE *argv, VALUE self)
2006
2061
  static VALUE
2007
2062
  pgconn_send_describe_prepared(VALUE self, VALUE stmt_name)
2008
2063
  {
2009
- VALUE error;
2010
- PGconn *conn = pg_get_pgconn(self);
2064
+ t_pg_connection *this = pg_get_connection_safe( self );
2011
2065
  /* returns 0 on failure */
2012
- if(gvl_PQsendDescribePrepared(conn, pg_cstr_enc(stmt_name, ENCODING_GET(self))) == 0) {
2013
- error = rb_exc_new2(rb_eUnableToSend, PQerrorMessage(conn));
2014
- rb_iv_set(error, "@connection", self);
2015
- rb_exc_raise(error);
2016
- }
2066
+ if(gvl_PQsendDescribePrepared(this->pgconn, pg_cstr_enc(stmt_name, this->enc_idx)) == 0)
2067
+ pg_raise_conn_error( rb_eUnableToSend, self, "%s", PQerrorMessage(this->pgconn));
2068
+
2069
+ pgconn_wait_for_flush( self );
2017
2070
  return Qnil;
2018
2071
  }
2019
2072
 
@@ -2028,36 +2081,18 @@ pgconn_send_describe_prepared(VALUE self, VALUE stmt_name)
2028
2081
  static VALUE
2029
2082
  pgconn_send_describe_portal(VALUE self, VALUE portal)
2030
2083
  {
2031
- VALUE error;
2032
- PGconn *conn = pg_get_pgconn(self);
2084
+ t_pg_connection *this = pg_get_connection_safe( self );
2033
2085
  /* returns 0 on failure */
2034
- if(gvl_PQsendDescribePortal(conn, pg_cstr_enc(portal, ENCODING_GET(self))) == 0) {
2035
- error = rb_exc_new2(rb_eUnableToSend, PQerrorMessage(conn));
2036
- rb_iv_set(error, "@connection", self);
2037
- rb_exc_raise(error);
2038
- }
2086
+ if(gvl_PQsendDescribePortal(this->pgconn, pg_cstr_enc(portal, this->enc_idx)) == 0)
2087
+ pg_raise_conn_error( rb_eUnableToSend, self, "%s", PQerrorMessage(this->pgconn));
2088
+
2089
+ pgconn_wait_for_flush( self );
2039
2090
  return Qnil;
2040
2091
  }
2041
2092
 
2042
2093
 
2043
- /*
2044
- * call-seq:
2045
- * conn.get_result() -> PG::Result
2046
- * conn.get_result() {|pg_result| block }
2047
- *
2048
- * Blocks waiting for the next result from a call to
2049
- * #send_query (or another asynchronous command), and returns
2050
- * it. Returns +nil+ if no more results are available.
2051
- *
2052
- * Note: call this function repeatedly until it returns +nil+, or else
2053
- * you will not be able to issue further commands.
2054
- *
2055
- * If the optional code block is given, it will be passed <i>result</i> as an argument,
2056
- * and the PG::Result object will automatically be cleared when the block terminates.
2057
- * In this instance, <code>conn.exec</code> returns the value of the block.
2058
- */
2059
2094
  static VALUE
2060
- pgconn_get_result(VALUE self)
2095
+ pgconn_sync_get_result(VALUE self)
2061
2096
  {
2062
2097
  PGconn *conn = pg_get_pgconn(self);
2063
2098
  PGresult *result;
@@ -2083,17 +2118,15 @@ pgconn_get_result(VALUE self)
2083
2118
  * or *notifies* to see if the state has changed.
2084
2119
  */
2085
2120
  static VALUE
2086
- pgconn_consume_input(self)
2087
- VALUE self;
2121
+ pgconn_consume_input(VALUE self)
2088
2122
  {
2089
- VALUE error;
2090
2123
  PGconn *conn = pg_get_pgconn(self);
2091
2124
  /* returns 0 on error */
2092
2125
  if(PQconsumeInput(conn) == 0) {
2093
- error = rb_exc_new2(rb_eConnectionBad, PQerrorMessage(conn));
2094
- rb_iv_set(error, "@connection", self);
2095
- rb_exc_raise(error);
2126
+ pgconn_close_socket_io(self);
2127
+ pg_raise_conn_error( rb_eConnectionBad, self, "%s", PQerrorMessage(conn));
2096
2128
  }
2129
+
2097
2130
  return Qnil;
2098
2131
  }
2099
2132
 
@@ -2102,37 +2135,18 @@ pgconn_consume_input(self)
2102
2135
  * conn.is_busy() -> Boolean
2103
2136
  *
2104
2137
  * Returns +true+ if a command is busy, that is, if
2105
- * PQgetResult would block. Otherwise returns +false+.
2138
+ * #get_result would block. Otherwise returns +false+.
2106
2139
  */
2107
2140
  static VALUE
2108
- pgconn_is_busy(self)
2109
- VALUE self;
2141
+ pgconn_is_busy(VALUE self)
2110
2142
  {
2111
2143
  return gvl_PQisBusy(pg_get_pgconn(self)) ? Qtrue : Qfalse;
2112
2144
  }
2113
2145
 
2114
- /*
2115
- * call-seq:
2116
- * conn.setnonblocking(Boolean) -> nil
2117
- *
2118
- * Sets the nonblocking status of the connection.
2119
- * In the blocking state, calls to #send_query
2120
- * will block until the message is sent to the server,
2121
- * but will not wait for the query results.
2122
- * In the nonblocking state, calls to #send_query
2123
- * will return an error if the socket is not ready for
2124
- * writing.
2125
- * Note: This function does not affect #exec, because
2126
- * that function doesn't return until the server has
2127
- * processed the query and returned the results.
2128
- * Returns +nil+.
2129
- */
2130
2146
  static VALUE
2131
- pgconn_setnonblocking(self, state)
2132
- VALUE self, state;
2147
+ pgconn_sync_setnonblocking(VALUE self, VALUE state)
2133
2148
  {
2134
2149
  int arg;
2135
- VALUE error;
2136
2150
  PGconn *conn = pg_get_pgconn(self);
2137
2151
  if(state == Qtrue)
2138
2152
  arg = 1;
@@ -2141,69 +2155,33 @@ pgconn_setnonblocking(self, state)
2141
2155
  else
2142
2156
  rb_raise(rb_eArgError, "Boolean value expected");
2143
2157
 
2144
- if(PQsetnonblocking(conn, arg) == -1) {
2145
- error = rb_exc_new2(rb_ePGerror, PQerrorMessage(conn));
2146
- rb_iv_set(error, "@connection", self);
2147
- rb_exc_raise(error);
2148
- }
2158
+ if(PQsetnonblocking(conn, arg) == -1)
2159
+ pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(conn));
2160
+
2149
2161
  return Qnil;
2150
2162
  }
2151
2163
 
2152
2164
 
2153
- /*
2154
- * call-seq:
2155
- * conn.isnonblocking() -> Boolean
2156
- *
2157
- * Returns +true+ if a command is busy, that is, if
2158
- * PQgetResult would block. Otherwise returns +false+.
2159
- */
2160
2165
  static VALUE
2161
- pgconn_isnonblocking(self)
2162
- VALUE self;
2166
+ pgconn_sync_isnonblocking(VALUE self)
2163
2167
  {
2164
2168
  return PQisnonblocking(pg_get_pgconn(self)) ? Qtrue : Qfalse;
2165
2169
  }
2166
2170
 
2167
- /*
2168
- * call-seq:
2169
- * conn.flush() -> Boolean
2170
- *
2171
- * Attempts to flush any queued output data to the server.
2172
- * Returns +true+ if data is successfully flushed, +false+
2173
- * if not (can only return +false+ if connection is
2174
- * nonblocking.
2175
- * Raises PG::Error if some other failure occurred.
2176
- */
2177
2171
  static VALUE
2178
- pgconn_flush(self)
2179
- VALUE self;
2172
+ pgconn_sync_flush(VALUE self)
2180
2173
  {
2181
2174
  PGconn *conn = pg_get_pgconn(self);
2182
- int ret;
2183
- VALUE error;
2184
- ret = PQflush(conn);
2185
- if(ret == -1) {
2186
- error = rb_exc_new2(rb_ePGerror, PQerrorMessage(conn));
2187
- rb_iv_set(error, "@connection", self);
2188
- rb_exc_raise(error);
2189
- }
2175
+ int ret = PQflush(conn);
2176
+ if(ret == -1)
2177
+ pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(conn));
2178
+
2190
2179
  return (ret) ? Qfalse : Qtrue;
2191
2180
  }
2192
2181
 
2193
- /*
2194
- * call-seq:
2195
- * conn.cancel() -> String
2196
- *
2197
- * Requests cancellation of the command currently being
2198
- * processed. (Only implemented in PostgreSQL >= 8.0)
2199
- *
2200
- * Returns +nil+ on success, or a string containing the
2201
- * error message if a failure occurs.
2202
- */
2203
2182
  static VALUE
2204
- pgconn_cancel(VALUE self)
2183
+ pgconn_sync_cancel(VALUE self)
2205
2184
  {
2206
- #ifdef HAVE_PQGETCANCEL
2207
2185
  char errbuf[256];
2208
2186
  PGcancel *cancel;
2209
2187
  VALUE retval;
@@ -2211,9 +2189,9 @@ pgconn_cancel(VALUE self)
2211
2189
 
2212
2190
  cancel = PQgetCancel(pg_get_pgconn(self));
2213
2191
  if(cancel == NULL)
2214
- rb_raise(rb_ePGerror,"Invalid connection!");
2192
+ pg_raise_conn_error( rb_ePGerror, self, "Invalid connection!");
2215
2193
 
2216
- ret = gvl_PQcancel(cancel, errbuf, 256);
2194
+ ret = gvl_PQcancel(cancel, errbuf, sizeof(errbuf));
2217
2195
  if(ret == 1)
2218
2196
  retval = Qnil;
2219
2197
  else
@@ -2221,9 +2199,6 @@ pgconn_cancel(VALUE self)
2221
2199
 
2222
2200
  PQfreeCancel(cancel);
2223
2201
  return retval;
2224
- #else
2225
- rb_notimplement();
2226
- #endif
2227
2202
  }
2228
2203
 
2229
2204
 
@@ -2237,7 +2212,7 @@ pgconn_cancel(VALUE self)
2237
2212
  static VALUE
2238
2213
  pgconn_notifies(VALUE self)
2239
2214
  {
2240
- PGconn* conn = pg_get_pgconn(self);
2215
+ t_pg_connection *this = pg_get_connection_safe( self );
2241
2216
  PGnotify *notification;
2242
2217
  VALUE hash;
2243
2218
  VALUE sym_relname, sym_be_pid, sym_extra;
@@ -2247,17 +2222,17 @@ pgconn_notifies(VALUE self)
2247
2222
  sym_be_pid = ID2SYM(rb_intern("be_pid"));
2248
2223
  sym_extra = ID2SYM(rb_intern("extra"));
2249
2224
 
2250
- notification = gvl_PQnotifies(conn);
2225
+ notification = gvl_PQnotifies(this->pgconn);
2251
2226
  if (notification == NULL) {
2252
2227
  return Qnil;
2253
2228
  }
2254
2229
 
2255
2230
  hash = rb_hash_new();
2256
- relname = rb_tainted_str_new2(notification->relname);
2231
+ relname = rb_str_new2(notification->relname);
2257
2232
  be_pid = INT2NUM(notification->be_pid);
2258
- extra = rb_tainted_str_new2(notification->extra);
2259
- PG_ENCODING_SET_NOCHECK( relname, ENCODING_GET(self) );
2260
- PG_ENCODING_SET_NOCHECK( extra, ENCODING_GET(self) );
2233
+ extra = rb_str_new2(notification->extra);
2234
+ PG_ENCODING_SET_NOCHECK( relname, this->enc_idx );
2235
+ PG_ENCODING_SET_NOCHECK( extra, this->enc_idx );
2261
2236
 
2262
2237
  rb_hash_aset(hash, sym_relname, relname);
2263
2238
  rb_hash_aset(hash, sym_be_pid, be_pid);
@@ -2267,96 +2242,63 @@ pgconn_notifies(VALUE self)
2267
2242
  return hash;
2268
2243
  }
2269
2244
 
2270
- /* Win32 + Ruby 1.8 */
2271
- #if !defined( HAVE_RUBY_VM_H ) && defined( _WIN32 )
2245
+ #if defined(_WIN32)
2272
2246
 
2273
- /*
2274
- * Duplicate the sockets from libpq and create temporary CRT FDs
2247
+ /* We use a specialized implementation of rb_io_wait() on Windows.
2248
+ * This is because rb_io_wait() and rb_wait_for_single_fd() are very slow on Windows.
2275
2249
  */
2276
- void create_crt_fd(fd_set *os_set, fd_set *crt_set)
2277
- {
2278
- int i;
2279
- crt_set->fd_count = os_set->fd_count;
2280
- for (i = 0; i < os_set->fd_count; i++) {
2281
- WSAPROTOCOL_INFO wsa_pi;
2282
- /* dupicate the SOCKET */
2283
- int r = WSADuplicateSocket(os_set->fd_array[i], GetCurrentProcessId(), &wsa_pi);
2284
- SOCKET s = WSASocket(wsa_pi.iAddressFamily, wsa_pi.iSocketType, wsa_pi.iProtocol, &wsa_pi, 0, 0);
2285
- /* create the CRT fd so ruby can get back to the SOCKET */
2286
- int fd = _open_osfhandle(s, O_RDWR|O_BINARY);
2287
- os_set->fd_array[i] = s;
2288
- crt_set->fd_array[i] = fd;
2289
- }
2290
- }
2291
2250
 
2292
- /*
2293
- * Clean up the CRT FDs from create_crt_fd()
2294
- */
2295
- void cleanup_crt_fd(fd_set *os_set, fd_set *crt_set)
2296
- {
2297
- int i;
2298
- for (i = 0; i < os_set->fd_count; i++) {
2299
- /* cleanup the CRT fd */
2300
- _close(crt_set->fd_array[i]);
2301
- /* cleanup the duplicated SOCKET */
2302
- closesocket(os_set->fd_array[i]);
2303
- }
2304
- }
2251
+ #if defined(HAVE_RUBY_FIBER_SCHEDULER_H)
2252
+ #include <ruby/fiber/scheduler.h>
2305
2253
  #endif
2306
2254
 
2307
- /* Win32 + Ruby 1.9+ */
2308
- #if defined( HAVE_RUBY_VM_H ) && defined( _WIN32 )
2309
- /*
2310
- * On Windows, use platform-specific strategies to wait for the socket
2311
- * instead of rb_thread_select().
2312
- */
2255
+ typedef enum {
2256
+ PG_RUBY_IO_READABLE = RB_WAITFD_IN,
2257
+ PG_RUBY_IO_WRITABLE = RB_WAITFD_OUT,
2258
+ PG_RUBY_IO_PRIORITY = RB_WAITFD_PRI,
2259
+ } pg_rb_io_event_t;
2313
2260
 
2314
2261
  int rb_w32_wait_events( HANDLE *events, int num, DWORD timeout );
2315
2262
 
2316
- /* If WIN32 and Ruby 1.9 do not use rb_thread_select() which sometimes hangs
2317
- * and does not wait (nor sleep) any time even if timeout is given.
2318
- * Instead use the Winsock events and rb_w32_wait_events(). */
2263
+ static VALUE
2264
+ pg_rb_thread_io_wait(VALUE io, VALUE events, VALUE timeout) {
2265
+ rb_io_t *fptr;
2266
+ struct timeval ptimeout;
2319
2267
 
2320
- static void *
2321
- wait_socket_readable( PGconn *conn, struct timeval *ptimeout, void *(*is_readable)(PGconn *) )
2322
- {
2323
- int sd = PQsocket( conn );
2324
- void *retval;
2325
2268
  struct timeval aborttime={0,0}, currtime, waittime;
2326
2269
  DWORD timeout_milisec = INFINITE;
2327
- DWORD wait_ret;
2328
- WSAEVENT hEvent;
2270
+ HANDLE hEvent = WSACreateEvent();
2329
2271
 
2330
- if ( sd < 0 )
2331
- rb_raise(rb_eConnectionBad, "PQsocket() can't get socket descriptor");
2332
-
2333
- hEvent = WSACreateEvent();
2272
+ long rb_events = NUM2UINT(events);
2273
+ long w32_events = 0;
2274
+ DWORD wait_ret;
2334
2275
 
2335
- /* Check for connection errors (PQisBusy is true on connection errors) */
2336
- if( PQconsumeInput(conn) == 0 ) {
2337
- WSACloseEvent( hEvent );
2338
- rb_raise( rb_eConnectionBad, "PQconsumeInput() %s", PQerrorMessage(conn) );
2339
- }
2276
+ GetOpenFile((io), fptr);
2277
+ if( !NIL_P(timeout) ){
2278
+ ptimeout.tv_sec = (time_t)(NUM2DBL(timeout));
2279
+ ptimeout.tv_usec = (time_t)((NUM2DBL(timeout) - (double)ptimeout.tv_sec) * 1e6);
2340
2280
 
2341
- if ( ptimeout ) {
2342
2281
  gettimeofday(&currtime, NULL);
2343
- timeradd(&currtime, ptimeout, &aborttime);
2282
+ timeradd(&currtime, &ptimeout, &aborttime);
2344
2283
  }
2345
2284
 
2346
- while ( !(retval=is_readable(conn)) ) {
2347
- if ( WSAEventSelect(sd, hEvent, FD_READ|FD_CLOSE) == SOCKET_ERROR ) {
2285
+ if(rb_events & PG_RUBY_IO_READABLE) w32_events |= FD_READ | FD_ACCEPT | FD_CLOSE;
2286
+ if(rb_events & PG_RUBY_IO_WRITABLE) w32_events |= FD_WRITE | FD_CONNECT;
2287
+ if(rb_events & PG_RUBY_IO_PRIORITY) w32_events |= FD_OOB;
2288
+
2289
+ for(;;) {
2290
+ if ( WSAEventSelect(_get_osfhandle(fptr->fd), hEvent, w32_events) == SOCKET_ERROR ) {
2348
2291
  WSACloseEvent( hEvent );
2349
2292
  rb_raise( rb_eConnectionBad, "WSAEventSelect socket error: %d", WSAGetLastError() );
2350
2293
  }
2351
2294
 
2352
- if ( ptimeout ) {
2295
+ if ( !NIL_P(timeout) ) {
2353
2296
  gettimeofday(&currtime, NULL);
2354
2297
  timersub(&aborttime, &currtime, &waittime);
2355
2298
  timeout_milisec = (DWORD)( waittime.tv_sec * 1e3 + waittime.tv_usec / 1e3 );
2356
2299
  }
2357
2300
 
2358
- /* Is the given timeout valid? */
2359
- if( !ptimeout || (waittime.tv_sec >= 0 && waittime.tv_usec >= 0) ){
2301
+ if( NIL_P(timeout) || (waittime.tv_sec >= 0 && waittime.tv_usec >= 0) ){
2360
2302
  /* Wait for the socket to become readable before checking again */
2361
2303
  wait_ret = rb_w32_wait_events( &hEvent, 1, timeout_milisec );
2362
2304
  } else {
@@ -2365,9 +2307,11 @@ wait_socket_readable( PGconn *conn, struct timeval *ptimeout, void *(*is_readabl
2365
2307
 
2366
2308
  if ( wait_ret == WAIT_TIMEOUT ) {
2367
2309
  WSACloseEvent( hEvent );
2368
- return NULL;
2310
+ return UINT2NUM(0);
2369
2311
  } else if ( wait_ret == WAIT_OBJECT_0 ) {
2312
+ WSACloseEvent( hEvent );
2370
2313
  /* The event we were waiting for. */
2314
+ return UINT2NUM(rb_events);
2371
2315
  } else if ( wait_ret == WAIT_OBJECT_0 + 1) {
2372
2316
  /* This indicates interruption from timer thread, GC, exception
2373
2317
  * from other threads etc... */
@@ -2379,42 +2323,66 @@ wait_socket_readable( PGconn *conn, struct timeval *ptimeout, void *(*is_readabl
2379
2323
  WSACloseEvent( hEvent );
2380
2324
  rb_raise( rb_eConnectionBad, "Wait on socket abandoned (WaitForMultipleObjects)" );
2381
2325
  }
2382
-
2383
- /* Check for connection errors (PQisBusy is true on connection errors) */
2384
- if ( PQconsumeInput(conn) == 0 ) {
2385
- WSACloseEvent( hEvent );
2386
- rb_raise( rb_eConnectionBad, "PQconsumeInput() %s", PQerrorMessage(conn) );
2387
- }
2388
2326
  }
2327
+ }
2389
2328
 
2390
- WSACloseEvent( hEvent );
2391
- return retval;
2329
+ static VALUE
2330
+ pg_rb_io_wait(VALUE io, VALUE events, VALUE timeout) {
2331
+ #if defined(HAVE_RUBY_FIBER_SCHEDULER_H)
2332
+ /* We don't support Fiber.scheduler on Windows ruby-3.0 because there is no fast way to check whether a scheduler is active.
2333
+ * Fortunatelly ruby-3.1 offers a C-API for it.
2334
+ */
2335
+ VALUE scheduler = rb_fiber_scheduler_current();
2336
+
2337
+ if (!NIL_P(scheduler)) {
2338
+ return rb_io_wait(io, events, timeout);
2339
+ }
2340
+ #endif
2341
+ return pg_rb_thread_io_wait(io, events, timeout);
2392
2342
  }
2393
2343
 
2344
+ #elif defined(HAVE_RB_IO_WAIT)
2345
+
2346
+ /* Use our own function and constants names, to avoid conflicts with truffleruby-head on its road to ruby-3.0 compatibility. */
2347
+ #define pg_rb_io_wait rb_io_wait
2348
+ #define PG_RUBY_IO_READABLE RUBY_IO_READABLE
2349
+ #define PG_RUBY_IO_WRITABLE RUBY_IO_WRITABLE
2350
+ #define PG_RUBY_IO_PRIORITY RUBY_IO_PRIORITY
2351
+
2394
2352
  #else
2353
+ /* For compat with ruby < 3.0 */
2354
+
2355
+ typedef enum {
2356
+ PG_RUBY_IO_READABLE = RB_WAITFD_IN,
2357
+ PG_RUBY_IO_WRITABLE = RB_WAITFD_OUT,
2358
+ PG_RUBY_IO_PRIORITY = RB_WAITFD_PRI,
2359
+ } pg_rb_io_event_t;
2395
2360
 
2396
- /* non Win32 or Win32+Ruby-1.8 */
2361
+ static VALUE
2362
+ pg_rb_io_wait(VALUE io, VALUE events, VALUE timeout) {
2363
+ rb_io_t *fptr;
2364
+ struct timeval waittime;
2365
+ int res;
2366
+
2367
+ GetOpenFile((io), fptr);
2368
+ if( !NIL_P(timeout) ){
2369
+ waittime.tv_sec = (time_t)(NUM2DBL(timeout));
2370
+ waittime.tv_usec = (time_t)((NUM2DBL(timeout) - (double)waittime.tv_sec) * 1e6);
2371
+ }
2372
+ res = rb_wait_for_single_fd(fptr->fd, NUM2UINT(events), NIL_P(timeout) ? NULL : &waittime);
2373
+
2374
+ return UINT2NUM(res);
2375
+ }
2376
+ #endif
2397
2377
 
2398
2378
  static void *
2399
- wait_socket_readable( PGconn *conn, struct timeval *ptimeout, void *(*is_readable)(PGconn *))
2379
+ wait_socket_readable( VALUE self, struct timeval *ptimeout, void *(*is_readable)(PGconn *))
2400
2380
  {
2401
- int sd = PQsocket( conn );
2402
- int ret;
2381
+ VALUE ret;
2403
2382
  void *retval;
2404
- rb_fdset_t sd_rset;
2405
2383
  struct timeval aborttime={0,0}, currtime, waittime;
2406
- #ifdef _WIN32
2407
- rb_fdset_t crt_sd_rset;
2408
- #endif
2409
-
2410
- if ( sd < 0 )
2411
- rb_raise(rb_eConnectionBad, "PQsocket() can't get socket descriptor");
2412
-
2413
- /* Check for connection errors (PQisBusy is true on connection errors) */
2414
- if ( PQconsumeInput(conn) == 0 )
2415
- rb_raise( rb_eConnectionBad, "PQconsumeInput() %s", PQerrorMessage(conn) );
2416
-
2417
- rb_fd_init( &sd_rset );
2384
+ VALUE wait_timeout = Qnil;
2385
+ PGconn *conn = pg_get_pgconn(self);
2418
2386
 
2419
2387
  if ( ptimeout ) {
2420
2388
  gettimeofday(&currtime, NULL);
@@ -2422,59 +2390,82 @@ wait_socket_readable( PGconn *conn, struct timeval *ptimeout, void *(*is_readabl
2422
2390
  }
2423
2391
 
2424
2392
  while ( !(retval=is_readable(conn)) ) {
2425
- rb_fd_zero( &sd_rset );
2426
- rb_fd_set( sd, &sd_rset );
2427
-
2428
- #ifdef _WIN32
2429
- /* Ruby's FD_SET is modified on win32 to convert a file descriptor
2430
- * to osfhandle, but we already get a osfhandle from PQsocket().
2431
- * Therefore it's overwritten here. */
2432
- sd_rset.fd_array[0] = sd;
2433
- create_crt_fd(&sd_rset, &crt_sd_rset);
2434
- #endif
2435
-
2436
2393
  if ( ptimeout ) {
2437
2394
  gettimeofday(&currtime, NULL);
2438
2395
  timersub(&aborttime, &currtime, &waittime);
2396
+ wait_timeout = DBL2NUM((double)(waittime.tv_sec) + (double)(waittime.tv_usec) / 1000000.0);
2439
2397
  }
2440
2398
 
2441
2399
  /* Is the given timeout valid? */
2442
2400
  if( !ptimeout || (waittime.tv_sec >= 0 && waittime.tv_usec >= 0) ){
2443
- /* Wait for the socket to become readable before checking again */
2444
- ret = rb_thread_fd_select( sd+1, &sd_rset, NULL, NULL, ptimeout ? &waittime : NULL );
2445
- } else {
2446
- ret = 0;
2447
- }
2448
-
2401
+ VALUE socket_io;
2449
2402
 
2450
- #ifdef _WIN32
2451
- cleanup_crt_fd(&sd_rset, &crt_sd_rset);
2452
- #endif
2403
+ /* before we wait for data, make sure everything has been sent */
2404
+ pgconn_async_flush(self);
2405
+ if ((retval=is_readable(conn)))
2406
+ return retval;
2453
2407
 
2454
- if ( ret < 0 ){
2455
- rb_fd_term( &sd_rset );
2456
- rb_sys_fail( "rb_thread_select()" );
2408
+ socket_io = pgconn_socket_io(self);
2409
+ /* Wait for the socket to become readable before checking again */
2410
+ ret = pg_rb_io_wait(socket_io, RB_INT2NUM(PG_RUBY_IO_READABLE), wait_timeout);
2411
+ } else {
2412
+ ret = Qfalse;
2457
2413
  }
2458
2414
 
2459
2415
  /* Return false if the select() timed out */
2460
- if ( ret == 0 ){
2461
- rb_fd_term( &sd_rset );
2416
+ if ( ret == Qfalse ){
2462
2417
  return NULL;
2463
2418
  }
2464
2419
 
2465
2420
  /* Check for connection errors (PQisBusy is true on connection errors) */
2466
2421
  if ( PQconsumeInput(conn) == 0 ){
2467
- rb_fd_term( &sd_rset );
2468
- rb_raise( rb_eConnectionBad, "PQconsumeInput() %s", PQerrorMessage(conn) );
2422
+ pgconn_close_socket_io(self);
2423
+ pg_raise_conn_error(rb_eConnectionBad, self, "PQconsumeInput() %s", PQerrorMessage(conn));
2469
2424
  }
2470
2425
  }
2471
2426
 
2472
- rb_fd_term( &sd_rset );
2473
2427
  return retval;
2474
2428
  }
2475
2429
 
2430
+ /*
2431
+ * call-seq:
2432
+ * conn.flush() -> Boolean
2433
+ *
2434
+ * Attempts to flush any queued output data to the server.
2435
+ * Returns +true+ if data is successfully flushed, +false+
2436
+ * if not. It can only return +false+ if connection is
2437
+ * in nonblocking mode.
2438
+ * Raises PG::Error if some other failure occurred.
2439
+ */
2440
+ static VALUE
2441
+ pgconn_async_flush(VALUE self)
2442
+ {
2443
+ while( pgconn_sync_flush(self) == Qfalse ){
2444
+ /* wait for the socket to become read- or write-ready */
2445
+ int events;
2446
+ VALUE socket_io = pgconn_socket_io(self);
2447
+ events = RB_NUM2INT(pg_rb_io_wait(socket_io, RB_INT2NUM(PG_RUBY_IO_READABLE | PG_RUBY_IO_WRITABLE), Qnil));
2448
+
2449
+ if (events & PG_RUBY_IO_READABLE)
2450
+ pgconn_consume_input(self);
2451
+ }
2452
+ return Qtrue;
2453
+ }
2454
+
2455
+ static VALUE
2456
+ pgconn_wait_for_flush( VALUE self ){
2457
+ if( !pg_get_connection_safe(self)->flush_data )
2458
+ return Qnil;
2459
+
2460
+ return pgconn_async_flush(self);
2461
+ }
2476
2462
 
2477
- #endif
2463
+ static VALUE
2464
+ pgconn_flush_data_set( VALUE self, VALUE enabled ){
2465
+ t_pg_connection *conn = pg_get_connection(self);
2466
+ conn->flush_data = RTEST(enabled);
2467
+ return enabled;
2468
+ }
2478
2469
 
2479
2470
  static void *
2480
2471
  notify_readable(PGconn *conn)
@@ -2484,27 +2475,20 @@ notify_readable(PGconn *conn)
2484
2475
 
2485
2476
  /*
2486
2477
  * call-seq:
2487
- * conn.wait_for_notify( [ timeout ] ) -> String
2488
- * conn.wait_for_notify( [ timeout ] ) { |event, pid| block }
2489
- * conn.wait_for_notify( [ timeout ] ) { |event, pid, payload| block } # PostgreSQL 9.0
2478
+ * conn.wait_for_notify( [ timeout ] ) { |event, pid, payload| block } -> String
2490
2479
  *
2491
2480
  * Blocks while waiting for notification(s), or until the optional
2492
2481
  * _timeout_ is reached, whichever comes first. _timeout_ is
2493
2482
  * measured in seconds and can be fractional.
2494
2483
  *
2495
- * Returns +nil+ if _timeout_ is reached, the name of the NOTIFY
2496
- * event otherwise. If used in block form, passes the name of the
2497
- * NOTIFY +event+ and the generating +pid+ into the block.
2498
- *
2499
- * Under PostgreSQL 9.0 and later, if the notification is sent with
2500
- * the optional +payload+ string, it will be given to the block as the
2501
- * third argument.
2502
- *
2484
+ * Returns +nil+ if _timeout_ is reached, the name of the NOTIFY event otherwise.
2485
+ * If used in block form, passes the name of the NOTIFY +event+, the generating
2486
+ * +pid+ and the optional +payload+ string into the block.
2503
2487
  */
2504
2488
  static VALUE
2505
2489
  pgconn_wait_for_notify(int argc, VALUE *argv, VALUE self)
2506
2490
  {
2507
- PGconn *conn = pg_get_pgconn( self );
2491
+ t_pg_connection *this = pg_get_connection_safe( self );
2508
2492
  PGnotify *pnotification;
2509
2493
  struct timeval timeout;
2510
2494
  struct timeval *ptimeout = NULL;
@@ -2520,20 +2504,18 @@ pgconn_wait_for_notify(int argc, VALUE *argv, VALUE self)
2520
2504
  ptimeout = &timeout;
2521
2505
  }
2522
2506
 
2523
- pnotification = (PGnotify*) wait_socket_readable( conn, ptimeout, notify_readable);
2507
+ pnotification = (PGnotify*) wait_socket_readable( self, ptimeout, notify_readable);
2524
2508
 
2525
2509
  /* Return nil if the select timed out */
2526
2510
  if ( !pnotification ) return Qnil;
2527
2511
 
2528
- relname = rb_tainted_str_new2( pnotification->relname );
2529
- PG_ENCODING_SET_NOCHECK( relname, ENCODING_GET(self) );
2512
+ relname = rb_str_new2( pnotification->relname );
2513
+ PG_ENCODING_SET_NOCHECK( relname, this->enc_idx );
2530
2514
  be_pid = INT2NUM( pnotification->be_pid );
2531
- #ifdef HAVE_ST_NOTIFY_EXTRA
2532
2515
  if ( *pnotification->extra ) {
2533
- extra = rb_tainted_str_new2( pnotification->extra );
2534
- PG_ENCODING_SET_NOCHECK( extra, ENCODING_GET(self) );
2516
+ extra = rb_str_new2( pnotification->extra );
2517
+ PG_ENCODING_SET_NOCHECK( extra, this->enc_idx );
2535
2518
  }
2536
- #endif
2537
2519
  PQfreemem( pnotification );
2538
2520
 
2539
2521
  if ( rb_block_given_p() )
@@ -2543,27 +2525,8 @@ pgconn_wait_for_notify(int argc, VALUE *argv, VALUE self)
2543
2525
  }
2544
2526
 
2545
2527
 
2546
- /*
2547
- * call-seq:
2548
- * conn.put_copy_data( buffer [, encoder] ) -> Boolean
2549
- *
2550
- * Transmits _buffer_ as copy data to the server.
2551
- * Returns true if the data was sent, false if it was
2552
- * not sent (false is only possible if the connection
2553
- * is in nonblocking mode, and this command would block).
2554
- *
2555
- * encoder can be a PG::Coder derivation (typically PG::TextEncoder::CopyRow).
2556
- * This encodes the received data fields from an Array of Strings. Optionally
2557
- * the encoder can type cast the fields form various Ruby types in one step,
2558
- * if PG::TextEncoder::CopyRow#type_map is set accordingly.
2559
- *
2560
- * Raises an exception if an error occurs.
2561
- *
2562
- * See also #copy_data.
2563
- *
2564
- */
2565
2528
  static VALUE
2566
- pgconn_put_copy_data(int argc, VALUE *argv, VALUE self)
2529
+ pgconn_sync_put_copy_data(int argc, VALUE *argv, VALUE self)
2567
2530
  {
2568
2531
  int ret;
2569
2532
  int len;
@@ -2580,18 +2543,16 @@ pgconn_put_copy_data(int argc, VALUE *argv, VALUE self)
2580
2543
  if( NIL_P(this->encoder_for_put_copy_data) ){
2581
2544
  buffer = value;
2582
2545
  } else {
2583
- p_coder = DATA_PTR( this->encoder_for_put_copy_data );
2546
+ p_coder = RTYPEDDATA_DATA( this->encoder_for_put_copy_data );
2584
2547
  }
2585
- } else if( rb_obj_is_kind_of(encoder, rb_cPG_Coder) ) {
2586
- Data_Get_Struct( encoder, t_pg_coder, p_coder );
2587
2548
  } else {
2588
- rb_raise( rb_eTypeError, "wrong encoder type %s (expected some kind of PG::Coder)",
2589
- rb_obj_classname( encoder ) );
2549
+ /* Check argument type and use argument encoder */
2550
+ TypedData_Get_Struct(encoder, t_pg_coder, &pg_coder_type, p_coder);
2590
2551
  }
2591
2552
 
2592
2553
  if( p_coder ){
2593
2554
  t_pg_coder_enc_func enc_func;
2594
- int enc_idx = ENCODING_GET(self);
2555
+ int enc_idx = this->enc_idx;
2595
2556
 
2596
2557
  enc_func = pg_coder_enc_func( p_coder );
2597
2558
  len = enc_func( p_coder, value, NULL, &intermediate, enc_idx);
@@ -2609,75 +2570,39 @@ pgconn_put_copy_data(int argc, VALUE *argv, VALUE self)
2609
2570
  Check_Type(buffer, T_STRING);
2610
2571
 
2611
2572
  ret = gvl_PQputCopyData(this->pgconn, RSTRING_PTR(buffer), RSTRING_LENINT(buffer));
2612
- if(ret == -1) {
2613
- VALUE error = rb_exc_new2(rb_ePGerror, PQerrorMessage(this->pgconn));
2614
- rb_iv_set(error, "@connection", self);
2615
- rb_exc_raise(error);
2616
- }
2573
+ if(ret == -1)
2574
+ pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(this->pgconn));
2575
+
2617
2576
  RB_GC_GUARD(intermediate);
2618
2577
  RB_GC_GUARD(buffer);
2619
2578
 
2620
2579
  return (ret) ? Qtrue : Qfalse;
2621
2580
  }
2622
2581
 
2623
- /*
2624
- * call-seq:
2625
- * conn.put_copy_end( [ error_message ] ) -> Boolean
2626
- *
2627
- * Sends end-of-data indication to the server.
2628
- *
2629
- * _error_message_ is an optional parameter, and if set,
2630
- * forces the COPY command to fail with the string
2631
- * _error_message_.
2632
- *
2633
- * Returns true if the end-of-data was sent, false if it was
2634
- * not sent (false is only possible if the connection
2635
- * is in nonblocking mode, and this command would block).
2636
- */
2637
2582
  static VALUE
2638
- pgconn_put_copy_end(int argc, VALUE *argv, VALUE self)
2583
+ pgconn_sync_put_copy_end(int argc, VALUE *argv, VALUE self)
2639
2584
  {
2640
2585
  VALUE str;
2641
- VALUE error;
2642
2586
  int ret;
2643
2587
  const char *error_message = NULL;
2644
- PGconn *conn = pg_get_pgconn(self);
2588
+ t_pg_connection *this = pg_get_connection_safe( self );
2645
2589
 
2646
2590
  if (rb_scan_args(argc, argv, "01", &str) == 0)
2647
2591
  error_message = NULL;
2648
2592
  else
2649
- error_message = pg_cstr_enc(str, ENCODING_GET(self));
2593
+ error_message = pg_cstr_enc(str, this->enc_idx);
2594
+
2595
+ ret = gvl_PQputCopyEnd(this->pgconn, error_message);
2596
+ if(ret == -1)
2597
+ pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(this->pgconn));
2650
2598
 
2651
- ret = gvl_PQputCopyEnd(conn, error_message);
2652
- if(ret == -1) {
2653
- error = rb_exc_new2(rb_ePGerror, PQerrorMessage(conn));
2654
- rb_iv_set(error, "@connection", self);
2655
- rb_exc_raise(error);
2656
- }
2657
2599
  return (ret) ? Qtrue : Qfalse;
2658
2600
  }
2659
2601
 
2660
- /*
2661
- * call-seq:
2662
- * conn.get_copy_data( [ async = false [, decoder = nil ]] ) -> String
2663
- *
2664
- * Return a string containing one row of data, +nil+
2665
- * if the copy is done, or +false+ if the call would
2666
- * block (only possible if _async_ is true).
2667
- *
2668
- * decoder can be a PG::Coder derivation (typically PG::TextDecoder::CopyRow).
2669
- * This decodes the received data fields as Array of Strings. Optionally
2670
- * the decoder can type cast the fields to various Ruby types in one step,
2671
- * if PG::TextDecoder::CopyRow#type_map is set accordingly.
2672
- *
2673
- * See also #copy_data.
2674
- *
2675
- */
2676
2602
  static VALUE
2677
- pgconn_get_copy_data(int argc, VALUE *argv, VALUE self )
2603
+ pgconn_sync_get_copy_data(int argc, VALUE *argv, VALUE self )
2678
2604
  {
2679
2605
  VALUE async_in;
2680
- VALUE error;
2681
2606
  VALUE result;
2682
2607
  int ret;
2683
2608
  char *buffer;
@@ -2689,20 +2614,16 @@ pgconn_get_copy_data(int argc, VALUE *argv, VALUE self )
2689
2614
 
2690
2615
  if( NIL_P(decoder) ){
2691
2616
  if( !NIL_P(this->decoder_for_get_copy_data) ){
2692
- p_coder = DATA_PTR( this->decoder_for_get_copy_data );
2617
+ p_coder = RTYPEDDATA_DATA( this->decoder_for_get_copy_data );
2693
2618
  }
2694
- } else if( rb_obj_is_kind_of(decoder, rb_cPG_Coder) ) {
2695
- Data_Get_Struct( decoder, t_pg_coder, p_coder );
2696
2619
  } else {
2697
- rb_raise( rb_eTypeError, "wrong decoder type %s (expected some kind of PG::Coder)",
2698
- rb_obj_classname( decoder ) );
2620
+ /* Check argument type and use argument decoder */
2621
+ TypedData_Get_Struct(decoder, t_pg_coder, &pg_coder_type, p_coder);
2699
2622
  }
2700
2623
 
2701
2624
  ret = gvl_PQgetCopyData(this->pgconn, &buffer, RTEST(async_in));
2702
- if(ret == -2) { /* error */
2703
- error = rb_exc_new2(rb_ePGerror, PQerrorMessage(this->pgconn));
2704
- rb_iv_set(error, "@connection", self);
2705
- rb_exc_raise(error);
2625
+ if(ret == -2){ /* error */
2626
+ pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(this->pgconn));
2706
2627
  }
2707
2628
  if(ret == -1) { /* No data left */
2708
2629
  return Qnil;
@@ -2713,9 +2634,9 @@ pgconn_get_copy_data(int argc, VALUE *argv, VALUE self )
2713
2634
 
2714
2635
  if( p_coder ){
2715
2636
  t_pg_coder_dec_func dec_func = pg_coder_dec_func( p_coder, p_coder->format );
2716
- result = dec_func( p_coder, buffer, ret, 0, 0, ENCODING_GET(self) );
2637
+ result = dec_func( p_coder, buffer, ret, 0, 0, this->enc_idx );
2717
2638
  } else {
2718
- result = rb_tainted_str_new(buffer, ret);
2639
+ result = rb_str_new(buffer, ret);
2719
2640
  }
2720
2641
 
2721
2642
  PQfreemem(buffer);
@@ -2728,9 +2649,16 @@ pgconn_get_copy_data(int argc, VALUE *argv, VALUE self )
2728
2649
  *
2729
2650
  * Sets connection's verbosity to _verbosity_ and returns
2730
2651
  * the previous setting. Available settings are:
2652
+ *
2731
2653
  * * PQERRORS_TERSE
2732
2654
  * * PQERRORS_DEFAULT
2733
2655
  * * PQERRORS_VERBOSE
2656
+ * * PQERRORS_SQLSTATE
2657
+ *
2658
+ * Changing the verbosity does not affect the messages available from already-existing PG::Result objects, only subsequently-created ones.
2659
+ * (But see PG::Result#verbose_error_message if you want to print a previous error with a different verbosity.)
2660
+ *
2661
+ * See also corresponding {libpq function}[https://www.postgresql.org/docs/current/libpq-control.html#LIBPQ-PQSETERRORVERBOSITY].
2734
2662
  */
2735
2663
  static VALUE
2736
2664
  pgconn_set_error_verbosity(VALUE self, VALUE in_verbosity)
@@ -2740,6 +2668,37 @@ pgconn_set_error_verbosity(VALUE self, VALUE in_verbosity)
2740
2668
  return INT2FIX(PQsetErrorVerbosity(conn, verbosity));
2741
2669
  }
2742
2670
 
2671
+ #ifdef HAVE_PQRESULTVERBOSEERRORMESSAGE
2672
+ /*
2673
+ * call-seq:
2674
+ * conn.set_error_context_visibility( context_visibility ) -> Integer
2675
+ *
2676
+ * Sets connection's context display mode to _context_visibility_ and returns
2677
+ * the previous setting. Available settings are:
2678
+ * * PQSHOW_CONTEXT_NEVER
2679
+ * * PQSHOW_CONTEXT_ERRORS
2680
+ * * PQSHOW_CONTEXT_ALWAYS
2681
+ *
2682
+ * This mode controls whether the CONTEXT field is included in messages (unless the verbosity setting is TERSE, in which case CONTEXT is never shown).
2683
+ * The NEVER mode never includes CONTEXT, while ALWAYS always includes it if available.
2684
+ * In ERRORS mode (the default), CONTEXT fields are included only for error messages, not for notices and warnings.
2685
+ *
2686
+ * Changing this mode does not affect the messages available from already-existing PG::Result objects, only subsequently-created ones.
2687
+ * (But see PG::Result#verbose_error_message if you want to print a previous error with a different display mode.)
2688
+ *
2689
+ * See also corresponding {libpq function}[https://www.postgresql.org/docs/current/libpq-control.html#LIBPQ-PQSETERRORCONTEXTVISIBILITY].
2690
+ *
2691
+ * Available since PostgreSQL-9.6
2692
+ */
2693
+ static VALUE
2694
+ pgconn_set_error_context_visibility(VALUE self, VALUE in_context_visibility)
2695
+ {
2696
+ PGconn *conn = pg_get_pgconn(self);
2697
+ PGContextVisibility context_visibility = NUM2INT(in_context_visibility);
2698
+ return INT2FIX(PQsetErrorContextVisibility(conn, context_visibility));
2699
+ }
2700
+ #endif
2701
+
2743
2702
  /*
2744
2703
  * call-seq:
2745
2704
  * conn.trace( stream ) -> nil
@@ -2758,7 +2717,7 @@ pgconn_trace(VALUE self, VALUE stream)
2758
2717
  VALUE new_file;
2759
2718
  t_pg_connection *this = pg_get_connection_safe( self );
2760
2719
 
2761
- if(rb_respond_to(stream,rb_intern("fileno")) == Qfalse)
2720
+ if(!rb_respond_to(stream,rb_intern("fileno")))
2762
2721
  rb_raise(rb_eArgError, "stream does not respond to method: fileno");
2763
2722
 
2764
2723
  fileno = rb_funcall(stream, rb_intern("fileno"), 0);
@@ -2891,8 +2850,8 @@ notice_processor_proxy(void *arg, const char *message)
2891
2850
  t_pg_connection *this = pg_get_connection( self );
2892
2851
 
2893
2852
  if (this->notice_receiver != Qnil) {
2894
- VALUE message_str = rb_tainted_str_new2(message);
2895
- PG_ENCODING_SET_NOCHECK( message_str, ENCODING_GET(self) );
2853
+ VALUE message_str = rb_str_new2(message);
2854
+ PG_ENCODING_SET_NOCHECK( message_str, this->enc_idx );
2896
2855
  rb_funcall(this->notice_receiver, rb_intern("call"), 1, message_str);
2897
2856
  }
2898
2857
  return;
@@ -2902,7 +2861,7 @@ notice_processor_proxy(void *arg, const char *message)
2902
2861
  * call-seq:
2903
2862
  * conn.set_notice_processor {|message| ... } -> Proc
2904
2863
  *
2905
- * See #set_notice_receiver for the desription of what this and the
2864
+ * See #set_notice_receiver for the description of what this and the
2906
2865
  * notice_processor methods do.
2907
2866
  *
2908
2867
  * This function takes a new block to act as the notice processor and returns
@@ -2950,76 +2909,33 @@ static VALUE
2950
2909
  pgconn_get_client_encoding(VALUE self)
2951
2910
  {
2952
2911
  char *encoding = (char *)pg_encoding_to_char(PQclientEncoding(pg_get_pgconn(self)));
2953
- return rb_tainted_str_new2(encoding);
2912
+ return rb_str_new2(encoding);
2954
2913
  }
2955
2914
 
2956
2915
 
2957
2916
  /*
2958
2917
  * call-seq:
2959
- * conn.set_client_encoding( encoding )
2918
+ * conn.sync_set_client_encoding( encoding )
2960
2919
  *
2961
- * Sets the client encoding to the _encoding_ String.
2920
+ * This function has the same behavior as #async_set_client_encoding, but is implemented using the synchronous command processing API of libpq.
2921
+ * See #async_exec for the differences between the two API variants.
2922
+ * 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.
2962
2923
  */
2963
2924
  static VALUE
2964
- pgconn_set_client_encoding(VALUE self, VALUE str)
2925
+ pgconn_sync_set_client_encoding(VALUE self, VALUE str)
2965
2926
  {
2966
2927
  PGconn *conn = pg_get_pgconn( self );
2967
2928
 
2968
2929
  Check_Type(str, T_STRING);
2969
2930
 
2970
- if ( (gvl_PQsetClientEncoding(conn, StringValueCStr(str))) == -1 ) {
2971
- rb_raise(rb_ePGerror, "invalid encoding name: %s",StringValueCStr(str));
2972
- }
2973
- #ifdef M17N_SUPPORTED
2931
+ if ( (gvl_PQsetClientEncoding(conn, StringValueCStr(str))) == -1 )
2932
+ pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(conn));
2933
+
2974
2934
  pgconn_set_internal_encoding_index( self );
2975
- #endif
2976
2935
 
2977
2936
  return Qnil;
2978
2937
  }
2979
2938
 
2980
- /*
2981
- * call-seq:
2982
- * conn.transaction { |conn| ... } -> result of the block
2983
- *
2984
- * Executes a +BEGIN+ at the start of the block,
2985
- * and a +COMMIT+ at the end of the block, or
2986
- * +ROLLBACK+ if any exception occurs.
2987
- */
2988
- static VALUE
2989
- pgconn_transaction(VALUE self)
2990
- {
2991
- PGconn *conn = pg_get_pgconn(self);
2992
- PGresult *result;
2993
- VALUE rb_pgresult;
2994
- VALUE block_result = Qnil;
2995
- int status;
2996
-
2997
- if (rb_block_given_p()) {
2998
- result = gvl_PQexec(conn, "BEGIN");
2999
- rb_pgresult = pg_new_result(result, self);
3000
- pg_result_check(rb_pgresult);
3001
- block_result = rb_protect(rb_yield, self, &status);
3002
- if(status == 0) {
3003
- result = gvl_PQexec(conn, "COMMIT");
3004
- rb_pgresult = pg_new_result(result, self);
3005
- pg_result_check(rb_pgresult);
3006
- }
3007
- else {
3008
- /* exception occurred, ROLLBACK and re-raise */
3009
- result = gvl_PQexec(conn, "ROLLBACK");
3010
- rb_pgresult = pg_new_result(result, self);
3011
- pg_result_check(rb_pgresult);
3012
- rb_jump_tag(status);
3013
- }
3014
-
3015
- }
3016
- else {
3017
- /* no block supplied? */
3018
- rb_raise(rb_eArgError, "Must supply block for PG::Connection#transaction");
3019
- }
3020
- return block_result;
3021
- }
3022
-
3023
2939
 
3024
2940
  /*
3025
2941
  * call-seq:
@@ -3064,14 +2980,12 @@ pgconn_s_quote_ident(VALUE self, VALUE str_or_array)
3064
2980
  int enc_idx;
3065
2981
 
3066
2982
  if( rb_obj_is_kind_of(self, rb_cPGconn) ){
3067
- enc_idx = ENCODING_GET( self );
2983
+ enc_idx = pg_get_connection(self)->enc_idx;
3068
2984
  }else{
3069
2985
  enc_idx = RB_TYPE_P(str_or_array, T_STRING) ? ENCODING_GET( str_or_array ) : rb_ascii8bit_encindex();
3070
2986
  }
3071
2987
  pg_text_enc_identifier(NULL, str_or_array, NULL, &ret, enc_idx);
3072
2988
 
3073
- OBJ_INFECT(ret, str_or_array);
3074
-
3075
2989
  return ret;
3076
2990
  }
3077
2991
 
@@ -3096,14 +3010,8 @@ get_result_readable(PGconn *conn)
3096
3010
  * If +true+ is returned, +conn.is_busy+ will return +false+
3097
3011
  * and +conn.get_result+ will not block.
3098
3012
  */
3099
- static VALUE
3013
+ VALUE
3100
3014
  pgconn_block( int argc, VALUE *argv, VALUE self ) {
3101
- PGconn *conn = pg_get_pgconn( self );
3102
-
3103
- /* If WIN32 and Ruby 1.9 do not use rb_thread_select() which sometimes hangs
3104
- * and does not wait (nor sleep) any time even if timeout is given.
3105
- * Instead use the Winsock events and rb_w32_wait_events(). */
3106
-
3107
3015
  struct timeval timeout;
3108
3016
  struct timeval *ptimeout = NULL;
3109
3017
  VALUE timeout_in;
@@ -3117,7 +3025,7 @@ pgconn_block( int argc, VALUE *argv, VALUE self ) {
3117
3025
  ptimeout = &timeout;
3118
3026
  }
3119
3027
 
3120
- ret = wait_socket_readable( conn, ptimeout, get_result_readable);
3028
+ ret = wait_socket_readable( self, ptimeout, get_result_readable);
3121
3029
 
3122
3030
  if( !ret )
3123
3031
  return Qfalse;
@@ -3126,6 +3034,42 @@ pgconn_block( int argc, VALUE *argv, VALUE self ) {
3126
3034
  }
3127
3035
 
3128
3036
 
3037
+ /*
3038
+ * call-seq:
3039
+ * conn.sync_get_last_result( ) -> PG::Result
3040
+ *
3041
+ * This function has the same behavior as #async_get_last_result, but is implemented using the synchronous command processing API of libpq.
3042
+ * See #async_exec for the differences between the two API variants.
3043
+ * 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.
3044
+ */
3045
+ static VALUE
3046
+ pgconn_sync_get_last_result(VALUE self)
3047
+ {
3048
+ PGconn *conn = pg_get_pgconn(self);
3049
+ VALUE rb_pgresult = Qnil;
3050
+ PGresult *cur, *prev;
3051
+
3052
+
3053
+ cur = prev = NULL;
3054
+ while ((cur = gvl_PQgetResult(conn)) != NULL) {
3055
+ int status;
3056
+
3057
+ if (prev) PQclear(prev);
3058
+ prev = cur;
3059
+
3060
+ status = PQresultStatus(cur);
3061
+ if (status == PGRES_COPY_OUT || status == PGRES_COPY_IN || status == PGRES_COPY_BOTH)
3062
+ break;
3063
+ }
3064
+
3065
+ if (prev) {
3066
+ rb_pgresult = pg_new_result( prev, self );
3067
+ pg_result_check(rb_pgresult);
3068
+ }
3069
+
3070
+ return rb_pgresult;
3071
+ }
3072
+
3129
3073
  /*
3130
3074
  * call-seq:
3131
3075
  * conn.get_last_result( ) -> PG::Result
@@ -3136,27 +3080,36 @@ pgconn_block( int argc, VALUE *argv, VALUE self ) {
3136
3080
  * returns the last non-NULL result, or +nil+ if no
3137
3081
  * results are available.
3138
3082
  *
3083
+ * If the last result contains a bad result_status, an
3084
+ * appropriate exception is raised.
3085
+ *
3139
3086
  * This function is similar to #get_result
3140
3087
  * except that it is designed to get one and only
3141
- * one result.
3088
+ * one result and that it checks the result state.
3142
3089
  */
3143
3090
  static VALUE
3144
- pgconn_get_last_result(VALUE self)
3091
+ pgconn_async_get_last_result(VALUE self)
3145
3092
  {
3146
3093
  PGconn *conn = pg_get_pgconn(self);
3147
3094
  VALUE rb_pgresult = Qnil;
3148
3095
  PGresult *cur, *prev;
3149
3096
 
3150
-
3151
- cur = prev = NULL;
3152
- while ((cur = gvl_PQgetResult(conn)) != NULL) {
3097
+ cur = prev = NULL;
3098
+ for(;;) {
3153
3099
  int status;
3154
3100
 
3101
+ /* wait for input (without blocking) before reading each result */
3102
+ wait_socket_readable(self, NULL, get_result_readable);
3103
+
3104
+ cur = gvl_PQgetResult(conn);
3105
+ if (cur == NULL)
3106
+ break;
3107
+
3155
3108
  if (prev) PQclear(prev);
3156
3109
  prev = cur;
3157
3110
 
3158
3111
  status = PQresultStatus(cur);
3159
- if (status == PGRES_COPY_OUT || status == PGRES_COPY_IN)
3112
+ if (status == PGRES_COPY_OUT || status == PGRES_COPY_IN || status == PGRES_COPY_BOTH)
3160
3113
  break;
3161
3114
  }
3162
3115
 
@@ -3170,25 +3123,108 @@ pgconn_get_last_result(VALUE self)
3170
3123
 
3171
3124
  /*
3172
3125
  * call-seq:
3173
- * conn.async_exec(sql [, params, result_format ] ) -> PG::Result
3174
- * conn.async_exec(sql [, params, result_format ] ) {|pg_result| block }
3126
+ * conn.discard_results()
3127
+ *
3128
+ * Silently discard any prior query result that application didn't eat.
3129
+ * This is done prior of Connection#exec and sibling methods and can
3130
+ * be called explicitly when using the async API.
3131
+ */
3132
+ static VALUE
3133
+ pgconn_discard_results(VALUE self)
3134
+ {
3135
+ PGconn *conn = pg_get_pgconn(self);
3136
+ VALUE socket_io;
3137
+
3138
+ if( PQtransactionStatus(conn) == PQTRANS_IDLE ) {
3139
+ return Qnil;
3140
+ }
3141
+
3142
+ socket_io = pgconn_socket_io(self);
3143
+
3144
+ for(;;) {
3145
+ PGresult *cur;
3146
+ int status;
3147
+
3148
+ /* pgconn_block() raises an exception in case of errors.
3149
+ * To avoid this call pg_rb_io_wait() and PQconsumeInput() without rb_raise().
3150
+ */
3151
+ while( gvl_PQisBusy(conn) ){
3152
+ pg_rb_io_wait(socket_io, RB_INT2NUM(PG_RUBY_IO_READABLE), Qnil);
3153
+ if ( PQconsumeInput(conn) == 0 ) {
3154
+ pgconn_close_socket_io(self);
3155
+ return Qfalse;
3156
+ }
3157
+ }
3158
+
3159
+ cur = gvl_PQgetResult(conn);
3160
+ if( cur == NULL) break;
3161
+
3162
+ status = PQresultStatus(cur);
3163
+ PQclear(cur);
3164
+ if (status == PGRES_COPY_IN){
3165
+ gvl_PQputCopyEnd(conn, "COPY terminated by new PQexec");
3166
+ }
3167
+ if (status == PGRES_COPY_OUT){
3168
+ for(;;) {
3169
+ char *buffer = NULL;
3170
+ int st = gvl_PQgetCopyData(conn, &buffer, 1);
3171
+ if( st == 0 ) {
3172
+ /* would block -> wait for readable data */
3173
+ pg_rb_io_wait(socket_io, RB_INT2NUM(PG_RUBY_IO_READABLE), Qnil);
3174
+ if ( PQconsumeInput(conn) == 0 ) {
3175
+ pgconn_close_socket_io(self);
3176
+ return Qfalse;
3177
+ }
3178
+ } else if( st > 0 ) {
3179
+ /* some data retrieved -> discard it */
3180
+ PQfreemem(buffer);
3181
+ } else {
3182
+ /* no more data */
3183
+ break;
3184
+ }
3185
+ }
3186
+ }
3187
+ }
3188
+
3189
+ return Qtrue;
3190
+ }
3191
+
3192
+ /*
3193
+ * call-seq:
3194
+ * conn.exec(sql) -> PG::Result
3195
+ * conn.exec(sql) {|pg_result| block }
3196
+ *
3197
+ * Sends SQL query request specified by _sql_ to PostgreSQL.
3198
+ * On success, it returns a PG::Result instance with all result rows and columns.
3199
+ * On failure, it raises a PG::Error.
3200
+ *
3201
+ * For backward compatibility, if you pass more than one parameter to this method,
3202
+ * it will call #exec_params for you. New code should explicitly use #exec_params if
3203
+ * argument placeholders are used.
3204
+ *
3205
+ * If the optional code block is given, it will be passed <i>result</i> as an argument,
3206
+ * and the PG::Result object will automatically be cleared when the block terminates.
3207
+ * In this instance, <code>conn.exec</code> returns the value of the block.
3208
+ *
3209
+ * #exec is an alias for #async_exec which is almost identical to #sync_exec .
3210
+ * #sync_exec is implemented on the simpler synchronous command processing API of libpq, whereas
3211
+ * #async_exec is implemented on the asynchronous API and on ruby's IO mechanisms.
3212
+ * Only #async_exec is compatible to <tt>Fiber.scheduler</tt> based asynchronous IO processing introduced in ruby-3.0.
3213
+ * Both methods ensure that other threads can process while waiting for the server to
3214
+ * complete the request, but #sync_exec blocks all signals to be processed until the query is finished.
3215
+ * This is most notably visible by a delayed reaction to Control+C.
3216
+ * It's not recommended to use explicit sync or async variants but #exec instead, unless you have a good reason to do so.
3175
3217
  *
3176
- * This function has the same behavior as #exec,
3177
- * but is implemented using the asynchronous command
3178
- * processing API of libpq.
3218
+ * See also corresponding {libpq function}[https://www.postgresql.org/docs/current/libpq-exec.html#LIBPQ-PQEXEC].
3179
3219
  */
3180
3220
  static VALUE
3181
3221
  pgconn_async_exec(int argc, VALUE *argv, VALUE self)
3182
3222
  {
3183
3223
  VALUE rb_pgresult = Qnil;
3184
3224
 
3185
- /* remove any remaining results from the queue */
3186
- pgconn_block( 0, NULL, self ); /* wait for input (without blocking) before reading the last result */
3187
- pgconn_get_last_result( self );
3188
-
3225
+ pgconn_discard_results( self );
3189
3226
  pgconn_send_query( argc, argv, self );
3190
- pgconn_block( 0, NULL, self );
3191
- rb_pgresult = pgconn_get_last_result( self );
3227
+ rb_pgresult = pgconn_async_get_last_result( self );
3192
3228
 
3193
3229
  if ( rb_block_given_p() ) {
3194
3230
  return rb_ensure( rb_yield, rb_pgresult, pg_result_clear, rb_pgresult );
@@ -3197,15 +3233,225 @@ pgconn_async_exec(int argc, VALUE *argv, VALUE self)
3197
3233
  }
3198
3234
 
3199
3235
 
3200
- #ifdef HAVE_PQSSLATTRIBUTE
3201
- /* Since PostgreSQL-9.5: */
3236
+ /*
3237
+ * call-seq:
3238
+ * conn.exec_params(sql, params [, result_format [, type_map ]] ) -> nil
3239
+ * conn.exec_params(sql, params [, result_format [, type_map ]] ) {|pg_result| block }
3240
+ *
3241
+ * Sends SQL query request specified by +sql+ to PostgreSQL using placeholders
3242
+ * for parameters.
3243
+ *
3244
+ * Returns a PG::Result instance on success. On failure, it raises a PG::Error.
3245
+ *
3246
+ * +params+ is an array of the bind parameters for the SQL query.
3247
+ * Each element of the +params+ array may be either:
3248
+ * a hash of the form:
3249
+ * {:value => String (value of bind parameter)
3250
+ * :type => Integer (oid of type of bind parameter)
3251
+ * :format => Integer (0 for text, 1 for binary)
3252
+ * }
3253
+ * or, it may be a String. If it is a string, that is equivalent to the hash:
3254
+ * { :value => <string value>, :type => 0, :format => 0 }
3255
+ *
3256
+ * PostgreSQL bind parameters are represented as $1, $2, $3, etc.,
3257
+ * inside the SQL query. The 0th element of the +params+ array is bound
3258
+ * to $1, the 1st element is bound to $2, etc. +nil+ is treated as +NULL+.
3259
+ *
3260
+ * If the types are not specified, they will be inferred by PostgreSQL.
3261
+ * Instead of specifying type oids, it's recommended to simply add
3262
+ * explicit casts in the query to ensure that the right type is used.
3263
+ *
3264
+ * For example: "SELECT $1::int"
3265
+ *
3266
+ * The optional +result_format+ should be 0 for text results, 1
3267
+ * for binary.
3268
+ *
3269
+ * +type_map+ can be a PG::TypeMap derivation (such as PG::BasicTypeMapForQueries).
3270
+ * This will type cast the params from various Ruby types before transmission
3271
+ * based on the encoders defined by the type map. When a type encoder is used
3272
+ * the format and oid of a given bind parameter are retrieved from the encoder
3273
+ * instead out of the hash form described above.
3274
+ *
3275
+ * If the optional code block is given, it will be passed <i>result</i> as an argument,
3276
+ * and the PG::Result object will automatically be cleared when the block terminates.
3277
+ * In this instance, <code>conn.exec</code> returns the value of the block.
3278
+ *
3279
+ * 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.
3280
+ * Unlike #exec, #exec_params allows at most one SQL command in the given string.
3281
+ * (There can be semicolons in it, but not more than one nonempty command.)
3282
+ * This is a limitation of the underlying protocol, but has some usefulness as an extra defense against SQL-injection attacks.
3283
+ *
3284
+ * See also corresponding {libpq function}[https://www.postgresql.org/docs/current/libpq-exec.html#LIBPQ-PQEXECPARAMS].
3285
+ */
3286
+ static VALUE
3287
+ pgconn_async_exec_params(int argc, VALUE *argv, VALUE self)
3288
+ {
3289
+ VALUE rb_pgresult = Qnil;
3290
+
3291
+ pgconn_discard_results( self );
3292
+ /* If called with no or nil parameters, use PQsendQuery for compatibility */
3293
+ if ( argc == 1 || (argc >= 2 && argc <= 4 && NIL_P(argv[1]) )) {
3294
+ pg_deprecated(3, ("forwarding async_exec_params to async_exec is deprecated"));
3295
+ pgconn_send_query( argc, argv, self );
3296
+ } else {
3297
+ pgconn_send_query_params( argc, argv, self );
3298
+ }
3299
+ rb_pgresult = pgconn_async_get_last_result( self );
3300
+
3301
+ if ( rb_block_given_p() ) {
3302
+ return rb_ensure( rb_yield, rb_pgresult, pg_result_clear, rb_pgresult );
3303
+ }
3304
+ return rb_pgresult;
3305
+ }
3306
+
3307
+
3308
+ /*
3309
+ * call-seq:
3310
+ * conn.prepare(stmt_name, sql [, param_types ] ) -> PG::Result
3311
+ *
3312
+ * Prepares statement _sql_ with name _name_ to be executed later.
3313
+ * Returns a PG::Result instance on success.
3314
+ * On failure, it raises a PG::Error.
3315
+ *
3316
+ * +param_types+ is an optional parameter to specify the Oids of the
3317
+ * types of the parameters.
3318
+ *
3319
+ * If the types are not specified, they will be inferred by PostgreSQL.
3320
+ * Instead of specifying type oids, it's recommended to simply add
3321
+ * explicit casts in the query to ensure that the right type is used.
3322
+ *
3323
+ * For example: "SELECT $1::int"
3324
+ *
3325
+ * PostgreSQL bind parameters are represented as $1, $2, $3, etc.,
3326
+ * inside the SQL query.
3327
+ *
3328
+ * See also corresponding {libpq function}[https://www.postgresql.org/docs/current/libpq-exec.html#LIBPQ-PQPREPARE].
3329
+ */
3330
+ static VALUE
3331
+ pgconn_async_prepare(int argc, VALUE *argv, VALUE self)
3332
+ {
3333
+ VALUE rb_pgresult = Qnil;
3334
+
3335
+ pgconn_discard_results( self );
3336
+ pgconn_send_prepare( argc, argv, self );
3337
+ rb_pgresult = pgconn_async_get_last_result( self );
3338
+
3339
+ if ( rb_block_given_p() ) {
3340
+ return rb_ensure( rb_yield, rb_pgresult, pg_result_clear, rb_pgresult );
3341
+ }
3342
+ return rb_pgresult;
3343
+ }
3344
+
3202
3345
 
3346
+ /*
3347
+ * call-seq:
3348
+ * conn.exec_prepared(statement_name [, params, result_format[, type_map]] ) -> PG::Result
3349
+ * conn.exec_prepared(statement_name [, params, result_format[, type_map]] ) {|pg_result| block }
3350
+ *
3351
+ * Execute prepared named statement specified by _statement_name_.
3352
+ * Returns a PG::Result instance on success.
3353
+ * On failure, it raises a PG::Error.
3354
+ *
3355
+ * +params+ is an array of the optional bind parameters for the
3356
+ * SQL query. Each element of the +params+ array may be either:
3357
+ * a hash of the form:
3358
+ * {:value => String (value of bind parameter)
3359
+ * :format => Integer (0 for text, 1 for binary)
3360
+ * }
3361
+ * or, it may be a String. If it is a string, that is equivalent to the hash:
3362
+ * { :value => <string value>, :format => 0 }
3363
+ *
3364
+ * PostgreSQL bind parameters are represented as $1, $2, $3, etc.,
3365
+ * inside the SQL query. The 0th element of the +params+ array is bound
3366
+ * to $1, the 1st element is bound to $2, etc. +nil+ is treated as +NULL+.
3367
+ *
3368
+ * The optional +result_format+ should be 0 for text results, 1
3369
+ * for binary.
3370
+ *
3371
+ * +type_map+ can be a PG::TypeMap derivation (such as PG::BasicTypeMapForQueries).
3372
+ * This will type cast the params from various Ruby types before transmission
3373
+ * based on the encoders defined by the type map. When a type encoder is used
3374
+ * the format and oid of a given bind parameter are retrieved from the encoder
3375
+ * instead out of the hash form described above.
3376
+ *
3377
+ * If the optional code block is given, it will be passed <i>result</i> as an argument,
3378
+ * and the PG::Result object will automatically be cleared when the block terminates.
3379
+ * In this instance, <code>conn.exec_prepared</code> returns the value of the block.
3380
+ *
3381
+ * See also corresponding {libpq function}[https://www.postgresql.org/docs/current/libpq-exec.html#LIBPQ-PQEXECPREPARED].
3382
+ */
3383
+ static VALUE
3384
+ pgconn_async_exec_prepared(int argc, VALUE *argv, VALUE self)
3385
+ {
3386
+ VALUE rb_pgresult = Qnil;
3387
+
3388
+ pgconn_discard_results( self );
3389
+ pgconn_send_query_prepared( argc, argv, self );
3390
+ rb_pgresult = pgconn_async_get_last_result( self );
3391
+
3392
+ if ( rb_block_given_p() ) {
3393
+ return rb_ensure( rb_yield, rb_pgresult, pg_result_clear, rb_pgresult );
3394
+ }
3395
+ return rb_pgresult;
3396
+ }
3397
+
3398
+
3399
+ /*
3400
+ * call-seq:
3401
+ * conn.describe_portal( portal_name ) -> PG::Result
3402
+ *
3403
+ * Retrieve information about the portal _portal_name_.
3404
+ *
3405
+ * See also corresponding {libpq function}[https://www.postgresql.org/docs/current/libpq-exec.html#LIBPQ-PQDESCRIBEPORTAL].
3406
+ */
3407
+ static VALUE
3408
+ pgconn_async_describe_portal(VALUE self, VALUE portal)
3409
+ {
3410
+ VALUE rb_pgresult = Qnil;
3411
+
3412
+ pgconn_discard_results( self );
3413
+ pgconn_send_describe_portal( self, portal );
3414
+ rb_pgresult = pgconn_async_get_last_result( self );
3415
+
3416
+ if ( rb_block_given_p() ) {
3417
+ return rb_ensure( rb_yield, rb_pgresult, pg_result_clear, rb_pgresult );
3418
+ }
3419
+ return rb_pgresult;
3420
+ }
3421
+
3422
+
3423
+ /*
3424
+ * call-seq:
3425
+ * conn.describe_prepared( statement_name ) -> PG::Result
3426
+ *
3427
+ * Retrieve information about the prepared statement _statement_name_.
3428
+ *
3429
+ * See also corresponding {libpq function}[https://www.postgresql.org/docs/current/libpq-exec.html#LIBPQ-PQDESCRIBEPREPARED].
3430
+ */
3431
+ static VALUE
3432
+ pgconn_async_describe_prepared(VALUE self, VALUE stmt_name)
3433
+ {
3434
+ VALUE rb_pgresult = Qnil;
3435
+
3436
+ pgconn_discard_results( self );
3437
+ pgconn_send_describe_prepared( self, stmt_name );
3438
+ rb_pgresult = pgconn_async_get_last_result( self );
3439
+
3440
+ if ( rb_block_given_p() ) {
3441
+ return rb_ensure( rb_yield, rb_pgresult, pg_result_clear, rb_pgresult );
3442
+ }
3443
+ return rb_pgresult;
3444
+ }
3445
+
3446
+
3447
+ #ifdef HAVE_PQSSLATTRIBUTE
3203
3448
  /*
3204
3449
  * call-seq:
3205
3450
  * conn.ssl_in_use? -> Boolean
3206
3451
  *
3207
- * Returns +true+ if the connection uses SSL, +false+ if not.
3452
+ * Returns +true+ if the connection uses SSL/TLS, +false+ if not.
3208
3453
  *
3454
+ * Available since PostgreSQL-9.5
3209
3455
  */
3210
3456
  static VALUE
3211
3457
  pgconn_ssl_in_use(VALUE self)
@@ -3237,7 +3483,9 @@ pgconn_ssl_in_use(VALUE self)
3237
3483
  * 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".
3238
3484
  *
3239
3485
  *
3240
- * See also #ssl_attribute_names and http://www.postgresql.org/docs/current/interactive/libpq-status.html#LIBPQ-PQSSLATTRIBUTE
3486
+ * See also #ssl_attribute_names and the {corresponding libpq function}[https://www.postgresql.org/docs/current/libpq-status.html#LIBPQ-PQSSLATTRIBUTE].
3487
+ *
3488
+ * Available since PostgreSQL-9.5
3241
3489
  */
3242
3490
  static VALUE
3243
3491
  pgconn_ssl_attribute(VALUE self, VALUE attribute_name)
@@ -3256,6 +3504,7 @@ pgconn_ssl_attribute(VALUE self, VALUE attribute_name)
3256
3504
  *
3257
3505
  * See also #ssl_attribute
3258
3506
  *
3507
+ * Available since PostgreSQL-9.5
3259
3508
  */
3260
3509
  static VALUE
3261
3510
  pgconn_ssl_attribute_names(VALUE self)
@@ -3274,6 +3523,122 @@ pgconn_ssl_attribute_names(VALUE self)
3274
3523
  #endif
3275
3524
 
3276
3525
 
3526
+ #ifdef HAVE_PQENTERPIPELINEMODE
3527
+ /*
3528
+ * call-seq:
3529
+ * conn.pipeline_status -> Integer
3530
+ *
3531
+ * Returns the current pipeline mode status of the libpq connection.
3532
+ *
3533
+ * PQpipelineStatus can return one of the following values:
3534
+ *
3535
+ * * PQ_PIPELINE_ON - The libpq connection is in pipeline mode.
3536
+ * * PQ_PIPELINE_OFF - The libpq connection is not in pipeline mode.
3537
+ * * PQ_PIPELINE_ABORTED - The libpq connection is in pipeline mode and an error occurred while processing the current pipeline.
3538
+ * The aborted flag is cleared when PQgetResult returns a result of type PGRES_PIPELINE_SYNC.
3539
+ *
3540
+ * Available since PostgreSQL-14
3541
+ */
3542
+ static VALUE
3543
+ pgconn_pipeline_status(VALUE self)
3544
+ {
3545
+ int res = PQpipelineStatus(pg_get_pgconn(self));
3546
+ return INT2FIX(res);
3547
+ }
3548
+
3549
+
3550
+ /*
3551
+ * call-seq:
3552
+ * conn.enter_pipeline_mode -> nil
3553
+ *
3554
+ * Causes a connection to enter pipeline mode if it is currently idle or already in pipeline mode.
3555
+ *
3556
+ * 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.
3557
+ * This function does not actually send anything to the server, it just changes the libpq connection state.
3558
+ *
3559
+ * Available since PostgreSQL-14
3560
+ */
3561
+ static VALUE
3562
+ pgconn_enter_pipeline_mode(VALUE self)
3563
+ {
3564
+ PGconn *conn = pg_get_pgconn(self);
3565
+ int res = PQenterPipelineMode(conn);
3566
+ if( res != 1 )
3567
+ pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(conn));
3568
+
3569
+ return Qnil;
3570
+ }
3571
+
3572
+ /*
3573
+ * call-seq:
3574
+ * conn.exit_pipeline_mode -> nil
3575
+ *
3576
+ * Causes a connection to exit pipeline mode if it is currently in pipeline mode with an empty queue and no pending results.
3577
+ *
3578
+ * Takes no action if not in pipeline mode.
3579
+ * 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.
3580
+ *
3581
+ * Available since PostgreSQL-14
3582
+ */
3583
+ static VALUE
3584
+ pgconn_exit_pipeline_mode(VALUE self)
3585
+ {
3586
+ PGconn *conn = pg_get_pgconn(self);
3587
+ int res = PQexitPipelineMode(conn);
3588
+ if( res != 1 )
3589
+ pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(conn));
3590
+
3591
+ return Qnil;
3592
+ }
3593
+
3594
+
3595
+ /*
3596
+ * call-seq:
3597
+ * conn.pipeline_sync -> nil
3598
+ *
3599
+ * Marks a synchronization point in a pipeline by sending a sync message and flushing the send buffer.
3600
+ * This serves as the delimiter of an implicit transaction and an error recovery point; see Section 34.5.1.3 of the PostgreSQL documentation.
3601
+ *
3602
+ * Raises PG::Error if the connection is not in pipeline mode or sending a sync message failed.
3603
+ *
3604
+ * Available since PostgreSQL-14
3605
+ */
3606
+ static VALUE
3607
+ pgconn_pipeline_sync(VALUE self)
3608
+ {
3609
+ PGconn *conn = pg_get_pgconn(self);
3610
+ int res = PQpipelineSync(conn);
3611
+ if( res != 1 )
3612
+ pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(conn));
3613
+
3614
+ return Qnil;
3615
+ }
3616
+
3617
+ /*
3618
+ * call-seq:
3619
+ * conn.pipeline_sync -> nil
3620
+ *
3621
+ * Sends a request for the server to flush its output buffer.
3622
+ *
3623
+ * 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.
3624
+ * This function is useful to cause the server to flush its output buffer in pipeline mode without establishing a synchronization point.
3625
+ * Note that the request is not itself flushed to the server automatically; use Connection#flush if necessary.
3626
+ *
3627
+ * Available since PostgreSQL-14
3628
+ */
3629
+ static VALUE
3630
+ pgconn_send_flush_request(VALUE self)
3631
+ {
3632
+ PGconn *conn = pg_get_pgconn(self);
3633
+ int res = PQsendFlushRequest(conn);
3634
+ if( res != 1 )
3635
+ pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(conn));
3636
+
3637
+ return Qnil;
3638
+ }
3639
+
3640
+ #endif
3641
+
3277
3642
  /**************************************************************************
3278
3643
  * LARGE OBJECT SUPPORT
3279
3644
  **************************************************************************/
@@ -3300,7 +3665,7 @@ pgconn_locreat(int argc, VALUE *argv, VALUE self)
3300
3665
 
3301
3666
  lo_oid = lo_creat(conn, mode);
3302
3667
  if (lo_oid == 0)
3303
- rb_raise(rb_ePGerror, "lo_creat failed");
3668
+ pg_raise_conn_error( rb_ePGerror, self, "lo_creat failed");
3304
3669
 
3305
3670
  return UINT2NUM(lo_oid);
3306
3671
  }
@@ -3321,7 +3686,7 @@ pgconn_locreate(VALUE self, VALUE in_lo_oid)
3321
3686
 
3322
3687
  ret = lo_create(conn, lo_oid);
3323
3688
  if (ret == InvalidOid)
3324
- rb_raise(rb_ePGerror, "lo_create failed");
3689
+ pg_raise_conn_error( rb_ePGerror, self, "lo_create failed");
3325
3690
 
3326
3691
  return UINT2NUM(ret);
3327
3692
  }
@@ -3345,7 +3710,7 @@ pgconn_loimport(VALUE self, VALUE filename)
3345
3710
 
3346
3711
  lo_oid = lo_import(conn, StringValueCStr(filename));
3347
3712
  if (lo_oid == 0) {
3348
- rb_raise(rb_ePGerror, "%s", PQerrorMessage(conn));
3713
+ pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(conn));
3349
3714
  }
3350
3715
  return UINT2NUM(lo_oid);
3351
3716
  }
@@ -3366,7 +3731,7 @@ pgconn_loexport(VALUE self, VALUE lo_oid, VALUE filename)
3366
3731
  oid = NUM2UINT(lo_oid);
3367
3732
 
3368
3733
  if (lo_export(conn, oid, StringValueCStr(filename)) < 0) {
3369
- rb_raise(rb_ePGerror, "%s", PQerrorMessage(conn));
3734
+ pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(conn));
3370
3735
  }
3371
3736
  return Qnil;
3372
3737
  }
@@ -3397,7 +3762,7 @@ pgconn_loopen(int argc, VALUE *argv, VALUE self)
3397
3762
  mode = NUM2INT(nmode);
3398
3763
 
3399
3764
  if((fd = lo_open(conn, lo_oid, mode)) < 0) {
3400
- rb_raise(rb_ePGerror, "can't open large object: %s", PQerrorMessage(conn));
3765
+ pg_raise_conn_error( rb_ePGerror, self, "can't open large object: %s", PQerrorMessage(conn));
3401
3766
  }
3402
3767
  return INT2FIX(fd);
3403
3768
  }
@@ -3419,11 +3784,11 @@ pgconn_lowrite(VALUE self, VALUE in_lo_desc, VALUE buffer)
3419
3784
  Check_Type(buffer, T_STRING);
3420
3785
 
3421
3786
  if( RSTRING_LEN(buffer) < 0) {
3422
- rb_raise(rb_ePGerror, "write buffer zero string");
3787
+ pg_raise_conn_error( rb_ePGerror, self, "write buffer zero string");
3423
3788
  }
3424
3789
  if((n = lo_write(conn, fd, StringValuePtr(buffer),
3425
3790
  RSTRING_LEN(buffer))) < 0) {
3426
- rb_raise(rb_ePGerror, "lo_write failed: %s", PQerrorMessage(conn));
3791
+ pg_raise_conn_error( rb_ePGerror, self, "lo_write failed: %s", PQerrorMessage(conn));
3427
3792
  }
3428
3793
 
3429
3794
  return INT2FIX(n);
@@ -3446,23 +3811,19 @@ pgconn_loread(VALUE self, VALUE in_lo_desc, VALUE in_len)
3446
3811
  VALUE str;
3447
3812
  char *buffer;
3448
3813
 
3449
- buffer = ALLOC_N(char, len);
3450
- if(buffer == NULL)
3451
- rb_raise(rb_eNoMemError, "ALLOC failed!");
3452
-
3453
- if (len < 0){
3454
- rb_raise(rb_ePGerror,"nagative length %d given", len);
3455
- }
3814
+ if (len < 0)
3815
+ pg_raise_conn_error( rb_ePGerror, self, "negative length %d given", len);
3456
3816
 
3817
+ buffer = ALLOC_N(char, len);
3457
3818
  if((ret = lo_read(conn, lo_desc, buffer, len)) < 0)
3458
- rb_raise(rb_ePGerror, "lo_read failed");
3819
+ pg_raise_conn_error( rb_ePGerror, self, "lo_read failed");
3459
3820
 
3460
3821
  if(ret == 0) {
3461
3822
  xfree(buffer);
3462
3823
  return Qnil;
3463
3824
  }
3464
3825
 
3465
- str = rb_tainted_str_new(buffer, ret);
3826
+ str = rb_str_new(buffer, ret);
3466
3827
  xfree(buffer);
3467
3828
 
3468
3829
  return str;
@@ -3485,7 +3846,7 @@ pgconn_lolseek(VALUE self, VALUE in_lo_desc, VALUE offset, VALUE whence)
3485
3846
  int ret;
3486
3847
 
3487
3848
  if((ret = lo_lseek(conn, lo_desc, NUM2INT(offset), NUM2INT(whence))) < 0) {
3488
- rb_raise(rb_ePGerror, "lo_lseek failed");
3849
+ pg_raise_conn_error( rb_ePGerror, self, "lo_lseek failed");
3489
3850
  }
3490
3851
 
3491
3852
  return INT2FIX(ret);
@@ -3505,7 +3866,7 @@ pgconn_lotell(VALUE self, VALUE in_lo_desc)
3505
3866
  int lo_desc = NUM2INT(in_lo_desc);
3506
3867
 
3507
3868
  if((position = lo_tell(conn, lo_desc)) < 0)
3508
- rb_raise(rb_ePGerror,"lo_tell failed");
3869
+ pg_raise_conn_error( rb_ePGerror, self, "lo_tell failed");
3509
3870
 
3510
3871
  return INT2FIX(position);
3511
3872
  }
@@ -3524,7 +3885,7 @@ pgconn_lotruncate(VALUE self, VALUE in_lo_desc, VALUE in_len)
3524
3885
  size_t len = NUM2INT(in_len);
3525
3886
 
3526
3887
  if(lo_truncate(conn,lo_desc,len) < 0)
3527
- rb_raise(rb_ePGerror,"lo_truncate failed");
3888
+ pg_raise_conn_error( rb_ePGerror, self, "lo_truncate failed");
3528
3889
 
3529
3890
  return Qnil;
3530
3891
  }
@@ -3542,7 +3903,7 @@ pgconn_loclose(VALUE self, VALUE in_lo_desc)
3542
3903
  int lo_desc = NUM2INT(in_lo_desc);
3543
3904
 
3544
3905
  if(lo_close(conn,lo_desc) < 0)
3545
- rb_raise(rb_ePGerror,"lo_close failed");
3906
+ pg_raise_conn_error( rb_ePGerror, self, "lo_close failed");
3546
3907
 
3547
3908
  return Qnil;
3548
3909
  }
@@ -3560,20 +3921,21 @@ pgconn_lounlink(VALUE self, VALUE in_oid)
3560
3921
  Oid oid = NUM2UINT(in_oid);
3561
3922
 
3562
3923
  if(lo_unlink(conn,oid) < 0)
3563
- rb_raise(rb_ePGerror,"lo_unlink failed");
3924
+ pg_raise_conn_error( rb_ePGerror, self, "lo_unlink failed");
3564
3925
 
3565
3926
  return Qnil;
3566
3927
  }
3567
3928
 
3568
3929
 
3569
- #ifdef M17N_SUPPORTED
3570
-
3571
- void
3930
+ static void
3572
3931
  pgconn_set_internal_encoding_index( VALUE self )
3573
3932
  {
3574
- PGconn *conn = pg_get_pgconn(self);
3575
- rb_encoding *enc = pg_conn_enc_get( conn );
3576
- PG_ENCODING_SET_NOCHECK( self, rb_enc_to_index(enc));
3933
+ int enc_idx;
3934
+ t_pg_connection *this = pg_get_connection_safe( self );
3935
+ rb_encoding *enc = pg_conn_enc_get( this->pgconn );
3936
+ enc_idx = rb_enc_to_index(enc);
3937
+ if( enc_idx >= (1<<(PG_ENC_IDX_BITS-1)) ) rb_raise(rb_eArgError, "unsupported encoding index %d", enc_idx);
3938
+ this->enc_idx = enc_idx;
3577
3939
  }
3578
3940
 
3579
3941
  /*
@@ -3616,13 +3978,12 @@ static VALUE pgconn_external_encoding(VALUE self);
3616
3978
  static VALUE
3617
3979
  pgconn_internal_encoding_set(VALUE self, VALUE enc)
3618
3980
  {
3619
- VALUE enc_inspect;
3620
3981
  if (NIL_P(enc)) {
3621
- pgconn_set_client_encoding( self, rb_usascii_str_new_cstr("SQL_ASCII") );
3982
+ pgconn_sync_set_client_encoding( self, rb_usascii_str_new_cstr("SQL_ASCII") );
3622
3983
  return enc;
3623
3984
  }
3624
3985
  else if ( TYPE(enc) == T_STRING && strcasecmp("JOHAB", StringValueCStr(enc)) == 0 ) {
3625
- pgconn_set_client_encoding(self, rb_usascii_str_new_cstr("JOHAB"));
3986
+ pgconn_sync_set_client_encoding(self, rb_usascii_str_new_cstr("JOHAB"));
3626
3987
  return enc;
3627
3988
  }
3628
3989
  else {
@@ -3637,11 +3998,6 @@ pgconn_internal_encoding_set(VALUE self, VALUE enc)
3637
3998
  pgconn_set_internal_encoding_index( self );
3638
3999
  return enc;
3639
4000
  }
3640
-
3641
- enc_inspect = rb_inspect(enc);
3642
- rb_raise( rb_ePGerror, "unknown encoding: %s", StringValueCStr(enc_inspect) );
3643
-
3644
- return Qnil;
3645
4001
  }
3646
4002
 
3647
4003
 
@@ -3660,42 +4016,55 @@ pgconn_external_encoding(VALUE self)
3660
4016
  rb_encoding *enc = NULL;
3661
4017
  const char *pg_encname = NULL;
3662
4018
 
3663
- /* Use cached value if found */
3664
- if ( RTEST(this->external_encoding) ) return this->external_encoding;
3665
-
3666
4019
  pg_encname = PQparameterStatus( this->pgconn, "server_encoding" );
3667
4020
  enc = pg_get_pg_encname_as_rb_encoding( pg_encname );
3668
- this->external_encoding = rb_enc_from_encoding( enc );
3669
-
3670
- return this->external_encoding;
4021
+ return rb_enc_from_encoding( enc );
3671
4022
  }
3672
4023
 
4024
+ /*
4025
+ * call-seq:
4026
+ * conn.set_client_encoding( encoding )
4027
+ *
4028
+ * Sets the client encoding to the _encoding_ String.
4029
+ */
4030
+ static VALUE
4031
+ pgconn_async_set_client_encoding(VALUE self, VALUE encname)
4032
+ {
4033
+ VALUE query_format, query;
4034
+
4035
+ Check_Type(encname, T_STRING);
4036
+ query_format = rb_str_new_cstr("set client_encoding to '%s'");
4037
+ query = rb_funcall(query_format, rb_intern("%"), 1, encname);
4038
+
4039
+ pgconn_async_exec(1, &query, self);
4040
+ pgconn_set_internal_encoding_index( self );
4041
+
4042
+ return Qnil;
4043
+ }
3673
4044
 
3674
4045
  static VALUE
3675
4046
  pgconn_set_client_encoding_async1( VALUE args )
3676
4047
  {
3677
4048
  VALUE self = ((VALUE*)args)[0];
3678
4049
  VALUE encname = ((VALUE*)args)[1];
3679
- VALUE query_format = rb_str_new_cstr("set client_encoding to '%s'");
3680
- VALUE query = rb_funcall(query_format, rb_intern("%"), 1, encname);
3681
-
3682
- pgconn_async_exec(1, &query, self);
4050
+ pgconn_async_set_client_encoding(self, encname);
3683
4051
  return 0;
3684
4052
  }
3685
4053
 
3686
4054
 
3687
4055
  static VALUE
3688
- pgconn_set_client_encoding_async2( VALUE arg )
4056
+ pgconn_set_client_encoding_async2( VALUE arg, VALUE ex )
3689
4057
  {
3690
4058
  UNUSED(arg);
4059
+ UNUSED(ex);
3691
4060
  return 1;
3692
4061
  }
3693
4062
 
3694
4063
 
3695
4064
  static VALUE
3696
- pgconn_set_client_encoding_async( VALUE self, const char *encname )
4065
+ pgconn_set_client_encoding_async( VALUE self, VALUE encname )
3697
4066
  {
3698
- VALUE args[] = { self, rb_str_new_cstr(encname) };
4067
+ VALUE args[] = { self, encname };
3699
4068
  return rb_rescue(pgconn_set_client_encoding_async1, (VALUE)&args, pgconn_set_client_encoding_async2, Qnil);
3700
4069
  }
3701
4070
 
@@ -3717,10 +4086,9 @@ pgconn_set_default_encoding( VALUE self )
3717
4086
 
3718
4087
  if (( enc = rb_default_internal_encoding() )) {
3719
4088
  encname = pg_get_rb_encoding_as_pg_encoding( enc );
3720
- if ( pgconn_set_client_encoding_async(self, encname) != 0 )
3721
- rb_warn( "Failed to set the default_internal encoding to %s: '%s'",
4089
+ if ( pgconn_set_client_encoding_async(self, rb_str_new_cstr(encname)) != 0 )
4090
+ rb_warning( "Failed to set the default_internal encoding to %s: '%s'",
3722
4091
  encname, PQerrorMessage(conn) );
3723
- pgconn_set_internal_encoding_index( self );
3724
4092
  return rb_enc_from_encoding( enc );
3725
4093
  } else {
3726
4094
  pgconn_set_internal_encoding_index( self );
@@ -3729,8 +4097,6 @@ pgconn_set_default_encoding( VALUE self )
3729
4097
  }
3730
4098
 
3731
4099
 
3732
- #endif /* M17N_SUPPORTED */
3733
-
3734
4100
  /*
3735
4101
  * call-seq:
3736
4102
  * res.type_map_for_queries = typemap
@@ -3744,12 +4110,12 @@ static VALUE
3744
4110
  pgconn_type_map_for_queries_set(VALUE self, VALUE typemap)
3745
4111
  {
3746
4112
  t_pg_connection *this = pg_get_connection( self );
4113
+ t_typemap *tm;
4114
+ UNUSED(tm);
4115
+
4116
+ /* Check type of method param */
4117
+ TypedData_Get_Struct(typemap, t_typemap, &pg_typemap_type, tm);
3747
4118
 
3748
- if ( !rb_obj_is_kind_of(typemap, rb_cTypeMap) ) {
3749
- rb_raise( rb_eTypeError, "wrong argument type %s (expected kind of PG::TypeMap)",
3750
- rb_obj_classname( typemap ) );
3751
- }
3752
- Check_Type(typemap, T_DATA);
3753
4119
  this->type_map_for_queries = typemap;
3754
4120
 
3755
4121
  return typemap;
@@ -3784,12 +4150,10 @@ static VALUE
3784
4150
  pgconn_type_map_for_results_set(VALUE self, VALUE typemap)
3785
4151
  {
3786
4152
  t_pg_connection *this = pg_get_connection( self );
4153
+ t_typemap *tm;
4154
+ UNUSED(tm);
3787
4155
 
3788
- if ( !rb_obj_is_kind_of(typemap, rb_cTypeMap) ) {
3789
- rb_raise( rb_eTypeError, "wrong argument type %s (expected kind of PG::TypeMap)",
3790
- rb_obj_classname( typemap ) );
3791
- }
3792
- Check_Type(typemap, T_DATA);
4156
+ TypedData_Get_Struct(typemap, t_typemap, &pg_typemap_type, tm);
3793
4157
  this->type_map_for_results = typemap;
3794
4158
 
3795
4159
  return typemap;
@@ -3824,20 +4188,19 @@ pgconn_type_map_for_results_get(VALUE self)
3824
4188
  *
3825
4189
  */
3826
4190
  static VALUE
3827
- pgconn_encoder_for_put_copy_data_set(VALUE self, VALUE typemap)
4191
+ pgconn_encoder_for_put_copy_data_set(VALUE self, VALUE encoder)
3828
4192
  {
3829
4193
  t_pg_connection *this = pg_get_connection( self );
3830
4194
 
3831
- if( typemap != Qnil ){
3832
- if ( !rb_obj_is_kind_of(typemap, rb_cPG_Coder) ) {
3833
- rb_raise( rb_eTypeError, "wrong argument type %s (expected kind of PG::Coder)",
3834
- rb_obj_classname( typemap ) );
3835
- }
3836
- Check_Type(typemap, T_DATA);
4195
+ if( encoder != Qnil ){
4196
+ t_pg_coder *co;
4197
+ UNUSED(co);
4198
+ /* Check argument type */
4199
+ TypedData_Get_Struct(encoder, t_pg_coder, &pg_coder_type, co);
3837
4200
  }
3838
- this->encoder_for_put_copy_data = typemap;
4201
+ this->encoder_for_put_copy_data = encoder;
3839
4202
 
3840
- return typemap;
4203
+ return encoder;
3841
4204
  }
3842
4205
 
3843
4206
  /*
@@ -3873,20 +4236,19 @@ pgconn_encoder_for_put_copy_data_get(VALUE self)
3873
4236
  *
3874
4237
  */
3875
4238
  static VALUE
3876
- pgconn_decoder_for_get_copy_data_set(VALUE self, VALUE typemap)
4239
+ pgconn_decoder_for_get_copy_data_set(VALUE self, VALUE decoder)
3877
4240
  {
3878
4241
  t_pg_connection *this = pg_get_connection( self );
3879
4242
 
3880
- if( typemap != Qnil ){
3881
- if ( !rb_obj_is_kind_of(typemap, rb_cPG_Coder) ) {
3882
- rb_raise( rb_eTypeError, "wrong argument type %s (expected kind of PG::Coder)",
3883
- rb_obj_classname( typemap ) );
3884
- }
3885
- Check_Type(typemap, T_DATA);
4243
+ if( decoder != Qnil ){
4244
+ t_pg_coder *co;
4245
+ UNUSED(co);
4246
+ /* Check argument type */
4247
+ TypedData_Get_Struct(decoder, t_pg_coder, &pg_coder_type, co);
3886
4248
  }
3887
- this->decoder_for_get_copy_data = typemap;
4249
+ this->decoder_for_get_copy_data = decoder;
3888
4250
 
3889
- return typemap;
4251
+ return decoder;
3890
4252
  }
3891
4253
 
3892
4254
  /*
@@ -3909,28 +4271,82 @@ pgconn_decoder_for_get_copy_data_get(VALUE self)
3909
4271
  return this->decoder_for_get_copy_data;
3910
4272
  }
3911
4273
 
4274
+ /*
4275
+ * call-seq:
4276
+ * conn.field_name_type = Symbol
4277
+ *
4278
+ * Set default type of field names of results retrieved by this connection.
4279
+ * It can be set to one of:
4280
+ * * +:string+ to use String based field names
4281
+ * * +:symbol+ to use Symbol based field names
4282
+ *
4283
+ * The default is +:string+ .
4284
+ *
4285
+ * Settings the type of field names affects only future results.
4286
+ *
4287
+ * See further description at PG::Result#field_name_type=
4288
+ *
4289
+ */
4290
+ static VALUE
4291
+ pgconn_field_name_type_set(VALUE self, VALUE sym)
4292
+ {
4293
+ t_pg_connection *this = pg_get_connection( self );
4294
+
4295
+ this->flags &= ~PG_RESULT_FIELD_NAMES_MASK;
4296
+ if( sym == sym_symbol ) this->flags |= PG_RESULT_FIELD_NAMES_SYMBOL;
4297
+ else if ( sym == sym_static_symbol ) this->flags |= PG_RESULT_FIELD_NAMES_STATIC_SYMBOL;
4298
+ else if ( sym == sym_string );
4299
+ else rb_raise(rb_eArgError, "invalid argument %+"PRIsVALUE, sym);
4300
+
4301
+ return sym;
4302
+ }
4303
+
4304
+ /*
4305
+ * call-seq:
4306
+ * conn.field_name_type -> Symbol
4307
+ *
4308
+ * Get type of field names.
4309
+ *
4310
+ * See description at #field_name_type=
4311
+ */
4312
+ static VALUE
4313
+ pgconn_field_name_type_get(VALUE self)
4314
+ {
4315
+ t_pg_connection *this = pg_get_connection( self );
4316
+
4317
+ if( this->flags & PG_RESULT_FIELD_NAMES_SYMBOL ){
4318
+ return sym_symbol;
4319
+ } else if( this->flags & PG_RESULT_FIELD_NAMES_STATIC_SYMBOL ){
4320
+ return sym_static_symbol;
4321
+ } else {
4322
+ return sym_string;
4323
+ }
4324
+ }
4325
+
3912
4326
 
3913
4327
  /*
3914
4328
  * Document-class: PG::Connection
3915
4329
  */
3916
4330
  void
3917
- init_pg_connection()
4331
+ init_pg_connection(void)
3918
4332
  {
3919
4333
  s_id_encode = rb_intern("encode");
4334
+ s_id_autoclose_set = rb_intern("autoclose=");
3920
4335
  sym_type = ID2SYM(rb_intern("type"));
3921
4336
  sym_format = ID2SYM(rb_intern("format"));
3922
4337
  sym_value = ID2SYM(rb_intern("value"));
4338
+ sym_string = ID2SYM(rb_intern("string"));
4339
+ sym_symbol = ID2SYM(rb_intern("symbol"));
4340
+ sym_static_symbol = ID2SYM(rb_intern("static_symbol"));
3923
4341
 
3924
4342
  rb_cPGconn = rb_define_class_under( rb_mPG, "Connection", rb_cObject );
4343
+ /* Help rdoc to known the Constants module */
4344
+ /* rb_mPGconstants = rb_define_module_under( rb_mPG, "Constants" ); */
3925
4345
  rb_include_module(rb_cPGconn, rb_mPGconstants);
3926
4346
 
3927
4347
  /****** PG::Connection CLASS METHODS ******/
3928
4348
  rb_define_alloc_func( rb_cPGconn, pgconn_s_allocate );
3929
4349
 
3930
- SINGLETON_ALIAS(rb_cPGconn, "connect", "new");
3931
- SINGLETON_ALIAS(rb_cPGconn, "open", "new");
3932
- SINGLETON_ALIAS(rb_cPGconn, "setdb", "new");
3933
- SINGLETON_ALIAS(rb_cPGconn, "setdblogin", "new");
3934
4350
  rb_define_singleton_method(rb_cPGconn, "escape_string", pgconn_s_escape, 1);
3935
4351
  SINGLETON_ALIAS(rb_cPGconn, "escape", "escape_string");
3936
4352
  rb_define_singleton_method(rb_cPGconn, "escape_bytea", pgconn_s_escape_bytea, 1);
@@ -3939,16 +4355,15 @@ init_pg_connection()
3939
4355
  rb_define_singleton_method(rb_cPGconn, "quote_ident", pgconn_s_quote_ident, 1);
3940
4356
  rb_define_singleton_method(rb_cPGconn, "connect_start", pgconn_s_connect_start, -1);
3941
4357
  rb_define_singleton_method(rb_cPGconn, "conndefaults", pgconn_s_conndefaults, 0);
3942
- #ifdef HAVE_PQPING
3943
- rb_define_singleton_method(rb_cPGconn, "ping", pgconn_s_ping, -1);
3944
- #endif
4358
+ rb_define_singleton_method(rb_cPGconn, "conninfo_parse", pgconn_s_conninfo_parse, 1);
4359
+ rb_define_singleton_method(rb_cPGconn, "sync_ping", pgconn_s_sync_ping, -1);
4360
+ rb_define_singleton_method(rb_cPGconn, "sync_connect", pgconn_s_sync_connect, -1);
3945
4361
 
3946
4362
  /****** PG::Connection INSTANCE METHODS: Connection Control ******/
3947
- rb_define_method(rb_cPGconn, "initialize", pgconn_init, -1);
3948
4363
  rb_define_method(rb_cPGconn, "connect_poll", pgconn_connect_poll, 0);
3949
4364
  rb_define_method(rb_cPGconn, "finish", pgconn_finish, 0);
3950
4365
  rb_define_method(rb_cPGconn, "finished?", pgconn_finished_p, 0);
3951
- rb_define_method(rb_cPGconn, "reset", pgconn_reset, 0);
4366
+ rb_define_method(rb_cPGconn, "sync_reset", pgconn_sync_reset, 0);
3952
4367
  rb_define_method(rb_cPGconn, "reset_start", pgconn_reset_start, 0);
3953
4368
  rb_define_method(rb_cPGconn, "reset_poll", pgconn_reset_poll, 0);
3954
4369
  rb_define_alias(rb_cPGconn, "close", "finish");
@@ -3958,11 +4373,12 @@ init_pg_connection()
3958
4373
  rb_define_method(rb_cPGconn, "user", pgconn_user, 0);
3959
4374
  rb_define_method(rb_cPGconn, "pass", pgconn_pass, 0);
3960
4375
  rb_define_method(rb_cPGconn, "host", pgconn_host, 0);
4376
+ #if defined(HAVE_PQRESULTMEMORYSIZE)
4377
+ rb_define_method(rb_cPGconn, "hostaddr", pgconn_hostaddr, 0);
4378
+ #endif
3961
4379
  rb_define_method(rb_cPGconn, "port", pgconn_port, 0);
3962
4380
  rb_define_method(rb_cPGconn, "tty", pgconn_tty, 0);
3963
- #ifdef HAVE_PQCONNINFO
3964
4381
  rb_define_method(rb_cPGconn, "conninfo", pgconn_conninfo, 0);
3965
- #endif
3966
4382
  rb_define_method(rb_cPGconn, "options", pgconn_options, 0);
3967
4383
  rb_define_method(rb_cPGconn, "status", pgconn_status, 0);
3968
4384
  rb_define_method(rb_cPGconn, "transaction_status", pgconn_transaction_status, 0);
@@ -3971,64 +4387,78 @@ init_pg_connection()
3971
4387
  rb_define_method(rb_cPGconn, "server_version", pgconn_server_version, 0);
3972
4388
  rb_define_method(rb_cPGconn, "error_message", pgconn_error_message, 0);
3973
4389
  rb_define_method(rb_cPGconn, "socket", pgconn_socket, 0);
3974
- #if !defined(_WIN32) || defined(HAVE_RB_W32_WRAP_IO_HANDLE)
3975
4390
  rb_define_method(rb_cPGconn, "socket_io", pgconn_socket_io, 0);
3976
- #endif
3977
4391
  rb_define_method(rb_cPGconn, "backend_pid", pgconn_backend_pid, 0);
4392
+ rb_define_method(rb_cPGconn, "backend_key", pgconn_backend_key, 0);
3978
4393
  rb_define_method(rb_cPGconn, "connection_needs_password", pgconn_connection_needs_password, 0);
3979
4394
  rb_define_method(rb_cPGconn, "connection_used_password", pgconn_connection_used_password, 0);
3980
4395
  /* rb_define_method(rb_cPGconn, "getssl", pgconn_getssl, 0); */
3981
4396
 
3982
4397
  /****** PG::Connection INSTANCE METHODS: Command Execution ******/
3983
- rb_define_method(rb_cPGconn, "exec", pgconn_exec, -1);
3984
- rb_define_alias(rb_cPGconn, "query", "exec");
3985
- rb_define_method(rb_cPGconn, "exec_params", pgconn_exec_params, -1);
3986
- rb_define_method(rb_cPGconn, "prepare", pgconn_prepare, -1);
3987
- rb_define_method(rb_cPGconn, "exec_prepared", pgconn_exec_prepared, -1);
3988
- rb_define_method(rb_cPGconn, "describe_prepared", pgconn_describe_prepared, 1);
3989
- rb_define_method(rb_cPGconn, "describe_portal", pgconn_describe_portal, 1);
4398
+ rb_define_method(rb_cPGconn, "sync_exec", pgconn_sync_exec, -1);
4399
+ rb_define_method(rb_cPGconn, "sync_exec_params", pgconn_sync_exec_params, -1);
4400
+ rb_define_method(rb_cPGconn, "sync_prepare", pgconn_sync_prepare, -1);
4401
+ rb_define_method(rb_cPGconn, "sync_exec_prepared", pgconn_sync_exec_prepared, -1);
4402
+ rb_define_method(rb_cPGconn, "sync_describe_prepared", pgconn_sync_describe_prepared, 1);
4403
+ rb_define_method(rb_cPGconn, "sync_describe_portal", pgconn_sync_describe_portal, 1);
4404
+
4405
+ rb_define_method(rb_cPGconn, "exec", pgconn_async_exec, -1);
4406
+ rb_define_method(rb_cPGconn, "exec_params", pgconn_async_exec_params, -1);
4407
+ rb_define_method(rb_cPGconn, "prepare", pgconn_async_prepare, -1);
4408
+ rb_define_method(rb_cPGconn, "exec_prepared", pgconn_async_exec_prepared, -1);
4409
+ rb_define_method(rb_cPGconn, "describe_prepared", pgconn_async_describe_prepared, 1);
4410
+ rb_define_method(rb_cPGconn, "describe_portal", pgconn_async_describe_portal, 1);
4411
+
4412
+ rb_define_alias(rb_cPGconn, "async_exec", "exec");
4413
+ rb_define_alias(rb_cPGconn, "async_query", "async_exec");
4414
+ rb_define_alias(rb_cPGconn, "async_exec_params", "exec_params");
4415
+ rb_define_alias(rb_cPGconn, "async_prepare", "prepare");
4416
+ rb_define_alias(rb_cPGconn, "async_exec_prepared", "exec_prepared");
4417
+ rb_define_alias(rb_cPGconn, "async_describe_prepared", "describe_prepared");
4418
+ rb_define_alias(rb_cPGconn, "async_describe_portal", "describe_portal");
4419
+
3990
4420
  rb_define_method(rb_cPGconn, "make_empty_pgresult", pgconn_make_empty_pgresult, 1);
3991
4421
  rb_define_method(rb_cPGconn, "escape_string", pgconn_s_escape, 1);
3992
4422
  rb_define_alias(rb_cPGconn, "escape", "escape_string");
3993
- #ifdef HAVE_PQESCAPELITERAL
3994
4423
  rb_define_method(rb_cPGconn, "escape_literal", pgconn_escape_literal, 1);
3995
- #endif
3996
- #ifdef HAVE_PQESCAPEIDENTIFIER
3997
4424
  rb_define_method(rb_cPGconn, "escape_identifier", pgconn_escape_identifier, 1);
3998
- #endif
3999
4425
  rb_define_method(rb_cPGconn, "escape_bytea", pgconn_s_escape_bytea, 1);
4000
4426
  rb_define_method(rb_cPGconn, "unescape_bytea", pgconn_s_unescape_bytea, 1);
4001
- #ifdef HAVE_PQSETSINGLEROWMODE
4002
4427
  rb_define_method(rb_cPGconn, "set_single_row_mode", pgconn_set_single_row_mode, 0);
4003
- #endif
4004
4428
 
4005
4429
  /****** PG::Connection INSTANCE METHODS: Asynchronous Command Processing ******/
4006
4430
  rb_define_method(rb_cPGconn, "send_query", pgconn_send_query, -1);
4431
+ rb_define_method(rb_cPGconn, "send_query_params", pgconn_send_query_params, -1);
4007
4432
  rb_define_method(rb_cPGconn, "send_prepare", pgconn_send_prepare, -1);
4008
4433
  rb_define_method(rb_cPGconn, "send_query_prepared", pgconn_send_query_prepared, -1);
4009
4434
  rb_define_method(rb_cPGconn, "send_describe_prepared", pgconn_send_describe_prepared, 1);
4010
4435
  rb_define_method(rb_cPGconn, "send_describe_portal", pgconn_send_describe_portal, 1);
4011
- rb_define_method(rb_cPGconn, "get_result", pgconn_get_result, 0);
4436
+ rb_define_method(rb_cPGconn, "sync_get_result", pgconn_sync_get_result, 0);
4012
4437
  rb_define_method(rb_cPGconn, "consume_input", pgconn_consume_input, 0);
4013
4438
  rb_define_method(rb_cPGconn, "is_busy", pgconn_is_busy, 0);
4014
- rb_define_method(rb_cPGconn, "setnonblocking", pgconn_setnonblocking, 1);
4015
- rb_define_method(rb_cPGconn, "isnonblocking", pgconn_isnonblocking, 0);
4016
- rb_define_alias(rb_cPGconn, "nonblocking?", "isnonblocking");
4017
- rb_define_method(rb_cPGconn, "flush", pgconn_flush, 0);
4439
+ rb_define_method(rb_cPGconn, "sync_setnonblocking", pgconn_sync_setnonblocking, 1);
4440
+ rb_define_method(rb_cPGconn, "sync_isnonblocking", pgconn_sync_isnonblocking, 0);
4441
+ rb_define_method(rb_cPGconn, "sync_flush", pgconn_sync_flush, 0);
4442
+ rb_define_method(rb_cPGconn, "flush", pgconn_async_flush, 0);
4443
+ rb_define_alias(rb_cPGconn, "async_flush", "flush");
4444
+ rb_define_method(rb_cPGconn, "discard_results", pgconn_discard_results, 0);
4018
4445
 
4019
4446
  /****** PG::Connection INSTANCE METHODS: Cancelling Queries in Progress ******/
4020
- rb_define_method(rb_cPGconn, "cancel", pgconn_cancel, 0);
4447
+ rb_define_method(rb_cPGconn, "sync_cancel", pgconn_sync_cancel, 0);
4021
4448
 
4022
4449
  /****** PG::Connection INSTANCE METHODS: NOTIFY ******/
4023
4450
  rb_define_method(rb_cPGconn, "notifies", pgconn_notifies, 0);
4024
4451
 
4025
4452
  /****** PG::Connection INSTANCE METHODS: COPY ******/
4026
- rb_define_method(rb_cPGconn, "put_copy_data", pgconn_put_copy_data, -1);
4027
- rb_define_method(rb_cPGconn, "put_copy_end", pgconn_put_copy_end, -1);
4028
- rb_define_method(rb_cPGconn, "get_copy_data", pgconn_get_copy_data, -1);
4453
+ rb_define_method(rb_cPGconn, "sync_put_copy_data", pgconn_sync_put_copy_data, -1);
4454
+ rb_define_method(rb_cPGconn, "sync_put_copy_end", pgconn_sync_put_copy_end, -1);
4455
+ rb_define_method(rb_cPGconn, "sync_get_copy_data", pgconn_sync_get_copy_data, -1);
4029
4456
 
4030
4457
  /****** PG::Connection INSTANCE METHODS: Control Functions ******/
4031
4458
  rb_define_method(rb_cPGconn, "set_error_verbosity", pgconn_set_error_verbosity, 1);
4459
+ #ifdef HAVE_PQRESULTVERBOSEERRORMESSAGE
4460
+ rb_define_method(rb_cPGconn, "set_error_context_visibility", pgconn_set_error_context_visibility, 1 );
4461
+ #endif
4032
4462
  rb_define_method(rb_cPGconn, "trace", pgconn_trace, 1);
4033
4463
  rb_define_method(rb_cPGconn, "untrace", pgconn_untrace, 0);
4034
4464
 
@@ -4038,16 +4468,21 @@ init_pg_connection()
4038
4468
 
4039
4469
  /****** PG::Connection INSTANCE METHODS: Other ******/
4040
4470
  rb_define_method(rb_cPGconn, "get_client_encoding", pgconn_get_client_encoding, 0);
4041
- rb_define_method(rb_cPGconn, "set_client_encoding", pgconn_set_client_encoding, 1);
4471
+ rb_define_method(rb_cPGconn, "sync_set_client_encoding", pgconn_sync_set_client_encoding, 1);
4472
+ rb_define_method(rb_cPGconn, "set_client_encoding", pgconn_async_set_client_encoding, 1);
4473
+ rb_define_alias(rb_cPGconn, "async_set_client_encoding", "set_client_encoding");
4042
4474
  rb_define_alias(rb_cPGconn, "client_encoding=", "set_client_encoding");
4043
- rb_define_method(rb_cPGconn, "transaction", pgconn_transaction, 0);
4044
4475
  rb_define_method(rb_cPGconn, "block", pgconn_block, -1);
4476
+ rb_define_private_method(rb_cPGconn, "flush_data=", pgconn_flush_data_set, 1);
4045
4477
  rb_define_method(rb_cPGconn, "wait_for_notify", pgconn_wait_for_notify, -1);
4046
4478
  rb_define_alias(rb_cPGconn, "notifies_wait", "wait_for_notify");
4047
4479
  rb_define_method(rb_cPGconn, "quote_ident", pgconn_s_quote_ident, 1);
4048
- rb_define_method(rb_cPGconn, "async_exec", pgconn_async_exec, -1);
4049
- rb_define_alias(rb_cPGconn, "async_query", "async_exec");
4050
- rb_define_method(rb_cPGconn, "get_last_result", pgconn_get_last_result, 0);
4480
+ rb_define_method(rb_cPGconn, "sync_get_last_result", pgconn_sync_get_last_result, 0);
4481
+ rb_define_method(rb_cPGconn, "get_last_result", pgconn_async_get_last_result, 0);
4482
+ rb_define_alias(rb_cPGconn, "async_get_last_result", "get_last_result");
4483
+ #ifdef HAVE_PQENCRYPTPASSWORDCONN
4484
+ rb_define_method(rb_cPGconn, "sync_encrypt_password", pgconn_sync_encrypt_password, -1);
4485
+ #endif
4051
4486
 
4052
4487
  #ifdef HAVE_PQSSLATTRIBUTE
4053
4488
  rb_define_method(rb_cPGconn, "ssl_in_use?", pgconn_ssl_in_use, 0);
@@ -4055,6 +4490,14 @@ init_pg_connection()
4055
4490
  rb_define_method(rb_cPGconn, "ssl_attribute_names", pgconn_ssl_attribute_names, 0);
4056
4491
  #endif
4057
4492
 
4493
+ #ifdef HAVE_PQENTERPIPELINEMODE
4494
+ rb_define_method(rb_cPGconn, "pipeline_status", pgconn_pipeline_status, 0);
4495
+ rb_define_method(rb_cPGconn, "enter_pipeline_mode", pgconn_enter_pipeline_mode, 0);
4496
+ rb_define_method(rb_cPGconn, "exit_pipeline_mode", pgconn_exit_pipeline_mode, 0);
4497
+ rb_define_method(rb_cPGconn, "pipeline_sync", pgconn_pipeline_sync, 0);
4498
+ rb_define_method(rb_cPGconn, "send_flush_request", pgconn_send_flush_request, 0);
4499
+ #endif
4500
+
4058
4501
  /****** PG::Connection INSTANCE METHODS: Large Object Support ******/
4059
4502
  rb_define_method(rb_cPGconn, "lo_creat", pgconn_locreat, -1);
4060
4503
  rb_define_alias(rb_cPGconn, "locreat", "lo_creat");
@@ -4083,12 +4526,10 @@ init_pg_connection()
4083
4526
  rb_define_method(rb_cPGconn, "lo_unlink", pgconn_lounlink, 1);
4084
4527
  rb_define_alias(rb_cPGconn, "lounlink", "lo_unlink");
4085
4528
 
4086
- #ifdef M17N_SUPPORTED
4087
4529
  rb_define_method(rb_cPGconn, "internal_encoding", pgconn_internal_encoding, 0);
4088
4530
  rb_define_method(rb_cPGconn, "internal_encoding=", pgconn_internal_encoding_set, 1);
4089
4531
  rb_define_method(rb_cPGconn, "external_encoding", pgconn_external_encoding, 0);
4090
4532
  rb_define_method(rb_cPGconn, "set_default_encoding", pgconn_set_default_encoding, 0);
4091
- #endif /* M17N_SUPPORTED */
4092
4533
 
4093
4534
  rb_define_method(rb_cPGconn, "type_map_for_queries=", pgconn_type_map_for_queries_set, 1);
4094
4535
  rb_define_method(rb_cPGconn, "type_map_for_queries", pgconn_type_map_for_queries_get, 0);
@@ -4098,5 +4539,7 @@ init_pg_connection()
4098
4539
  rb_define_method(rb_cPGconn, "encoder_for_put_copy_data", pgconn_encoder_for_put_copy_data_get, 0);
4099
4540
  rb_define_method(rb_cPGconn, "decoder_for_get_copy_data=", pgconn_decoder_for_get_copy_data_set, 1);
4100
4541
  rb_define_method(rb_cPGconn, "decoder_for_get_copy_data", pgconn_decoder_for_get_copy_data_get, 0);
4101
- }
4102
4542
 
4543
+ rb_define_method(rb_cPGconn, "field_name_type=", pgconn_field_name_type_set, 1 );
4544
+ rb_define_method(rb_cPGconn, "field_name_type", pgconn_field_name_type_get, 0 );
4545
+ }