pg 0.21.0 → 1.4.4

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 +390 -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 +84 -0
  25. data/ext/errorcodes.rb +1 -1
  26. data/ext/errorcodes.txt +23 -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 +211 -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 +1441 -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 +667 -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,19 @@ 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
+ return INT2NUM(atoi(port));
651
706
  }
652
707
 
653
708
  /*
654
709
  * call-seq:
655
710
  * conn.tty()
656
711
  *
657
- * Returns the connected pgtty. (Obsolete)
712
+ * Obsolete function.
658
713
  */
659
714
  static VALUE
660
715
  pgconn_tty(VALUE self)
661
716
  {
662
- char *tty = PQtty(pg_get_pgconn(self));
663
- if (!tty) return Qnil;
664
- return rb_tainted_str_new2(tty);
717
+ return rb_str_new2("");
665
718
  }
666
719
 
667
720
  /*
@@ -675,17 +728,17 @@ pgconn_options(VALUE self)
675
728
  {
676
729
  char *options = PQoptions(pg_get_pgconn(self));
677
730
  if (!options) return Qnil;
678
- return rb_tainted_str_new2(options);
731
+ return rb_str_new2(options);
679
732
  }
680
733
 
681
734
 
682
- #ifdef HAVE_PQCONNINFO
683
735
  /*
684
736
  * call-seq:
685
737
  * conn.conninfo -> hash
686
738
  *
687
739
  * Returns the connection options used by a live connection.
688
740
  *
741
+ * Available since PostgreSQL-9.3
689
742
  */
690
743
  static VALUE
691
744
  pgconn_conninfo( VALUE self )
@@ -698,14 +751,20 @@ pgconn_conninfo( VALUE self )
698
751
 
699
752
  return array;
700
753
  }
701
- #endif
702
754
 
703
755
 
704
756
  /*
705
757
  * call-seq:
706
758
  * conn.status()
707
759
  *
708
- * Returns status of connection : CONNECTION_OK or CONNECTION_BAD
760
+ * Returns the status of the connection, which is one:
761
+ * PG::Constants::CONNECTION_OK
762
+ * PG::Constants::CONNECTION_BAD
763
+ *
764
+ * ... and other constants of kind PG::Constants::CONNECTION_*
765
+ *
766
+ * Example:
767
+ * PG.constants.grep(/CONNECTION_/).find{|c| PG.const_get(c) == conn.status} # => :CONNECTION_OK
709
768
  */
710
769
  static VALUE
711
770
  pgconn_status(VALUE self)
@@ -755,7 +814,7 @@ pgconn_parameter_status(VALUE self, VALUE param_name)
755
814
  if(ret == NULL)
756
815
  return Qnil;
757
816
  else
758
- return rb_tainted_str_new2(ret);
817
+ return rb_str_new2(ret);
759
818
  }
760
819
 
761
820
  /*
@@ -793,20 +852,25 @@ pgconn_server_version(VALUE self)
793
852
  * call-seq:
794
853
  * conn.error_message -> String
795
854
  *
796
- * Returns the error message about connection.
855
+ * Returns the error message most recently generated by an operation on the connection.
856
+ *
857
+ * Nearly all libpq functions will set a message for conn.error_message if they fail.
858
+ * Note that by libpq convention, a nonempty error_message result can consist of multiple lines, and will include a trailing newline.
797
859
  */
798
860
  static VALUE
799
861
  pgconn_error_message(VALUE self)
800
862
  {
801
863
  char *error = PQerrorMessage(pg_get_pgconn(self));
802
864
  if (!error) return Qnil;
803
- return rb_tainted_str_new2(error);
865
+ return rb_str_new2(error);
804
866
  }
805
867
 
806
868
  /*
807
869
  * call-seq:
808
870
  * conn.socket() -> Integer
809
871
  *
872
+ * This method is deprecated. Please use the more portable method #socket_io .
873
+ *
810
874
  * Returns the socket's file descriptor for this connection.
811
875
  * <tt>IO.for_fd()</tt> can be used to build a proper IO object to the socket.
812
876
  * If you do so, you will likely also want to set <tt>autoclose=false</tt>
@@ -815,60 +879,64 @@ pgconn_error_message(VALUE self)
815
879
  * creates an IO that's associated with the connection object itself,
816
880
  * and so won't go out of scope until the connection does.
817
881
  *
818
- * *Note:* On Windows the file descriptor is not really usable,
882
+ * *Note:* On Windows the file descriptor is not usable,
819
883
  * since it can not be used to build a Ruby IO object.
820
884
  */
821
885
  static VALUE
822
886
  pgconn_socket(VALUE self)
823
887
  {
824
888
  int sd;
889
+ pg_deprecated(4, ("conn.socket is deprecated and should be replaced by conn.socket_io"));
890
+
825
891
  if( (sd = PQsocket(pg_get_pgconn(self))) < 0)
826
- rb_raise(rb_eConnectionBad, "PQsocket() can't get socket descriptor");
892
+ pg_raise_conn_error( rb_eConnectionBad, self, "PQsocket() can't get socket descriptor");
893
+
827
894
  return INT2NUM(sd);
828
895
  }
829
896
 
830
-
831
- #if !defined(_WIN32) || defined(HAVE_RB_W32_WRAP_IO_HANDLE)
832
-
833
897
  /*
834
898
  * call-seq:
835
899
  * conn.socket_io() -> IO
836
900
  *
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.
901
+ * Fetch an IO object created from the Connection's underlying socket.
902
+ * 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.
903
+ * <tt>IO#wait_*able</tt> is is <tt>Fiber.scheduler</tt> compatible in contrast to <tt>IO.select</tt>.
840
904
  *
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.
905
+ * The IO object can change while the connection is established, but is memorized afterwards.
906
+ * So be sure not to cache the IO object, but repeat calling <tt>conn.socket_io</tt> instead.
844
907
  *
845
- * This method can also be used on Windows but requires Ruby-2.0+.
908
+ * Using this method also works on Windows in contrast to using #socket .
909
+ * 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
910
  */
847
911
  static VALUE
848
912
  pgconn_socket_io(VALUE self)
849
913
  {
850
914
  int sd;
851
915
  int ruby_sd;
852
- ID id_autoclose = rb_intern("autoclose=");
853
916
  t_pg_connection *this = pg_get_connection_safe( self );
917
+ VALUE cSocket;
854
918
  VALUE socket_io = this->socket_io;
855
919
 
856
920
  if ( !RTEST(socket_io) ) {
857
- if( (sd = PQsocket(this->pgconn)) < 0)
858
- rb_raise(rb_eConnectionBad, "PQsocket() can't get socket descriptor");
921
+ if( (sd = PQsocket(this->pgconn)) < 0){
922
+ pg_raise_conn_error( rb_eConnectionBad, self, "PQsocket() can't get socket descriptor");
923
+ }
859
924
 
860
925
  #ifdef _WIN32
861
926
  ruby_sd = rb_w32_wrap_io_handle((HANDLE)(intptr_t)sd, O_RDWR|O_BINARY|O_NOINHERIT);
927
+ if( ruby_sd == -1 )
928
+ pg_raise_conn_error( rb_eConnectionBad, self, "Could not wrap win32 socket handle");
929
+
930
+ this->ruby_sd = ruby_sd;
862
931
  #else
863
932
  ruby_sd = sd;
864
933
  #endif
865
934
 
866
- socket_io = rb_funcall( rb_cIO, rb_intern("for_fd"), 1, INT2NUM(ruby_sd) );
935
+ cSocket = rb_const_get(rb_cObject, rb_intern("BasicSocket"));
936
+ socket_io = rb_funcall( cSocket, rb_intern("for_fd"), 1, INT2NUM(ruby_sd));
867
937
 
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
- }
938
+ /* Disable autoclose feature */
939
+ rb_funcall( socket_io, s_id_autoclose_set, 1, Qfalse );
872
940
 
873
941
  this->socket_io = socket_io;
874
942
  }
@@ -876,8 +944,6 @@ pgconn_socket_io(VALUE self)
876
944
  return socket_io;
877
945
  }
878
946
 
879
- #endif
880
-
881
947
  /*
882
948
  * call-seq:
883
949
  * conn.backend_pid() -> Integer
@@ -892,6 +958,51 @@ pgconn_backend_pid(VALUE self)
892
958
  return INT2NUM(PQbackendPID(pg_get_pgconn(self)));
893
959
  }
894
960
 
961
+ typedef struct
962
+ {
963
+ struct sockaddr_storage addr;
964
+ socklen_t salen;
965
+ } SockAddr;
966
+
967
+ /* Copy of struct pg_cancel from libpq-int.h
968
+ *
969
+ * See https://github.com/postgres/postgres/blame/master/src/interfaces/libpq/libpq-int.h#L577-L586
970
+ */
971
+ struct pg_cancel
972
+ {
973
+ SockAddr raddr; /* Remote address */
974
+ int be_pid; /* PID of backend --- needed for cancels */
975
+ int be_key; /* key of backend --- needed for cancels */
976
+ };
977
+
978
+ /*
979
+ * call-seq:
980
+ * conn.backend_key() -> Integer
981
+ *
982
+ * Returns the key of the backend server process for this connection.
983
+ * This key can be used to cancel queries on the server.
984
+ */
985
+ static VALUE
986
+ pgconn_backend_key(VALUE self)
987
+ {
988
+ int be_key;
989
+ struct pg_cancel *cancel;
990
+ PGconn *conn = pg_get_pgconn(self);
991
+
992
+ cancel = (struct pg_cancel*)PQgetCancel(conn);
993
+ if(cancel == NULL)
994
+ pg_raise_conn_error( rb_ePGerror, self, "Invalid connection!");
995
+
996
+ if( cancel->be_pid != PQbackendPID(conn) )
997
+ rb_raise(rb_ePGerror,"Unexpected binary struct layout - please file a bug report at ruby-pg!");
998
+
999
+ be_key = cancel->be_key;
1000
+
1001
+ PQfreeCancel(cancel);
1002
+
1003
+ return INT2NUM(be_key);
1004
+ }
1005
+
895
1006
  /*
896
1007
  * call-seq:
897
1008
  * conn.connection_needs_password() -> Boolean
@@ -922,44 +1033,35 @@ pgconn_connection_used_password(VALUE self)
922
1033
  /* :TODO: get_ssl */
923
1034
 
924
1035
 
925
- static VALUE pgconn_exec_params( int, VALUE *, VALUE );
1036
+ static VALUE pgconn_sync_exec_params( int, VALUE *, VALUE );
926
1037
 
927
1038
  /*
928
1039
  * call-seq:
929
- * conn.exec(sql) -> PG::Result
930
- * conn.exec(sql) {|pg_result| block }
931
- *
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.
1040
+ * conn.sync_exec(sql) -> PG::Result
1041
+ * conn.sync_exec(sql) {|pg_result| block }
935
1042
  *
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.
1043
+ * This function has the same behavior as #async_exec, but is implemented using the synchronous command processing API of libpq.
1044
+ * It's not recommended to use explicit sync or async variants but #exec instead, unless you have a good reason to do so.
939
1045
  *
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.
1046
+ * Both #sync_exec and #async_exec release the GVL while waiting for server response, so that concurrent threads will get executed.
1047
+ * However #async_exec has two advantages:
943
1048
  *
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.
1049
+ * 1. #async_exec can be aborted by signals (like Ctrl-C), while #exec blocks signal processing until the query is answered.
1050
+ * 2. Ruby VM gets notified about IO blocked operations and can pass them through <tt>Fiber.scheduler</tt>.
1051
+ * So only <tt>async_*</tt> methods are compatible to event based schedulers like the async gem.
950
1052
  */
951
1053
  static VALUE
952
- pgconn_exec(int argc, VALUE *argv, VALUE self)
1054
+ pgconn_sync_exec(int argc, VALUE *argv, VALUE self)
953
1055
  {
954
- PGconn *conn = pg_get_pgconn(self);
1056
+ t_pg_connection *this = pg_get_connection_safe( self );
955
1057
  PGresult *result = NULL;
956
1058
  VALUE rb_pgresult;
957
1059
 
958
- /* If called with no parameters, use PQexec */
959
- if ( argc == 1 ) {
1060
+ /* If called with no or nil parameters, use PQexec for compatibility */
1061
+ if ( argc == 1 || (argc >= 2 && argc <= 4 && NIL_P(argv[1]) )) {
960
1062
  VALUE query_str = argv[0];
961
1063
 
962
- result = gvl_PQexec(conn, pg_cstr_enc(query_str, ENCODING_GET(self)));
1064
+ result = gvl_PQexec(this->pgconn, pg_cstr_enc(query_str, this->enc_idx));
963
1065
  rb_pgresult = pg_new_result(result, self);
964
1066
  pg_result_check(rb_pgresult);
965
1067
  if (rb_block_given_p()) {
@@ -967,11 +1069,10 @@ pgconn_exec(int argc, VALUE *argv, VALUE self)
967
1069
  }
968
1070
  return rb_pgresult;
969
1071
  }
1072
+ pg_deprecated(0, ("forwarding exec to exec_params is deprecated"));
970
1073
 
971
1074
  /* Otherwise, just call #exec_params instead for backward-compatibility */
972
- else {
973
- return pgconn_exec_params( argc, argv, self );
974
- }
1075
+ return pgconn_sync_exec_params( argc, argv, self );
975
1076
 
976
1077
  }
977
1078
 
@@ -1003,7 +1104,7 @@ struct query_params_data {
1003
1104
  * Filled by alloc_query_params()
1004
1105
  */
1005
1106
 
1006
- /* Wraps the pointer of allocated memory, if function parameters dont't
1107
+ /* Wraps the pointer of allocated memory, if function parameters don't
1007
1108
  * fit in the memory_pool below.
1008
1109
  */
1009
1110
  VALUE heap_pool;
@@ -1021,7 +1122,7 @@ struct query_params_data {
1021
1122
  Oid *types;
1022
1123
 
1023
1124
  /* This array takes the string values for the timeframe of the query,
1024
- * if param value convertion is required
1125
+ * if param value conversion is required
1025
1126
  */
1026
1127
  VALUE gc_array;
1027
1128
 
@@ -1035,8 +1136,9 @@ struct query_params_data {
1035
1136
  };
1036
1137
 
1037
1138
  static void
1038
- free_typecast_heap_chain(struct linked_typecast_data *chain_entry)
1139
+ free_typecast_heap_chain(void *_chain_entry)
1039
1140
  {
1141
+ struct linked_typecast_data *chain_entry = (struct linked_typecast_data *)_chain_entry;
1040
1142
  while(chain_entry){
1041
1143
  struct linked_typecast_data *next = chain_entry->next;
1042
1144
  xfree(chain_entry);
@@ -1044,6 +1146,18 @@ free_typecast_heap_chain(struct linked_typecast_data *chain_entry)
1044
1146
  }
1045
1147
  }
1046
1148
 
1149
+ static const rb_data_type_t pg_typecast_buffer_type = {
1150
+ "PG::Connection typecast buffer chain",
1151
+ {
1152
+ (RUBY_DATA_FUNC) NULL,
1153
+ free_typecast_heap_chain,
1154
+ (size_t (*)(const void *))NULL,
1155
+ },
1156
+ 0,
1157
+ 0,
1158
+ RUBY_TYPED_FREE_IMMEDIATELY,
1159
+ };
1160
+
1047
1161
  static char *
1048
1162
  alloc_typecast_buf( VALUE *typecast_heap_chain, int len )
1049
1163
  {
@@ -1054,17 +1168,28 @@ alloc_typecast_buf( VALUE *typecast_heap_chain, int len )
1054
1168
  /* Did we already wrap a memory chain per T_DATA object? */
1055
1169
  if( NIL_P( *typecast_heap_chain ) ){
1056
1170
  /* 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 );
1171
+ *typecast_heap_chain = TypedData_Wrap_Struct( rb_cObject, &pg_typecast_buffer_type, allocated );
1058
1172
  allocated->next = NULL;
1059
1173
  } else {
1060
1174
  /* Append to the chain */
1061
- allocated->next = DATA_PTR( *typecast_heap_chain );
1062
- DATA_PTR( *typecast_heap_chain ) = allocated;
1175
+ allocated->next = RTYPEDDATA_DATA( *typecast_heap_chain );
1176
+ RTYPEDDATA_DATA( *typecast_heap_chain ) = allocated;
1063
1177
  }
1064
1178
 
1065
1179
  return &allocated->data[0];
1066
1180
  }
1067
1181
 
1182
+ static const rb_data_type_t pg_query_heap_pool_type = {
1183
+ "PG::Connection query heap pool",
1184
+ {
1185
+ (RUBY_DATA_FUNC) NULL,
1186
+ RUBY_TYPED_DEFAULT_FREE,
1187
+ (size_t (*)(const void *))NULL,
1188
+ },
1189
+ 0,
1190
+ 0,
1191
+ RUBY_TYPED_FREE_IMMEDIATELY,
1192
+ };
1068
1193
 
1069
1194
  static int
1070
1195
  alloc_query_params(struct query_params_data *paramsData)
@@ -1079,7 +1204,7 @@ alloc_query_params(struct query_params_data *paramsData)
1079
1204
 
1080
1205
  Check_Type(paramsData->params, T_ARRAY);
1081
1206
 
1082
- p_typemap = DATA_PTR( paramsData->typemap );
1207
+ p_typemap = RTYPEDDATA_DATA( paramsData->typemap );
1083
1208
  p_typemap->funcs.fit_to_query( paramsData->typemap, paramsData->params );
1084
1209
 
1085
1210
  paramsData->heap_pool = Qnil;
@@ -1098,7 +1223,7 @@ alloc_query_params(struct query_params_data *paramsData)
1098
1223
  /* Allocate one combined memory pool for all possible function parameters */
1099
1224
  memory_pool = (char*)xmalloc( required_pool_size );
1100
1225
  /* 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 );
1226
+ paramsData->heap_pool = TypedData_Wrap_Struct( rb_cObject, &pg_query_heap_pool_type, memory_pool );
1102
1227
  required_pool_size = 0;
1103
1228
  }else{
1104
1229
  /* Use stack memory for function parameters */
@@ -1211,85 +1336,52 @@ pgconn_query_assign_typemap( VALUE self, struct query_params_data *paramsData )
1211
1336
  /* Use default typemap for queries. It's type is checked when assigned. */
1212
1337
  paramsData->typemap = pg_get_connection(self)->type_map_for_queries;
1213
1338
  }else{
1339
+ t_typemap *tm;
1340
+ UNUSED(tm);
1341
+
1214
1342
  /* 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 );
1343
+ TypedData_Get_Struct(paramsData->typemap, t_typemap, &pg_typemap_type, tm);
1220
1344
  }
1221
1345
  }
1222
1346
 
1223
1347
  /*
1224
1348
  * 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.
1349
+ * conn.sync_exec_params(sql, params[, result_format[, type_map]] ) -> PG::Result
1350
+ * conn.sync_exec_params(sql, params[, result_format[, type_map]] ) {|pg_result| block }
1255
1351
  *
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.
1261
- *
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.
1352
+ * This function has the same behavior as #async_exec_params, but is implemented using the synchronous command processing API of libpq.
1353
+ * See #async_exec for the differences between the two API variants.
1354
+ * 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
1355
  */
1266
1356
  static VALUE
1267
- pgconn_exec_params( int argc, VALUE *argv, VALUE self )
1357
+ pgconn_sync_exec_params( int argc, VALUE *argv, VALUE self )
1268
1358
  {
1269
- PGconn *conn = pg_get_pgconn(self);
1359
+ t_pg_connection *this = pg_get_connection_safe( self );
1270
1360
  PGresult *result = NULL;
1271
1361
  VALUE rb_pgresult;
1272
1362
  VALUE command, in_res_fmt;
1273
1363
  int nParams;
1274
1364
  int resultFormat;
1275
- struct query_params_data paramsData = { ENCODING_GET(self) };
1365
+ struct query_params_data paramsData = { this->enc_idx };
1276
1366
 
1367
+ /* For compatibility we accept 1 to 4 parameters */
1277
1368
  rb_scan_args(argc, argv, "13", &command, &paramsData.params, &in_res_fmt, &paramsData.typemap);
1278
1369
  paramsData.with_types = 1;
1279
1370
 
1280
1371
  /*
1281
- * Handle the edge-case where the caller is coming from #exec, but passed an explict +nil+
1282
- * for the second parameter.
1372
+ * For backward compatibility no or +nil+ for the second parameter
1373
+ * is passed to #exec
1283
1374
  */
1284
1375
  if ( NIL_P(paramsData.params) ) {
1285
- return pgconn_exec( 1, argv, self );
1376
+ pg_deprecated(1, ("forwarding exec_params to exec is deprecated"));
1377
+ return pgconn_sync_exec( 1, argv, self );
1286
1378
  }
1287
1379
  pgconn_query_assign_typemap( self, &paramsData );
1288
1380
 
1289
1381
  resultFormat = NIL_P(in_res_fmt) ? 0 : NUM2INT(in_res_fmt);
1290
1382
  nParams = alloc_query_params( &paramsData );
1291
1383
 
1292
- result = gvl_PQexecParams(conn, pg_cstr_enc(command, paramsData.enc_idx), nParams, paramsData.types,
1384
+ result = gvl_PQexecParams(this->pgconn, pg_cstr_enc(command, paramsData.enc_idx), nParams, paramsData.types,
1293
1385
  (const char * const *)paramsData.values, paramsData.lengths, paramsData.formats, resultFormat);
1294
1386
 
1295
1387
  free_query_params( &paramsData );
@@ -1306,28 +1398,16 @@ pgconn_exec_params( int argc, VALUE *argv, VALUE self )
1306
1398
 
1307
1399
  /*
1308
1400
  * 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"
1401
+ * conn.sync_prepare(stmt_name, sql [, param_types ] ) -> PG::Result
1323
1402
  *
1324
- * PostgreSQL bind parameters are represented as $1, $1, $2, etc.,
1325
- * inside the SQL query.
1403
+ * This function has the same behavior as #async_prepare, but is implemented using the synchronous command processing API of libpq.
1404
+ * See #async_exec for the differences between the two API variants.
1405
+ * It's not recommended to use explicit sync or async variants but #prepare instead, unless you have a good reason to do so.
1326
1406
  */
1327
1407
  static VALUE
1328
- pgconn_prepare(int argc, VALUE *argv, VALUE self)
1408
+ pgconn_sync_prepare(int argc, VALUE *argv, VALUE self)
1329
1409
  {
1330
- PGconn *conn = pg_get_pgconn(self);
1410
+ t_pg_connection *this = pg_get_connection_safe( self );
1331
1411
  PGresult *result = NULL;
1332
1412
  VALUE rb_pgresult;
1333
1413
  VALUE name, command, in_paramtypes;
@@ -1337,7 +1417,7 @@ pgconn_prepare(int argc, VALUE *argv, VALUE self)
1337
1417
  Oid *paramTypes = NULL;
1338
1418
  const char *name_cstr;
1339
1419
  const char *command_cstr;
1340
- int enc_idx = ENCODING_GET(self);
1420
+ int enc_idx = this->enc_idx;
1341
1421
 
1342
1422
  rb_scan_args(argc, argv, "21", &name, &command, &in_paramtypes);
1343
1423
  name_cstr = pg_cstr_enc(name, enc_idx);
@@ -1355,7 +1435,7 @@ pgconn_prepare(int argc, VALUE *argv, VALUE self)
1355
1435
  paramTypes[i] = NUM2UINT(param);
1356
1436
  }
1357
1437
  }
1358
- result = gvl_PQprepare(conn, name_cstr, command_cstr, nParams, paramTypes);
1438
+ result = gvl_PQprepare(this->pgconn, name_cstr, command_cstr, nParams, paramTypes);
1359
1439
 
1360
1440
  xfree(paramTypes);
1361
1441
 
@@ -1366,49 +1446,23 @@ pgconn_prepare(int argc, VALUE *argv, VALUE self)
1366
1446
 
1367
1447
  /*
1368
1448
  * 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.
1449
+ * conn.sync_exec_prepared(statement_name [, params, result_format[, type_map]] ) -> PG::Result
1450
+ * conn.sync_exec_prepared(statement_name [, params, result_format[, type_map]] ) {|pg_result| block }
1375
1451
  *
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.
1391
- *
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.
1452
+ * This function has the same behavior as #async_exec_prepared, but is implemented using the synchronous command processing API of libpq.
1453
+ * See #async_exec for the differences between the two API variants.
1454
+ * 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
1455
  */
1402
1456
  static VALUE
1403
- pgconn_exec_prepared(int argc, VALUE *argv, VALUE self)
1457
+ pgconn_sync_exec_prepared(int argc, VALUE *argv, VALUE self)
1404
1458
  {
1405
- PGconn *conn = pg_get_pgconn(self);
1459
+ t_pg_connection *this = pg_get_connection_safe( self );
1406
1460
  PGresult *result = NULL;
1407
1461
  VALUE rb_pgresult;
1408
1462
  VALUE name, in_res_fmt;
1409
1463
  int nParams;
1410
1464
  int resultFormat;
1411
- struct query_params_data paramsData = { ENCODING_GET(self) };
1465
+ struct query_params_data paramsData = { this->enc_idx };
1412
1466
 
1413
1467
  rb_scan_args(argc, argv, "13", &name, &paramsData.params, &in_res_fmt, &paramsData.typemap);
1414
1468
  paramsData.with_types = 0;
@@ -1421,7 +1475,7 @@ pgconn_exec_prepared(int argc, VALUE *argv, VALUE self)
1421
1475
  resultFormat = NIL_P(in_res_fmt) ? 0 : NUM2INT(in_res_fmt);
1422
1476
  nParams = alloc_query_params( &paramsData );
1423
1477
 
1424
- result = gvl_PQexecPrepared(conn, pg_cstr_enc(name, paramsData.enc_idx), nParams,
1478
+ result = gvl_PQexecPrepared(this->pgconn, pg_cstr_enc(name, paramsData.enc_idx), nParams,
1425
1479
  (const char * const *)paramsData.values, paramsData.lengths, paramsData.formats,
1426
1480
  resultFormat);
1427
1481
 
@@ -1438,25 +1492,26 @@ pgconn_exec_prepared(int argc, VALUE *argv, VALUE self)
1438
1492
 
1439
1493
  /*
1440
1494
  * call-seq:
1441
- * conn.describe_prepared( statement_name ) -> PG::Result
1495
+ * conn.sync_describe_prepared( statement_name ) -> PG::Result
1442
1496
  *
1443
- * Retrieve information about the prepared statement
1444
- * _statement_name_.
1497
+ * This function has the same behavior as #async_describe_prepared, but is implemented using the synchronous command processing API of libpq.
1498
+ * See #async_exec for the differences between the two API variants.
1499
+ * 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
1500
  */
1446
1501
  static VALUE
1447
- pgconn_describe_prepared(VALUE self, VALUE stmt_name)
1502
+ pgconn_sync_describe_prepared(VALUE self, VALUE stmt_name)
1448
1503
  {
1449
1504
  PGresult *result;
1450
1505
  VALUE rb_pgresult;
1451
- PGconn *conn = pg_get_pgconn(self);
1506
+ t_pg_connection *this = pg_get_connection_safe( self );
1452
1507
  const char *stmt;
1453
1508
  if(NIL_P(stmt_name)) {
1454
1509
  stmt = NULL;
1455
1510
  }
1456
1511
  else {
1457
- stmt = pg_cstr_enc(stmt_name, ENCODING_GET(self));
1512
+ stmt = pg_cstr_enc(stmt_name, this->enc_idx);
1458
1513
  }
1459
- result = gvl_PQdescribePrepared(conn, stmt);
1514
+ result = gvl_PQdescribePrepared(this->pgconn, stmt);
1460
1515
  rb_pgresult = pg_new_result(result, self);
1461
1516
  pg_result_check(rb_pgresult);
1462
1517
  return rb_pgresult;
@@ -1465,25 +1520,26 @@ pgconn_describe_prepared(VALUE self, VALUE stmt_name)
1465
1520
 
1466
1521
  /*
1467
1522
  * call-seq:
1468
- * conn.describe_portal( portal_name ) -> PG::Result
1523
+ * conn.sync_describe_portal( portal_name ) -> PG::Result
1469
1524
  *
1470
- * Retrieve information about the portal _portal_name_.
1525
+ * This function has the same behavior as #async_describe_portal, but is implemented using the synchronous command processing API of libpq.
1526
+ * See #async_exec for the differences between the two API variants.
1527
+ * 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
1528
  */
1472
1529
  static VALUE
1473
- pgconn_describe_portal(self, stmt_name)
1474
- VALUE self, stmt_name;
1530
+ pgconn_sync_describe_portal(VALUE self, VALUE stmt_name)
1475
1531
  {
1476
1532
  PGresult *result;
1477
1533
  VALUE rb_pgresult;
1478
- PGconn *conn = pg_get_pgconn(self);
1534
+ t_pg_connection *this = pg_get_connection_safe( self );
1479
1535
  const char *stmt;
1480
1536
  if(NIL_P(stmt_name)) {
1481
1537
  stmt = NULL;
1482
1538
  }
1483
1539
  else {
1484
- stmt = pg_cstr_enc(stmt_name, ENCODING_GET(self));
1540
+ stmt = pg_cstr_enc(stmt_name, this->enc_idx);
1485
1541
  }
1486
- result = gvl_PQdescribePortal(conn, stmt);
1542
+ result = gvl_PQdescribePortal(this->pgconn, stmt);
1487
1543
  rb_pgresult = pg_new_result(result, self);
1488
1544
  pg_result_check(rb_pgresult);
1489
1545
  return rb_pgresult;
@@ -1505,6 +1561,9 @@ pgconn_describe_portal(self, stmt_name)
1505
1561
  * * +PGRES_NONFATAL_ERROR+
1506
1562
  * * +PGRES_FATAL_ERROR+
1507
1563
  * * +PGRES_COPY_BOTH+
1564
+ * * +PGRES_SINGLE_TUPLE+
1565
+ * * +PGRES_PIPELINE_SYNC+
1566
+ * * +PGRES_PIPELINE_ABORTED+
1508
1567
  */
1509
1568
  static VALUE
1510
1569
  pgconn_make_empty_pgresult(VALUE self, VALUE status)
@@ -1530,13 +1589,15 @@ pgconn_make_empty_pgresult(VALUE self, VALUE status)
1530
1589
  * Consider using exec_params, which avoids the need for passing values
1531
1590
  * inside of SQL commands.
1532
1591
  *
1533
- * Encoding of escaped string will be equal to client encoding of connection.
1592
+ * Character encoding of escaped string will be equal to client encoding of connection.
1534
1593
  *
1535
1594
  * NOTE: This class version of this method can only be used safely in client
1536
1595
  * programs that use a single PostgreSQL connection at a time (in this case it can
1537
1596
  * find out what it needs to know "behind the scenes"). It might give the wrong
1538
1597
  * results if used in programs that use multiple database connections; use the
1539
1598
  * same method on the connection object in such cases.
1599
+ *
1600
+ * See also convenience functions #escape_literal and #escape_identifier which also add proper quotes around the string.
1540
1601
  */
1541
1602
  static VALUE
1542
1603
  pgconn_s_escape(VALUE self, VALUE string)
@@ -1547,8 +1608,8 @@ pgconn_s_escape(VALUE self, VALUE string)
1547
1608
  int enc_idx;
1548
1609
  int singleton = !rb_obj_is_kind_of(self, rb_cPGconn);
1549
1610
 
1550
- Check_Type(string, T_STRING);
1551
- enc_idx = ENCODING_GET( singleton ? string : self );
1611
+ StringValueCStr(string);
1612
+ enc_idx = singleton ? ENCODING_GET(string) : pg_get_connection(self)->enc_idx;
1552
1613
  if( ENCODING_GET(string) != enc_idx ){
1553
1614
  string = rb_str_export_to_enc(string, rb_enc_from_index(enc_idx));
1554
1615
  }
@@ -1558,14 +1619,13 @@ pgconn_s_escape(VALUE self, VALUE string)
1558
1619
  if( !singleton ) {
1559
1620
  size = PQescapeStringConn(pg_get_pgconn(self), RSTRING_PTR(result),
1560
1621
  RSTRING_PTR(string), RSTRING_LEN(string), &error);
1561
- if(error) {
1562
- rb_raise(rb_ePGerror, "%s", PQerrorMessage(pg_get_pgconn(self)));
1563
- }
1622
+ if(error)
1623
+ pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(pg_get_pgconn(self)));
1624
+
1564
1625
  } else {
1565
1626
  size = PQescapeString(RSTRING_PTR(result), RSTRING_PTR(string), RSTRING_LEN(string));
1566
1627
  }
1567
1628
  rb_str_set_len(result, size);
1568
- OBJ_INFECT(result, string);
1569
1629
 
1570
1630
  return result;
1571
1631
  }
@@ -1611,7 +1671,6 @@ pgconn_s_escape_bytea(VALUE self, VALUE str)
1611
1671
  }
1612
1672
 
1613
1673
  ret = rb_str_new((char*)to, to_len - 1);
1614
- OBJ_INFECT(ret, str);
1615
1674
  PQfreemem(to);
1616
1675
  return ret;
1617
1676
  }
@@ -1641,50 +1700,42 @@ pgconn_s_unescape_bytea(VALUE self, VALUE str)
1641
1700
  to = PQunescapeBytea(from, &to_len);
1642
1701
 
1643
1702
  ret = rb_str_new((char*)to, to_len);
1644
- OBJ_INFECT(ret, str);
1645
1703
  PQfreemem(to);
1646
1704
  return ret;
1647
1705
  }
1648
1706
 
1649
- #ifdef HAVE_PQESCAPELITERAL
1650
1707
  /*
1651
1708
  * call-seq:
1652
1709
  * conn.escape_literal( str ) -> String
1653
1710
  *
1654
1711
  * Escape an arbitrary String +str+ as a literal.
1712
+ *
1713
+ * See also PG::TextEncoder::QuotedLiteral for a type cast integrated version of this function.
1655
1714
  */
1656
1715
  static VALUE
1657
1716
  pgconn_escape_literal(VALUE self, VALUE string)
1658
1717
  {
1659
- PGconn *conn = pg_get_pgconn(self);
1718
+ t_pg_connection *this = pg_get_connection_safe( self );
1660
1719
  char *escaped = NULL;
1661
- VALUE error;
1662
1720
  VALUE result = Qnil;
1663
- int enc_idx = ENCODING_GET(self);
1721
+ int enc_idx = this->enc_idx;
1664
1722
 
1665
- Check_Type(string, T_STRING);
1723
+ StringValueCStr(string);
1666
1724
  if( ENCODING_GET(string) != enc_idx ){
1667
1725
  string = rb_str_export_to_enc(string, rb_enc_from_index(enc_idx));
1668
1726
  }
1669
1727
 
1670
- escaped = PQescapeLiteral(conn, RSTRING_PTR(string), RSTRING_LEN(string));
1728
+ escaped = PQescapeLiteral(this->pgconn, RSTRING_PTR(string), RSTRING_LEN(string));
1671
1729
  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
- }
1730
+ pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(this->pgconn));
1731
+
1678
1732
  result = rb_str_new2(escaped);
1679
1733
  PQfreemem(escaped);
1680
- OBJ_INFECT(result, string);
1681
1734
  PG_ENCODING_SET_NOCHECK(result, enc_idx);
1682
1735
 
1683
1736
  return result;
1684
1737
  }
1685
- #endif
1686
1738
 
1687
- #ifdef HAVE_PQESCAPEIDENTIFIER
1688
1739
  /*
1689
1740
  * call-seq:
1690
1741
  * conn.escape_identifier( str ) -> String
@@ -1698,35 +1749,27 @@ pgconn_escape_literal(VALUE self, VALUE string)
1698
1749
  static VALUE
1699
1750
  pgconn_escape_identifier(VALUE self, VALUE string)
1700
1751
  {
1701
- PGconn *conn = pg_get_pgconn(self);
1752
+ t_pg_connection *this = pg_get_connection_safe( self );
1702
1753
  char *escaped = NULL;
1703
- VALUE error;
1704
1754
  VALUE result = Qnil;
1705
- int enc_idx = ENCODING_GET(self);
1755
+ int enc_idx = this->enc_idx;
1706
1756
 
1707
- Check_Type(string, T_STRING);
1757
+ StringValueCStr(string);
1708
1758
  if( ENCODING_GET(string) != enc_idx ){
1709
1759
  string = rb_str_export_to_enc(string, rb_enc_from_index(enc_idx));
1710
1760
  }
1711
1761
 
1712
- escaped = PQescapeIdentifier(conn, RSTRING_PTR(string), RSTRING_LEN(string));
1762
+ escaped = PQescapeIdentifier(this->pgconn, RSTRING_PTR(string), RSTRING_LEN(string));
1713
1763
  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
- }
1764
+ pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(this->pgconn));
1765
+
1720
1766
  result = rb_str_new2(escaped);
1721
1767
  PQfreemem(escaped);
1722
- OBJ_INFECT(result, string);
1723
1768
  PG_ENCODING_SET_NOCHECK(result, enc_idx);
1724
1769
 
1725
1770
  return result;
1726
1771
  }
1727
- #endif
1728
1772
 
1729
- #ifdef HAVE_PQSETSINGLEROWMODE
1730
1773
  /*
1731
1774
  * call-seq:
1732
1775
  * conn.set_single_row_mode -> self
@@ -1762,34 +1805,64 @@ pgconn_escape_identifier(VALUE self, VALUE string)
1762
1805
  * # do something with the received row
1763
1806
  * end
1764
1807
  * end
1765
- *
1766
1808
  */
1767
1809
  static VALUE
1768
1810
  pgconn_set_single_row_mode(VALUE self)
1769
1811
  {
1770
1812
  PGconn *conn = pg_get_pgconn(self);
1771
- VALUE error;
1772
1813
 
1773
1814
  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
- }
1815
+ pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(conn));
1779
1816
 
1780
1817
  return self;
1781
1818
  }
1782
- #endif
1819
+
1820
+ static VALUE pgconn_send_query_params(int argc, VALUE *argv, VALUE self);
1821
+
1822
+ /*
1823
+ * call-seq:
1824
+ * conn.send_query(sql) -> nil
1825
+ *
1826
+ * Sends SQL query request specified by _sql_ to PostgreSQL for
1827
+ * asynchronous processing, and immediately returns.
1828
+ * On failure, it raises a PG::Error.
1829
+ *
1830
+ * For backward compatibility, if you pass more than one parameter to this method,
1831
+ * it will call #send_query_params for you. New code should explicitly use #send_query_params if
1832
+ * argument placeholders are used.
1833
+ *
1834
+ */
1835
+ static VALUE
1836
+ pgconn_send_query(int argc, VALUE *argv, VALUE self)
1837
+ {
1838
+ t_pg_connection *this = pg_get_connection_safe( self );
1839
+
1840
+ /* If called with no or nil parameters, use PQexec for compatibility */
1841
+ if ( argc == 1 || (argc >= 2 && argc <= 4 && NIL_P(argv[1]) )) {
1842
+ if(gvl_PQsendQuery(this->pgconn, pg_cstr_enc(argv[0], this->enc_idx)) == 0)
1843
+ pg_raise_conn_error( rb_eUnableToSend, self, "%s", PQerrorMessage(this->pgconn));
1844
+
1845
+ pgconn_wait_for_flush( self );
1846
+ return Qnil;
1847
+ }
1848
+
1849
+ pg_deprecated(2, ("forwarding async_exec to async_exec_params and send_query to send_query_params is deprecated"));
1850
+
1851
+ /* If called with parameters, and optionally result_format,
1852
+ * use PQsendQueryParams
1853
+ */
1854
+ return pgconn_send_query_params( argc, argv, self);
1855
+ }
1783
1856
 
1784
1857
  /*
1785
1858
  * call-seq:
1786
- * conn.send_query(sql [, params, result_format[, type_map ]] ) -> nil
1859
+ * conn.send_query_params(sql, params [, result_format [, type_map ]] ) -> nil
1787
1860
  *
1788
1861
  * Sends SQL query request specified by _sql_ to PostgreSQL for
1789
1862
  * asynchronous processing, and immediately returns.
1790
1863
  * On failure, it raises a PG::Error.
1791
1864
  *
1792
- * +params+ is an optional array of the bind parameters for the SQL query.
1865
+ * +params+ is an array of the bind parameters for the SQL query.
1793
1866
  * Each element of the +params+ array may be either:
1794
1867
  * a hash of the form:
1795
1868
  * {:value => String (value of bind parameter)
@@ -1799,7 +1872,7 @@ pgconn_set_single_row_mode(VALUE self)
1799
1872
  * or, it may be a String. If it is a string, that is equivalent to the hash:
1800
1873
  * { :value => <string value>, :type => 0, :format => 0 }
1801
1874
  *
1802
- * PostgreSQL bind parameters are represented as $1, $1, $2, etc.,
1875
+ * PostgreSQL bind parameters are represented as $1, $2, $3, etc.,
1803
1876
  * inside the SQL query. The 0th element of the +params+ array is bound
1804
1877
  * to $1, the 1st element is bound to $2, etc. +nil+ is treated as +NULL+.
1805
1878
  *
@@ -1812,55 +1885,39 @@ pgconn_set_single_row_mode(VALUE self)
1812
1885
  * The optional +result_format+ should be 0 for text results, 1
1813
1886
  * for binary.
1814
1887
  *
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
1888
+ * +type_map+ can be a PG::TypeMap derivation (such as PG::BasicTypeMapForQueries).
1889
+ * This will type cast the params from various Ruby types before transmission
1817
1890
  * based on the encoders defined by the type map. When a type encoder is used
1818
1891
  * the format and oid of a given bind parameter are retrieved from the encoder
1819
1892
  * instead out of the hash form described above.
1820
1893
  *
1821
1894
  */
1822
1895
  static VALUE
1823
- pgconn_send_query(int argc, VALUE *argv, VALUE self)
1896
+ pgconn_send_query_params(int argc, VALUE *argv, VALUE self)
1824
1897
  {
1825
- PGconn *conn = pg_get_pgconn(self);
1898
+ t_pg_connection *this = pg_get_connection_safe( self );
1826
1899
  int result;
1827
1900
  VALUE command, in_res_fmt;
1828
- VALUE error;
1829
1901
  int nParams;
1830
1902
  int resultFormat;
1831
- struct query_params_data paramsData = { ENCODING_GET(self) };
1903
+ struct query_params_data paramsData = { this->enc_idx };
1832
1904
 
1833
- rb_scan_args(argc, argv, "13", &command, &paramsData.params, &in_res_fmt, &paramsData.typemap);
1905
+ rb_scan_args(argc, argv, "22", &command, &paramsData.params, &in_res_fmt, &paramsData.typemap);
1834
1906
  paramsData.with_types = 1;
1835
1907
 
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
1908
  pgconn_query_assign_typemap( self, &paramsData );
1851
1909
  resultFormat = NIL_P(in_res_fmt) ? 0 : NUM2INT(in_res_fmt);
1852
1910
  nParams = alloc_query_params( &paramsData );
1853
1911
 
1854
- result = gvl_PQsendQueryParams(conn, pg_cstr_enc(command, paramsData.enc_idx), nParams, paramsData.types,
1912
+ result = gvl_PQsendQueryParams(this->pgconn, pg_cstr_enc(command, paramsData.enc_idx), nParams, paramsData.types,
1855
1913
  (const char * const *)paramsData.values, paramsData.lengths, paramsData.formats, resultFormat);
1856
1914
 
1857
1915
  free_query_params( &paramsData );
1858
1916
 
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
- }
1917
+ if(result == 0)
1918
+ pg_raise_conn_error( rb_eUnableToSend, self, "%s", PQerrorMessage(this->pgconn));
1919
+
1920
+ pgconn_wait_for_flush( self );
1864
1921
  return Qnil;
1865
1922
  }
1866
1923
 
@@ -1881,23 +1938,22 @@ pgconn_send_query(int argc, VALUE *argv, VALUE self)
1881
1938
  *
1882
1939
  * For example: "SELECT $1::int"
1883
1940
  *
1884
- * PostgreSQL bind parameters are represented as $1, $1, $2, etc.,
1941
+ * PostgreSQL bind parameters are represented as $1, $2, $3, etc.,
1885
1942
  * inside the SQL query.
1886
1943
  */
1887
1944
  static VALUE
1888
1945
  pgconn_send_prepare(int argc, VALUE *argv, VALUE self)
1889
1946
  {
1890
- PGconn *conn = pg_get_pgconn(self);
1947
+ t_pg_connection *this = pg_get_connection_safe( self );
1891
1948
  int result;
1892
1949
  VALUE name, command, in_paramtypes;
1893
1950
  VALUE param;
1894
- VALUE error;
1895
1951
  int i = 0;
1896
1952
  int nParams = 0;
1897
1953
  Oid *paramTypes = NULL;
1898
1954
  const char *name_cstr;
1899
1955
  const char *command_cstr;
1900
- int enc_idx = ENCODING_GET(self);
1956
+ int enc_idx = this->enc_idx;
1901
1957
 
1902
1958
  rb_scan_args(argc, argv, "21", &name, &command, &in_paramtypes);
1903
1959
  name_cstr = pg_cstr_enc(name, enc_idx);
@@ -1915,15 +1971,14 @@ pgconn_send_prepare(int argc, VALUE *argv, VALUE self)
1915
1971
  paramTypes[i] = NUM2UINT(param);
1916
1972
  }
1917
1973
  }
1918
- result = gvl_PQsendPrepare(conn, name_cstr, command_cstr, nParams, paramTypes);
1974
+ result = gvl_PQsendPrepare(this->pgconn, name_cstr, command_cstr, nParams, paramTypes);
1919
1975
 
1920
1976
  xfree(paramTypes);
1921
1977
 
1922
1978
  if(result == 0) {
1923
- error = rb_exc_new2(rb_eUnableToSend, PQerrorMessage(conn));
1924
- rb_iv_set(error, "@connection", self);
1925
- rb_exc_raise(error);
1979
+ pg_raise_conn_error( rb_eUnableToSend, self, "%s", PQerrorMessage(this->pgconn));
1926
1980
  }
1981
+ pgconn_wait_for_flush( self );
1927
1982
  return Qnil;
1928
1983
  }
1929
1984
 
@@ -1945,15 +2000,15 @@ pgconn_send_prepare(int argc, VALUE *argv, VALUE self)
1945
2000
  * or, it may be a String. If it is a string, that is equivalent to the hash:
1946
2001
  * { :value => <string value>, :format => 0 }
1947
2002
  *
1948
- * PostgreSQL bind parameters are represented as $1, $1, $2, etc.,
2003
+ * PostgreSQL bind parameters are represented as $1, $2, $3, etc.,
1949
2004
  * inside the SQL query. The 0th element of the +params+ array is bound
1950
2005
  * to $1, the 1st element is bound to $2, etc. +nil+ is treated as +NULL+.
1951
2006
  *
1952
2007
  * The optional +result_format+ should be 0 for text results, 1
1953
2008
  * for binary.
1954
2009
  *
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
2010
+ * +type_map+ can be a PG::TypeMap derivation (such as PG::BasicTypeMapForQueries).
2011
+ * This will type cast the params from various Ruby types before transmission
1957
2012
  * based on the encoders defined by the type map. When a type encoder is used
1958
2013
  * the format and oid of a given bind parameter are retrieved from the encoder
1959
2014
  * instead out of the hash form described above.
@@ -1962,37 +2017,34 @@ pgconn_send_prepare(int argc, VALUE *argv, VALUE self)
1962
2017
  static VALUE
1963
2018
  pgconn_send_query_prepared(int argc, VALUE *argv, VALUE self)
1964
2019
  {
1965
- PGconn *conn = pg_get_pgconn(self);
2020
+ t_pg_connection *this = pg_get_connection_safe( self );
1966
2021
  int result;
1967
2022
  VALUE name, in_res_fmt;
1968
- VALUE error;
1969
2023
  int nParams;
1970
2024
  int resultFormat;
1971
- struct query_params_data paramsData = { ENCODING_GET(self) };
2025
+ struct query_params_data paramsData = { this->enc_idx };
1972
2026
 
1973
2027
  rb_scan_args(argc, argv, "13", &name, &paramsData.params, &in_res_fmt, &paramsData.typemap);
1974
2028
  paramsData.with_types = 0;
1975
2029
 
1976
2030
  if(NIL_P(paramsData.params)) {
1977
2031
  paramsData.params = rb_ary_new2(0);
1978
- resultFormat = 0;
1979
2032
  }
1980
2033
  pgconn_query_assign_typemap( self, &paramsData );
1981
2034
 
1982
2035
  resultFormat = NIL_P(in_res_fmt) ? 0 : NUM2INT(in_res_fmt);
1983
2036
  nParams = alloc_query_params( &paramsData );
1984
2037
 
1985
- result = gvl_PQsendQueryPrepared(conn, pg_cstr_enc(name, paramsData.enc_idx), nParams,
2038
+ result = gvl_PQsendQueryPrepared(this->pgconn, pg_cstr_enc(name, paramsData.enc_idx), nParams,
1986
2039
  (const char * const *)paramsData.values, paramsData.lengths, paramsData.formats,
1987
2040
  resultFormat);
1988
2041
 
1989
2042
  free_query_params( &paramsData );
1990
2043
 
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
- }
2044
+ if(result == 0)
2045
+ pg_raise_conn_error( rb_eUnableToSend, self, "%s", PQerrorMessage(this->pgconn));
2046
+
2047
+ pgconn_wait_for_flush( self );
1996
2048
  return Qnil;
1997
2049
  }
1998
2050
 
@@ -2006,14 +2058,12 @@ pgconn_send_query_prepared(int argc, VALUE *argv, VALUE self)
2006
2058
  static VALUE
2007
2059
  pgconn_send_describe_prepared(VALUE self, VALUE stmt_name)
2008
2060
  {
2009
- VALUE error;
2010
- PGconn *conn = pg_get_pgconn(self);
2061
+ t_pg_connection *this = pg_get_connection_safe( self );
2011
2062
  /* 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
- }
2063
+ if(gvl_PQsendDescribePrepared(this->pgconn, pg_cstr_enc(stmt_name, this->enc_idx)) == 0)
2064
+ pg_raise_conn_error( rb_eUnableToSend, self, "%s", PQerrorMessage(this->pgconn));
2065
+
2066
+ pgconn_wait_for_flush( self );
2017
2067
  return Qnil;
2018
2068
  }
2019
2069
 
@@ -2028,36 +2078,18 @@ pgconn_send_describe_prepared(VALUE self, VALUE stmt_name)
2028
2078
  static VALUE
2029
2079
  pgconn_send_describe_portal(VALUE self, VALUE portal)
2030
2080
  {
2031
- VALUE error;
2032
- PGconn *conn = pg_get_pgconn(self);
2081
+ t_pg_connection *this = pg_get_connection_safe( self );
2033
2082
  /* 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
- }
2083
+ if(gvl_PQsendDescribePortal(this->pgconn, pg_cstr_enc(portal, this->enc_idx)) == 0)
2084
+ pg_raise_conn_error( rb_eUnableToSend, self, "%s", PQerrorMessage(this->pgconn));
2085
+
2086
+ pgconn_wait_for_flush( self );
2039
2087
  return Qnil;
2040
2088
  }
2041
2089
 
2042
2090
 
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
2091
  static VALUE
2060
- pgconn_get_result(VALUE self)
2092
+ pgconn_sync_get_result(VALUE self)
2061
2093
  {
2062
2094
  PGconn *conn = pg_get_pgconn(self);
2063
2095
  PGresult *result;
@@ -2083,17 +2115,15 @@ pgconn_get_result(VALUE self)
2083
2115
  * or *notifies* to see if the state has changed.
2084
2116
  */
2085
2117
  static VALUE
2086
- pgconn_consume_input(self)
2087
- VALUE self;
2118
+ pgconn_consume_input(VALUE self)
2088
2119
  {
2089
- VALUE error;
2090
2120
  PGconn *conn = pg_get_pgconn(self);
2091
2121
  /* returns 0 on error */
2092
2122
  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);
2123
+ pgconn_close_socket_io(self);
2124
+ pg_raise_conn_error( rb_eConnectionBad, self, "%s", PQerrorMessage(conn));
2096
2125
  }
2126
+
2097
2127
  return Qnil;
2098
2128
  }
2099
2129
 
@@ -2102,37 +2132,18 @@ pgconn_consume_input(self)
2102
2132
  * conn.is_busy() -> Boolean
2103
2133
  *
2104
2134
  * Returns +true+ if a command is busy, that is, if
2105
- * PQgetResult would block. Otherwise returns +false+.
2135
+ * #get_result would block. Otherwise returns +false+.
2106
2136
  */
2107
2137
  static VALUE
2108
- pgconn_is_busy(self)
2109
- VALUE self;
2138
+ pgconn_is_busy(VALUE self)
2110
2139
  {
2111
2140
  return gvl_PQisBusy(pg_get_pgconn(self)) ? Qtrue : Qfalse;
2112
2141
  }
2113
2142
 
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
2143
  static VALUE
2131
- pgconn_setnonblocking(self, state)
2132
- VALUE self, state;
2144
+ pgconn_sync_setnonblocking(VALUE self, VALUE state)
2133
2145
  {
2134
2146
  int arg;
2135
- VALUE error;
2136
2147
  PGconn *conn = pg_get_pgconn(self);
2137
2148
  if(state == Qtrue)
2138
2149
  arg = 1;
@@ -2141,69 +2152,33 @@ pgconn_setnonblocking(self, state)
2141
2152
  else
2142
2153
  rb_raise(rb_eArgError, "Boolean value expected");
2143
2154
 
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
- }
2155
+ if(PQsetnonblocking(conn, arg) == -1)
2156
+ pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(conn));
2157
+
2149
2158
  return Qnil;
2150
2159
  }
2151
2160
 
2152
2161
 
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
2162
  static VALUE
2161
- pgconn_isnonblocking(self)
2162
- VALUE self;
2163
+ pgconn_sync_isnonblocking(VALUE self)
2163
2164
  {
2164
2165
  return PQisnonblocking(pg_get_pgconn(self)) ? Qtrue : Qfalse;
2165
2166
  }
2166
2167
 
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
2168
  static VALUE
2178
- pgconn_flush(self)
2179
- VALUE self;
2169
+ pgconn_sync_flush(VALUE self)
2180
2170
  {
2181
2171
  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
- }
2172
+ int ret = PQflush(conn);
2173
+ if(ret == -1)
2174
+ pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(conn));
2175
+
2190
2176
  return (ret) ? Qfalse : Qtrue;
2191
2177
  }
2192
2178
 
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
2179
  static VALUE
2204
- pgconn_cancel(VALUE self)
2180
+ pgconn_sync_cancel(VALUE self)
2205
2181
  {
2206
- #ifdef HAVE_PQGETCANCEL
2207
2182
  char errbuf[256];
2208
2183
  PGcancel *cancel;
2209
2184
  VALUE retval;
@@ -2211,9 +2186,9 @@ pgconn_cancel(VALUE self)
2211
2186
 
2212
2187
  cancel = PQgetCancel(pg_get_pgconn(self));
2213
2188
  if(cancel == NULL)
2214
- rb_raise(rb_ePGerror,"Invalid connection!");
2189
+ pg_raise_conn_error( rb_ePGerror, self, "Invalid connection!");
2215
2190
 
2216
- ret = gvl_PQcancel(cancel, errbuf, 256);
2191
+ ret = gvl_PQcancel(cancel, errbuf, sizeof(errbuf));
2217
2192
  if(ret == 1)
2218
2193
  retval = Qnil;
2219
2194
  else
@@ -2221,9 +2196,6 @@ pgconn_cancel(VALUE self)
2221
2196
 
2222
2197
  PQfreeCancel(cancel);
2223
2198
  return retval;
2224
- #else
2225
- rb_notimplement();
2226
- #endif
2227
2199
  }
2228
2200
 
2229
2201
 
@@ -2237,7 +2209,7 @@ pgconn_cancel(VALUE self)
2237
2209
  static VALUE
2238
2210
  pgconn_notifies(VALUE self)
2239
2211
  {
2240
- PGconn* conn = pg_get_pgconn(self);
2212
+ t_pg_connection *this = pg_get_connection_safe( self );
2241
2213
  PGnotify *notification;
2242
2214
  VALUE hash;
2243
2215
  VALUE sym_relname, sym_be_pid, sym_extra;
@@ -2247,17 +2219,17 @@ pgconn_notifies(VALUE self)
2247
2219
  sym_be_pid = ID2SYM(rb_intern("be_pid"));
2248
2220
  sym_extra = ID2SYM(rb_intern("extra"));
2249
2221
 
2250
- notification = gvl_PQnotifies(conn);
2222
+ notification = gvl_PQnotifies(this->pgconn);
2251
2223
  if (notification == NULL) {
2252
2224
  return Qnil;
2253
2225
  }
2254
2226
 
2255
2227
  hash = rb_hash_new();
2256
- relname = rb_tainted_str_new2(notification->relname);
2228
+ relname = rb_str_new2(notification->relname);
2257
2229
  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) );
2230
+ extra = rb_str_new2(notification->extra);
2231
+ PG_ENCODING_SET_NOCHECK( relname, this->enc_idx );
2232
+ PG_ENCODING_SET_NOCHECK( extra, this->enc_idx );
2261
2233
 
2262
2234
  rb_hash_aset(hash, sym_relname, relname);
2263
2235
  rb_hash_aset(hash, sym_be_pid, be_pid);
@@ -2267,96 +2239,63 @@ pgconn_notifies(VALUE self)
2267
2239
  return hash;
2268
2240
  }
2269
2241
 
2270
- /* Win32 + Ruby 1.8 */
2271
- #if !defined( HAVE_RUBY_VM_H ) && defined( _WIN32 )
2242
+ #if defined(_WIN32)
2272
2243
 
2273
- /*
2274
- * Duplicate the sockets from libpq and create temporary CRT FDs
2244
+ /* We use a specialized implementation of rb_io_wait() on Windows.
2245
+ * This is because rb_io_wait() and rb_wait_for_single_fd() are very slow on Windows.
2275
2246
  */
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
2247
 
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
- }
2248
+ #if defined(HAVE_RUBY_FIBER_SCHEDULER_H)
2249
+ #include <ruby/fiber/scheduler.h>
2305
2250
  #endif
2306
2251
 
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
- */
2252
+ typedef enum {
2253
+ PG_RUBY_IO_READABLE = RB_WAITFD_IN,
2254
+ PG_RUBY_IO_WRITABLE = RB_WAITFD_OUT,
2255
+ PG_RUBY_IO_PRIORITY = RB_WAITFD_PRI,
2256
+ } pg_rb_io_event_t;
2313
2257
 
2314
2258
  int rb_w32_wait_events( HANDLE *events, int num, DWORD timeout );
2315
2259
 
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(). */
2260
+ static VALUE
2261
+ pg_rb_thread_io_wait(VALUE io, VALUE events, VALUE timeout) {
2262
+ rb_io_t *fptr;
2263
+ struct timeval ptimeout;
2319
2264
 
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
2265
  struct timeval aborttime={0,0}, currtime, waittime;
2326
2266
  DWORD timeout_milisec = INFINITE;
2327
- DWORD wait_ret;
2328
- WSAEVENT hEvent;
2329
-
2330
- if ( sd < 0 )
2331
- rb_raise(rb_eConnectionBad, "PQsocket() can't get socket descriptor");
2267
+ HANDLE hEvent = WSACreateEvent();
2332
2268
 
2333
- hEvent = WSACreateEvent();
2269
+ long rb_events = NUM2UINT(events);
2270
+ long w32_events = 0;
2271
+ DWORD wait_ret;
2334
2272
 
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
- }
2273
+ GetOpenFile((io), fptr);
2274
+ if( !NIL_P(timeout) ){
2275
+ ptimeout.tv_sec = (time_t)(NUM2DBL(timeout));
2276
+ ptimeout.tv_usec = (time_t)((NUM2DBL(timeout) - (double)ptimeout.tv_sec) * 1e6);
2340
2277
 
2341
- if ( ptimeout ) {
2342
2278
  gettimeofday(&currtime, NULL);
2343
- timeradd(&currtime, ptimeout, &aborttime);
2279
+ timeradd(&currtime, &ptimeout, &aborttime);
2344
2280
  }
2345
2281
 
2346
- while ( !(retval=is_readable(conn)) ) {
2347
- if ( WSAEventSelect(sd, hEvent, FD_READ|FD_CLOSE) == SOCKET_ERROR ) {
2282
+ if(rb_events & PG_RUBY_IO_READABLE) w32_events |= FD_READ | FD_ACCEPT | FD_CLOSE;
2283
+ if(rb_events & PG_RUBY_IO_WRITABLE) w32_events |= FD_WRITE | FD_CONNECT;
2284
+ if(rb_events & PG_RUBY_IO_PRIORITY) w32_events |= FD_OOB;
2285
+
2286
+ for(;;) {
2287
+ if ( WSAEventSelect(_get_osfhandle(fptr->fd), hEvent, w32_events) == SOCKET_ERROR ) {
2348
2288
  WSACloseEvent( hEvent );
2349
2289
  rb_raise( rb_eConnectionBad, "WSAEventSelect socket error: %d", WSAGetLastError() );
2350
2290
  }
2351
2291
 
2352
- if ( ptimeout ) {
2292
+ if ( !NIL_P(timeout) ) {
2353
2293
  gettimeofday(&currtime, NULL);
2354
2294
  timersub(&aborttime, &currtime, &waittime);
2355
2295
  timeout_milisec = (DWORD)( waittime.tv_sec * 1e3 + waittime.tv_usec / 1e3 );
2356
2296
  }
2357
2297
 
2358
- /* Is the given timeout valid? */
2359
- if( !ptimeout || (waittime.tv_sec >= 0 && waittime.tv_usec >= 0) ){
2298
+ if( NIL_P(timeout) || (waittime.tv_sec >= 0 && waittime.tv_usec >= 0) ){
2360
2299
  /* Wait for the socket to become readable before checking again */
2361
2300
  wait_ret = rb_w32_wait_events( &hEvent, 1, timeout_milisec );
2362
2301
  } else {
@@ -2365,9 +2304,11 @@ wait_socket_readable( PGconn *conn, struct timeval *ptimeout, void *(*is_readabl
2365
2304
 
2366
2305
  if ( wait_ret == WAIT_TIMEOUT ) {
2367
2306
  WSACloseEvent( hEvent );
2368
- return NULL;
2307
+ return UINT2NUM(0);
2369
2308
  } else if ( wait_ret == WAIT_OBJECT_0 ) {
2309
+ WSACloseEvent( hEvent );
2370
2310
  /* The event we were waiting for. */
2311
+ return UINT2NUM(rb_events);
2371
2312
  } else if ( wait_ret == WAIT_OBJECT_0 + 1) {
2372
2313
  /* This indicates interruption from timer thread, GC, exception
2373
2314
  * from other threads etc... */
@@ -2379,42 +2320,66 @@ wait_socket_readable( PGconn *conn, struct timeval *ptimeout, void *(*is_readabl
2379
2320
  WSACloseEvent( hEvent );
2380
2321
  rb_raise( rb_eConnectionBad, "Wait on socket abandoned (WaitForMultipleObjects)" );
2381
2322
  }
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
2323
  }
2324
+ }
2389
2325
 
2390
- WSACloseEvent( hEvent );
2391
- return retval;
2326
+ static VALUE
2327
+ pg_rb_io_wait(VALUE io, VALUE events, VALUE timeout) {
2328
+ #if defined(HAVE_RUBY_FIBER_SCHEDULER_H)
2329
+ /* We don't support Fiber.scheduler on Windows ruby-3.0 because there is no fast way to check whether a scheduler is active.
2330
+ * Fortunatelly ruby-3.1 offers a C-API for it.
2331
+ */
2332
+ VALUE scheduler = rb_fiber_scheduler_current();
2333
+
2334
+ if (!NIL_P(scheduler)) {
2335
+ return rb_io_wait(io, events, timeout);
2336
+ }
2337
+ #endif
2338
+ return pg_rb_thread_io_wait(io, events, timeout);
2392
2339
  }
2393
2340
 
2341
+ #elif defined(HAVE_RB_IO_WAIT)
2342
+
2343
+ /* Use our own function and constants names, to avoid conflicts with truffleruby-head on its road to ruby-3.0 compatibility. */
2344
+ #define pg_rb_io_wait rb_io_wait
2345
+ #define PG_RUBY_IO_READABLE RUBY_IO_READABLE
2346
+ #define PG_RUBY_IO_WRITABLE RUBY_IO_WRITABLE
2347
+ #define PG_RUBY_IO_PRIORITY RUBY_IO_PRIORITY
2348
+
2394
2349
  #else
2350
+ /* For compat with ruby < 3.0 */
2351
+
2352
+ typedef enum {
2353
+ PG_RUBY_IO_READABLE = RB_WAITFD_IN,
2354
+ PG_RUBY_IO_WRITABLE = RB_WAITFD_OUT,
2355
+ PG_RUBY_IO_PRIORITY = RB_WAITFD_PRI,
2356
+ } pg_rb_io_event_t;
2357
+
2358
+ static VALUE
2359
+ pg_rb_io_wait(VALUE io, VALUE events, VALUE timeout) {
2360
+ rb_io_t *fptr;
2361
+ struct timeval waittime;
2362
+ int res;
2363
+
2364
+ GetOpenFile((io), fptr);
2365
+ if( !NIL_P(timeout) ){
2366
+ waittime.tv_sec = (time_t)(NUM2DBL(timeout));
2367
+ waittime.tv_usec = (time_t)((NUM2DBL(timeout) - (double)waittime.tv_sec) * 1e6);
2368
+ }
2369
+ res = rb_wait_for_single_fd(fptr->fd, NUM2UINT(events), NIL_P(timeout) ? NULL : &waittime);
2395
2370
 
2396
- /* non Win32 or Win32+Ruby-1.8 */
2371
+ return UINT2NUM(res);
2372
+ }
2373
+ #endif
2397
2374
 
2398
2375
  static void *
2399
- wait_socket_readable( PGconn *conn, struct timeval *ptimeout, void *(*is_readable)(PGconn *))
2376
+ wait_socket_readable( VALUE self, struct timeval *ptimeout, void *(*is_readable)(PGconn *))
2400
2377
  {
2401
- int sd = PQsocket( conn );
2402
- int ret;
2378
+ VALUE ret;
2403
2379
  void *retval;
2404
- rb_fdset_t sd_rset;
2405
2380
  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 );
2381
+ VALUE wait_timeout = Qnil;
2382
+ PGconn *conn = pg_get_pgconn(self);
2418
2383
 
2419
2384
  if ( ptimeout ) {
2420
2385
  gettimeofday(&currtime, NULL);
@@ -2422,59 +2387,82 @@ wait_socket_readable( PGconn *conn, struct timeval *ptimeout, void *(*is_readabl
2422
2387
  }
2423
2388
 
2424
2389
  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
2390
  if ( ptimeout ) {
2437
2391
  gettimeofday(&currtime, NULL);
2438
2392
  timersub(&aborttime, &currtime, &waittime);
2393
+ wait_timeout = DBL2NUM((double)(waittime.tv_sec) + (double)(waittime.tv_usec) / 1000000.0);
2439
2394
  }
2440
2395
 
2441
2396
  /* Is the given timeout valid? */
2442
2397
  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
- }
2398
+ VALUE socket_io;
2448
2399
 
2400
+ /* before we wait for data, make sure everything has been sent */
2401
+ pgconn_async_flush(self);
2402
+ if ((retval=is_readable(conn)))
2403
+ return retval;
2449
2404
 
2450
- #ifdef _WIN32
2451
- cleanup_crt_fd(&sd_rset, &crt_sd_rset);
2452
- #endif
2453
-
2454
- if ( ret < 0 ){
2455
- rb_fd_term( &sd_rset );
2456
- rb_sys_fail( "rb_thread_select()" );
2405
+ socket_io = pgconn_socket_io(self);
2406
+ /* Wait for the socket to become readable before checking again */
2407
+ ret = pg_rb_io_wait(socket_io, RB_INT2NUM(PG_RUBY_IO_READABLE), wait_timeout);
2408
+ } else {
2409
+ ret = Qfalse;
2457
2410
  }
2458
2411
 
2459
2412
  /* Return false if the select() timed out */
2460
- if ( ret == 0 ){
2461
- rb_fd_term( &sd_rset );
2413
+ if ( ret == Qfalse ){
2462
2414
  return NULL;
2463
2415
  }
2464
2416
 
2465
2417
  /* Check for connection errors (PQisBusy is true on connection errors) */
2466
2418
  if ( PQconsumeInput(conn) == 0 ){
2467
- rb_fd_term( &sd_rset );
2468
- rb_raise( rb_eConnectionBad, "PQconsumeInput() %s", PQerrorMessage(conn) );
2419
+ pgconn_close_socket_io(self);
2420
+ pg_raise_conn_error(rb_eConnectionBad, self, "PQconsumeInput() %s", PQerrorMessage(conn));
2469
2421
  }
2470
2422
  }
2471
2423
 
2472
- rb_fd_term( &sd_rset );
2473
2424
  return retval;
2474
2425
  }
2475
2426
 
2427
+ /*
2428
+ * call-seq:
2429
+ * conn.flush() -> Boolean
2430
+ *
2431
+ * Attempts to flush any queued output data to the server.
2432
+ * Returns +true+ if data is successfully flushed, +false+
2433
+ * if not. It can only return +false+ if connection is
2434
+ * in nonblocking mode.
2435
+ * Raises PG::Error if some other failure occurred.
2436
+ */
2437
+ static VALUE
2438
+ pgconn_async_flush(VALUE self)
2439
+ {
2440
+ while( pgconn_sync_flush(self) == Qfalse ){
2441
+ /* wait for the socket to become read- or write-ready */
2442
+ int events;
2443
+ VALUE socket_io = pgconn_socket_io(self);
2444
+ events = RB_NUM2INT(pg_rb_io_wait(socket_io, RB_INT2NUM(PG_RUBY_IO_READABLE | PG_RUBY_IO_WRITABLE), Qnil));
2445
+
2446
+ if (events & PG_RUBY_IO_READABLE)
2447
+ pgconn_consume_input(self);
2448
+ }
2449
+ return Qtrue;
2450
+ }
2451
+
2452
+ static VALUE
2453
+ pgconn_wait_for_flush( VALUE self ){
2454
+ if( !pg_get_connection_safe(self)->flush_data )
2455
+ return Qnil;
2456
+
2457
+ return pgconn_async_flush(self);
2458
+ }
2476
2459
 
2477
- #endif
2460
+ static VALUE
2461
+ pgconn_flush_data_set( VALUE self, VALUE enabled ){
2462
+ t_pg_connection *conn = pg_get_connection(self);
2463
+ conn->flush_data = RTEST(enabled);
2464
+ return enabled;
2465
+ }
2478
2466
 
2479
2467
  static void *
2480
2468
  notify_readable(PGconn *conn)
@@ -2484,27 +2472,20 @@ notify_readable(PGconn *conn)
2484
2472
 
2485
2473
  /*
2486
2474
  * 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
2475
+ * conn.wait_for_notify( [ timeout ] ) { |event, pid, payload| block } -> String
2490
2476
  *
2491
2477
  * Blocks while waiting for notification(s), or until the optional
2492
2478
  * _timeout_ is reached, whichever comes first. _timeout_ is
2493
2479
  * measured in seconds and can be fractional.
2494
2480
  *
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
- *
2481
+ * Returns +nil+ if _timeout_ is reached, the name of the NOTIFY event otherwise.
2482
+ * If used in block form, passes the name of the NOTIFY +event+, the generating
2483
+ * +pid+ and the optional +payload+ string into the block.
2503
2484
  */
2504
2485
  static VALUE
2505
2486
  pgconn_wait_for_notify(int argc, VALUE *argv, VALUE self)
2506
2487
  {
2507
- PGconn *conn = pg_get_pgconn( self );
2488
+ t_pg_connection *this = pg_get_connection_safe( self );
2508
2489
  PGnotify *pnotification;
2509
2490
  struct timeval timeout;
2510
2491
  struct timeval *ptimeout = NULL;
@@ -2520,20 +2501,18 @@ pgconn_wait_for_notify(int argc, VALUE *argv, VALUE self)
2520
2501
  ptimeout = &timeout;
2521
2502
  }
2522
2503
 
2523
- pnotification = (PGnotify*) wait_socket_readable( conn, ptimeout, notify_readable);
2504
+ pnotification = (PGnotify*) wait_socket_readable( self, ptimeout, notify_readable);
2524
2505
 
2525
2506
  /* Return nil if the select timed out */
2526
2507
  if ( !pnotification ) return Qnil;
2527
2508
 
2528
- relname = rb_tainted_str_new2( pnotification->relname );
2529
- PG_ENCODING_SET_NOCHECK( relname, ENCODING_GET(self) );
2509
+ relname = rb_str_new2( pnotification->relname );
2510
+ PG_ENCODING_SET_NOCHECK( relname, this->enc_idx );
2530
2511
  be_pid = INT2NUM( pnotification->be_pid );
2531
- #ifdef HAVE_ST_NOTIFY_EXTRA
2532
2512
  if ( *pnotification->extra ) {
2533
- extra = rb_tainted_str_new2( pnotification->extra );
2534
- PG_ENCODING_SET_NOCHECK( extra, ENCODING_GET(self) );
2513
+ extra = rb_str_new2( pnotification->extra );
2514
+ PG_ENCODING_SET_NOCHECK( extra, this->enc_idx );
2535
2515
  }
2536
- #endif
2537
2516
  PQfreemem( pnotification );
2538
2517
 
2539
2518
  if ( rb_block_given_p() )
@@ -2543,27 +2522,8 @@ pgconn_wait_for_notify(int argc, VALUE *argv, VALUE self)
2543
2522
  }
2544
2523
 
2545
2524
 
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
2525
  static VALUE
2566
- pgconn_put_copy_data(int argc, VALUE *argv, VALUE self)
2526
+ pgconn_sync_put_copy_data(int argc, VALUE *argv, VALUE self)
2567
2527
  {
2568
2528
  int ret;
2569
2529
  int len;
@@ -2580,18 +2540,16 @@ pgconn_put_copy_data(int argc, VALUE *argv, VALUE self)
2580
2540
  if( NIL_P(this->encoder_for_put_copy_data) ){
2581
2541
  buffer = value;
2582
2542
  } else {
2583
- p_coder = DATA_PTR( this->encoder_for_put_copy_data );
2543
+ p_coder = RTYPEDDATA_DATA( this->encoder_for_put_copy_data );
2584
2544
  }
2585
- } else if( rb_obj_is_kind_of(encoder, rb_cPG_Coder) ) {
2586
- Data_Get_Struct( encoder, t_pg_coder, p_coder );
2587
2545
  } else {
2588
- rb_raise( rb_eTypeError, "wrong encoder type %s (expected some kind of PG::Coder)",
2589
- rb_obj_classname( encoder ) );
2546
+ /* Check argument type and use argument encoder */
2547
+ TypedData_Get_Struct(encoder, t_pg_coder, &pg_coder_type, p_coder);
2590
2548
  }
2591
2549
 
2592
2550
  if( p_coder ){
2593
2551
  t_pg_coder_enc_func enc_func;
2594
- int enc_idx = ENCODING_GET(self);
2552
+ int enc_idx = this->enc_idx;
2595
2553
 
2596
2554
  enc_func = pg_coder_enc_func( p_coder );
2597
2555
  len = enc_func( p_coder, value, NULL, &intermediate, enc_idx);
@@ -2609,75 +2567,39 @@ pgconn_put_copy_data(int argc, VALUE *argv, VALUE self)
2609
2567
  Check_Type(buffer, T_STRING);
2610
2568
 
2611
2569
  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
- }
2570
+ if(ret == -1)
2571
+ pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(this->pgconn));
2572
+
2617
2573
  RB_GC_GUARD(intermediate);
2618
2574
  RB_GC_GUARD(buffer);
2619
2575
 
2620
2576
  return (ret) ? Qtrue : Qfalse;
2621
2577
  }
2622
2578
 
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
2579
  static VALUE
2638
- pgconn_put_copy_end(int argc, VALUE *argv, VALUE self)
2580
+ pgconn_sync_put_copy_end(int argc, VALUE *argv, VALUE self)
2639
2581
  {
2640
2582
  VALUE str;
2641
- VALUE error;
2642
2583
  int ret;
2643
2584
  const char *error_message = NULL;
2644
- PGconn *conn = pg_get_pgconn(self);
2585
+ t_pg_connection *this = pg_get_connection_safe( self );
2645
2586
 
2646
2587
  if (rb_scan_args(argc, argv, "01", &str) == 0)
2647
2588
  error_message = NULL;
2648
2589
  else
2649
- error_message = pg_cstr_enc(str, ENCODING_GET(self));
2590
+ error_message = pg_cstr_enc(str, this->enc_idx);
2591
+
2592
+ ret = gvl_PQputCopyEnd(this->pgconn, error_message);
2593
+ if(ret == -1)
2594
+ pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(this->pgconn));
2650
2595
 
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
2596
  return (ret) ? Qtrue : Qfalse;
2658
2597
  }
2659
2598
 
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
2599
  static VALUE
2677
- pgconn_get_copy_data(int argc, VALUE *argv, VALUE self )
2600
+ pgconn_sync_get_copy_data(int argc, VALUE *argv, VALUE self )
2678
2601
  {
2679
2602
  VALUE async_in;
2680
- VALUE error;
2681
2603
  VALUE result;
2682
2604
  int ret;
2683
2605
  char *buffer;
@@ -2689,20 +2611,16 @@ pgconn_get_copy_data(int argc, VALUE *argv, VALUE self )
2689
2611
 
2690
2612
  if( NIL_P(decoder) ){
2691
2613
  if( !NIL_P(this->decoder_for_get_copy_data) ){
2692
- p_coder = DATA_PTR( this->decoder_for_get_copy_data );
2614
+ p_coder = RTYPEDDATA_DATA( this->decoder_for_get_copy_data );
2693
2615
  }
2694
- } else if( rb_obj_is_kind_of(decoder, rb_cPG_Coder) ) {
2695
- Data_Get_Struct( decoder, t_pg_coder, p_coder );
2696
2616
  } else {
2697
- rb_raise( rb_eTypeError, "wrong decoder type %s (expected some kind of PG::Coder)",
2698
- rb_obj_classname( decoder ) );
2617
+ /* Check argument type and use argument decoder */
2618
+ TypedData_Get_Struct(decoder, t_pg_coder, &pg_coder_type, p_coder);
2699
2619
  }
2700
2620
 
2701
2621
  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);
2622
+ if(ret == -2){ /* error */
2623
+ pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(this->pgconn));
2706
2624
  }
2707
2625
  if(ret == -1) { /* No data left */
2708
2626
  return Qnil;
@@ -2713,9 +2631,9 @@ pgconn_get_copy_data(int argc, VALUE *argv, VALUE self )
2713
2631
 
2714
2632
  if( p_coder ){
2715
2633
  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) );
2634
+ result = dec_func( p_coder, buffer, ret, 0, 0, this->enc_idx );
2717
2635
  } else {
2718
- result = rb_tainted_str_new(buffer, ret);
2636
+ result = rb_str_new(buffer, ret);
2719
2637
  }
2720
2638
 
2721
2639
  PQfreemem(buffer);
@@ -2728,9 +2646,16 @@ pgconn_get_copy_data(int argc, VALUE *argv, VALUE self )
2728
2646
  *
2729
2647
  * Sets connection's verbosity to _verbosity_ and returns
2730
2648
  * the previous setting. Available settings are:
2649
+ *
2731
2650
  * * PQERRORS_TERSE
2732
2651
  * * PQERRORS_DEFAULT
2733
2652
  * * PQERRORS_VERBOSE
2653
+ * * PQERRORS_SQLSTATE
2654
+ *
2655
+ * Changing the verbosity does not affect the messages available from already-existing PG::Result objects, only subsequently-created ones.
2656
+ * (But see PG::Result#verbose_error_message if you want to print a previous error with a different verbosity.)
2657
+ *
2658
+ * See also corresponding {libpq function}[https://www.postgresql.org/docs/current/libpq-control.html#LIBPQ-PQSETERRORVERBOSITY].
2734
2659
  */
2735
2660
  static VALUE
2736
2661
  pgconn_set_error_verbosity(VALUE self, VALUE in_verbosity)
@@ -2740,6 +2665,37 @@ pgconn_set_error_verbosity(VALUE self, VALUE in_verbosity)
2740
2665
  return INT2FIX(PQsetErrorVerbosity(conn, verbosity));
2741
2666
  }
2742
2667
 
2668
+ #ifdef HAVE_PQRESULTVERBOSEERRORMESSAGE
2669
+ /*
2670
+ * call-seq:
2671
+ * conn.set_error_context_visibility( context_visibility ) -> Integer
2672
+ *
2673
+ * Sets connection's context display mode to _context_visibility_ and returns
2674
+ * the previous setting. Available settings are:
2675
+ * * PQSHOW_CONTEXT_NEVER
2676
+ * * PQSHOW_CONTEXT_ERRORS
2677
+ * * PQSHOW_CONTEXT_ALWAYS
2678
+ *
2679
+ * This mode controls whether the CONTEXT field is included in messages (unless the verbosity setting is TERSE, in which case CONTEXT is never shown).
2680
+ * The NEVER mode never includes CONTEXT, while ALWAYS always includes it if available.
2681
+ * In ERRORS mode (the default), CONTEXT fields are included only for error messages, not for notices and warnings.
2682
+ *
2683
+ * Changing this mode does not affect the messages available from already-existing PG::Result objects, only subsequently-created ones.
2684
+ * (But see PG::Result#verbose_error_message if you want to print a previous error with a different display mode.)
2685
+ *
2686
+ * See also corresponding {libpq function}[https://www.postgresql.org/docs/current/libpq-control.html#LIBPQ-PQSETERRORCONTEXTVISIBILITY].
2687
+ *
2688
+ * Available since PostgreSQL-9.6
2689
+ */
2690
+ static VALUE
2691
+ pgconn_set_error_context_visibility(VALUE self, VALUE in_context_visibility)
2692
+ {
2693
+ PGconn *conn = pg_get_pgconn(self);
2694
+ PGContextVisibility context_visibility = NUM2INT(in_context_visibility);
2695
+ return INT2FIX(PQsetErrorContextVisibility(conn, context_visibility));
2696
+ }
2697
+ #endif
2698
+
2743
2699
  /*
2744
2700
  * call-seq:
2745
2701
  * conn.trace( stream ) -> nil
@@ -2758,7 +2714,7 @@ pgconn_trace(VALUE self, VALUE stream)
2758
2714
  VALUE new_file;
2759
2715
  t_pg_connection *this = pg_get_connection_safe( self );
2760
2716
 
2761
- if(rb_respond_to(stream,rb_intern("fileno")) == Qfalse)
2717
+ if(!rb_respond_to(stream,rb_intern("fileno")))
2762
2718
  rb_raise(rb_eArgError, "stream does not respond to method: fileno");
2763
2719
 
2764
2720
  fileno = rb_funcall(stream, rb_intern("fileno"), 0);
@@ -2891,8 +2847,8 @@ notice_processor_proxy(void *arg, const char *message)
2891
2847
  t_pg_connection *this = pg_get_connection( self );
2892
2848
 
2893
2849
  if (this->notice_receiver != Qnil) {
2894
- VALUE message_str = rb_tainted_str_new2(message);
2895
- PG_ENCODING_SET_NOCHECK( message_str, ENCODING_GET(self) );
2850
+ VALUE message_str = rb_str_new2(message);
2851
+ PG_ENCODING_SET_NOCHECK( message_str, this->enc_idx );
2896
2852
  rb_funcall(this->notice_receiver, rb_intern("call"), 1, message_str);
2897
2853
  }
2898
2854
  return;
@@ -2902,7 +2858,7 @@ notice_processor_proxy(void *arg, const char *message)
2902
2858
  * call-seq:
2903
2859
  * conn.set_notice_processor {|message| ... } -> Proc
2904
2860
  *
2905
- * See #set_notice_receiver for the desription of what this and the
2861
+ * See #set_notice_receiver for the description of what this and the
2906
2862
  * notice_processor methods do.
2907
2863
  *
2908
2864
  * This function takes a new block to act as the notice processor and returns
@@ -2950,76 +2906,33 @@ static VALUE
2950
2906
  pgconn_get_client_encoding(VALUE self)
2951
2907
  {
2952
2908
  char *encoding = (char *)pg_encoding_to_char(PQclientEncoding(pg_get_pgconn(self)));
2953
- return rb_tainted_str_new2(encoding);
2909
+ return rb_str_new2(encoding);
2954
2910
  }
2955
2911
 
2956
2912
 
2957
2913
  /*
2958
2914
  * call-seq:
2959
- * conn.set_client_encoding( encoding )
2915
+ * conn.sync_set_client_encoding( encoding )
2960
2916
  *
2961
- * Sets the client encoding to the _encoding_ String.
2917
+ * This function has the same behavior as #async_set_client_encoding, but is implemented using the synchronous command processing API of libpq.
2918
+ * See #async_exec for the differences between the two API variants.
2919
+ * 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
2920
  */
2963
2921
  static VALUE
2964
- pgconn_set_client_encoding(VALUE self, VALUE str)
2922
+ pgconn_sync_set_client_encoding(VALUE self, VALUE str)
2965
2923
  {
2966
2924
  PGconn *conn = pg_get_pgconn( self );
2967
2925
 
2968
2926
  Check_Type(str, T_STRING);
2969
2927
 
2970
- if ( (gvl_PQsetClientEncoding(conn, StringValueCStr(str))) == -1 ) {
2971
- rb_raise(rb_ePGerror, "invalid encoding name: %s",StringValueCStr(str));
2972
- }
2973
- #ifdef M17N_SUPPORTED
2928
+ if ( (gvl_PQsetClientEncoding(conn, StringValueCStr(str))) == -1 )
2929
+ pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(conn));
2930
+
2974
2931
  pgconn_set_internal_encoding_index( self );
2975
- #endif
2976
2932
 
2977
2933
  return Qnil;
2978
2934
  }
2979
2935
 
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
2936
 
3024
2937
  /*
3025
2938
  * call-seq:
@@ -3064,14 +2977,12 @@ pgconn_s_quote_ident(VALUE self, VALUE str_or_array)
3064
2977
  int enc_idx;
3065
2978
 
3066
2979
  if( rb_obj_is_kind_of(self, rb_cPGconn) ){
3067
- enc_idx = ENCODING_GET( self );
2980
+ enc_idx = pg_get_connection(self)->enc_idx;
3068
2981
  }else{
3069
2982
  enc_idx = RB_TYPE_P(str_or_array, T_STRING) ? ENCODING_GET( str_or_array ) : rb_ascii8bit_encindex();
3070
2983
  }
3071
2984
  pg_text_enc_identifier(NULL, str_or_array, NULL, &ret, enc_idx);
3072
2985
 
3073
- OBJ_INFECT(ret, str_or_array);
3074
-
3075
2986
  return ret;
3076
2987
  }
3077
2988
 
@@ -3096,14 +3007,8 @@ get_result_readable(PGconn *conn)
3096
3007
  * If +true+ is returned, +conn.is_busy+ will return +false+
3097
3008
  * and +conn.get_result+ will not block.
3098
3009
  */
3099
- static VALUE
3010
+ VALUE
3100
3011
  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
3012
  struct timeval timeout;
3108
3013
  struct timeval *ptimeout = NULL;
3109
3014
  VALUE timeout_in;
@@ -3117,7 +3022,7 @@ pgconn_block( int argc, VALUE *argv, VALUE self ) {
3117
3022
  ptimeout = &timeout;
3118
3023
  }
3119
3024
 
3120
- ret = wait_socket_readable( conn, ptimeout, get_result_readable);
3025
+ ret = wait_socket_readable( self, ptimeout, get_result_readable);
3121
3026
 
3122
3027
  if( !ret )
3123
3028
  return Qfalse;
@@ -3126,6 +3031,42 @@ pgconn_block( int argc, VALUE *argv, VALUE self ) {
3126
3031
  }
3127
3032
 
3128
3033
 
3034
+ /*
3035
+ * call-seq:
3036
+ * conn.sync_get_last_result( ) -> PG::Result
3037
+ *
3038
+ * This function has the same behavior as #async_get_last_result, but is implemented using the synchronous command processing API of libpq.
3039
+ * See #async_exec for the differences between the two API variants.
3040
+ * 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.
3041
+ */
3042
+ static VALUE
3043
+ pgconn_sync_get_last_result(VALUE self)
3044
+ {
3045
+ PGconn *conn = pg_get_pgconn(self);
3046
+ VALUE rb_pgresult = Qnil;
3047
+ PGresult *cur, *prev;
3048
+
3049
+
3050
+ cur = prev = NULL;
3051
+ while ((cur = gvl_PQgetResult(conn)) != NULL) {
3052
+ int status;
3053
+
3054
+ if (prev) PQclear(prev);
3055
+ prev = cur;
3056
+
3057
+ status = PQresultStatus(cur);
3058
+ if (status == PGRES_COPY_OUT || status == PGRES_COPY_IN || status == PGRES_COPY_BOTH)
3059
+ break;
3060
+ }
3061
+
3062
+ if (prev) {
3063
+ rb_pgresult = pg_new_result( prev, self );
3064
+ pg_result_check(rb_pgresult);
3065
+ }
3066
+
3067
+ return rb_pgresult;
3068
+ }
3069
+
3129
3070
  /*
3130
3071
  * call-seq:
3131
3072
  * conn.get_last_result( ) -> PG::Result
@@ -3136,27 +3077,36 @@ pgconn_block( int argc, VALUE *argv, VALUE self ) {
3136
3077
  * returns the last non-NULL result, or +nil+ if no
3137
3078
  * results are available.
3138
3079
  *
3080
+ * If the last result contains a bad result_status, an
3081
+ * appropriate exception is raised.
3082
+ *
3139
3083
  * This function is similar to #get_result
3140
3084
  * except that it is designed to get one and only
3141
- * one result.
3085
+ * one result and that it checks the result state.
3142
3086
  */
3143
3087
  static VALUE
3144
- pgconn_get_last_result(VALUE self)
3088
+ pgconn_async_get_last_result(VALUE self)
3145
3089
  {
3146
3090
  PGconn *conn = pg_get_pgconn(self);
3147
3091
  VALUE rb_pgresult = Qnil;
3148
3092
  PGresult *cur, *prev;
3149
3093
 
3150
-
3151
- cur = prev = NULL;
3152
- while ((cur = gvl_PQgetResult(conn)) != NULL) {
3094
+ cur = prev = NULL;
3095
+ for(;;) {
3153
3096
  int status;
3154
3097
 
3098
+ /* wait for input (without blocking) before reading each result */
3099
+ wait_socket_readable(self, NULL, get_result_readable);
3100
+
3101
+ cur = gvl_PQgetResult(conn);
3102
+ if (cur == NULL)
3103
+ break;
3104
+
3155
3105
  if (prev) PQclear(prev);
3156
3106
  prev = cur;
3157
3107
 
3158
3108
  status = PQresultStatus(cur);
3159
- if (status == PGRES_COPY_OUT || status == PGRES_COPY_IN)
3109
+ if (status == PGRES_COPY_OUT || status == PGRES_COPY_IN || status == PGRES_COPY_BOTH)
3160
3110
  break;
3161
3111
  }
3162
3112
 
@@ -3170,25 +3120,108 @@ pgconn_get_last_result(VALUE self)
3170
3120
 
3171
3121
  /*
3172
3122
  * call-seq:
3173
- * conn.async_exec(sql [, params, result_format ] ) -> PG::Result
3174
- * conn.async_exec(sql [, params, result_format ] ) {|pg_result| block }
3123
+ * conn.discard_results()
3175
3124
  *
3176
- * This function has the same behavior as #exec,
3177
- * but is implemented using the asynchronous command
3178
- * processing API of libpq.
3125
+ * Silently discard any prior query result that application didn't eat.
3126
+ * This is done prior of Connection#exec and sibling methods and can
3127
+ * be called explicitly when using the async API.
3128
+ */
3129
+ static VALUE
3130
+ pgconn_discard_results(VALUE self)
3131
+ {
3132
+ PGconn *conn = pg_get_pgconn(self);
3133
+ VALUE socket_io;
3134
+
3135
+ if( PQtransactionStatus(conn) == PQTRANS_IDLE ) {
3136
+ return Qnil;
3137
+ }
3138
+
3139
+ socket_io = pgconn_socket_io(self);
3140
+
3141
+ for(;;) {
3142
+ PGresult *cur;
3143
+ int status;
3144
+
3145
+ /* pgconn_block() raises an exception in case of errors.
3146
+ * To avoid this call pg_rb_io_wait() and PQconsumeInput() without rb_raise().
3147
+ */
3148
+ while( gvl_PQisBusy(conn) ){
3149
+ pg_rb_io_wait(socket_io, RB_INT2NUM(PG_RUBY_IO_READABLE), Qnil);
3150
+ if ( PQconsumeInput(conn) == 0 ) {
3151
+ pgconn_close_socket_io(self);
3152
+ return Qfalse;
3153
+ }
3154
+ }
3155
+
3156
+ cur = gvl_PQgetResult(conn);
3157
+ if( cur == NULL) break;
3158
+
3159
+ status = PQresultStatus(cur);
3160
+ PQclear(cur);
3161
+ if (status == PGRES_COPY_IN){
3162
+ gvl_PQputCopyEnd(conn, "COPY terminated by new PQexec");
3163
+ }
3164
+ if (status == PGRES_COPY_OUT){
3165
+ for(;;) {
3166
+ char *buffer = NULL;
3167
+ int st = gvl_PQgetCopyData(conn, &buffer, 1);
3168
+ if( st == 0 ) {
3169
+ /* would block -> wait for readable data */
3170
+ pg_rb_io_wait(socket_io, RB_INT2NUM(PG_RUBY_IO_READABLE), Qnil);
3171
+ if ( PQconsumeInput(conn) == 0 ) {
3172
+ pgconn_close_socket_io(self);
3173
+ return Qfalse;
3174
+ }
3175
+ } else if( st > 0 ) {
3176
+ /* some data retrieved -> discard it */
3177
+ PQfreemem(buffer);
3178
+ } else {
3179
+ /* no more data */
3180
+ break;
3181
+ }
3182
+ }
3183
+ }
3184
+ }
3185
+
3186
+ return Qtrue;
3187
+ }
3188
+
3189
+ /*
3190
+ * call-seq:
3191
+ * conn.exec(sql) -> PG::Result
3192
+ * conn.exec(sql) {|pg_result| block }
3193
+ *
3194
+ * Sends SQL query request specified by _sql_ to PostgreSQL.
3195
+ * On success, it returns a PG::Result instance with all result rows and columns.
3196
+ * On failure, it raises a PG::Error.
3197
+ *
3198
+ * For backward compatibility, if you pass more than one parameter to this method,
3199
+ * it will call #exec_params for you. New code should explicitly use #exec_params if
3200
+ * argument placeholders are used.
3201
+ *
3202
+ * If the optional code block is given, it will be passed <i>result</i> as an argument,
3203
+ * and the PG::Result object will automatically be cleared when the block terminates.
3204
+ * In this instance, <code>conn.exec</code> returns the value of the block.
3205
+ *
3206
+ * #exec is an alias for #async_exec which is almost identical to #sync_exec .
3207
+ * #sync_exec is implemented on the simpler synchronous command processing API of libpq, whereas
3208
+ * #async_exec is implemented on the asynchronous API and on ruby's IO mechanisms.
3209
+ * Only #async_exec is compatible to <tt>Fiber.scheduler</tt> based asynchronous IO processing introduced in ruby-3.0.
3210
+ * Both methods ensure that other threads can process while waiting for the server to
3211
+ * complete the request, but #sync_exec blocks all signals to be processed until the query is finished.
3212
+ * This is most notably visible by a delayed reaction to Control+C.
3213
+ * It's not recommended to use explicit sync or async variants but #exec instead, unless you have a good reason to do so.
3214
+ *
3215
+ * See also corresponding {libpq function}[https://www.postgresql.org/docs/current/libpq-exec.html#LIBPQ-PQEXEC].
3179
3216
  */
3180
3217
  static VALUE
3181
3218
  pgconn_async_exec(int argc, VALUE *argv, VALUE self)
3182
3219
  {
3183
3220
  VALUE rb_pgresult = Qnil;
3184
3221
 
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
-
3222
+ pgconn_discard_results( self );
3189
3223
  pgconn_send_query( argc, argv, self );
3190
- pgconn_block( 0, NULL, self );
3191
- rb_pgresult = pgconn_get_last_result( self );
3224
+ rb_pgresult = pgconn_async_get_last_result( self );
3192
3225
 
3193
3226
  if ( rb_block_given_p() ) {
3194
3227
  return rb_ensure( rb_yield, rb_pgresult, pg_result_clear, rb_pgresult );
@@ -3197,15 +3230,225 @@ pgconn_async_exec(int argc, VALUE *argv, VALUE self)
3197
3230
  }
3198
3231
 
3199
3232
 
3200
- #ifdef HAVE_PQSSLATTRIBUTE
3201
- /* Since PostgreSQL-9.5: */
3233
+ /*
3234
+ * call-seq:
3235
+ * conn.exec_params(sql, params [, result_format [, type_map ]] ) -> nil
3236
+ * conn.exec_params(sql, params [, result_format [, type_map ]] ) {|pg_result| block }
3237
+ *
3238
+ * Sends SQL query request specified by +sql+ to PostgreSQL using placeholders
3239
+ * for parameters.
3240
+ *
3241
+ * Returns a PG::Result instance on success. On failure, it raises a PG::Error.
3242
+ *
3243
+ * +params+ is an array of the bind parameters for the SQL query.
3244
+ * Each element of the +params+ array may be either:
3245
+ * a hash of the form:
3246
+ * {:value => String (value of bind parameter)
3247
+ * :type => Integer (oid of type of bind parameter)
3248
+ * :format => Integer (0 for text, 1 for binary)
3249
+ * }
3250
+ * or, it may be a String. If it is a string, that is equivalent to the hash:
3251
+ * { :value => <string value>, :type => 0, :format => 0 }
3252
+ *
3253
+ * PostgreSQL bind parameters are represented as $1, $2, $3, etc.,
3254
+ * inside the SQL query. The 0th element of the +params+ array is bound
3255
+ * to $1, the 1st element is bound to $2, etc. +nil+ is treated as +NULL+.
3256
+ *
3257
+ * If the types are not specified, they will be inferred by PostgreSQL.
3258
+ * Instead of specifying type oids, it's recommended to simply add
3259
+ * explicit casts in the query to ensure that the right type is used.
3260
+ *
3261
+ * For example: "SELECT $1::int"
3262
+ *
3263
+ * The optional +result_format+ should be 0 for text results, 1
3264
+ * for binary.
3265
+ *
3266
+ * +type_map+ can be a PG::TypeMap derivation (such as PG::BasicTypeMapForQueries).
3267
+ * This will type cast the params from various Ruby types before transmission
3268
+ * based on the encoders defined by the type map. When a type encoder is used
3269
+ * the format and oid of a given bind parameter are retrieved from the encoder
3270
+ * instead out of the hash form described above.
3271
+ *
3272
+ * If the optional code block is given, it will be passed <i>result</i> as an argument,
3273
+ * and the PG::Result object will automatically be cleared when the block terminates.
3274
+ * In this instance, <code>conn.exec</code> returns the value of the block.
3275
+ *
3276
+ * 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.
3277
+ * Unlike #exec, #exec_params allows at most one SQL command in the given string.
3278
+ * (There can be semicolons in it, but not more than one nonempty command.)
3279
+ * This is a limitation of the underlying protocol, but has some usefulness as an extra defense against SQL-injection attacks.
3280
+ *
3281
+ * See also corresponding {libpq function}[https://www.postgresql.org/docs/current/libpq-exec.html#LIBPQ-PQEXECPARAMS].
3282
+ */
3283
+ static VALUE
3284
+ pgconn_async_exec_params(int argc, VALUE *argv, VALUE self)
3285
+ {
3286
+ VALUE rb_pgresult = Qnil;
3287
+
3288
+ pgconn_discard_results( self );
3289
+ /* If called with no or nil parameters, use PQsendQuery for compatibility */
3290
+ if ( argc == 1 || (argc >= 2 && argc <= 4 && NIL_P(argv[1]) )) {
3291
+ pg_deprecated(3, ("forwarding async_exec_params to async_exec is deprecated"));
3292
+ pgconn_send_query( argc, argv, self );
3293
+ } else {
3294
+ pgconn_send_query_params( argc, argv, self );
3295
+ }
3296
+ rb_pgresult = pgconn_async_get_last_result( self );
3297
+
3298
+ if ( rb_block_given_p() ) {
3299
+ return rb_ensure( rb_yield, rb_pgresult, pg_result_clear, rb_pgresult );
3300
+ }
3301
+ return rb_pgresult;
3302
+ }
3303
+
3304
+
3305
+ /*
3306
+ * call-seq:
3307
+ * conn.prepare(stmt_name, sql [, param_types ] ) -> PG::Result
3308
+ *
3309
+ * Prepares statement _sql_ with name _name_ to be executed later.
3310
+ * Returns a PG::Result instance on success.
3311
+ * On failure, it raises a PG::Error.
3312
+ *
3313
+ * +param_types+ is an optional parameter to specify the Oids of the
3314
+ * types of the parameters.
3315
+ *
3316
+ * If the types are not specified, they will be inferred by PostgreSQL.
3317
+ * Instead of specifying type oids, it's recommended to simply add
3318
+ * explicit casts in the query to ensure that the right type is used.
3319
+ *
3320
+ * For example: "SELECT $1::int"
3321
+ *
3322
+ * PostgreSQL bind parameters are represented as $1, $2, $3, etc.,
3323
+ * inside the SQL query.
3324
+ *
3325
+ * See also corresponding {libpq function}[https://www.postgresql.org/docs/current/libpq-exec.html#LIBPQ-PQPREPARE].
3326
+ */
3327
+ static VALUE
3328
+ pgconn_async_prepare(int argc, VALUE *argv, VALUE self)
3329
+ {
3330
+ VALUE rb_pgresult = Qnil;
3331
+
3332
+ pgconn_discard_results( self );
3333
+ pgconn_send_prepare( argc, argv, self );
3334
+ rb_pgresult = pgconn_async_get_last_result( self );
3335
+
3336
+ if ( rb_block_given_p() ) {
3337
+ return rb_ensure( rb_yield, rb_pgresult, pg_result_clear, rb_pgresult );
3338
+ }
3339
+ return rb_pgresult;
3340
+ }
3341
+
3342
+
3343
+ /*
3344
+ * call-seq:
3345
+ * conn.exec_prepared(statement_name [, params, result_format[, type_map]] ) -> PG::Result
3346
+ * conn.exec_prepared(statement_name [, params, result_format[, type_map]] ) {|pg_result| block }
3347
+ *
3348
+ * Execute prepared named statement specified by _statement_name_.
3349
+ * Returns a PG::Result instance on success.
3350
+ * On failure, it raises a PG::Error.
3351
+ *
3352
+ * +params+ is an array of the optional bind parameters for the
3353
+ * SQL query. Each element of the +params+ array may be either:
3354
+ * a hash of the form:
3355
+ * {:value => String (value of bind parameter)
3356
+ * :format => Integer (0 for text, 1 for binary)
3357
+ * }
3358
+ * or, it may be a String. If it is a string, that is equivalent to the hash:
3359
+ * { :value => <string value>, :format => 0 }
3360
+ *
3361
+ * PostgreSQL bind parameters are represented as $1, $2, $3, etc.,
3362
+ * inside the SQL query. The 0th element of the +params+ array is bound
3363
+ * to $1, the 1st element is bound to $2, etc. +nil+ is treated as +NULL+.
3364
+ *
3365
+ * The optional +result_format+ should be 0 for text results, 1
3366
+ * for binary.
3367
+ *
3368
+ * +type_map+ can be a PG::TypeMap derivation (such as PG::BasicTypeMapForQueries).
3369
+ * This will type cast the params from various Ruby types before transmission
3370
+ * based on the encoders defined by the type map. When a type encoder is used
3371
+ * the format and oid of a given bind parameter are retrieved from the encoder
3372
+ * instead out of the hash form described above.
3373
+ *
3374
+ * If the optional code block is given, it will be passed <i>result</i> as an argument,
3375
+ * and the PG::Result object will automatically be cleared when the block terminates.
3376
+ * In this instance, <code>conn.exec_prepared</code> returns the value of the block.
3377
+ *
3378
+ * See also corresponding {libpq function}[https://www.postgresql.org/docs/current/libpq-exec.html#LIBPQ-PQEXECPREPARED].
3379
+ */
3380
+ static VALUE
3381
+ pgconn_async_exec_prepared(int argc, VALUE *argv, VALUE self)
3382
+ {
3383
+ VALUE rb_pgresult = Qnil;
3384
+
3385
+ pgconn_discard_results( self );
3386
+ pgconn_send_query_prepared( argc, argv, self );
3387
+ rb_pgresult = pgconn_async_get_last_result( self );
3388
+
3389
+ if ( rb_block_given_p() ) {
3390
+ return rb_ensure( rb_yield, rb_pgresult, pg_result_clear, rb_pgresult );
3391
+ }
3392
+ return rb_pgresult;
3393
+ }
3394
+
3202
3395
 
3396
+ /*
3397
+ * call-seq:
3398
+ * conn.describe_portal( portal_name ) -> PG::Result
3399
+ *
3400
+ * Retrieve information about the portal _portal_name_.
3401
+ *
3402
+ * See also corresponding {libpq function}[https://www.postgresql.org/docs/current/libpq-exec.html#LIBPQ-PQDESCRIBEPORTAL].
3403
+ */
3404
+ static VALUE
3405
+ pgconn_async_describe_portal(VALUE self, VALUE portal)
3406
+ {
3407
+ VALUE rb_pgresult = Qnil;
3408
+
3409
+ pgconn_discard_results( self );
3410
+ pgconn_send_describe_portal( self, portal );
3411
+ rb_pgresult = pgconn_async_get_last_result( self );
3412
+
3413
+ if ( rb_block_given_p() ) {
3414
+ return rb_ensure( rb_yield, rb_pgresult, pg_result_clear, rb_pgresult );
3415
+ }
3416
+ return rb_pgresult;
3417
+ }
3418
+
3419
+
3420
+ /*
3421
+ * call-seq:
3422
+ * conn.describe_prepared( statement_name ) -> PG::Result
3423
+ *
3424
+ * Retrieve information about the prepared statement _statement_name_.
3425
+ *
3426
+ * See also corresponding {libpq function}[https://www.postgresql.org/docs/current/libpq-exec.html#LIBPQ-PQDESCRIBEPREPARED].
3427
+ */
3428
+ static VALUE
3429
+ pgconn_async_describe_prepared(VALUE self, VALUE stmt_name)
3430
+ {
3431
+ VALUE rb_pgresult = Qnil;
3432
+
3433
+ pgconn_discard_results( self );
3434
+ pgconn_send_describe_prepared( self, stmt_name );
3435
+ rb_pgresult = pgconn_async_get_last_result( self );
3436
+
3437
+ if ( rb_block_given_p() ) {
3438
+ return rb_ensure( rb_yield, rb_pgresult, pg_result_clear, rb_pgresult );
3439
+ }
3440
+ return rb_pgresult;
3441
+ }
3442
+
3443
+
3444
+ #ifdef HAVE_PQSSLATTRIBUTE
3203
3445
  /*
3204
3446
  * call-seq:
3205
3447
  * conn.ssl_in_use? -> Boolean
3206
3448
  *
3207
- * Returns +true+ if the connection uses SSL, +false+ if not.
3449
+ * Returns +true+ if the connection uses SSL/TLS, +false+ if not.
3208
3450
  *
3451
+ * Available since PostgreSQL-9.5
3209
3452
  */
3210
3453
  static VALUE
3211
3454
  pgconn_ssl_in_use(VALUE self)
@@ -3237,7 +3480,9 @@ pgconn_ssl_in_use(VALUE self)
3237
3480
  * 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
3481
  *
3239
3482
  *
3240
- * See also #ssl_attribute_names and http://www.postgresql.org/docs/current/interactive/libpq-status.html#LIBPQ-PQSSLATTRIBUTE
3483
+ * See also #ssl_attribute_names and the {corresponding libpq function}[https://www.postgresql.org/docs/current/libpq-status.html#LIBPQ-PQSSLATTRIBUTE].
3484
+ *
3485
+ * Available since PostgreSQL-9.5
3241
3486
  */
3242
3487
  static VALUE
3243
3488
  pgconn_ssl_attribute(VALUE self, VALUE attribute_name)
@@ -3256,6 +3501,7 @@ pgconn_ssl_attribute(VALUE self, VALUE attribute_name)
3256
3501
  *
3257
3502
  * See also #ssl_attribute
3258
3503
  *
3504
+ * Available since PostgreSQL-9.5
3259
3505
  */
3260
3506
  static VALUE
3261
3507
  pgconn_ssl_attribute_names(VALUE self)
@@ -3274,6 +3520,122 @@ pgconn_ssl_attribute_names(VALUE self)
3274
3520
  #endif
3275
3521
 
3276
3522
 
3523
+ #ifdef HAVE_PQENTERPIPELINEMODE
3524
+ /*
3525
+ * call-seq:
3526
+ * conn.pipeline_status -> Integer
3527
+ *
3528
+ * Returns the current pipeline mode status of the libpq connection.
3529
+ *
3530
+ * PQpipelineStatus can return one of the following values:
3531
+ *
3532
+ * * PQ_PIPELINE_ON - The libpq connection is in pipeline mode.
3533
+ * * PQ_PIPELINE_OFF - The libpq connection is not in pipeline mode.
3534
+ * * PQ_PIPELINE_ABORTED - The libpq connection is in pipeline mode and an error occurred while processing the current pipeline.
3535
+ * The aborted flag is cleared when PQgetResult returns a result of type PGRES_PIPELINE_SYNC.
3536
+ *
3537
+ * Available since PostgreSQL-14
3538
+ */
3539
+ static VALUE
3540
+ pgconn_pipeline_status(VALUE self)
3541
+ {
3542
+ int res = PQpipelineStatus(pg_get_pgconn(self));
3543
+ return INT2FIX(res);
3544
+ }
3545
+
3546
+
3547
+ /*
3548
+ * call-seq:
3549
+ * conn.enter_pipeline_mode -> nil
3550
+ *
3551
+ * Causes a connection to enter pipeline mode if it is currently idle or already in pipeline mode.
3552
+ *
3553
+ * 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.
3554
+ * This function does not actually send anything to the server, it just changes the libpq connection state.
3555
+ *
3556
+ * Available since PostgreSQL-14
3557
+ */
3558
+ static VALUE
3559
+ pgconn_enter_pipeline_mode(VALUE self)
3560
+ {
3561
+ PGconn *conn = pg_get_pgconn(self);
3562
+ int res = PQenterPipelineMode(conn);
3563
+ if( res != 1 )
3564
+ pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(conn));
3565
+
3566
+ return Qnil;
3567
+ }
3568
+
3569
+ /*
3570
+ * call-seq:
3571
+ * conn.exit_pipeline_mode -> nil
3572
+ *
3573
+ * Causes a connection to exit pipeline mode if it is currently in pipeline mode with an empty queue and no pending results.
3574
+ *
3575
+ * Takes no action if not in pipeline mode.
3576
+ * 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.
3577
+ *
3578
+ * Available since PostgreSQL-14
3579
+ */
3580
+ static VALUE
3581
+ pgconn_exit_pipeline_mode(VALUE self)
3582
+ {
3583
+ PGconn *conn = pg_get_pgconn(self);
3584
+ int res = PQexitPipelineMode(conn);
3585
+ if( res != 1 )
3586
+ pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(conn));
3587
+
3588
+ return Qnil;
3589
+ }
3590
+
3591
+
3592
+ /*
3593
+ * call-seq:
3594
+ * conn.pipeline_sync -> nil
3595
+ *
3596
+ * Marks a synchronization point in a pipeline by sending a sync message and flushing the send buffer.
3597
+ * This serves as the delimiter of an implicit transaction and an error recovery point; see Section 34.5.1.3 of the PostgreSQL documentation.
3598
+ *
3599
+ * Raises PG::Error if the connection is not in pipeline mode or sending a sync message failed.
3600
+ *
3601
+ * Available since PostgreSQL-14
3602
+ */
3603
+ static VALUE
3604
+ pgconn_pipeline_sync(VALUE self)
3605
+ {
3606
+ PGconn *conn = pg_get_pgconn(self);
3607
+ int res = PQpipelineSync(conn);
3608
+ if( res != 1 )
3609
+ pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(conn));
3610
+
3611
+ return Qnil;
3612
+ }
3613
+
3614
+ /*
3615
+ * call-seq:
3616
+ * conn.pipeline_sync -> nil
3617
+ *
3618
+ * Sends a request for the server to flush its output buffer.
3619
+ *
3620
+ * 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.
3621
+ * This function is useful to cause the server to flush its output buffer in pipeline mode without establishing a synchronization point.
3622
+ * Note that the request is not itself flushed to the server automatically; use Connection#flush if necessary.
3623
+ *
3624
+ * Available since PostgreSQL-14
3625
+ */
3626
+ static VALUE
3627
+ pgconn_send_flush_request(VALUE self)
3628
+ {
3629
+ PGconn *conn = pg_get_pgconn(self);
3630
+ int res = PQsendFlushRequest(conn);
3631
+ if( res != 1 )
3632
+ pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(conn));
3633
+
3634
+ return Qnil;
3635
+ }
3636
+
3637
+ #endif
3638
+
3277
3639
  /**************************************************************************
3278
3640
  * LARGE OBJECT SUPPORT
3279
3641
  **************************************************************************/
@@ -3300,7 +3662,7 @@ pgconn_locreat(int argc, VALUE *argv, VALUE self)
3300
3662
 
3301
3663
  lo_oid = lo_creat(conn, mode);
3302
3664
  if (lo_oid == 0)
3303
- rb_raise(rb_ePGerror, "lo_creat failed");
3665
+ pg_raise_conn_error( rb_ePGerror, self, "lo_creat failed");
3304
3666
 
3305
3667
  return UINT2NUM(lo_oid);
3306
3668
  }
@@ -3321,7 +3683,7 @@ pgconn_locreate(VALUE self, VALUE in_lo_oid)
3321
3683
 
3322
3684
  ret = lo_create(conn, lo_oid);
3323
3685
  if (ret == InvalidOid)
3324
- rb_raise(rb_ePGerror, "lo_create failed");
3686
+ pg_raise_conn_error( rb_ePGerror, self, "lo_create failed");
3325
3687
 
3326
3688
  return UINT2NUM(ret);
3327
3689
  }
@@ -3345,7 +3707,7 @@ pgconn_loimport(VALUE self, VALUE filename)
3345
3707
 
3346
3708
  lo_oid = lo_import(conn, StringValueCStr(filename));
3347
3709
  if (lo_oid == 0) {
3348
- rb_raise(rb_ePGerror, "%s", PQerrorMessage(conn));
3710
+ pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(conn));
3349
3711
  }
3350
3712
  return UINT2NUM(lo_oid);
3351
3713
  }
@@ -3366,7 +3728,7 @@ pgconn_loexport(VALUE self, VALUE lo_oid, VALUE filename)
3366
3728
  oid = NUM2UINT(lo_oid);
3367
3729
 
3368
3730
  if (lo_export(conn, oid, StringValueCStr(filename)) < 0) {
3369
- rb_raise(rb_ePGerror, "%s", PQerrorMessage(conn));
3731
+ pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(conn));
3370
3732
  }
3371
3733
  return Qnil;
3372
3734
  }
@@ -3397,7 +3759,7 @@ pgconn_loopen(int argc, VALUE *argv, VALUE self)
3397
3759
  mode = NUM2INT(nmode);
3398
3760
 
3399
3761
  if((fd = lo_open(conn, lo_oid, mode)) < 0) {
3400
- rb_raise(rb_ePGerror, "can't open large object: %s", PQerrorMessage(conn));
3762
+ pg_raise_conn_error( rb_ePGerror, self, "can't open large object: %s", PQerrorMessage(conn));
3401
3763
  }
3402
3764
  return INT2FIX(fd);
3403
3765
  }
@@ -3419,11 +3781,11 @@ pgconn_lowrite(VALUE self, VALUE in_lo_desc, VALUE buffer)
3419
3781
  Check_Type(buffer, T_STRING);
3420
3782
 
3421
3783
  if( RSTRING_LEN(buffer) < 0) {
3422
- rb_raise(rb_ePGerror, "write buffer zero string");
3784
+ pg_raise_conn_error( rb_ePGerror, self, "write buffer zero string");
3423
3785
  }
3424
3786
  if((n = lo_write(conn, fd, StringValuePtr(buffer),
3425
3787
  RSTRING_LEN(buffer))) < 0) {
3426
- rb_raise(rb_ePGerror, "lo_write failed: %s", PQerrorMessage(conn));
3788
+ pg_raise_conn_error( rb_ePGerror, self, "lo_write failed: %s", PQerrorMessage(conn));
3427
3789
  }
3428
3790
 
3429
3791
  return INT2FIX(n);
@@ -3446,23 +3808,19 @@ pgconn_loread(VALUE self, VALUE in_lo_desc, VALUE in_len)
3446
3808
  VALUE str;
3447
3809
  char *buffer;
3448
3810
 
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
- }
3811
+ if (len < 0)
3812
+ pg_raise_conn_error( rb_ePGerror, self, "negative length %d given", len);
3456
3813
 
3814
+ buffer = ALLOC_N(char, len);
3457
3815
  if((ret = lo_read(conn, lo_desc, buffer, len)) < 0)
3458
- rb_raise(rb_ePGerror, "lo_read failed");
3816
+ pg_raise_conn_error( rb_ePGerror, self, "lo_read failed");
3459
3817
 
3460
3818
  if(ret == 0) {
3461
3819
  xfree(buffer);
3462
3820
  return Qnil;
3463
3821
  }
3464
3822
 
3465
- str = rb_tainted_str_new(buffer, ret);
3823
+ str = rb_str_new(buffer, ret);
3466
3824
  xfree(buffer);
3467
3825
 
3468
3826
  return str;
@@ -3485,7 +3843,7 @@ pgconn_lolseek(VALUE self, VALUE in_lo_desc, VALUE offset, VALUE whence)
3485
3843
  int ret;
3486
3844
 
3487
3845
  if((ret = lo_lseek(conn, lo_desc, NUM2INT(offset), NUM2INT(whence))) < 0) {
3488
- rb_raise(rb_ePGerror, "lo_lseek failed");
3846
+ pg_raise_conn_error( rb_ePGerror, self, "lo_lseek failed");
3489
3847
  }
3490
3848
 
3491
3849
  return INT2FIX(ret);
@@ -3505,7 +3863,7 @@ pgconn_lotell(VALUE self, VALUE in_lo_desc)
3505
3863
  int lo_desc = NUM2INT(in_lo_desc);
3506
3864
 
3507
3865
  if((position = lo_tell(conn, lo_desc)) < 0)
3508
- rb_raise(rb_ePGerror,"lo_tell failed");
3866
+ pg_raise_conn_error( rb_ePGerror, self, "lo_tell failed");
3509
3867
 
3510
3868
  return INT2FIX(position);
3511
3869
  }
@@ -3524,7 +3882,7 @@ pgconn_lotruncate(VALUE self, VALUE in_lo_desc, VALUE in_len)
3524
3882
  size_t len = NUM2INT(in_len);
3525
3883
 
3526
3884
  if(lo_truncate(conn,lo_desc,len) < 0)
3527
- rb_raise(rb_ePGerror,"lo_truncate failed");
3885
+ pg_raise_conn_error( rb_ePGerror, self, "lo_truncate failed");
3528
3886
 
3529
3887
  return Qnil;
3530
3888
  }
@@ -3542,7 +3900,7 @@ pgconn_loclose(VALUE self, VALUE in_lo_desc)
3542
3900
  int lo_desc = NUM2INT(in_lo_desc);
3543
3901
 
3544
3902
  if(lo_close(conn,lo_desc) < 0)
3545
- rb_raise(rb_ePGerror,"lo_close failed");
3903
+ pg_raise_conn_error( rb_ePGerror, self, "lo_close failed");
3546
3904
 
3547
3905
  return Qnil;
3548
3906
  }
@@ -3560,20 +3918,21 @@ pgconn_lounlink(VALUE self, VALUE in_oid)
3560
3918
  Oid oid = NUM2UINT(in_oid);
3561
3919
 
3562
3920
  if(lo_unlink(conn,oid) < 0)
3563
- rb_raise(rb_ePGerror,"lo_unlink failed");
3921
+ pg_raise_conn_error( rb_ePGerror, self, "lo_unlink failed");
3564
3922
 
3565
3923
  return Qnil;
3566
3924
  }
3567
3925
 
3568
3926
 
3569
- #ifdef M17N_SUPPORTED
3570
-
3571
- void
3927
+ static void
3572
3928
  pgconn_set_internal_encoding_index( VALUE self )
3573
3929
  {
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));
3930
+ int enc_idx;
3931
+ t_pg_connection *this = pg_get_connection_safe( self );
3932
+ rb_encoding *enc = pg_conn_enc_get( this->pgconn );
3933
+ enc_idx = rb_enc_to_index(enc);
3934
+ if( enc_idx >= (1<<(PG_ENC_IDX_BITS-1)) ) rb_raise(rb_eArgError, "unsupported encoding index %d", enc_idx);
3935
+ this->enc_idx = enc_idx;
3577
3936
  }
3578
3937
 
3579
3938
  /*
@@ -3616,13 +3975,12 @@ static VALUE pgconn_external_encoding(VALUE self);
3616
3975
  static VALUE
3617
3976
  pgconn_internal_encoding_set(VALUE self, VALUE enc)
3618
3977
  {
3619
- VALUE enc_inspect;
3620
3978
  if (NIL_P(enc)) {
3621
- pgconn_set_client_encoding( self, rb_usascii_str_new_cstr("SQL_ASCII") );
3979
+ pgconn_sync_set_client_encoding( self, rb_usascii_str_new_cstr("SQL_ASCII") );
3622
3980
  return enc;
3623
3981
  }
3624
3982
  else if ( TYPE(enc) == T_STRING && strcasecmp("JOHAB", StringValueCStr(enc)) == 0 ) {
3625
- pgconn_set_client_encoding(self, rb_usascii_str_new_cstr("JOHAB"));
3983
+ pgconn_sync_set_client_encoding(self, rb_usascii_str_new_cstr("JOHAB"));
3626
3984
  return enc;
3627
3985
  }
3628
3986
  else {
@@ -3637,11 +3995,6 @@ pgconn_internal_encoding_set(VALUE self, VALUE enc)
3637
3995
  pgconn_set_internal_encoding_index( self );
3638
3996
  return enc;
3639
3997
  }
3640
-
3641
- enc_inspect = rb_inspect(enc);
3642
- rb_raise( rb_ePGerror, "unknown encoding: %s", StringValueCStr(enc_inspect) );
3643
-
3644
- return Qnil;
3645
3998
  }
3646
3999
 
3647
4000
 
@@ -3660,42 +4013,55 @@ pgconn_external_encoding(VALUE self)
3660
4013
  rb_encoding *enc = NULL;
3661
4014
  const char *pg_encname = NULL;
3662
4015
 
3663
- /* Use cached value if found */
3664
- if ( RTEST(this->external_encoding) ) return this->external_encoding;
3665
-
3666
4016
  pg_encname = PQparameterStatus( this->pgconn, "server_encoding" );
3667
4017
  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;
4018
+ return rb_enc_from_encoding( enc );
3671
4019
  }
3672
4020
 
4021
+ /*
4022
+ * call-seq:
4023
+ * conn.set_client_encoding( encoding )
4024
+ *
4025
+ * Sets the client encoding to the _encoding_ String.
4026
+ */
4027
+ static VALUE
4028
+ pgconn_async_set_client_encoding(VALUE self, VALUE encname)
4029
+ {
4030
+ VALUE query_format, query;
4031
+
4032
+ Check_Type(encname, T_STRING);
4033
+ query_format = rb_str_new_cstr("set client_encoding to '%s'");
4034
+ query = rb_funcall(query_format, rb_intern("%"), 1, encname);
4035
+
4036
+ pgconn_async_exec(1, &query, self);
4037
+ pgconn_set_internal_encoding_index( self );
4038
+
4039
+ return Qnil;
4040
+ }
3673
4041
 
3674
4042
  static VALUE
3675
4043
  pgconn_set_client_encoding_async1( VALUE args )
3676
4044
  {
3677
4045
  VALUE self = ((VALUE*)args)[0];
3678
4046
  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);
4047
+ pgconn_async_set_client_encoding(self, encname);
3683
4048
  return 0;
3684
4049
  }
3685
4050
 
3686
4051
 
3687
4052
  static VALUE
3688
- pgconn_set_client_encoding_async2( VALUE arg )
4053
+ pgconn_set_client_encoding_async2( VALUE arg, VALUE ex )
3689
4054
  {
3690
4055
  UNUSED(arg);
4056
+ UNUSED(ex);
3691
4057
  return 1;
3692
4058
  }
3693
4059
 
3694
4060
 
3695
4061
  static VALUE
3696
- pgconn_set_client_encoding_async( VALUE self, const char *encname )
4062
+ pgconn_set_client_encoding_async( VALUE self, VALUE encname )
3697
4063
  {
3698
- VALUE args[] = { self, rb_str_new_cstr(encname) };
4064
+ VALUE args[] = { self, encname };
3699
4065
  return rb_rescue(pgconn_set_client_encoding_async1, (VALUE)&args, pgconn_set_client_encoding_async2, Qnil);
3700
4066
  }
3701
4067
 
@@ -3717,10 +4083,9 @@ pgconn_set_default_encoding( VALUE self )
3717
4083
 
3718
4084
  if (( enc = rb_default_internal_encoding() )) {
3719
4085
  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'",
4086
+ if ( pgconn_set_client_encoding_async(self, rb_str_new_cstr(encname)) != 0 )
4087
+ rb_warning( "Failed to set the default_internal encoding to %s: '%s'",
3722
4088
  encname, PQerrorMessage(conn) );
3723
- pgconn_set_internal_encoding_index( self );
3724
4089
  return rb_enc_from_encoding( enc );
3725
4090
  } else {
3726
4091
  pgconn_set_internal_encoding_index( self );
@@ -3729,8 +4094,6 @@ pgconn_set_default_encoding( VALUE self )
3729
4094
  }
3730
4095
 
3731
4096
 
3732
- #endif /* M17N_SUPPORTED */
3733
-
3734
4097
  /*
3735
4098
  * call-seq:
3736
4099
  * res.type_map_for_queries = typemap
@@ -3744,12 +4107,12 @@ static VALUE
3744
4107
  pgconn_type_map_for_queries_set(VALUE self, VALUE typemap)
3745
4108
  {
3746
4109
  t_pg_connection *this = pg_get_connection( self );
4110
+ t_typemap *tm;
4111
+ UNUSED(tm);
4112
+
4113
+ /* Check type of method param */
4114
+ TypedData_Get_Struct(typemap, t_typemap, &pg_typemap_type, tm);
3747
4115
 
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
4116
  this->type_map_for_queries = typemap;
3754
4117
 
3755
4118
  return typemap;
@@ -3784,12 +4147,10 @@ static VALUE
3784
4147
  pgconn_type_map_for_results_set(VALUE self, VALUE typemap)
3785
4148
  {
3786
4149
  t_pg_connection *this = pg_get_connection( self );
4150
+ t_typemap *tm;
4151
+ UNUSED(tm);
3787
4152
 
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);
4153
+ TypedData_Get_Struct(typemap, t_typemap, &pg_typemap_type, tm);
3793
4154
  this->type_map_for_results = typemap;
3794
4155
 
3795
4156
  return typemap;
@@ -3824,20 +4185,19 @@ pgconn_type_map_for_results_get(VALUE self)
3824
4185
  *
3825
4186
  */
3826
4187
  static VALUE
3827
- pgconn_encoder_for_put_copy_data_set(VALUE self, VALUE typemap)
4188
+ pgconn_encoder_for_put_copy_data_set(VALUE self, VALUE encoder)
3828
4189
  {
3829
4190
  t_pg_connection *this = pg_get_connection( self );
3830
4191
 
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);
4192
+ if( encoder != Qnil ){
4193
+ t_pg_coder *co;
4194
+ UNUSED(co);
4195
+ /* Check argument type */
4196
+ TypedData_Get_Struct(encoder, t_pg_coder, &pg_coder_type, co);
3837
4197
  }
3838
- this->encoder_for_put_copy_data = typemap;
4198
+ this->encoder_for_put_copy_data = encoder;
3839
4199
 
3840
- return typemap;
4200
+ return encoder;
3841
4201
  }
3842
4202
 
3843
4203
  /*
@@ -3873,20 +4233,19 @@ pgconn_encoder_for_put_copy_data_get(VALUE self)
3873
4233
  *
3874
4234
  */
3875
4235
  static VALUE
3876
- pgconn_decoder_for_get_copy_data_set(VALUE self, VALUE typemap)
4236
+ pgconn_decoder_for_get_copy_data_set(VALUE self, VALUE decoder)
3877
4237
  {
3878
4238
  t_pg_connection *this = pg_get_connection( self );
3879
4239
 
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);
4240
+ if( decoder != Qnil ){
4241
+ t_pg_coder *co;
4242
+ UNUSED(co);
4243
+ /* Check argument type */
4244
+ TypedData_Get_Struct(decoder, t_pg_coder, &pg_coder_type, co);
3886
4245
  }
3887
- this->decoder_for_get_copy_data = typemap;
4246
+ this->decoder_for_get_copy_data = decoder;
3888
4247
 
3889
- return typemap;
4248
+ return decoder;
3890
4249
  }
3891
4250
 
3892
4251
  /*
@@ -3909,28 +4268,82 @@ pgconn_decoder_for_get_copy_data_get(VALUE self)
3909
4268
  return this->decoder_for_get_copy_data;
3910
4269
  }
3911
4270
 
4271
+ /*
4272
+ * call-seq:
4273
+ * conn.field_name_type = Symbol
4274
+ *
4275
+ * Set default type of field names of results retrieved by this connection.
4276
+ * It can be set to one of:
4277
+ * * +:string+ to use String based field names
4278
+ * * +:symbol+ to use Symbol based field names
4279
+ *
4280
+ * The default is +:string+ .
4281
+ *
4282
+ * Settings the type of field names affects only future results.
4283
+ *
4284
+ * See further description at PG::Result#field_name_type=
4285
+ *
4286
+ */
4287
+ static VALUE
4288
+ pgconn_field_name_type_set(VALUE self, VALUE sym)
4289
+ {
4290
+ t_pg_connection *this = pg_get_connection( self );
4291
+
4292
+ this->flags &= ~PG_RESULT_FIELD_NAMES_MASK;
4293
+ if( sym == sym_symbol ) this->flags |= PG_RESULT_FIELD_NAMES_SYMBOL;
4294
+ else if ( sym == sym_static_symbol ) this->flags |= PG_RESULT_FIELD_NAMES_STATIC_SYMBOL;
4295
+ else if ( sym == sym_string );
4296
+ else rb_raise(rb_eArgError, "invalid argument %+"PRIsVALUE, sym);
4297
+
4298
+ return sym;
4299
+ }
4300
+
4301
+ /*
4302
+ * call-seq:
4303
+ * conn.field_name_type -> Symbol
4304
+ *
4305
+ * Get type of field names.
4306
+ *
4307
+ * See description at #field_name_type=
4308
+ */
4309
+ static VALUE
4310
+ pgconn_field_name_type_get(VALUE self)
4311
+ {
4312
+ t_pg_connection *this = pg_get_connection( self );
4313
+
4314
+ if( this->flags & PG_RESULT_FIELD_NAMES_SYMBOL ){
4315
+ return sym_symbol;
4316
+ } else if( this->flags & PG_RESULT_FIELD_NAMES_STATIC_SYMBOL ){
4317
+ return sym_static_symbol;
4318
+ } else {
4319
+ return sym_string;
4320
+ }
4321
+ }
4322
+
3912
4323
 
3913
4324
  /*
3914
4325
  * Document-class: PG::Connection
3915
4326
  */
3916
4327
  void
3917
- init_pg_connection()
4328
+ init_pg_connection(void)
3918
4329
  {
3919
4330
  s_id_encode = rb_intern("encode");
4331
+ s_id_autoclose_set = rb_intern("autoclose=");
3920
4332
  sym_type = ID2SYM(rb_intern("type"));
3921
4333
  sym_format = ID2SYM(rb_intern("format"));
3922
4334
  sym_value = ID2SYM(rb_intern("value"));
4335
+ sym_string = ID2SYM(rb_intern("string"));
4336
+ sym_symbol = ID2SYM(rb_intern("symbol"));
4337
+ sym_static_symbol = ID2SYM(rb_intern("static_symbol"));
3923
4338
 
3924
4339
  rb_cPGconn = rb_define_class_under( rb_mPG, "Connection", rb_cObject );
4340
+ /* Help rdoc to known the Constants module */
4341
+ /* rb_mPGconstants = rb_define_module_under( rb_mPG, "Constants" ); */
3925
4342
  rb_include_module(rb_cPGconn, rb_mPGconstants);
3926
4343
 
3927
4344
  /****** PG::Connection CLASS METHODS ******/
3928
4345
  rb_define_alloc_func( rb_cPGconn, pgconn_s_allocate );
3929
4346
 
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
4347
  rb_define_singleton_method(rb_cPGconn, "escape_string", pgconn_s_escape, 1);
3935
4348
  SINGLETON_ALIAS(rb_cPGconn, "escape", "escape_string");
3936
4349
  rb_define_singleton_method(rb_cPGconn, "escape_bytea", pgconn_s_escape_bytea, 1);
@@ -3939,16 +4352,15 @@ init_pg_connection()
3939
4352
  rb_define_singleton_method(rb_cPGconn, "quote_ident", pgconn_s_quote_ident, 1);
3940
4353
  rb_define_singleton_method(rb_cPGconn, "connect_start", pgconn_s_connect_start, -1);
3941
4354
  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
4355
+ rb_define_singleton_method(rb_cPGconn, "conninfo_parse", pgconn_s_conninfo_parse, 1);
4356
+ rb_define_singleton_method(rb_cPGconn, "sync_ping", pgconn_s_sync_ping, -1);
4357
+ rb_define_singleton_method(rb_cPGconn, "sync_connect", pgconn_s_sync_connect, -1);
3945
4358
 
3946
4359
  /****** PG::Connection INSTANCE METHODS: Connection Control ******/
3947
- rb_define_method(rb_cPGconn, "initialize", pgconn_init, -1);
3948
4360
  rb_define_method(rb_cPGconn, "connect_poll", pgconn_connect_poll, 0);
3949
4361
  rb_define_method(rb_cPGconn, "finish", pgconn_finish, 0);
3950
4362
  rb_define_method(rb_cPGconn, "finished?", pgconn_finished_p, 0);
3951
- rb_define_method(rb_cPGconn, "reset", pgconn_reset, 0);
4363
+ rb_define_method(rb_cPGconn, "sync_reset", pgconn_sync_reset, 0);
3952
4364
  rb_define_method(rb_cPGconn, "reset_start", pgconn_reset_start, 0);
3953
4365
  rb_define_method(rb_cPGconn, "reset_poll", pgconn_reset_poll, 0);
3954
4366
  rb_define_alias(rb_cPGconn, "close", "finish");
@@ -3958,11 +4370,12 @@ init_pg_connection()
3958
4370
  rb_define_method(rb_cPGconn, "user", pgconn_user, 0);
3959
4371
  rb_define_method(rb_cPGconn, "pass", pgconn_pass, 0);
3960
4372
  rb_define_method(rb_cPGconn, "host", pgconn_host, 0);
4373
+ #if defined(HAVE_PQRESULTMEMORYSIZE)
4374
+ rb_define_method(rb_cPGconn, "hostaddr", pgconn_hostaddr, 0);
4375
+ #endif
3961
4376
  rb_define_method(rb_cPGconn, "port", pgconn_port, 0);
3962
4377
  rb_define_method(rb_cPGconn, "tty", pgconn_tty, 0);
3963
- #ifdef HAVE_PQCONNINFO
3964
4378
  rb_define_method(rb_cPGconn, "conninfo", pgconn_conninfo, 0);
3965
- #endif
3966
4379
  rb_define_method(rb_cPGconn, "options", pgconn_options, 0);
3967
4380
  rb_define_method(rb_cPGconn, "status", pgconn_status, 0);
3968
4381
  rb_define_method(rb_cPGconn, "transaction_status", pgconn_transaction_status, 0);
@@ -3971,64 +4384,78 @@ init_pg_connection()
3971
4384
  rb_define_method(rb_cPGconn, "server_version", pgconn_server_version, 0);
3972
4385
  rb_define_method(rb_cPGconn, "error_message", pgconn_error_message, 0);
3973
4386
  rb_define_method(rb_cPGconn, "socket", pgconn_socket, 0);
3974
- #if !defined(_WIN32) || defined(HAVE_RB_W32_WRAP_IO_HANDLE)
3975
4387
  rb_define_method(rb_cPGconn, "socket_io", pgconn_socket_io, 0);
3976
- #endif
3977
4388
  rb_define_method(rb_cPGconn, "backend_pid", pgconn_backend_pid, 0);
4389
+ rb_define_method(rb_cPGconn, "backend_key", pgconn_backend_key, 0);
3978
4390
  rb_define_method(rb_cPGconn, "connection_needs_password", pgconn_connection_needs_password, 0);
3979
4391
  rb_define_method(rb_cPGconn, "connection_used_password", pgconn_connection_used_password, 0);
3980
4392
  /* rb_define_method(rb_cPGconn, "getssl", pgconn_getssl, 0); */
3981
4393
 
3982
4394
  /****** 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);
4395
+ rb_define_method(rb_cPGconn, "sync_exec", pgconn_sync_exec, -1);
4396
+ rb_define_method(rb_cPGconn, "sync_exec_params", pgconn_sync_exec_params, -1);
4397
+ rb_define_method(rb_cPGconn, "sync_prepare", pgconn_sync_prepare, -1);
4398
+ rb_define_method(rb_cPGconn, "sync_exec_prepared", pgconn_sync_exec_prepared, -1);
4399
+ rb_define_method(rb_cPGconn, "sync_describe_prepared", pgconn_sync_describe_prepared, 1);
4400
+ rb_define_method(rb_cPGconn, "sync_describe_portal", pgconn_sync_describe_portal, 1);
4401
+
4402
+ rb_define_method(rb_cPGconn, "exec", pgconn_async_exec, -1);
4403
+ rb_define_method(rb_cPGconn, "exec_params", pgconn_async_exec_params, -1);
4404
+ rb_define_method(rb_cPGconn, "prepare", pgconn_async_prepare, -1);
4405
+ rb_define_method(rb_cPGconn, "exec_prepared", pgconn_async_exec_prepared, -1);
4406
+ rb_define_method(rb_cPGconn, "describe_prepared", pgconn_async_describe_prepared, 1);
4407
+ rb_define_method(rb_cPGconn, "describe_portal", pgconn_async_describe_portal, 1);
4408
+
4409
+ rb_define_alias(rb_cPGconn, "async_exec", "exec");
4410
+ rb_define_alias(rb_cPGconn, "async_query", "async_exec");
4411
+ rb_define_alias(rb_cPGconn, "async_exec_params", "exec_params");
4412
+ rb_define_alias(rb_cPGconn, "async_prepare", "prepare");
4413
+ rb_define_alias(rb_cPGconn, "async_exec_prepared", "exec_prepared");
4414
+ rb_define_alias(rb_cPGconn, "async_describe_prepared", "describe_prepared");
4415
+ rb_define_alias(rb_cPGconn, "async_describe_portal", "describe_portal");
4416
+
3990
4417
  rb_define_method(rb_cPGconn, "make_empty_pgresult", pgconn_make_empty_pgresult, 1);
3991
4418
  rb_define_method(rb_cPGconn, "escape_string", pgconn_s_escape, 1);
3992
4419
  rb_define_alias(rb_cPGconn, "escape", "escape_string");
3993
- #ifdef HAVE_PQESCAPELITERAL
3994
4420
  rb_define_method(rb_cPGconn, "escape_literal", pgconn_escape_literal, 1);
3995
- #endif
3996
- #ifdef HAVE_PQESCAPEIDENTIFIER
3997
4421
  rb_define_method(rb_cPGconn, "escape_identifier", pgconn_escape_identifier, 1);
3998
- #endif
3999
4422
  rb_define_method(rb_cPGconn, "escape_bytea", pgconn_s_escape_bytea, 1);
4000
4423
  rb_define_method(rb_cPGconn, "unescape_bytea", pgconn_s_unescape_bytea, 1);
4001
- #ifdef HAVE_PQSETSINGLEROWMODE
4002
4424
  rb_define_method(rb_cPGconn, "set_single_row_mode", pgconn_set_single_row_mode, 0);
4003
- #endif
4004
4425
 
4005
4426
  /****** PG::Connection INSTANCE METHODS: Asynchronous Command Processing ******/
4006
4427
  rb_define_method(rb_cPGconn, "send_query", pgconn_send_query, -1);
4428
+ rb_define_method(rb_cPGconn, "send_query_params", pgconn_send_query_params, -1);
4007
4429
  rb_define_method(rb_cPGconn, "send_prepare", pgconn_send_prepare, -1);
4008
4430
  rb_define_method(rb_cPGconn, "send_query_prepared", pgconn_send_query_prepared, -1);
4009
4431
  rb_define_method(rb_cPGconn, "send_describe_prepared", pgconn_send_describe_prepared, 1);
4010
4432
  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);
4433
+ rb_define_method(rb_cPGconn, "sync_get_result", pgconn_sync_get_result, 0);
4012
4434
  rb_define_method(rb_cPGconn, "consume_input", pgconn_consume_input, 0);
4013
4435
  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);
4436
+ rb_define_method(rb_cPGconn, "sync_setnonblocking", pgconn_sync_setnonblocking, 1);
4437
+ rb_define_method(rb_cPGconn, "sync_isnonblocking", pgconn_sync_isnonblocking, 0);
4438
+ rb_define_method(rb_cPGconn, "sync_flush", pgconn_sync_flush, 0);
4439
+ rb_define_method(rb_cPGconn, "flush", pgconn_async_flush, 0);
4440
+ rb_define_alias(rb_cPGconn, "async_flush", "flush");
4441
+ rb_define_method(rb_cPGconn, "discard_results", pgconn_discard_results, 0);
4018
4442
 
4019
4443
  /****** PG::Connection INSTANCE METHODS: Cancelling Queries in Progress ******/
4020
- rb_define_method(rb_cPGconn, "cancel", pgconn_cancel, 0);
4444
+ rb_define_method(rb_cPGconn, "sync_cancel", pgconn_sync_cancel, 0);
4021
4445
 
4022
4446
  /****** PG::Connection INSTANCE METHODS: NOTIFY ******/
4023
4447
  rb_define_method(rb_cPGconn, "notifies", pgconn_notifies, 0);
4024
4448
 
4025
4449
  /****** 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);
4450
+ rb_define_method(rb_cPGconn, "sync_put_copy_data", pgconn_sync_put_copy_data, -1);
4451
+ rb_define_method(rb_cPGconn, "sync_put_copy_end", pgconn_sync_put_copy_end, -1);
4452
+ rb_define_method(rb_cPGconn, "sync_get_copy_data", pgconn_sync_get_copy_data, -1);
4029
4453
 
4030
4454
  /****** PG::Connection INSTANCE METHODS: Control Functions ******/
4031
4455
  rb_define_method(rb_cPGconn, "set_error_verbosity", pgconn_set_error_verbosity, 1);
4456
+ #ifdef HAVE_PQRESULTVERBOSEERRORMESSAGE
4457
+ rb_define_method(rb_cPGconn, "set_error_context_visibility", pgconn_set_error_context_visibility, 1 );
4458
+ #endif
4032
4459
  rb_define_method(rb_cPGconn, "trace", pgconn_trace, 1);
4033
4460
  rb_define_method(rb_cPGconn, "untrace", pgconn_untrace, 0);
4034
4461
 
@@ -4038,16 +4465,21 @@ init_pg_connection()
4038
4465
 
4039
4466
  /****** PG::Connection INSTANCE METHODS: Other ******/
4040
4467
  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);
4468
+ rb_define_method(rb_cPGconn, "sync_set_client_encoding", pgconn_sync_set_client_encoding, 1);
4469
+ rb_define_method(rb_cPGconn, "set_client_encoding", pgconn_async_set_client_encoding, 1);
4470
+ rb_define_alias(rb_cPGconn, "async_set_client_encoding", "set_client_encoding");
4042
4471
  rb_define_alias(rb_cPGconn, "client_encoding=", "set_client_encoding");
4043
- rb_define_method(rb_cPGconn, "transaction", pgconn_transaction, 0);
4044
4472
  rb_define_method(rb_cPGconn, "block", pgconn_block, -1);
4473
+ rb_define_private_method(rb_cPGconn, "flush_data=", pgconn_flush_data_set, 1);
4045
4474
  rb_define_method(rb_cPGconn, "wait_for_notify", pgconn_wait_for_notify, -1);
4046
4475
  rb_define_alias(rb_cPGconn, "notifies_wait", "wait_for_notify");
4047
4476
  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);
4477
+ rb_define_method(rb_cPGconn, "sync_get_last_result", pgconn_sync_get_last_result, 0);
4478
+ rb_define_method(rb_cPGconn, "get_last_result", pgconn_async_get_last_result, 0);
4479
+ rb_define_alias(rb_cPGconn, "async_get_last_result", "get_last_result");
4480
+ #ifdef HAVE_PQENCRYPTPASSWORDCONN
4481
+ rb_define_method(rb_cPGconn, "sync_encrypt_password", pgconn_sync_encrypt_password, -1);
4482
+ #endif
4051
4483
 
4052
4484
  #ifdef HAVE_PQSSLATTRIBUTE
4053
4485
  rb_define_method(rb_cPGconn, "ssl_in_use?", pgconn_ssl_in_use, 0);
@@ -4055,6 +4487,14 @@ init_pg_connection()
4055
4487
  rb_define_method(rb_cPGconn, "ssl_attribute_names", pgconn_ssl_attribute_names, 0);
4056
4488
  #endif
4057
4489
 
4490
+ #ifdef HAVE_PQENTERPIPELINEMODE
4491
+ rb_define_method(rb_cPGconn, "pipeline_status", pgconn_pipeline_status, 0);
4492
+ rb_define_method(rb_cPGconn, "enter_pipeline_mode", pgconn_enter_pipeline_mode, 0);
4493
+ rb_define_method(rb_cPGconn, "exit_pipeline_mode", pgconn_exit_pipeline_mode, 0);
4494
+ rb_define_method(rb_cPGconn, "pipeline_sync", pgconn_pipeline_sync, 0);
4495
+ rb_define_method(rb_cPGconn, "send_flush_request", pgconn_send_flush_request, 0);
4496
+ #endif
4497
+
4058
4498
  /****** PG::Connection INSTANCE METHODS: Large Object Support ******/
4059
4499
  rb_define_method(rb_cPGconn, "lo_creat", pgconn_locreat, -1);
4060
4500
  rb_define_alias(rb_cPGconn, "locreat", "lo_creat");
@@ -4083,12 +4523,10 @@ init_pg_connection()
4083
4523
  rb_define_method(rb_cPGconn, "lo_unlink", pgconn_lounlink, 1);
4084
4524
  rb_define_alias(rb_cPGconn, "lounlink", "lo_unlink");
4085
4525
 
4086
- #ifdef M17N_SUPPORTED
4087
4526
  rb_define_method(rb_cPGconn, "internal_encoding", pgconn_internal_encoding, 0);
4088
4527
  rb_define_method(rb_cPGconn, "internal_encoding=", pgconn_internal_encoding_set, 1);
4089
4528
  rb_define_method(rb_cPGconn, "external_encoding", pgconn_external_encoding, 0);
4090
4529
  rb_define_method(rb_cPGconn, "set_default_encoding", pgconn_set_default_encoding, 0);
4091
- #endif /* M17N_SUPPORTED */
4092
4530
 
4093
4531
  rb_define_method(rb_cPGconn, "type_map_for_queries=", pgconn_type_map_for_queries_set, 1);
4094
4532
  rb_define_method(rb_cPGconn, "type_map_for_queries", pgconn_type_map_for_queries_get, 0);
@@ -4098,5 +4536,7 @@ init_pg_connection()
4098
4536
  rb_define_method(rb_cPGconn, "encoder_for_put_copy_data", pgconn_encoder_for_put_copy_data_get, 0);
4099
4537
  rb_define_method(rb_cPGconn, "decoder_for_get_copy_data=", pgconn_decoder_for_get_copy_data_set, 1);
4100
4538
  rb_define_method(rb_cPGconn, "decoder_for_get_copy_data", pgconn_decoder_for_get_copy_data_get, 0);
4101
- }
4102
4539
 
4540
+ rb_define_method(rb_cPGconn, "field_name_type=", pgconn_field_name_type_set, 1 );
4541
+ rb_define_method(rb_cPGconn, "field_name_type", pgconn_field_name_type_get, 0 );
4542
+ }