pg 0.18.2 → 1.5.4

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