pg 0.15.1 → 1.2.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (86) hide show
  1. checksums.yaml +5 -5
  2. checksums.yaml.gz.sig +0 -0
  3. data.tar.gz.sig +0 -0
  4. data/BSDL +2 -2
  5. data/ChangeLog +0 -3022
  6. data/History.rdoc +370 -4
  7. data/Manifest.txt +39 -19
  8. data/README-Windows.rdoc +17 -28
  9. data/README.ja.rdoc +1 -2
  10. data/README.rdoc +113 -14
  11. data/Rakefile +97 -36
  12. data/Rakefile.cross +109 -83
  13. data/ext/errorcodes.def +1032 -0
  14. data/ext/errorcodes.rb +45 -0
  15. data/ext/errorcodes.txt +494 -0
  16. data/ext/extconf.rb +55 -52
  17. data/ext/gvl_wrappers.c +4 -0
  18. data/ext/gvl_wrappers.h +94 -38
  19. data/ext/pg.c +273 -121
  20. data/ext/pg.h +292 -50
  21. data/ext/pg_binary_decoder.c +229 -0
  22. data/ext/pg_binary_encoder.c +163 -0
  23. data/ext/pg_coder.c +561 -0
  24. data/ext/pg_connection.c +1811 -1051
  25. data/ext/pg_copy_coder.c +599 -0
  26. data/ext/pg_errors.c +95 -0
  27. data/ext/pg_record_coder.c +491 -0
  28. data/ext/pg_result.c +917 -203
  29. data/ext/pg_text_decoder.c +987 -0
  30. data/ext/pg_text_encoder.c +814 -0
  31. data/ext/pg_tuple.c +549 -0
  32. data/ext/pg_type_map.c +166 -0
  33. data/ext/pg_type_map_all_strings.c +116 -0
  34. data/ext/pg_type_map_by_class.c +244 -0
  35. data/ext/pg_type_map_by_column.c +313 -0
  36. data/ext/pg_type_map_by_mri_type.c +284 -0
  37. data/ext/pg_type_map_by_oid.c +356 -0
  38. data/ext/pg_type_map_in_ruby.c +299 -0
  39. data/ext/pg_util.c +149 -0
  40. data/ext/pg_util.h +65 -0
  41. data/lib/pg.rb +31 -9
  42. data/lib/pg/basic_type_mapping.rb +522 -0
  43. data/lib/pg/binary_decoder.rb +23 -0
  44. data/lib/pg/coder.rb +104 -0
  45. data/lib/pg/connection.rb +235 -30
  46. data/lib/pg/constants.rb +2 -1
  47. data/lib/pg/exceptions.rb +2 -1
  48. data/lib/pg/result.rb +33 -6
  49. data/lib/pg/text_decoder.rb +46 -0
  50. data/lib/pg/text_encoder.rb +59 -0
  51. data/lib/pg/tuple.rb +30 -0
  52. data/lib/pg/type_map_by_column.rb +16 -0
  53. data/spec/{lib/helpers.rb → helpers.rb} +154 -52
  54. data/spec/pg/basic_type_mapping_spec.rb +630 -0
  55. data/spec/pg/connection_spec.rb +1352 -426
  56. data/spec/pg/connection_sync_spec.rb +41 -0
  57. data/spec/pg/result_spec.rb +508 -105
  58. data/spec/pg/tuple_spec.rb +333 -0
  59. data/spec/pg/type_map_by_class_spec.rb +138 -0
  60. data/spec/pg/type_map_by_column_spec.rb +226 -0
  61. data/spec/pg/type_map_by_mri_type_spec.rb +136 -0
  62. data/spec/pg/type_map_by_oid_spec.rb +149 -0
  63. data/spec/pg/type_map_in_ruby_spec.rb +164 -0
  64. data/spec/pg/type_map_spec.rb +22 -0
  65. data/spec/pg/type_spec.rb +1123 -0
  66. data/spec/pg_spec.rb +35 -16
  67. metadata +163 -84
  68. metadata.gz.sig +0 -0
  69. data/sample/array_insert.rb +0 -20
  70. data/sample/async_api.rb +0 -106
  71. data/sample/async_copyto.rb +0 -39
  72. data/sample/async_mixed.rb +0 -56
  73. data/sample/check_conn.rb +0 -21
  74. data/sample/copyfrom.rb +0 -81
  75. data/sample/copyto.rb +0 -19
  76. data/sample/cursor.rb +0 -21
  77. data/sample/disk_usage_report.rb +0 -186
  78. data/sample/issue-119.rb +0 -94
  79. data/sample/losample.rb +0 -69
  80. data/sample/minimal-testcase.rb +0 -17
  81. data/sample/notify_wait.rb +0 -72
  82. data/sample/pg_statistics.rb +0 -294
  83. data/sample/replication_monitor.rb +0 -231
  84. data/sample/test_binary_values.rb +0 -33
  85. data/sample/wal_shipper.rb +0 -434
  86. data/sample/warehouse_partitions.rb +0 -320
data/ext/pg_connection.c CHANGED
@@ -1,91 +1,160 @@
1
1
  /*
2
2
  * pg_connection.c - PG::Connection class extension
3
- * $Id: pg_connection.c,v 4514df7221a8 2013/04/08 18:09:43 ged $
3
+ * $Id$
4
4
  *
5
5
  */
6
6
 
7
7
  #include "pg.h"
8
8
 
9
+ /* Number of bytes that are reserved on the stack for query params. */
10
+ #define QUERYDATA_BUFFER_SIZE 4000
11
+
9
12
 
10
13
  VALUE rb_cPGconn;
14
+ static ID s_id_encode;
15
+ static VALUE sym_type, sym_format, sym_value;
16
+ static VALUE sym_symbol, sym_string, sym_static_symbol;
11
17
 
12
18
  static PQnoticeReceiver default_notice_receiver = NULL;
13
19
  static PQnoticeProcessor default_notice_processor = NULL;
14
20
 
15
- static PGconn *pgconn_check( VALUE );
16
21
  static VALUE pgconn_finish( VALUE );
17
- #ifdef M17N_SUPPORTED
18
22
  static VALUE pgconn_set_default_encoding( VALUE self );
19
- #endif
20
-
21
- #ifndef HAVE_RB_THREAD_FD_SELECT
22
- #define rb_fdset_t fd_set
23
- #define rb_fd_init(f)
24
- #define rb_fd_zero(f) FD_ZERO(f)
25
- #define rb_fd_set(n, f) FD_SET(n, f)
26
- #define rb_fd_term(f)
27
- #define rb_thread_fd_select rb_thread_select
28
- #endif
23
+ static void pgconn_set_internal_encoding_index( VALUE );
29
24
 
30
25
  /*
31
26
  * Global functions
32
27
  */
33
28
 
34
29
  /*
35
- * Fetch the data pointer and check it for sanity.
30
+ * Fetch the PG::Connection object data pointer.
31
+ */
32
+ t_pg_connection *
33
+ pg_get_connection( VALUE self )
34
+ {
35
+ t_pg_connection *this;
36
+ Data_Get_Struct( self, t_pg_connection, this);
37
+
38
+ return this;
39
+ }
40
+
41
+ /*
42
+ * Fetch the PG::Connection object data pointer and check it's
43
+ * PGconn data pointer for sanity.
44
+ */
45
+ static t_pg_connection *
46
+ pg_get_connection_safe( VALUE self )
47
+ {
48
+ t_pg_connection *this;
49
+ Data_Get_Struct( self, t_pg_connection, this);
50
+
51
+ if ( !this->pgconn )
52
+ rb_raise( rb_eConnectionBad, "connection is closed" );
53
+
54
+ return this;
55
+ }
56
+
57
+ /*
58
+ * Fetch the PGconn data pointer and check it for sanity.
59
+ *
60
+ * Note: This function is used externally by the sequel_pg gem,
61
+ * so do changes carefully.
62
+ *
36
63
  */
37
64
  PGconn *
38
65
  pg_get_pgconn( VALUE self )
39
66
  {
40
- PGconn *conn = pgconn_check( self );
67
+ t_pg_connection *this;
68
+ Data_Get_Struct( self, t_pg_connection, this);
41
69
 
42
- if ( !conn )
43
- rb_raise( rb_ePGerror, "connection is closed" );
70
+ if ( !this->pgconn )
71
+ rb_raise( rb_eConnectionBad, "connection is closed" );
44
72
 
45
- return conn;
73
+ return this->pgconn;
46
74
  }
47
75
 
48
76
 
77
+
49
78
  /*
50
79
  * Close the associated socket IO object if there is one.
51
80
  */
52
- void
81
+ static void
53
82
  pgconn_close_socket_io( VALUE self )
54
83
  {
55
- VALUE socket_io = rb_iv_get( self, "@socket_io" );
84
+ t_pg_connection *this = pg_get_connection( self );
85
+ VALUE socket_io = this->socket_io;
56
86
 
57
87
  if ( RTEST(socket_io) ) {
58
- #if defined(_WIN32) && defined(HAVE_RB_W32_WRAP_IO_HANDLE)
59
- int ruby_sd = NUM2INT(rb_funcall( socket_io, rb_intern("fileno"), 0 ));
60
- if( rb_w32_unwrap_io_handle(ruby_sd) ){
61
- rb_raise(rb_ePGerror, "Could not unwrap win32 socket handle");
88
+ #if defined(_WIN32)
89
+ if( rb_w32_unwrap_io_handle(this->ruby_sd) ){
90
+ rb_raise(rb_eConnectionBad, "Could not unwrap win32 socket handle");
62
91
  }
63
92
  #endif
64
93
  rb_funcall( socket_io, rb_intern("close"), 0 );
65
94
  }
66
95
 
67
- rb_iv_set( self, "@socket_io", Qnil );
96
+ this->socket_io = Qnil;
68
97
  }
69
98
 
70
99
 
71
100
  /*
72
- * Allocation/
101
+ * Create a Ruby Array of Hashes out of a PGconninfoOptions array.
73
102
  */
103
+ static VALUE
104
+ pgconn_make_conninfo_array( const PQconninfoOption *options )
105
+ {
106
+ VALUE ary = rb_ary_new();
107
+ VALUE hash;
108
+ int i = 0;
74
109
 
75
- /*
76
- * Object validity checker. Returns the data pointer.
77
- */
78
- static PGconn *
79
- pgconn_check( VALUE self ) {
110
+ if (!options) return Qnil;
111
+
112
+ for(i = 0; options[i].keyword != NULL; i++) {
113
+ hash = rb_hash_new();
114
+ if(options[i].keyword)
115
+ rb_hash_aset(hash, ID2SYM(rb_intern("keyword")), rb_str_new2(options[i].keyword));
116
+ if(options[i].envvar)
117
+ rb_hash_aset(hash, ID2SYM(rb_intern("envvar")), rb_str_new2(options[i].envvar));
118
+ if(options[i].compiled)
119
+ rb_hash_aset(hash, ID2SYM(rb_intern("compiled")), rb_str_new2(options[i].compiled));
120
+ if(options[i].val)
121
+ rb_hash_aset(hash, ID2SYM(rb_intern("val")), rb_str_new2(options[i].val));
122
+ if(options[i].label)
123
+ rb_hash_aset(hash, ID2SYM(rb_intern("label")), rb_str_new2(options[i].label));
124
+ if(options[i].dispchar)
125
+ rb_hash_aset(hash, ID2SYM(rb_intern("dispchar")), rb_str_new2(options[i].dispchar));
126
+ rb_hash_aset(hash, ID2SYM(rb_intern("dispsize")), INT2NUM(options[i].dispsize));
127
+ rb_ary_push(ary, hash);
128
+ }
80
129
 
81
- Check_Type( self, T_DATA );
130
+ return ary;
131
+ }
132
+
133
+ static const char *pg_cstr_enc(VALUE str, int enc_idx){
134
+ const char *ptr = StringValueCStr(str);
135
+ if( ENCODING_GET(str) == enc_idx ){
136
+ return ptr;
137
+ } else {
138
+ str = rb_str_export_to_enc(str, rb_enc_from_index(enc_idx));
139
+ return StringValueCStr(str);
140
+ }
141
+ }
82
142
 
83
- if ( !rb_obj_is_kind_of(self, rb_cPGconn) ) {
84
- rb_raise( rb_eTypeError, "wrong argument type %s (expected PG::Connection)",
85
- rb_obj_classname( self ) );
86
- }
87
143
 
88
- return DATA_PTR( self );
144
+ /*
145
+ * GC Mark function
146
+ */
147
+ static void
148
+ pgconn_gc_mark( t_pg_connection *this )
149
+ {
150
+ rb_gc_mark( this->socket_io );
151
+ rb_gc_mark( this->notice_receiver );
152
+ rb_gc_mark( this->notice_processor );
153
+ rb_gc_mark( this->type_map_for_queries );
154
+ rb_gc_mark( this->type_map_for_results );
155
+ rb_gc_mark( this->trace_stream );
156
+ rb_gc_mark( this->encoder_for_put_copy_data );
157
+ rb_gc_mark( this->decoder_for_get_copy_data );
89
158
  }
90
159
 
91
160
 
@@ -93,10 +162,16 @@ pgconn_check( VALUE self ) {
93
162
  * GC Free function
94
163
  */
95
164
  static void
96
- pgconn_gc_free( PGconn *conn )
165
+ pgconn_gc_free( t_pg_connection *this )
97
166
  {
98
- if (conn != NULL)
99
- PQfinish( conn );
167
+ #if defined(_WIN32)
168
+ if ( RTEST(this->socket_io) )
169
+ rb_w32_unwrap_io_handle( this->ruby_sd );
170
+ #endif
171
+ if (this->pgconn != NULL)
172
+ PQfinish( this->pgconn );
173
+
174
+ xfree(this);
100
175
  }
101
176
 
102
177
 
@@ -113,7 +188,20 @@ pgconn_gc_free( PGconn *conn )
113
188
  static VALUE
114
189
  pgconn_s_allocate( VALUE klass )
115
190
  {
116
- return Data_Wrap_Struct( klass, NULL, pgconn_gc_free, NULL );
191
+ t_pg_connection *this;
192
+ VALUE self = Data_Make_Struct( klass, t_pg_connection, pgconn_gc_mark, pgconn_gc_free, this );
193
+
194
+ this->pgconn = NULL;
195
+ this->socket_io = Qnil;
196
+ this->notice_receiver = Qnil;
197
+ this->notice_processor = Qnil;
198
+ this->type_map_for_queries = pg_typemap_all_strings;
199
+ this->type_map_for_results = pg_typemap_all_strings;
200
+ this->encoder_for_put_copy_data = Qnil;
201
+ this->decoder_for_get_copy_data = Qnil;
202
+ this->trace_stream = Qnil;
203
+
204
+ return self;
117
205
  }
118
206
 
119
207
 
@@ -128,32 +216,27 @@ pgconn_s_allocate( VALUE klass )
128
216
  *
129
217
  * Create a connection to the specified server.
130
218
  *
219
+ * +connection_hash+ must be a ruby Hash with connection parameters.
220
+ * See the {list of valid parameters}[https://www.postgresql.org/docs/current/libpq-connect.html#LIBPQ-PARAMKEYWORDS] in the PostgreSQL documentation.
221
+ *
222
+ * There are two accepted formats for +connection_string+: plain <code>keyword = value</code> strings and URIs.
223
+ * See the documentation of {connection strings}[https://www.postgresql.org/docs/current/libpq-connect.html#LIBPQ-CONNSTRING].
224
+ *
225
+ * The positional parameter form has the same functionality except that the missing parameters will always take on default values. The parameters are:
131
226
  * [+host+]
132
227
  * server hostname
133
- * [+hostaddr+]
134
- * server address (avoids hostname lookup, overrides +host+)
135
228
  * [+port+]
136
229
  * server port number
230
+ * [+options+]
231
+ * backend options
232
+ * [+tty+]
233
+ * (ignored in newer versions of PostgreSQL)
137
234
  * [+dbname+]
138
235
  * connecting database name
139
236
  * [+user+]
140
237
  * login user name
141
238
  * [+password+]
142
239
  * login password
143
- * [+connect_timeout+]
144
- * maximum time to wait for connection to succeed
145
- * [+options+]
146
- * backend options
147
- * [+tty+]
148
- * (ignored in newer versions of PostgreSQL)
149
- * [+sslmode+]
150
- * (disable|allow|prefer|require)
151
- * [+krbsrvname+]
152
- * kerberos service name
153
- * [+gsslib+]
154
- * GSS library to use for GSSAPI authentication
155
- * [+service+]
156
- * service name to use for additional parameters
157
240
  *
158
241
  * Examples:
159
242
  *
@@ -169,7 +252,7 @@ pgconn_s_allocate( VALUE klass )
169
252
  * # As an Array
170
253
  * PG::Connection.new( nil, 5432, nil, nil, 'test', nil, nil )
171
254
  *
172
- * If the Ruby default internal encoding is set (i.e., Encoding.default_internal != nil), the
255
+ * If the Ruby default internal encoding is set (i.e., <code>Encoding.default_internal != nil</code>), the
173
256
  * connection will have its +client_encoding+ set accordingly.
174
257
  *
175
258
  * Raises a PG::Error if the connection fails.
@@ -177,28 +260,24 @@ pgconn_s_allocate( VALUE klass )
177
260
  static VALUE
178
261
  pgconn_init(int argc, VALUE *argv, VALUE self)
179
262
  {
180
- PGconn *conn = NULL;
263
+ t_pg_connection *this;
181
264
  VALUE conninfo;
182
265
  VALUE error;
183
266
 
267
+ this = pg_get_connection( self );
184
268
  conninfo = rb_funcall2( rb_cPGconn, rb_intern("parse_connect_args"), argc, argv );
185
- conn = PQconnectdb(StringValuePtr(conninfo));
269
+ this->pgconn = gvl_PQconnectdb(StringValueCStr(conninfo));
186
270
 
187
- if(conn == NULL)
188
- rb_raise(rb_ePGerror, "PQconnectStart() unable to allocate structure");
189
-
190
- Check_Type(self, T_DATA);
191
- DATA_PTR(self) = conn;
271
+ if(this->pgconn == NULL)
272
+ rb_raise(rb_ePGerror, "PQconnectdb() unable to allocate structure");
192
273
 
193
- if (PQstatus(conn) == CONNECTION_BAD) {
194
- error = rb_exc_new2(rb_ePGerror, PQerrorMessage(conn));
274
+ if (PQstatus(this->pgconn) == CONNECTION_BAD) {
275
+ error = rb_exc_new2(rb_eConnectionBad, PQerrorMessage(this->pgconn));
195
276
  rb_iv_set(error, "@connection", self);
196
277
  rb_exc_raise(error);
197
278
  }
198
279
 
199
- #ifdef M17N_SUPPORTED
200
280
  pgconn_set_default_encoding( self );
201
- #endif
202
281
 
203
282
  if (rb_block_given_p()) {
204
283
  return rb_ensure(rb_yield, self, pgconn_finish, self);
@@ -212,40 +291,40 @@ pgconn_init(int argc, VALUE *argv, VALUE self)
212
291
  * PG::Connection.connect_start(connection_string) -> conn
213
292
  * PG::Connection.connect_start(host, port, options, tty, dbname, login, password) -> conn
214
293
  *
215
- * This is an asynchronous version of PG::Connection.connect().
294
+ * This is an asynchronous version of PG::Connection.new.
216
295
  *
217
296
  * Use #connect_poll to poll the status of the connection.
218
297
  *
219
298
  * NOTE: this does *not* set the connection's +client_encoding+ for you if
220
- * Encoding.default_internal is set. To set it after the connection is established,
299
+ * +Encoding.default_internal+ is set. To set it after the connection is established,
221
300
  * call #internal_encoding=. You can also set it automatically by setting
222
- * ENV['PGCLIENTENCODING'], or include the 'options' connection parameter.
301
+ * <code>ENV['PGCLIENTENCODING']</code>, or include the 'options' connection parameter.
302
+ *
303
+ * See also the 'sample' directory of this gem and the corresponding {libpq functions}[https://www.postgresql.org/docs/current/libpq-connect.html#LIBPQ-PQCONNECTSTARTPARAMS].
223
304
  *
224
305
  */
225
306
  static VALUE
226
307
  pgconn_s_connect_start( int argc, VALUE *argv, VALUE klass )
227
308
  {
228
- PGconn *conn = NULL;
229
309
  VALUE rb_conn;
230
310
  VALUE conninfo;
231
311
  VALUE error;
312
+ t_pg_connection *this;
232
313
 
233
314
  /*
234
315
  * PG::Connection.connect_start must act as both alloc() and initialize()
235
316
  * because it is not invoked by calling new().
236
317
  */
237
318
  rb_conn = pgconn_s_allocate( klass );
319
+ this = pg_get_connection( rb_conn );
238
320
  conninfo = rb_funcall2( klass, rb_intern("parse_connect_args"), argc, argv );
239
- conn = PQconnectStart( StringValuePtr(conninfo) );
321
+ this->pgconn = gvl_PQconnectStart( StringValueCStr(conninfo) );
240
322
 
241
- if( conn == NULL )
323
+ if( this->pgconn == NULL )
242
324
  rb_raise(rb_ePGerror, "PQconnectStart() unable to allocate structure");
243
325
 
244
- Check_Type(rb_conn, T_DATA);
245
- DATA_PTR(rb_conn) = conn;
246
-
247
- if ( PQstatus(conn) == CONNECTION_BAD ) {
248
- error = rb_exc_new2(rb_ePGerror, PQerrorMessage(conn));
326
+ if ( PQstatus(this->pgconn) == CONNECTION_BAD ) {
327
+ error = rb_exc_new2(rb_eConnectionBad, PQerrorMessage(this->pgconn));
249
328
  rb_iv_set(error, "@connection", rb_conn);
250
329
  rb_exc_raise(error);
251
330
  }
@@ -256,15 +335,16 @@ pgconn_s_connect_start( int argc, VALUE *argv, VALUE klass )
256
335
  return rb_conn;
257
336
  }
258
337
 
259
- #ifdef HAVE_PQPING
260
338
  /*
261
339
  * call-seq:
262
- * PG::Connection.ping(connection_hash) -> Fixnum
263
- * PG::Connection.ping(connection_string) -> Fixnum
264
- * PG::Connection.ping(host, port, options, tty, dbname, login, password) -> Fixnum
340
+ * PG::Connection.ping(connection_hash) -> Integer
341
+ * PG::Connection.ping(connection_string) -> Integer
342
+ * PG::Connection.ping(host, port, options, tty, dbname, login, password) -> Integer
265
343
  *
266
344
  * Check server status.
267
345
  *
346
+ * See PG::Connection.new for a description of the parameters.
347
+ *
268
348
  * Returns one of:
269
349
  * [+PQPING_OK+]
270
350
  * server is accepting connections
@@ -282,13 +362,15 @@ pgconn_s_ping( int argc, VALUE *argv, VALUE klass )
282
362
  VALUE conninfo;
283
363
 
284
364
  conninfo = rb_funcall2( klass, rb_intern("parse_connect_args"), argc, argv );
285
- ping = PQping( StringValuePtr(conninfo) );
365
+ ping = PQping( StringValueCStr(conninfo) );
286
366
 
287
367
  return INT2FIX((int)ping);
288
368
  }
289
- #endif
369
+
290
370
 
291
371
  /*
372
+ * Document-method: PG::Connection.conndefaults
373
+ *
292
374
  * call-seq:
293
375
  * PG::Connection.conndefaults() -> Array
294
376
  *
@@ -312,44 +394,72 @@ static VALUE
312
394
  pgconn_s_conndefaults(VALUE self)
313
395
  {
314
396
  PQconninfoOption *options = PQconndefaults();
315
- VALUE ary = rb_ary_new();
316
- VALUE hash;
317
- int i = 0;
397
+ VALUE array = pgconn_make_conninfo_array( options );
398
+
399
+ PQconninfoFree(options);
318
400
 
319
401
  UNUSED( self );
320
402
 
321
- for(i = 0; options[i].keyword != NULL; i++) {
322
- hash = rb_hash_new();
323
- if(options[i].keyword)
324
- rb_hash_aset(hash, ID2SYM(rb_intern("keyword")), rb_str_new2(options[i].keyword));
325
- if(options[i].envvar)
326
- rb_hash_aset(hash, ID2SYM(rb_intern("envvar")), rb_str_new2(options[i].envvar));
327
- if(options[i].compiled)
328
- rb_hash_aset(hash, ID2SYM(rb_intern("compiled")), rb_str_new2(options[i].compiled));
329
- if(options[i].val)
330
- rb_hash_aset(hash, ID2SYM(rb_intern("val")), rb_str_new2(options[i].val));
331
- if(options[i].label)
332
- rb_hash_aset(hash, ID2SYM(rb_intern("label")), rb_str_new2(options[i].label));
333
- if(options[i].dispchar)
334
- rb_hash_aset(hash, ID2SYM(rb_intern("dispchar")), rb_str_new2(options[i].dispchar));
335
- rb_hash_aset(hash, ID2SYM(rb_intern("dispsize")), INT2NUM(options[i].dispsize));
336
- rb_ary_push(ary, hash);
403
+ return array;
404
+ }
405
+
406
+
407
+ #ifdef HAVE_PQENCRYPTPASSWORDCONN
408
+ /*
409
+ * call-seq:
410
+ * conn.encrypt_password( password, username, algorithm=nil ) -> String
411
+ *
412
+ * This function is intended to be used by client applications that wish to send commands like <tt>ALTER USER joe PASSWORD 'pwd'</tt>.
413
+ * It is good practice not to send the original cleartext password in such a command, because it might be exposed in command logs, activity displays, and so on.
414
+ * Instead, use this function to convert the password to encrypted form before it is sent.
415
+ *
416
+ * The +password+ and +username+ arguments are the cleartext password, and the SQL name of the user it is for.
417
+ * +algorithm+ specifies the encryption algorithm to use to encrypt the password.
418
+ * Currently supported algorithms are +md5+ and +scram-sha-256+ (+on+ and +off+ are also accepted as aliases for +md5+, for compatibility with older server versions).
419
+ * Note that support for +scram-sha-256+ was introduced in PostgreSQL version 10, and will not work correctly with older server versions.
420
+ * If algorithm is omitted or +nil+, this function will query the server for the current value of the +password_encryption+ setting.
421
+ * That can block, and will fail if the current transaction is aborted, or if the connection is busy executing another query.
422
+ * If you wish to use the default algorithm for the server but want to avoid blocking, query +password_encryption+ yourself before calling #encrypt_password, and pass that value as the algorithm.
423
+ *
424
+ * Return value is the encrypted password.
425
+ * The caller can assume the string doesn't contain any special characters that would require escaping.
426
+ *
427
+ * Available since PostgreSQL-10.
428
+ * See also corresponding {libpq function}[https://www.postgresql.org/docs/current/libpq-misc.html#LIBPQ-PQENCRYPTPASSWORDCONN].
429
+ */
430
+ static VALUE
431
+ pgconn_encrypt_password(int argc, VALUE *argv, VALUE self)
432
+ {
433
+ char *encrypted = NULL;
434
+ VALUE rval = Qnil;
435
+ VALUE password, username, algorithm;
436
+ PGconn *conn = pg_get_pgconn(self);
437
+
438
+ rb_scan_args( argc, argv, "21", &password, &username, &algorithm );
439
+
440
+ Check_Type(password, T_STRING);
441
+ Check_Type(username, T_STRING);
442
+
443
+ encrypted = gvl_PQencryptPasswordConn(conn, StringValueCStr(password), StringValueCStr(username), RTEST(algorithm) ? StringValueCStr(algorithm) : NULL);
444
+ if ( encrypted ) {
445
+ rval = rb_str_new2( encrypted );
446
+ PQfreemem( encrypted );
447
+ } else {
448
+ rb_raise(rb_ePGerror, "%s", PQerrorMessage(conn));
337
449
  }
338
- PQconninfoFree(options);
339
- return ary;
450
+
451
+ return rval;
340
452
  }
453
+ #endif
341
454
 
342
455
 
343
456
  /*
344
457
  * call-seq:
345
458
  * PG::Connection.encrypt_password( password, username ) -> String
346
459
  *
347
- * This function is intended to be used by client applications that
348
- * send commands like: +ALTER USER joe PASSWORD 'pwd'+.
349
- * The arguments are the cleartext password, and the SQL name
350
- * of the user it is for.
460
+ * This is an older, deprecated version of #encrypt_password.
461
+ * The difference is that this function always uses +md5+ as the encryption algorithm.
351
462
  *
352
- * Return value is the encrypted password.
353
463
  */
354
464
  static VALUE
355
465
  pgconn_s_encrypt_password(VALUE self, VALUE password, VALUE username)
@@ -362,13 +472,10 @@ pgconn_s_encrypt_password(VALUE self, VALUE password, VALUE username)
362
472
  Check_Type(password, T_STRING);
363
473
  Check_Type(username, T_STRING);
364
474
 
365
- encrypted = PQencryptPassword(StringValuePtr(password), StringValuePtr(username));
475
+ encrypted = PQencryptPassword(StringValueCStr(password), StringValueCStr(username));
366
476
  rval = rb_str_new2( encrypted );
367
477
  PQfreemem( encrypted );
368
478
 
369
- OBJ_INFECT( rval, password );
370
- OBJ_INFECT( rval, username );
371
-
372
479
  return rval;
373
480
  }
374
481
 
@@ -379,7 +486,7 @@ pgconn_s_encrypt_password(VALUE self, VALUE password, VALUE username)
379
486
 
380
487
  /*
381
488
  * call-seq:
382
- * conn.connect_poll() -> Fixnum
489
+ * conn.connect_poll() -> Integer
383
490
  *
384
491
  * Returns one of:
385
492
  * [+PGRES_POLLING_READING+]
@@ -415,7 +522,7 @@ static VALUE
415
522
  pgconn_connect_poll(VALUE self)
416
523
  {
417
524
  PostgresPollingStatusType status;
418
- status = PQconnectPoll(pg_get_pgconn(self));
525
+ status = gvl_PQconnectPoll(pg_get_pgconn(self));
419
526
  return INT2FIX((int)status);
420
527
  }
421
528
 
@@ -428,9 +535,11 @@ pgconn_connect_poll(VALUE self)
428
535
  static VALUE
429
536
  pgconn_finish( VALUE self )
430
537
  {
538
+ t_pg_connection *this = pg_get_connection_safe( self );
539
+
431
540
  pgconn_close_socket_io( self );
432
- PQfinish( pg_get_pgconn(self) );
433
- DATA_PTR( self ) = NULL;
541
+ PQfinish( this->pgconn );
542
+ this->pgconn = NULL;
434
543
  return Qnil;
435
544
  }
436
545
 
@@ -444,7 +553,8 @@ pgconn_finish( VALUE self )
444
553
  static VALUE
445
554
  pgconn_finished_p( VALUE self )
446
555
  {
447
- if ( DATA_PTR(self) ) return Qfalse;
556
+ t_pg_connection *this = pg_get_connection( self );
557
+ if ( this->pgconn ) return Qfalse;
448
558
  return Qtrue;
449
559
  }
450
560
 
@@ -460,7 +570,7 @@ static VALUE
460
570
  pgconn_reset( VALUE self )
461
571
  {
462
572
  pgconn_close_socket_io( self );
463
- PQreset( pg_get_pgconn(self) );
573
+ gvl_PQreset( pg_get_pgconn(self) );
464
574
  return self;
465
575
  }
466
576
 
@@ -478,14 +588,14 @@ static VALUE
478
588
  pgconn_reset_start(VALUE self)
479
589
  {
480
590
  pgconn_close_socket_io( self );
481
- if(PQresetStart(pg_get_pgconn(self)) == 0)
482
- rb_raise(rb_ePGerror, "reset has failed");
591
+ if(gvl_PQresetStart(pg_get_pgconn(self)) == 0)
592
+ rb_raise(rb_eUnableToSend, "reset has failed");
483
593
  return Qnil;
484
594
  }
485
595
 
486
596
  /*
487
597
  * call-seq:
488
- * conn.reset_poll -> Fixnum
598
+ * conn.reset_poll -> Integer
489
599
  *
490
600
  * Checks the status of a connection reset operation.
491
601
  * See #connect_start and #connect_poll for
@@ -495,10 +605,11 @@ static VALUE
495
605
  pgconn_reset_poll(VALUE self)
496
606
  {
497
607
  PostgresPollingStatusType status;
498
- status = PQresetPoll(pg_get_pgconn(self));
608
+ status = gvl_PQresetPoll(pg_get_pgconn(self));
499
609
  return INT2FIX((int)status);
500
610
  }
501
611
 
612
+
502
613
  /*
503
614
  * call-seq:
504
615
  * conn.db()
@@ -510,7 +621,7 @@ pgconn_db(VALUE self)
510
621
  {
511
622
  char *db = PQdb(pg_get_pgconn(self));
512
623
  if (!db) return Qnil;
513
- return rb_tainted_str_new2(db);
624
+ return rb_str_new2(db);
514
625
  }
515
626
 
516
627
  /*
@@ -524,21 +635,21 @@ pgconn_user(VALUE self)
524
635
  {
525
636
  char *user = PQuser(pg_get_pgconn(self));
526
637
  if (!user) return Qnil;
527
- return rb_tainted_str_new2(user);
638
+ return rb_str_new2(user);
528
639
  }
529
640
 
530
641
  /*
531
642
  * call-seq:
532
643
  * conn.pass()
533
644
  *
534
- * Returns the authenticated user name.
645
+ * Returns the authenticated password.
535
646
  */
536
647
  static VALUE
537
648
  pgconn_pass(VALUE self)
538
649
  {
539
650
  char *user = PQpass(pg_get_pgconn(self));
540
651
  if (!user) return Qnil;
541
- return rb_tainted_str_new2(user);
652
+ return rb_str_new2(user);
542
653
  }
543
654
 
544
655
  /*
@@ -552,7 +663,7 @@ pgconn_host(VALUE self)
552
663
  {
553
664
  char *host = PQhost(pg_get_pgconn(self));
554
665
  if (!host) return Qnil;
555
- return rb_tainted_str_new2(host);
666
+ return rb_str_new2(host);
556
667
  }
557
668
 
558
669
  /*
@@ -579,7 +690,7 @@ pgconn_tty(VALUE self)
579
690
  {
580
691
  char *tty = PQtty(pg_get_pgconn(self));
581
692
  if (!tty) return Qnil;
582
- return rb_tainted_str_new2(tty);
693
+ return rb_str_new2(tty);
583
694
  }
584
695
 
585
696
  /*
@@ -593,8 +704,32 @@ pgconn_options(VALUE self)
593
704
  {
594
705
  char *options = PQoptions(pg_get_pgconn(self));
595
706
  if (!options) return Qnil;
596
- return rb_tainted_str_new2(options);
707
+ return rb_str_new2(options);
708
+ }
709
+
710
+
711
+ #ifdef HAVE_PQCONNINFO
712
+ /*
713
+ * call-seq:
714
+ * conn.conninfo -> hash
715
+ *
716
+ * Returns the connection options used by a live connection.
717
+ *
718
+ * Available since PostgreSQL-9.3
719
+ */
720
+ static VALUE
721
+ pgconn_conninfo( VALUE self )
722
+ {
723
+ PGconn *conn = pg_get_pgconn(self);
724
+ PQconninfoOption *options = PQconninfo( conn );
725
+ VALUE array = pgconn_make_conninfo_array( options );
726
+
727
+ PQconninfoFree(options);
728
+
729
+ return array;
597
730
  }
731
+ #endif
732
+
598
733
 
599
734
  /*
600
735
  * call-seq:
@@ -646,11 +781,11 @@ pgconn_transaction_status(VALUE self)
646
781
  static VALUE
647
782
  pgconn_parameter_status(VALUE self, VALUE param_name)
648
783
  {
649
- const char *ret = PQparameterStatus(pg_get_pgconn(self), StringValuePtr(param_name));
784
+ const char *ret = PQparameterStatus(pg_get_pgconn(self), StringValueCStr(param_name));
650
785
  if(ret == NULL)
651
786
  return Qnil;
652
787
  else
653
- return rb_tainted_str_new2(ret);
788
+ return rb_str_new2(ret);
654
789
  }
655
790
 
656
791
  /*
@@ -695,12 +830,14 @@ pgconn_error_message(VALUE self)
695
830
  {
696
831
  char *error = PQerrorMessage(pg_get_pgconn(self));
697
832
  if (!error) return Qnil;
698
- return rb_tainted_str_new2(error);
833
+ return rb_str_new2(error);
699
834
  }
700
835
 
701
836
  /*
702
837
  * call-seq:
703
- * conn.socket() -> Fixnum
838
+ * conn.socket() -> Integer
839
+ *
840
+ * This method is deprecated. Please use the more portable method #socket_io .
704
841
  *
705
842
  * Returns the socket's file descriptor for this connection.
706
843
  * <tt>IO.for_fd()</tt> can be used to build a proper IO object to the socket.
@@ -710,34 +847,31 @@ pgconn_error_message(VALUE self)
710
847
  * creates an IO that's associated with the connection object itself,
711
848
  * and so won't go out of scope until the connection does.
712
849
  *
713
- * *Note:* On Windows the file descriptor is not really usable,
850
+ * *Note:* On Windows the file descriptor is not usable,
714
851
  * since it can not be used to build a Ruby IO object.
715
852
  */
716
853
  static VALUE
717
854
  pgconn_socket(VALUE self)
718
855
  {
719
856
  int sd;
857
+ pg_deprecated(4, ("conn.socket is deprecated and should be replaced by conn.socket_io"));
858
+
720
859
  if( (sd = PQsocket(pg_get_pgconn(self))) < 0)
721
- rb_raise(rb_ePGerror, "Can't get socket descriptor");
860
+ rb_raise(rb_eConnectionBad, "PQsocket() can't get socket descriptor");
722
861
  return INT2NUM(sd);
723
862
  }
724
863
 
725
-
726
- #if !defined(_WIN32) || defined(HAVE_RB_W32_WRAP_IO_HANDLE)
727
-
728
864
  /*
729
865
  * call-seq:
730
866
  * conn.socket_io() -> IO
731
867
  *
732
- * Fetch a memoized IO object created from the Connection's underlying socket.
868
+ * Fetch a memorized IO object created from the Connection's underlying socket.
733
869
  * This object can be used for IO.select to wait for events while running
734
870
  * asynchronous API calls.
735
871
  *
736
872
  * Using this instead of #socket avoids the problem of the underlying connection
737
873
  * being closed by Ruby when an IO created using <tt>IO.for_fd(conn.socket)</tt>
738
- * goes out of scope.
739
- *
740
- * This method can also be used on Windows but requires Ruby-2.0+.
874
+ * goes out of scope. In contrast to #socket, it also works on Windows.
741
875
  */
742
876
  static VALUE
743
877
  pgconn_socket_io(VALUE self)
@@ -745,36 +879,34 @@ pgconn_socket_io(VALUE self)
745
879
  int sd;
746
880
  int ruby_sd;
747
881
  ID id_autoclose = rb_intern("autoclose=");
748
- VALUE socket_io = rb_iv_get( self, "@socket_io" );
882
+ t_pg_connection *this = pg_get_connection_safe( self );
883
+ VALUE socket_io = this->socket_io;
749
884
 
750
885
  if ( !RTEST(socket_io) ) {
751
- if( (sd = PQsocket(pg_get_pgconn(self))) < 0)
752
- rb_raise(rb_ePGerror, "Can't get socket descriptor");
886
+ if( (sd = PQsocket(this->pgconn)) < 0)
887
+ rb_raise(rb_eConnectionBad, "PQsocket() can't get socket descriptor");
753
888
 
754
889
  #ifdef _WIN32
755
890
  ruby_sd = rb_w32_wrap_io_handle((HANDLE)(intptr_t)sd, O_RDWR|O_BINARY|O_NOINHERIT);
891
+ this->ruby_sd = ruby_sd;
756
892
  #else
757
893
  ruby_sd = sd;
758
894
  #endif
759
895
 
760
896
  socket_io = rb_funcall( rb_cIO, rb_intern("for_fd"), 1, INT2NUM(ruby_sd) );
761
897
 
762
- /* Disable autoclose feature, when supported */
763
- if( rb_respond_to(socket_io, id_autoclose) ){
764
- rb_funcall( socket_io, id_autoclose, 1, Qfalse );
765
- }
898
+ /* Disable autoclose feature */
899
+ rb_funcall( socket_io, id_autoclose, 1, Qfalse );
766
900
 
767
- rb_iv_set( self, "@socket_io", socket_io );
901
+ this->socket_io = socket_io;
768
902
  }
769
903
 
770
904
  return socket_io;
771
905
  }
772
906
 
773
- #endif
774
-
775
907
  /*
776
908
  * call-seq:
777
- * conn.backend_pid() -> Fixnum
909
+ * conn.backend_pid() -> Integer
778
910
  *
779
911
  * Returns the process ID of the backend server
780
912
  * process for this connection.
@@ -820,33 +952,31 @@ static VALUE pgconn_exec_params( int, VALUE *, VALUE );
820
952
 
821
953
  /*
822
954
  * call-seq:
823
- * conn.exec(sql) -> PG::Result
824
- * conn.exec(sql) {|pg_result| block }
955
+ * conn.sync_exec(sql) -> PG::Result
956
+ * conn.sync_exec(sql) {|pg_result| block }
825
957
  *
826
- * Sends SQL query request specified by _sql_ to PostgreSQL.
827
- * Returns a PG::Result instance on success.
828
- * On failure, it raises a PG::Error.
958
+ * This function has the same behavior as #async_exec, but is implemented using the synchronous command processing API of libpq.
959
+ * It's not recommended to use explicit sync or async variants but #exec instead, unless you have a good reason to do so.
829
960
  *
830
- * For backward compatibility, if you pass more than one parameter to this method,
831
- * it will call #exec_params for you. New code should explicitly use #exec_params if
832
- * argument placeholders are used.
961
+ * Both #sync_exec and #async_exec release the GVL while waiting for server response, so that concurrent threads will get executed.
962
+ * However #async_exec has two advantages:
833
963
  *
834
- * If the optional code block is given, it will be passed <i>result</i> as an argument,
835
- * and the PG::Result object will automatically be cleared when the block terminates.
836
- * In this instance, <code>conn.exec</code> returns the value of the block.
964
+ * 1. #async_exec can be aborted by signals (like Ctrl-C), while #exec blocks signal processing until the query is answered.
965
+ * 2. Ruby VM gets notified about IO blocked operations.
966
+ * It can therefore schedule things like garbage collection, while queries are running like in this proposal: https://bugs.ruby-lang.org/issues/14723
837
967
  */
838
968
  static VALUE
839
969
  pgconn_exec(int argc, VALUE *argv, VALUE self)
840
970
  {
841
- PGconn *conn = pg_get_pgconn(self);
971
+ t_pg_connection *this = pg_get_connection_safe( self );
842
972
  PGresult *result = NULL;
843
973
  VALUE rb_pgresult;
844
974
 
845
- /* If called with no parameters, use PQexec */
846
- if ( argc == 1 ) {
847
- Check_Type(argv[0], T_STRING);
975
+ /* If called with no or nil parameters, use PQexec for compatibility */
976
+ if ( argc == 1 || (argc >= 2 && argc <= 4 && NIL_P(argv[1]) )) {
977
+ VALUE query_str = argv[0];
848
978
 
849
- result = gvl_PQexec(conn, StringValuePtr(argv[0]));
979
+ result = gvl_PQexec(this->pgconn, pg_cstr_enc(query_str, this->enc_idx));
850
980
  rb_pgresult = pg_new_result(result, self);
851
981
  pg_result_check(rb_pgresult);
852
982
  if (rb_block_given_p()) {
@@ -854,159 +984,304 @@ pgconn_exec(int argc, VALUE *argv, VALUE self)
854
984
  }
855
985
  return rb_pgresult;
856
986
  }
987
+ pg_deprecated(0, ("forwarding exec to exec_params is deprecated"));
857
988
 
858
989
  /* Otherwise, just call #exec_params instead for backward-compatibility */
859
- else {
860
- return pgconn_exec_params( argc, argv, self );
861
- }
990
+ return pgconn_exec_params( argc, argv, self );
862
991
 
863
992
  }
864
993
 
865
994
 
866
- /*
867
- * call-seq:
868
- * conn.exec_params(sql, params[, result_format ] ) -> PG::Result
869
- * conn.exec_params(sql, params[, result_format ] ) {|pg_result| block }
870
- *
871
- * Sends SQL query request specified by +sql+ to PostgreSQL using placeholders
872
- * for parameters.
873
- *
874
- * Returns a PG::Result instance on success. On failure, it raises a PG::Error.
875
- *
876
- * +params+ is an array of the bind parameters for the SQL query.
877
- * Each element of the +params+ array may be either:
878
- * a hash of the form:
879
- * {:value => String (value of bind parameter)
880
- * :type => Fixnum (oid of type of bind parameter)
881
- * :format => Fixnum (0 for text, 1 for binary)
882
- * }
883
- * or, it may be a String. If it is a string, that is equivalent to the hash:
884
- * { :value => <string value>, :type => 0, :format => 0 }
885
- *
886
- * PostgreSQL bind parameters are represented as $1, $1, $2, etc.,
887
- * inside the SQL query. The 0th element of the +params+ array is bound
888
- * to $1, the 1st element is bound to $2, etc. +nil+ is treated as +NULL+.
889
- *
890
- * If the types are not specified, they will be inferred by PostgreSQL.
891
- * Instead of specifying type oids, it's recommended to simply add
892
- * explicit casts in the query to ensure that the right type is used.
893
- *
894
- * For example: "SELECT $1::int"
895
- *
896
- * The optional +result_format+ should be 0 for text results, 1
897
- * for binary.
898
- *
899
- * If the optional code block is given, it will be passed <i>result</i> as an argument,
900
- * and the PG::Result object will automatically be cleared when the block terminates.
901
- * In this instance, <code>conn.exec</code> returns the value of the block.
902
- */
903
- static VALUE
904
- pgconn_exec_params( int argc, VALUE *argv, VALUE self )
905
- {
906
- PGconn *conn = pg_get_pgconn(self);
907
- PGresult *result = NULL;
908
- VALUE rb_pgresult;
909
- VALUE command, params, in_res_fmt;
910
- VALUE param, param_type, param_value, param_format;
911
- VALUE param_value_tmp;
912
- VALUE sym_type, sym_value, sym_format;
913
- VALUE gc_array;
914
- int i=0;
915
- int nParams;
916
- Oid *paramTypes;
917
- char ** paramValues;
918
- int *paramLengths;
919
- int *paramFormats;
920
- int resultFormat;
995
+ struct linked_typecast_data {
996
+ struct linked_typecast_data *next;
997
+ char data[0];
998
+ };
921
999
 
922
- rb_scan_args(argc, argv, "12", &command, &params, &in_res_fmt);
1000
+ /* This struct is allocated on the stack for all query execution functions. */
1001
+ struct query_params_data {
923
1002
 
924
1003
  /*
925
- * Handle the edge-case where the caller is coming from #exec, but passed an explict +nil+
926
- * for the second parameter.
1004
+ * Filled by caller
927
1005
  */
928
- if ( NIL_P(params) ) {
929
- return pgconn_exec( 1, argv, self );
930
- }
931
1006
 
932
- Check_Type(params, T_ARRAY);
1007
+ /* The character encoding index of the connection. Any strings
1008
+ * given as query parameters are converted to this encoding.
1009
+ */
1010
+ int enc_idx;
1011
+ /* Is the query function to execute one with types array? */
1012
+ int with_types;
1013
+ /* Array of query params from user space */
1014
+ VALUE params;
1015
+ /* The typemap given from user space */
1016
+ VALUE typemap;
933
1017
 
934
- if ( NIL_P(in_res_fmt) ) {
935
- resultFormat = 0;
936
- }
937
- else {
938
- resultFormat = NUM2INT(in_res_fmt);
939
- }
1018
+ /*
1019
+ * Filled by alloc_query_params()
1020
+ */
940
1021
 
941
- gc_array = rb_ary_new();
942
- rb_gc_register_address(&gc_array);
1022
+ /* Wraps the pointer of allocated memory, if function parameters dont't
1023
+ * fit in the memory_pool below.
1024
+ */
1025
+ VALUE heap_pool;
943
1026
 
944
- sym_type = ID2SYM(rb_intern("type"));
945
- sym_value = ID2SYM(rb_intern("value"));
946
- sym_format = ID2SYM(rb_intern("format"));
947
- nParams = (int)RARRAY_LEN(params);
948
- paramTypes = ALLOC_N(Oid, nParams);
949
- paramValues = ALLOC_N(char *, nParams);
950
- paramLengths = ALLOC_N(int, nParams);
951
- paramFormats = ALLOC_N(int, nParams);
952
-
953
- for ( i = 0; i < nParams; i++ ) {
954
- param = rb_ary_entry(params, i);
955
- if (TYPE(param) == T_HASH) {
956
- param_type = rb_hash_aref(param, sym_type);
957
- param_value_tmp = rb_hash_aref(param, sym_value);
958
- if(param_value_tmp == Qnil)
959
- param_value = param_value_tmp;
960
- else
961
- param_value = rb_obj_as_string(param_value_tmp);
962
- param_format = rb_hash_aref(param, sym_format);
963
- }
964
- else {
965
- param_type = Qnil;
966
- if(param == Qnil)
967
- param_value = param;
968
- else
969
- param_value = rb_obj_as_string(param);
970
- param_format = Qnil;
971
- }
1027
+ /* Pointer to the value string pointers (either within memory_pool or heap_pool).
1028
+ * The value strings itself are either directly within RString memory or,
1029
+ * in case of type casted values, within memory_pool or typecast_heap_chain.
1030
+ */
1031
+ char **values;
1032
+ /* Pointer to the param lengths (either within memory_pool or heap_pool) */
1033
+ int *lengths;
1034
+ /* Pointer to the format codes (either within memory_pool or heap_pool) */
1035
+ int *formats;
1036
+ /* Pointer to the OID types (either within memory_pool or heap_pool) */
1037
+ Oid *types;
1038
+
1039
+ /* This array takes the string values for the timeframe of the query,
1040
+ * if param value convertion is required
1041
+ */
1042
+ VALUE gc_array;
972
1043
 
973
- if(param_type == Qnil)
974
- paramTypes[i] = 0;
975
- else
976
- paramTypes[i] = NUM2INT(param_type);
1044
+ /* Wraps a single linked list of allocated memory chunks for type casted params.
1045
+ * Used when the memory_pool is to small.
1046
+ */
1047
+ VALUE typecast_heap_chain;
977
1048
 
978
- if(param_value == Qnil) {
979
- paramValues[i] = NULL;
980
- paramLengths[i] = 0;
981
- }
982
- else {
983
- Check_Type(param_value, T_STRING);
984
- /* make sure param_value doesn't get freed by the GC */
985
- rb_ary_push(gc_array, param_value);
986
- paramValues[i] = StringValuePtr(param_value);
987
- paramLengths[i] = (int)RSTRING_LEN(param_value);
988
- }
1049
+ /* This memory pool is used to place above query function parameters on it. */
1050
+ char memory_pool[QUERYDATA_BUFFER_SIZE];
1051
+ };
989
1052
 
990
- if(param_format == Qnil)
991
- paramFormats[i] = 0;
992
- else
993
- paramFormats[i] = NUM2INT(param_format);
1053
+ static void
1054
+ free_typecast_heap_chain(struct linked_typecast_data *chain_entry)
1055
+ {
1056
+ while(chain_entry){
1057
+ struct linked_typecast_data *next = chain_entry->next;
1058
+ xfree(chain_entry);
1059
+ chain_entry = next;
994
1060
  }
1061
+ }
995
1062
 
996
- result = gvl_PQexecParams(conn, StringValuePtr(command), nParams, paramTypes,
997
- (const char * const *)paramValues, paramLengths, paramFormats, resultFormat);
998
-
999
- rb_gc_unregister_address(&gc_array);
1063
+ static char *
1064
+ alloc_typecast_buf( VALUE *typecast_heap_chain, int len )
1065
+ {
1066
+ /* Allocate a new memory chunk from heap */
1067
+ struct linked_typecast_data *allocated =
1068
+ (struct linked_typecast_data *)xmalloc(sizeof(struct linked_typecast_data) + len);
1069
+
1070
+ /* Did we already wrap a memory chain per T_DATA object? */
1071
+ if( NIL_P( *typecast_heap_chain ) ){
1072
+ /* Leave free'ing of the buffer chain to the GC, when paramsData has left the stack */
1073
+ *typecast_heap_chain = Data_Wrap_Struct( rb_cObject, NULL, free_typecast_heap_chain, allocated );
1074
+ allocated->next = NULL;
1075
+ } else {
1076
+ /* Append to the chain */
1077
+ allocated->next = DATA_PTR( *typecast_heap_chain );
1078
+ DATA_PTR( *typecast_heap_chain ) = allocated;
1079
+ }
1000
1080
 
1001
- xfree(paramTypes);
1002
- xfree(paramValues);
1003
- xfree(paramLengths);
1004
- xfree(paramFormats);
1081
+ return &allocated->data[0];
1082
+ }
1005
1083
 
1006
- rb_pgresult = pg_new_result(result, self);
1007
- pg_result_check(rb_pgresult);
1008
1084
 
1009
- if (rb_block_given_p()) {
1085
+ static int
1086
+ alloc_query_params(struct query_params_data *paramsData)
1087
+ {
1088
+ VALUE param_value;
1089
+ t_typemap *p_typemap;
1090
+ int nParams;
1091
+ int i=0;
1092
+ t_pg_coder *conv;
1093
+ unsigned int required_pool_size;
1094
+ char *memory_pool;
1095
+
1096
+ Check_Type(paramsData->params, T_ARRAY);
1097
+
1098
+ p_typemap = DATA_PTR( paramsData->typemap );
1099
+ p_typemap->funcs.fit_to_query( paramsData->typemap, paramsData->params );
1100
+
1101
+ paramsData->heap_pool = Qnil;
1102
+ paramsData->typecast_heap_chain = Qnil;
1103
+ paramsData->gc_array = Qnil;
1104
+
1105
+ nParams = (int)RARRAY_LEN(paramsData->params);
1106
+
1107
+ required_pool_size = nParams * (
1108
+ sizeof(char *) +
1109
+ sizeof(int) +
1110
+ sizeof(int) +
1111
+ (paramsData->with_types ? sizeof(Oid) : 0));
1112
+
1113
+ if( sizeof(paramsData->memory_pool) < required_pool_size ){
1114
+ /* Allocate one combined memory pool for all possible function parameters */
1115
+ memory_pool = (char*)xmalloc( required_pool_size );
1116
+ /* Leave free'ing of the buffer to the GC, when paramsData has left the stack */
1117
+ paramsData->heap_pool = Data_Wrap_Struct( rb_cObject, NULL, -1, memory_pool );
1118
+ required_pool_size = 0;
1119
+ }else{
1120
+ /* Use stack memory for function parameters */
1121
+ memory_pool = paramsData->memory_pool;
1122
+ }
1123
+
1124
+ paramsData->values = (char **)memory_pool;
1125
+ paramsData->lengths = (int *)((char*)paramsData->values + sizeof(char *) * nParams);
1126
+ paramsData->formats = (int *)((char*)paramsData->lengths + sizeof(int) * nParams);
1127
+ paramsData->types = (Oid *)((char*)paramsData->formats + sizeof(int) * nParams);
1128
+
1129
+ {
1130
+ char *typecast_buf = paramsData->memory_pool + required_pool_size;
1131
+
1132
+ for ( i = 0; i < nParams; i++ ) {
1133
+ param_value = rb_ary_entry(paramsData->params, i);
1134
+
1135
+ paramsData->formats[i] = 0;
1136
+ if( paramsData->with_types )
1137
+ paramsData->types[i] = 0;
1138
+
1139
+ /* Let the given typemap select a coder for this param */
1140
+ conv = p_typemap->funcs.typecast_query_param(p_typemap, param_value, i);
1141
+
1142
+ /* Using a coder object for the param_value? Then set it's format code and oid. */
1143
+ if( conv ){
1144
+ paramsData->formats[i] = conv->format;
1145
+ if( paramsData->with_types )
1146
+ paramsData->types[i] = conv->oid;
1147
+ } else {
1148
+ /* No coder, but got we a hash form for the query param?
1149
+ * Then take format code and oid from there. */
1150
+ if (TYPE(param_value) == T_HASH) {
1151
+ VALUE format_value = rb_hash_aref(param_value, sym_format);
1152
+ if( !NIL_P(format_value) )
1153
+ paramsData->formats[i] = NUM2INT(format_value);
1154
+ if( paramsData->with_types ){
1155
+ VALUE type_value = rb_hash_aref(param_value, sym_type);
1156
+ if( !NIL_P(type_value) )
1157
+ paramsData->types[i] = NUM2UINT(type_value);
1158
+ }
1159
+ param_value = rb_hash_aref(param_value, sym_value);
1160
+ }
1161
+ }
1162
+
1163
+ if( NIL_P(param_value) ){
1164
+ paramsData->values[i] = NULL;
1165
+ paramsData->lengths[i] = 0;
1166
+ } else {
1167
+ t_pg_coder_enc_func enc_func = pg_coder_enc_func( conv );
1168
+ VALUE intermediate;
1169
+
1170
+ /* 1st pass for retiving the required memory space */
1171
+ int len = enc_func(conv, param_value, NULL, &intermediate, paramsData->enc_idx);
1172
+
1173
+ if( len == -1 ){
1174
+ /* The intermediate value is a String that can be used directly. */
1175
+
1176
+ /* Ensure that the String object is zero terminated as expected by libpq. */
1177
+ if( paramsData->formats[i] == 0 )
1178
+ StringValueCStr(intermediate);
1179
+ /* In case a new string object was generated, make sure it doesn't get freed by the GC */
1180
+ if( intermediate != param_value ){
1181
+ if( NIL_P(paramsData->gc_array) )
1182
+ paramsData->gc_array = rb_ary_new();
1183
+ rb_ary_push(paramsData->gc_array, intermediate);
1184
+ }
1185
+ paramsData->values[i] = RSTRING_PTR(intermediate);
1186
+ paramsData->lengths[i] = RSTRING_LENINT(intermediate);
1187
+
1188
+ } else {
1189
+ /* Is the stack memory pool too small to take the type casted value? */
1190
+ if( sizeof(paramsData->memory_pool) < required_pool_size + len + 1){
1191
+ typecast_buf = alloc_typecast_buf( &paramsData->typecast_heap_chain, len + 1 );
1192
+ }
1193
+
1194
+ /* 2nd pass for writing the data to prepared buffer */
1195
+ len = enc_func(conv, param_value, typecast_buf, &intermediate, paramsData->enc_idx);
1196
+ paramsData->values[i] = typecast_buf;
1197
+ if( paramsData->formats[i] == 0 ){
1198
+ /* text format strings must be zero terminated and lengths are ignored */
1199
+ typecast_buf[len] = 0;
1200
+ typecast_buf += len + 1;
1201
+ required_pool_size += len + 1;
1202
+ } else {
1203
+ paramsData->lengths[i] = len;
1204
+ typecast_buf += len;
1205
+ required_pool_size += len;
1206
+ }
1207
+ }
1208
+
1209
+ RB_GC_GUARD(intermediate);
1210
+ }
1211
+ }
1212
+ }
1213
+
1214
+ return nParams;
1215
+ }
1216
+
1217
+ static void
1218
+ free_query_params(struct query_params_data *paramsData)
1219
+ {
1220
+ /* currently nothing to free */
1221
+ }
1222
+
1223
+ void
1224
+ pgconn_query_assign_typemap( VALUE self, struct query_params_data *paramsData )
1225
+ {
1226
+ if(NIL_P(paramsData->typemap)){
1227
+ /* Use default typemap for queries. It's type is checked when assigned. */
1228
+ paramsData->typemap = pg_get_connection(self)->type_map_for_queries;
1229
+ }else{
1230
+ /* Check type of method param */
1231
+ if ( !rb_obj_is_kind_of(paramsData->typemap, rb_cTypeMap) ) {
1232
+ rb_raise( rb_eTypeError, "wrong argument type %s (expected kind of PG::TypeMap)",
1233
+ rb_obj_classname( paramsData->typemap ) );
1234
+ }
1235
+ Check_Type( paramsData->typemap, T_DATA );
1236
+ }
1237
+ }
1238
+
1239
+ /*
1240
+ * call-seq:
1241
+ * conn.sync_exec_params(sql, params[, result_format[, type_map]] ) -> PG::Result
1242
+ * conn.sync_exec_params(sql, params[, result_format[, type_map]] ) {|pg_result| block }
1243
+ *
1244
+ * This function has the same behavior as #async_exec_params, but is implemented using the synchronous command processing API of libpq.
1245
+ * See #async_exec for the differences between the two API variants.
1246
+ * It's not recommended to use explicit sync or async variants but #exec_params instead, unless you have a good reason to do so.
1247
+ */
1248
+ static VALUE
1249
+ pgconn_exec_params( int argc, VALUE *argv, VALUE self )
1250
+ {
1251
+ t_pg_connection *this = pg_get_connection_safe( self );
1252
+ PGresult *result = NULL;
1253
+ VALUE rb_pgresult;
1254
+ VALUE command, in_res_fmt;
1255
+ int nParams;
1256
+ int resultFormat;
1257
+ struct query_params_data paramsData = { this->enc_idx };
1258
+
1259
+ /* For compatibility we accept 1 to 4 parameters */
1260
+ rb_scan_args(argc, argv, "13", &command, &paramsData.params, &in_res_fmt, &paramsData.typemap);
1261
+ paramsData.with_types = 1;
1262
+
1263
+ /*
1264
+ * For backward compatibility no or +nil+ for the second parameter
1265
+ * is passed to #exec
1266
+ */
1267
+ if ( NIL_P(paramsData.params) ) {
1268
+ pg_deprecated(1, ("forwarding exec_params to exec is deprecated"));
1269
+ return pgconn_exec( 1, argv, self );
1270
+ }
1271
+ pgconn_query_assign_typemap( self, &paramsData );
1272
+
1273
+ resultFormat = NIL_P(in_res_fmt) ? 0 : NUM2INT(in_res_fmt);
1274
+ nParams = alloc_query_params( &paramsData );
1275
+
1276
+ result = gvl_PQexecParams(this->pgconn, pg_cstr_enc(command, paramsData.enc_idx), nParams, paramsData.types,
1277
+ (const char * const *)paramsData.values, paramsData.lengths, paramsData.formats, resultFormat);
1278
+
1279
+ free_query_params( &paramsData );
1280
+
1281
+ rb_pgresult = pg_new_result(result, self);
1282
+ pg_result_check(rb_pgresult);
1283
+
1284
+ if (rb_block_given_p()) {
1010
1285
  return rb_ensure(rb_yield, rb_pgresult, pg_result_clear, rb_pgresult);
1011
1286
  }
1012
1287
 
@@ -1015,28 +1290,16 @@ pgconn_exec_params( int argc, VALUE *argv, VALUE self )
1015
1290
 
1016
1291
  /*
1017
1292
  * call-seq:
1018
- * conn.prepare(stmt_name, sql [, param_types ] ) -> PG::Result
1293
+ * conn.sync_prepare(stmt_name, sql [, param_types ] ) -> PG::Result
1019
1294
  *
1020
- * Prepares statement _sql_ with name _name_ to be executed later.
1021
- * Returns a PG::Result instance on success.
1022
- * On failure, it raises a PG::Error.
1023
- *
1024
- * +param_types+ is an optional parameter to specify the Oids of the
1025
- * types of the parameters.
1026
- *
1027
- * If the types are not specified, they will be inferred by PostgreSQL.
1028
- * Instead of specifying type oids, it's recommended to simply add
1029
- * explicit casts in the query to ensure that the right type is used.
1030
- *
1031
- * For example: "SELECT $1::int"
1032
- *
1033
- * PostgreSQL bind parameters are represented as $1, $1, $2, etc.,
1034
- * inside the SQL query.
1295
+ * This function has the same behavior as #async_prepare, but is implemented using the synchronous command processing API of libpq.
1296
+ * See #async_exec for the differences between the two API variants.
1297
+ * It's not recommended to use explicit sync or async variants but #prepare instead, unless you have a good reason to do so.
1035
1298
  */
1036
1299
  static VALUE
1037
1300
  pgconn_prepare(int argc, VALUE *argv, VALUE self)
1038
1301
  {
1039
- PGconn *conn = pg_get_pgconn(self);
1302
+ t_pg_connection *this = pg_get_connection_safe( self );
1040
1303
  PGresult *result = NULL;
1041
1304
  VALUE rb_pgresult;
1042
1305
  VALUE name, command, in_paramtypes;
@@ -1044,10 +1307,13 @@ pgconn_prepare(int argc, VALUE *argv, VALUE self)
1044
1307
  int i = 0;
1045
1308
  int nParams = 0;
1046
1309
  Oid *paramTypes = NULL;
1310
+ const char *name_cstr;
1311
+ const char *command_cstr;
1312
+ int enc_idx = this->enc_idx;
1047
1313
 
1048
1314
  rb_scan_args(argc, argv, "21", &name, &command, &in_paramtypes);
1049
- Check_Type(name, T_STRING);
1050
- Check_Type(command, T_STRING);
1315
+ name_cstr = pg_cstr_enc(name, enc_idx);
1316
+ command_cstr = pg_cstr_enc(command, enc_idx);
1051
1317
 
1052
1318
  if(! NIL_P(in_paramtypes)) {
1053
1319
  Check_Type(in_paramtypes, T_ARRAY);
@@ -1055,15 +1321,13 @@ pgconn_prepare(int argc, VALUE *argv, VALUE self)
1055
1321
  paramTypes = ALLOC_N(Oid, nParams);
1056
1322
  for(i = 0; i < nParams; i++) {
1057
1323
  param = rb_ary_entry(in_paramtypes, i);
1058
- Check_Type(param, T_FIXNUM);
1059
1324
  if(param == Qnil)
1060
1325
  paramTypes[i] = 0;
1061
1326
  else
1062
- paramTypes[i] = NUM2INT(param);
1327
+ paramTypes[i] = NUM2UINT(param);
1063
1328
  }
1064
1329
  }
1065
- result = gvl_PQprepare(conn, StringValuePtr(name), StringValuePtr(command),
1066
- nParams, paramTypes);
1330
+ result = gvl_PQprepare(this->pgconn, name_cstr, command_cstr, nParams, paramTypes);
1067
1331
 
1068
1332
  xfree(paramTypes);
1069
1333
 
@@ -1074,122 +1338,40 @@ pgconn_prepare(int argc, VALUE *argv, VALUE self)
1074
1338
 
1075
1339
  /*
1076
1340
  * call-seq:
1077
- * conn.exec_prepared(statement_name [, params, result_format ] ) -> PG::Result
1078
- * conn.exec_prepared(statement_name [, params, result_format ] ) {|pg_result| block }
1341
+ * conn.sync_exec_prepared(statement_name [, params, result_format[, type_map]] ) -> PG::Result
1342
+ * conn.sync_exec_prepared(statement_name [, params, result_format[, type_map]] ) {|pg_result| block }
1079
1343
  *
1080
- * Execute prepared named statement specified by _statement_name_.
1081
- * Returns a PG::Result instance on success.
1082
- * On failure, it raises a PG::Error.
1083
- *
1084
- * +params+ is an array of the optional bind parameters for the
1085
- * SQL query. Each element of the +params+ array may be either:
1086
- * a hash of the form:
1087
- * {:value => String (value of bind parameter)
1088
- * :format => Fixnum (0 for text, 1 for binary)
1089
- * }
1090
- * or, it may be a String. If it is a string, that is equivalent to the hash:
1091
- * { :value => <string value>, :format => 0 }
1092
- *
1093
- * PostgreSQL bind parameters are represented as $1, $1, $2, etc.,
1094
- * inside the SQL query. The 0th element of the +params+ array is bound
1095
- * to $1, the 1st element is bound to $2, etc. +nil+ is treated as +NULL+.
1096
- *
1097
- * The optional +result_format+ should be 0 for text results, 1
1098
- * for binary.
1099
- *
1100
- * If the optional code block is given, it will be passed <i>result</i> as an argument,
1101
- * and the PG::Result object will automatically be cleared when the block terminates.
1102
- * In this instance, <code>conn.exec_prepared</code> returns the value of the block.
1344
+ * This function has the same behavior as #async_exec_prepared, but is implemented using the synchronous command processing API of libpq.
1345
+ * See #async_exec for the differences between the two API variants.
1346
+ * It's not recommended to use explicit sync or async variants but #exec_prepared instead, unless you have a good reason to do so.
1103
1347
  */
1104
1348
  static VALUE
1105
1349
  pgconn_exec_prepared(int argc, VALUE *argv, VALUE self)
1106
1350
  {
1107
- PGconn *conn = pg_get_pgconn(self);
1351
+ t_pg_connection *this = pg_get_connection_safe( self );
1108
1352
  PGresult *result = NULL;
1109
1353
  VALUE rb_pgresult;
1110
- VALUE name, params, in_res_fmt;
1111
- VALUE param, param_value, param_format;
1112
- VALUE param_value_tmp;
1113
- VALUE sym_value, sym_format;
1114
- VALUE gc_array;
1115
- int i = 0;
1354
+ VALUE name, in_res_fmt;
1116
1355
  int nParams;
1117
- char ** paramValues;
1118
- int *paramLengths;
1119
- int *paramFormats;
1120
1356
  int resultFormat;
1357
+ struct query_params_data paramsData = { this->enc_idx };
1121
1358
 
1359
+ rb_scan_args(argc, argv, "13", &name, &paramsData.params, &in_res_fmt, &paramsData.typemap);
1360
+ paramsData.with_types = 0;
1122
1361
 
1123
- rb_scan_args(argc, argv, "12", &name, &params, &in_res_fmt);
1124
- Check_Type(name, T_STRING);
1125
-
1126
- if(NIL_P(params)) {
1127
- params = rb_ary_new2(0);
1128
- resultFormat = 0;
1129
- }
1130
- else {
1131
- Check_Type(params, T_ARRAY);
1132
- }
1133
-
1134
- if(NIL_P(in_res_fmt)) {
1135
- resultFormat = 0;
1362
+ if(NIL_P(paramsData.params)) {
1363
+ paramsData.params = rb_ary_new2(0);
1136
1364
  }
1137
- else {
1138
- resultFormat = NUM2INT(in_res_fmt);
1139
- }
1140
-
1141
- gc_array = rb_ary_new();
1142
- rb_gc_register_address(&gc_array);
1143
- sym_value = ID2SYM(rb_intern("value"));
1144
- sym_format = ID2SYM(rb_intern("format"));
1145
- nParams = (int)RARRAY_LEN(params);
1146
- paramValues = ALLOC_N(char *, nParams);
1147
- paramLengths = ALLOC_N(int, nParams);
1148
- paramFormats = ALLOC_N(int, nParams);
1149
- for(i = 0; i < nParams; i++) {
1150
- param = rb_ary_entry(params, i);
1151
- if (TYPE(param) == T_HASH) {
1152
- param_value_tmp = rb_hash_aref(param, sym_value);
1153
- if(param_value_tmp == Qnil)
1154
- param_value = param_value_tmp;
1155
- else
1156
- param_value = rb_obj_as_string(param_value_tmp);
1157
- param_format = rb_hash_aref(param, sym_format);
1158
- }
1159
- else {
1160
- if(param == Qnil)
1161
- param_value = param;
1162
- else
1163
- param_value = rb_obj_as_string(param);
1164
- param_format = INT2NUM(0);
1165
- }
1166
- if(param_value == Qnil) {
1167
- paramValues[i] = NULL;
1168
- paramLengths[i] = 0;
1169
- }
1170
- else {
1171
- Check_Type(param_value, T_STRING);
1172
- /* make sure param_value doesn't get freed by the GC */
1173
- rb_ary_push(gc_array, param_value);
1174
- paramValues[i] = StringValuePtr(param_value);
1175
- paramLengths[i] = (int)RSTRING_LEN(param_value);
1176
- }
1365
+ pgconn_query_assign_typemap( self, &paramsData );
1177
1366
 
1178
- if(param_format == Qnil)
1179
- paramFormats[i] = 0;
1180
- else
1181
- paramFormats[i] = NUM2INT(param_format);
1182
- }
1367
+ resultFormat = NIL_P(in_res_fmt) ? 0 : NUM2INT(in_res_fmt);
1368
+ nParams = alloc_query_params( &paramsData );
1183
1369
 
1184
- result = gvl_PQexecPrepared(conn, StringValuePtr(name), nParams,
1185
- (const char * const *)paramValues, paramLengths, paramFormats,
1370
+ result = gvl_PQexecPrepared(this->pgconn, pg_cstr_enc(name, paramsData.enc_idx), nParams,
1371
+ (const char * const *)paramsData.values, paramsData.lengths, paramsData.formats,
1186
1372
  resultFormat);
1187
1373
 
1188
- rb_gc_unregister_address(&gc_array);
1189
-
1190
- xfree(paramValues);
1191
- xfree(paramLengths);
1192
- xfree(paramFormats);
1374
+ free_query_params( &paramsData );
1193
1375
 
1194
1376
  rb_pgresult = pg_new_result(result, self);
1195
1377
  pg_result_check(rb_pgresult);
@@ -1202,26 +1384,26 @@ pgconn_exec_prepared(int argc, VALUE *argv, VALUE self)
1202
1384
 
1203
1385
  /*
1204
1386
  * call-seq:
1205
- * conn.describe_prepared( statement_name ) -> PG::Result
1387
+ * conn.sync_describe_prepared( statement_name ) -> PG::Result
1206
1388
  *
1207
- * Retrieve information about the prepared statement
1208
- * _statement_name_.
1389
+ * This function has the same behavior as #async_describe_prepared, but is implemented using the synchronous command processing API of libpq.
1390
+ * See #async_exec for the differences between the two API variants.
1391
+ * It's not recommended to use explicit sync or async variants but #describe_prepared instead, unless you have a good reason to do so.
1209
1392
  */
1210
1393
  static VALUE
1211
1394
  pgconn_describe_prepared(VALUE self, VALUE stmt_name)
1212
1395
  {
1213
1396
  PGresult *result;
1214
1397
  VALUE rb_pgresult;
1215
- PGconn *conn = pg_get_pgconn(self);
1216
- char *stmt;
1217
- if(stmt_name == Qnil) {
1398
+ t_pg_connection *this = pg_get_connection_safe( self );
1399
+ const char *stmt;
1400
+ if(NIL_P(stmt_name)) {
1218
1401
  stmt = NULL;
1219
1402
  }
1220
1403
  else {
1221
- Check_Type(stmt_name, T_STRING);
1222
- stmt = StringValuePtr(stmt_name);
1404
+ stmt = pg_cstr_enc(stmt_name, this->enc_idx);
1223
1405
  }
1224
- result = gvl_PQdescribePrepared(conn, stmt);
1406
+ result = gvl_PQdescribePrepared(this->pgconn, stmt);
1225
1407
  rb_pgresult = pg_new_result(result, self);
1226
1408
  pg_result_check(rb_pgresult);
1227
1409
  return rb_pgresult;
@@ -1230,9 +1412,11 @@ pgconn_describe_prepared(VALUE self, VALUE stmt_name)
1230
1412
 
1231
1413
  /*
1232
1414
  * call-seq:
1233
- * conn.describe_portal( portal_name ) -> PG::Result
1415
+ * conn.sync_describe_portal( portal_name ) -> PG::Result
1234
1416
  *
1235
- * Retrieve information about the portal _portal_name_.
1417
+ * This function has the same behavior as #async_describe_portal, but is implemented using the synchronous command processing API of libpq.
1418
+ * See #async_exec for the differences between the two API variants.
1419
+ * It's not recommended to use explicit sync or async variants but #describe_portal instead, unless you have a good reason to do so.
1236
1420
  */
1237
1421
  static VALUE
1238
1422
  pgconn_describe_portal(self, stmt_name)
@@ -1240,16 +1424,15 @@ pgconn_describe_portal(self, stmt_name)
1240
1424
  {
1241
1425
  PGresult *result;
1242
1426
  VALUE rb_pgresult;
1243
- PGconn *conn = pg_get_pgconn(self);
1244
- char *stmt;
1245
- if(stmt_name == Qnil) {
1427
+ t_pg_connection *this = pg_get_connection_safe( self );
1428
+ const char *stmt;
1429
+ if(NIL_P(stmt_name)) {
1246
1430
  stmt = NULL;
1247
1431
  }
1248
1432
  else {
1249
- Check_Type(stmt_name, T_STRING);
1250
- stmt = StringValuePtr(stmt_name);
1433
+ stmt = pg_cstr_enc(stmt_name, this->enc_idx);
1251
1434
  }
1252
- result = gvl_PQdescribePortal(conn, stmt);
1435
+ result = gvl_PQdescribePortal(this->pgconn, stmt);
1253
1436
  rb_pgresult = pg_new_result(result, self);
1254
1437
  pg_result_check(rb_pgresult);
1255
1438
  return rb_pgresult;
@@ -1289,10 +1472,6 @@ pgconn_make_empty_pgresult(VALUE self, VALUE status)
1289
1472
  * call-seq:
1290
1473
  * conn.escape_string( str ) -> String
1291
1474
  *
1292
- * Connection instance method for versions of 8.1 and higher of libpq
1293
- * uses PQescapeStringConn, which is safer. Avoid calling as a class method,
1294
- * the class method uses the deprecated PQescapeString() API function.
1295
- *
1296
1475
  * Returns a SQL-safe version of the String _str_.
1297
1476
  * This is the preferred way to make strings safe for inclusion in
1298
1477
  * SQL queries.
@@ -1300,44 +1479,43 @@ pgconn_make_empty_pgresult(VALUE self, VALUE status)
1300
1479
  * Consider using exec_params, which avoids the need for passing values
1301
1480
  * inside of SQL commands.
1302
1481
  *
1303
- * Encoding of escaped string will be equal to client encoding of connection.
1482
+ * Character encoding of escaped string will be equal to client encoding of connection.
1483
+ *
1484
+ * NOTE: This class version of this method can only be used safely in client
1485
+ * programs that use a single PostgreSQL connection at a time (in this case it can
1486
+ * find out what it needs to know "behind the scenes"). It might give the wrong
1487
+ * results if used in programs that use multiple database connections; use the
1488
+ * same method on the connection object in such cases.
1489
+ *
1490
+ * See also convenience functions #escape_literal and #escape_identifier which also add proper quotes around the string.
1304
1491
  */
1305
1492
  static VALUE
1306
1493
  pgconn_s_escape(VALUE self, VALUE string)
1307
1494
  {
1308
- char *escaped;
1309
1495
  size_t size;
1310
1496
  int error;
1311
1497
  VALUE result;
1312
- #ifdef M17N_SUPPORTED
1313
- rb_encoding* enc;
1314
- #endif
1498
+ int enc_idx;
1499
+ int singleton = !rb_obj_is_kind_of(self, rb_cPGconn);
1315
1500
 
1316
- Check_Type(string, T_STRING);
1501
+ StringValueCStr(string);
1502
+ enc_idx = singleton ? ENCODING_GET(string) : pg_get_connection(self)->enc_idx;
1503
+ if( ENCODING_GET(string) != enc_idx ){
1504
+ string = rb_str_export_to_enc(string, rb_enc_from_index(enc_idx));
1505
+ }
1317
1506
 
1318
- escaped = ALLOC_N(char, RSTRING_LEN(string) * 2 + 1);
1319
- if(rb_obj_class(self) == rb_cPGconn) {
1320
- size = PQescapeStringConn(pg_get_pgconn(self), escaped,
1507
+ result = rb_str_new(NULL, RSTRING_LEN(string) * 2 + 1);
1508
+ PG_ENCODING_SET_NOCHECK(result, enc_idx);
1509
+ if( !singleton ) {
1510
+ size = PQescapeStringConn(pg_get_pgconn(self), RSTRING_PTR(result),
1321
1511
  RSTRING_PTR(string), RSTRING_LEN(string), &error);
1322
1512
  if(error) {
1323
- xfree(escaped);
1324
1513
  rb_raise(rb_ePGerror, "%s", PQerrorMessage(pg_get_pgconn(self)));
1325
1514
  }
1326
1515
  } else {
1327
- size = PQescapeString(escaped, RSTRING_PTR(string), (int)RSTRING_LEN(string));
1328
- }
1329
- result = rb_str_new(escaped, size);
1330
- xfree(escaped);
1331
- OBJ_INFECT(result, string);
1332
-
1333
- #ifdef M17N_SUPPORTED
1334
- if ( rb_obj_class(self) == rb_cPGconn ) {
1335
- enc = pg_conn_enc_get( pg_get_pgconn(self) );
1336
- } else {
1337
- enc = rb_enc_get(string);
1516
+ size = PQescapeString(RSTRING_PTR(result), RSTRING_PTR(string), RSTRING_LEN(string));
1338
1517
  }
1339
- rb_enc_associate(result, enc);
1340
- #endif
1518
+ rb_str_set_len(result, size);
1341
1519
 
1342
1520
  return result;
1343
1521
  }
@@ -1346,13 +1524,6 @@ pgconn_s_escape(VALUE self, VALUE string)
1346
1524
  * call-seq:
1347
1525
  * conn.escape_bytea( string ) -> String
1348
1526
  *
1349
- * Connection instance method for versions of 8.1 and higher of libpq
1350
- * uses PQescapeByteaConn, which is safer. Avoid calling as a class method,
1351
- * the class method uses the deprecated PQescapeBytea() API function.
1352
- *
1353
- * Use the instance method version of this function, it is safer than the
1354
- * class method.
1355
- *
1356
1527
  * Escapes binary data for use within an SQL command with the type +bytea+.
1357
1528
  *
1358
1529
  * Certain byte values must be escaped (but all byte values may be escaped)
@@ -1365,6 +1536,12 @@ pgconn_s_escape(VALUE self, VALUE string)
1365
1536
  *
1366
1537
  * Consider using exec_params, which avoids the need for passing values inside of
1367
1538
  * SQL commands.
1539
+ *
1540
+ * NOTE: This class version of this method can only be used safely in client
1541
+ * programs that use a single PostgreSQL connection at a time (in this case it can
1542
+ * find out what it needs to know "behind the scenes"). It might give the wrong
1543
+ * results if used in programs that use multiple database connections; use the
1544
+ * same method on the connection object in such cases.
1368
1545
  */
1369
1546
  static VALUE
1370
1547
  pgconn_s_escape_bytea(VALUE self, VALUE str)
@@ -1377,14 +1554,13 @@ pgconn_s_escape_bytea(VALUE self, VALUE str)
1377
1554
  from = (unsigned char*)RSTRING_PTR(str);
1378
1555
  from_len = RSTRING_LEN(str);
1379
1556
 
1380
- if(rb_obj_class(self) == rb_cPGconn) {
1557
+ if ( rb_obj_is_kind_of(self, rb_cPGconn) ) {
1381
1558
  to = PQescapeByteaConn(pg_get_pgconn(self), from, from_len, &to_len);
1382
1559
  } else {
1383
1560
  to = PQescapeBytea( from, from_len, &to_len);
1384
1561
  }
1385
1562
 
1386
1563
  ret = rb_str_new((char*)to, to_len - 1);
1387
- OBJ_INFECT(ret, str);
1388
1564
  PQfreemem(to);
1389
1565
  return ret;
1390
1566
  }
@@ -1409,83 +1585,91 @@ pgconn_s_unescape_bytea(VALUE self, VALUE str)
1409
1585
  UNUSED( self );
1410
1586
 
1411
1587
  Check_Type(str, T_STRING);
1412
- from = (unsigned char*)StringValuePtr(str);
1588
+ from = (unsigned char*)StringValueCStr(str);
1413
1589
 
1414
1590
  to = PQunescapeBytea(from, &to_len);
1415
1591
 
1416
1592
  ret = rb_str_new((char*)to, to_len);
1417
- OBJ_INFECT(ret, str);
1418
1593
  PQfreemem(to);
1419
1594
  return ret;
1420
1595
  }
1421
1596
 
1422
- #ifdef HAVE_PQESCAPELITERAL
1423
1597
  /*
1424
1598
  * call-seq:
1425
1599
  * conn.escape_literal( str ) -> String
1426
1600
  *
1427
1601
  * Escape an arbitrary String +str+ as a literal.
1602
+ *
1603
+ * See also PG::TextEncoder::QuotedLiteral for a type cast integrated version of this function.
1428
1604
  */
1429
1605
  static VALUE
1430
1606
  pgconn_escape_literal(VALUE self, VALUE string)
1431
1607
  {
1432
- PGconn *conn = pg_get_pgconn(self);
1608
+ t_pg_connection *this = pg_get_connection_safe( self );
1433
1609
  char *escaped = NULL;
1434
1610
  VALUE error;
1435
1611
  VALUE result = Qnil;
1612
+ int enc_idx = this->enc_idx;
1436
1613
 
1437
- Check_Type(string, T_STRING);
1614
+ StringValueCStr(string);
1615
+ if( ENCODING_GET(string) != enc_idx ){
1616
+ string = rb_str_export_to_enc(string, rb_enc_from_index(enc_idx));
1617
+ }
1438
1618
 
1439
- escaped = PQescapeLiteral(conn, RSTRING_PTR(string), RSTRING_LEN(string));
1619
+ escaped = PQescapeLiteral(this->pgconn, RSTRING_PTR(string), RSTRING_LEN(string));
1440
1620
  if (escaped == NULL)
1441
1621
  {
1442
- error = rb_exc_new2(rb_ePGerror, PQerrorMessage(conn));
1622
+ error = rb_exc_new2(rb_ePGerror, PQerrorMessage(this->pgconn));
1443
1623
  rb_iv_set(error, "@connection", self);
1444
1624
  rb_exc_raise(error);
1445
1625
  return Qnil;
1446
1626
  }
1447
1627
  result = rb_str_new2(escaped);
1448
1628
  PQfreemem(escaped);
1449
- OBJ_INFECT(result, string);
1629
+ PG_ENCODING_SET_NOCHECK(result, enc_idx);
1450
1630
 
1451
1631
  return result;
1452
1632
  }
1453
- #endif
1454
1633
 
1455
- #ifdef HAVE_PQESCAPEIDENTIFIER
1456
1634
  /*
1457
1635
  * call-seq:
1458
1636
  * conn.escape_identifier( str ) -> String
1459
1637
  *
1460
1638
  * Escape an arbitrary String +str+ as an identifier.
1639
+ *
1640
+ * This method does the same as #quote_ident with a String argument,
1641
+ * but it doesn't support an Array argument and it makes use of libpq
1642
+ * to process the string.
1461
1643
  */
1462
1644
  static VALUE
1463
1645
  pgconn_escape_identifier(VALUE self, VALUE string)
1464
1646
  {
1465
- PGconn *conn = pg_get_pgconn(self);
1647
+ t_pg_connection *this = pg_get_connection_safe( self );
1466
1648
  char *escaped = NULL;
1467
1649
  VALUE error;
1468
1650
  VALUE result = Qnil;
1651
+ int enc_idx = this->enc_idx;
1469
1652
 
1470
- Check_Type(string, T_STRING);
1653
+ StringValueCStr(string);
1654
+ if( ENCODING_GET(string) != enc_idx ){
1655
+ string = rb_str_export_to_enc(string, rb_enc_from_index(enc_idx));
1656
+ }
1471
1657
 
1472
- escaped = PQescapeIdentifier(conn, RSTRING_PTR(string), RSTRING_LEN(string));
1658
+ escaped = PQescapeIdentifier(this->pgconn, RSTRING_PTR(string), RSTRING_LEN(string));
1473
1659
  if (escaped == NULL)
1474
1660
  {
1475
- error = rb_exc_new2(rb_ePGerror, PQerrorMessage(conn));
1661
+ error = rb_exc_new2(rb_ePGerror, PQerrorMessage(this->pgconn));
1476
1662
  rb_iv_set(error, "@connection", self);
1477
1663
  rb_exc_raise(error);
1478
1664
  return Qnil;
1479
1665
  }
1480
1666
  result = rb_str_new2(escaped);
1481
1667
  PQfreemem(escaped);
1482
- OBJ_INFECT(result, string);
1668
+ PG_ENCODING_SET_NOCHECK(result, enc_idx);
1483
1669
 
1484
1670
  return result;
1485
1671
  }
1486
- #endif
1487
1672
 
1488
- #ifdef HAVE_PQSETSINGLEROWMODE
1489
1673
  /*
1490
1674
  * call-seq:
1491
1675
  * conn.set_single_row_mode -> self
@@ -1496,7 +1680,7 @@ pgconn_escape_identifier(VALUE self, VALUE string)
1496
1680
  * Then call Connection#get_result repeatedly, until it returns nil.
1497
1681
  *
1498
1682
  * Each (but the last) received Result has exactly one row and a
1499
- * Result#result_status of PGRES_SINGLE_TUPLE. The last row has
1683
+ * Result#result_status of PGRES_SINGLE_TUPLE. The last Result has
1500
1684
  * zero rows and is used to indicate a successful execution of the query.
1501
1685
  * All of these Result objects will contain the same row description data
1502
1686
  * (column names, types, etc) that an ordinary Result object for the query
@@ -1521,7 +1705,6 @@ pgconn_escape_identifier(VALUE self, VALUE string)
1521
1705
  * # do something with the received row
1522
1706
  * end
1523
1707
  * end
1524
- *
1525
1708
  */
1526
1709
  static VALUE
1527
1710
  pgconn_set_single_row_mode(VALUE self)
@@ -1538,22 +1721,60 @@ pgconn_set_single_row_mode(VALUE self)
1538
1721
 
1539
1722
  return self;
1540
1723
  }
1541
- #endif
1724
+
1725
+ static VALUE pgconn_send_query_params(int argc, VALUE *argv, VALUE self);
1726
+
1727
+ /*
1728
+ * call-seq:
1729
+ * conn.send_query(sql) -> nil
1730
+ *
1731
+ * Sends SQL query request specified by _sql_ to PostgreSQL for
1732
+ * asynchronous processing, and immediately returns.
1733
+ * On failure, it raises a PG::Error.
1734
+ *
1735
+ * For backward compatibility, if you pass more than one parameter to this method,
1736
+ * it will call #send_query_params for you. New code should explicitly use #send_query_params if
1737
+ * argument placeholders are used.
1738
+ *
1739
+ */
1740
+ static VALUE
1741
+ pgconn_send_query(int argc, VALUE *argv, VALUE self)
1742
+ {
1743
+ t_pg_connection *this = pg_get_connection_safe( self );
1744
+ VALUE error;
1745
+
1746
+ /* If called with no or nil parameters, use PQexec for compatibility */
1747
+ if ( argc == 1 || (argc >= 2 && argc <= 4 && NIL_P(argv[1]) )) {
1748
+ if(gvl_PQsendQuery(this->pgconn, pg_cstr_enc(argv[0], this->enc_idx)) == 0) {
1749
+ error = rb_exc_new2(rb_eUnableToSend, PQerrorMessage(this->pgconn));
1750
+ rb_iv_set(error, "@connection", self);
1751
+ rb_exc_raise(error);
1752
+ }
1753
+ return Qnil;
1754
+ }
1755
+
1756
+ pg_deprecated(2, ("forwarding async_exec to async_exec_params and send_query to send_query_params is deprecated"));
1757
+
1758
+ /* If called with parameters, and optionally result_format,
1759
+ * use PQsendQueryParams
1760
+ */
1761
+ return pgconn_send_query_params( argc, argv, self);
1762
+ }
1542
1763
 
1543
1764
  /*
1544
1765
  * call-seq:
1545
- * conn.send_query(sql [, params, result_format ] ) -> nil
1766
+ * conn.send_query_params(sql, params [, result_format [, type_map ]] ) -> nil
1546
1767
  *
1547
1768
  * Sends SQL query request specified by _sql_ to PostgreSQL for
1548
1769
  * asynchronous processing, and immediately returns.
1549
1770
  * On failure, it raises a PG::Error.
1550
1771
  *
1551
- * +params+ is an optional array of the bind parameters for the SQL query.
1772
+ * +params+ is an array of the bind parameters for the SQL query.
1552
1773
  * Each element of the +params+ array may be either:
1553
1774
  * a hash of the form:
1554
1775
  * {:value => String (value of bind parameter)
1555
- * :type => Fixnum (oid of type of bind parameter)
1556
- * :format => Fixnum (0 for text, 1 for binary)
1776
+ * :type => Integer (oid of type of bind parameter)
1777
+ * :format => Integer (0 for text, 1 for binary)
1557
1778
  * }
1558
1779
  * or, it may be a String. If it is a string, that is equivalent to the hash:
1559
1780
  * { :value => <string value>, :type => 0, :format => 0 }
@@ -1570,116 +1791,39 @@ pgconn_set_single_row_mode(VALUE self)
1570
1791
  *
1571
1792
  * The optional +result_format+ should be 0 for text results, 1
1572
1793
  * for binary.
1794
+ *
1795
+ * +type_map+ can be a PG::TypeMap derivation (such as PG::BasicTypeMapForQueries).
1796
+ * This will type cast the params from various Ruby types before transmission
1797
+ * based on the encoders defined by the type map. When a type encoder is used
1798
+ * the format and oid of a given bind parameter are retrieved from the encoder
1799
+ * instead out of the hash form described above.
1800
+ *
1573
1801
  */
1574
1802
  static VALUE
1575
- pgconn_send_query(int argc, VALUE *argv, VALUE self)
1803
+ pgconn_send_query_params(int argc, VALUE *argv, VALUE self)
1576
1804
  {
1577
- PGconn *conn = pg_get_pgconn(self);
1805
+ t_pg_connection *this = pg_get_connection_safe( self );
1578
1806
  int result;
1579
- VALUE command, params, in_res_fmt;
1580
- VALUE param, param_type, param_value, param_format;
1581
- VALUE param_value_tmp;
1582
- VALUE sym_type, sym_value, sym_format;
1583
- VALUE gc_array;
1807
+ VALUE command, in_res_fmt;
1584
1808
  VALUE error;
1585
- int i=0;
1586
1809
  int nParams;
1587
- Oid *paramTypes;
1588
- char ** paramValues;
1589
- int *paramLengths;
1590
- int *paramFormats;
1591
1810
  int resultFormat;
1811
+ struct query_params_data paramsData = { this->enc_idx };
1592
1812
 
1593
- rb_scan_args(argc, argv, "12", &command, &params, &in_res_fmt);
1594
- Check_Type(command, T_STRING);
1595
-
1596
- /* If called with no parameters, use PQsendQuery */
1597
- if(NIL_P(params)) {
1598
- if(PQsendQuery(conn,StringValuePtr(command)) == 0) {
1599
- error = rb_exc_new2(rb_ePGerror, PQerrorMessage(conn));
1600
- rb_iv_set(error, "@connection", self);
1601
- rb_exc_raise(error);
1602
- }
1603
- return Qnil;
1604
- }
1605
-
1606
- /* If called with parameters, and optionally result_format,
1607
- * use PQsendQueryParams
1608
- */
1609
- Check_Type(params, T_ARRAY);
1610
-
1611
- if(NIL_P(in_res_fmt)) {
1612
- resultFormat = 0;
1613
- }
1614
- else {
1615
- resultFormat = NUM2INT(in_res_fmt);
1616
- }
1617
-
1618
- gc_array = rb_ary_new();
1619
- rb_gc_register_address(&gc_array);
1620
- sym_type = ID2SYM(rb_intern("type"));
1621
- sym_value = ID2SYM(rb_intern("value"));
1622
- sym_format = ID2SYM(rb_intern("format"));
1623
- nParams = (int)RARRAY_LEN(params);
1624
- paramTypes = ALLOC_N(Oid, nParams);
1625
- paramValues = ALLOC_N(char *, nParams);
1626
- paramLengths = ALLOC_N(int, nParams);
1627
- paramFormats = ALLOC_N(int, nParams);
1628
- for(i = 0; i < nParams; i++) {
1629
- param = rb_ary_entry(params, i);
1630
- if (TYPE(param) == T_HASH) {
1631
- param_type = rb_hash_aref(param, sym_type);
1632
- param_value_tmp = rb_hash_aref(param, sym_value);
1633
- if(param_value_tmp == Qnil)
1634
- param_value = param_value_tmp;
1635
- else
1636
- param_value = rb_obj_as_string(param_value_tmp);
1637
- param_format = rb_hash_aref(param, sym_format);
1638
- }
1639
- else {
1640
- param_type = INT2NUM(0);
1641
- if(param == Qnil)
1642
- param_value = param;
1643
- else
1644
- param_value = rb_obj_as_string(param);
1645
- param_format = INT2NUM(0);
1646
- }
1647
-
1648
- if(param_type == Qnil)
1649
- paramTypes[i] = 0;
1650
- else
1651
- paramTypes[i] = NUM2INT(param_type);
1652
-
1653
- if(param_value == Qnil) {
1654
- paramValues[i] = NULL;
1655
- paramLengths[i] = 0;
1656
- }
1657
- else {
1658
- Check_Type(param_value, T_STRING);
1659
- /* make sure param_value doesn't get freed by the GC */
1660
- rb_ary_push(gc_array, param_value);
1661
- paramValues[i] = StringValuePtr(param_value);
1662
- paramLengths[i] = (int)RSTRING_LEN(param_value);
1663
- }
1664
-
1665
- if(param_format == Qnil)
1666
- paramFormats[i] = 0;
1667
- else
1668
- paramFormats[i] = NUM2INT(param_format);
1669
- }
1813
+ rb_scan_args(argc, argv, "22", &command, &paramsData.params, &in_res_fmt, &paramsData.typemap);
1814
+ paramsData.with_types = 1;
1670
1815
 
1671
- result = PQsendQueryParams(conn, StringValuePtr(command), nParams, paramTypes,
1672
- (const char * const *)paramValues, paramLengths, paramFormats, resultFormat);
1816
+ pgconn_query_assign_typemap( self, &paramsData );
1817
+ resultFormat = NIL_P(in_res_fmt) ? 0 : NUM2INT(in_res_fmt);
1818
+ nParams = alloc_query_params( &paramsData );
1673
1819
 
1674
- rb_gc_unregister_address(&gc_array);
1820
+ result = gvl_PQsendQueryParams(this->pgconn, pg_cstr_enc(command, paramsData.enc_idx), nParams, paramsData.types,
1821
+ (const char * const *)paramsData.values, paramsData.lengths, paramsData.formats, resultFormat);
1675
1822
 
1676
- xfree(paramTypes);
1677
- xfree(paramValues);
1678
- xfree(paramLengths);
1679
- xfree(paramFormats);
1823
+ free_query_params( &paramsData );
1680
1824
 
1681
1825
  if(result == 0) {
1682
- error = rb_exc_new2(rb_ePGerror, PQerrorMessage(conn));
1826
+ error = rb_exc_new2(rb_eUnableToSend, PQerrorMessage(this->pgconn));
1683
1827
  rb_iv_set(error, "@connection", self);
1684
1828
  rb_exc_raise(error);
1685
1829
  }
@@ -1709,7 +1853,7 @@ pgconn_send_query(int argc, VALUE *argv, VALUE self)
1709
1853
  static VALUE
1710
1854
  pgconn_send_prepare(int argc, VALUE *argv, VALUE self)
1711
1855
  {
1712
- PGconn *conn = pg_get_pgconn(self);
1856
+ t_pg_connection *this = pg_get_connection_safe( self );
1713
1857
  int result;
1714
1858
  VALUE name, command, in_paramtypes;
1715
1859
  VALUE param;
@@ -1717,10 +1861,13 @@ pgconn_send_prepare(int argc, VALUE *argv, VALUE self)
1717
1861
  int i = 0;
1718
1862
  int nParams = 0;
1719
1863
  Oid *paramTypes = NULL;
1864
+ const char *name_cstr;
1865
+ const char *command_cstr;
1866
+ int enc_idx = this->enc_idx;
1720
1867
 
1721
1868
  rb_scan_args(argc, argv, "21", &name, &command, &in_paramtypes);
1722
- Check_Type(name, T_STRING);
1723
- Check_Type(command, T_STRING);
1869
+ name_cstr = pg_cstr_enc(name, enc_idx);
1870
+ command_cstr = pg_cstr_enc(command, enc_idx);
1724
1871
 
1725
1872
  if(! NIL_P(in_paramtypes)) {
1726
1873
  Check_Type(in_paramtypes, T_ARRAY);
@@ -1728,20 +1875,18 @@ pgconn_send_prepare(int argc, VALUE *argv, VALUE self)
1728
1875
  paramTypes = ALLOC_N(Oid, nParams);
1729
1876
  for(i = 0; i < nParams; i++) {
1730
1877
  param = rb_ary_entry(in_paramtypes, i);
1731
- Check_Type(param, T_FIXNUM);
1732
1878
  if(param == Qnil)
1733
1879
  paramTypes[i] = 0;
1734
1880
  else
1735
- paramTypes[i] = NUM2INT(param);
1881
+ paramTypes[i] = NUM2UINT(param);
1736
1882
  }
1737
1883
  }
1738
- result = PQsendPrepare(conn, StringValuePtr(name), StringValuePtr(command),
1739
- nParams, paramTypes);
1884
+ result = gvl_PQsendPrepare(this->pgconn, name_cstr, command_cstr, nParams, paramTypes);
1740
1885
 
1741
1886
  xfree(paramTypes);
1742
1887
 
1743
1888
  if(result == 0) {
1744
- error = rb_exc_new2(rb_ePGerror, PQerrorMessage(conn));
1889
+ error = rb_exc_new2(rb_eUnableToSend, PQerrorMessage(this->pgconn));
1745
1890
  rb_iv_set(error, "@connection", self);
1746
1891
  rb_exc_raise(error);
1747
1892
  }
@@ -1750,7 +1895,7 @@ pgconn_send_prepare(int argc, VALUE *argv, VALUE self)
1750
1895
 
1751
1896
  /*
1752
1897
  * call-seq:
1753
- * conn.send_query_prepared( statement_name [, params, result_format ] )
1898
+ * conn.send_query_prepared( statement_name [, params, result_format[, type_map ]] )
1754
1899
  * -> nil
1755
1900
  *
1756
1901
  * Execute prepared named statement specified by _statement_name_
@@ -1761,7 +1906,7 @@ pgconn_send_prepare(int argc, VALUE *argv, VALUE self)
1761
1906
  * SQL query. Each element of the +params+ array may be either:
1762
1907
  * a hash of the form:
1763
1908
  * {:value => String (value of bind parameter)
1764
- * :format => Fixnum (0 for text, 1 for binary)
1909
+ * :format => Integer (0 for text, 1 for binary)
1765
1910
  * }
1766
1911
  * or, it may be a String. If it is a string, that is equivalent to the hash:
1767
1912
  * { :value => <string value>, :format => 0 }
@@ -1772,99 +1917,45 @@ pgconn_send_prepare(int argc, VALUE *argv, VALUE self)
1772
1917
  *
1773
1918
  * The optional +result_format+ should be 0 for text results, 1
1774
1919
  * for binary.
1920
+ *
1921
+ * +type_map+ can be a PG::TypeMap derivation (such as PG::BasicTypeMapForQueries).
1922
+ * This will type cast the params from various Ruby types before transmission
1923
+ * based on the encoders defined by the type map. When a type encoder is used
1924
+ * the format and oid of a given bind parameter are retrieved from the encoder
1925
+ * instead out of the hash form described above.
1926
+ *
1775
1927
  */
1776
1928
  static VALUE
1777
1929
  pgconn_send_query_prepared(int argc, VALUE *argv, VALUE self)
1778
1930
  {
1779
- PGconn *conn = pg_get_pgconn(self);
1931
+ t_pg_connection *this = pg_get_connection_safe( self );
1780
1932
  int result;
1781
- VALUE name, params, in_res_fmt;
1782
- VALUE param, param_value, param_format;
1783
- VALUE param_value_tmp;
1784
- VALUE sym_value, sym_format;
1785
- VALUE gc_array;
1933
+ VALUE name, in_res_fmt;
1786
1934
  VALUE error;
1787
- int i = 0;
1788
1935
  int nParams;
1789
- char ** paramValues;
1790
- int *paramLengths;
1791
- int *paramFormats;
1792
1936
  int resultFormat;
1937
+ struct query_params_data paramsData = { this->enc_idx };
1793
1938
 
1794
- rb_scan_args(argc, argv, "12", &name, &params, &in_res_fmt);
1795
- Check_Type(name, T_STRING);
1796
-
1797
- if(NIL_P(params)) {
1798
- params = rb_ary_new2(0);
1799
- resultFormat = 0;
1800
- }
1801
- else {
1802
- Check_Type(params, T_ARRAY);
1803
- }
1939
+ rb_scan_args(argc, argv, "13", &name, &paramsData.params, &in_res_fmt, &paramsData.typemap);
1940
+ paramsData.with_types = 0;
1804
1941
 
1805
- if(NIL_P(in_res_fmt)) {
1942
+ if(NIL_P(paramsData.params)) {
1943
+ paramsData.params = rb_ary_new2(0);
1806
1944
  resultFormat = 0;
1807
1945
  }
1808
- else {
1809
- resultFormat = NUM2INT(in_res_fmt);
1810
- }
1811
-
1812
- gc_array = rb_ary_new();
1813
- rb_gc_register_address(&gc_array);
1814
- sym_value = ID2SYM(rb_intern("value"));
1815
- sym_format = ID2SYM(rb_intern("format"));
1816
- nParams = (int)RARRAY_LEN(params);
1817
- paramValues = ALLOC_N(char *, nParams);
1818
- paramLengths = ALLOC_N(int, nParams);
1819
- paramFormats = ALLOC_N(int, nParams);
1820
- for(i = 0; i < nParams; i++) {
1821
- param = rb_ary_entry(params, i);
1822
- if (TYPE(param) == T_HASH) {
1823
- param_value_tmp = rb_hash_aref(param, sym_value);
1824
- if(param_value_tmp == Qnil)
1825
- param_value = param_value_tmp;
1826
- else
1827
- param_value = rb_obj_as_string(param_value_tmp);
1828
- param_format = rb_hash_aref(param, sym_format);
1829
- }
1830
- else {
1831
- if(param == Qnil)
1832
- param_value = param;
1833
- else
1834
- param_value = rb_obj_as_string(param);
1835
- param_format = INT2NUM(0);
1836
- }
1837
-
1838
- if(param_value == Qnil) {
1839
- paramValues[i] = NULL;
1840
- paramLengths[i] = 0;
1841
- }
1842
- else {
1843
- Check_Type(param_value, T_STRING);
1844
- /* make sure param_value doesn't get freed by the GC */
1845
- rb_ary_push(gc_array, param_value);
1846
- paramValues[i] = StringValuePtr(param_value);
1847
- paramLengths[i] = (int)RSTRING_LEN(param_value);
1848
- }
1946
+ pgconn_query_assign_typemap( self, &paramsData );
1849
1947
 
1850
- if(param_format == Qnil)
1851
- paramFormats[i] = 0;
1852
- else
1853
- paramFormats[i] = NUM2INT(param_format);
1854
- }
1948
+ resultFormat = NIL_P(in_res_fmt) ? 0 : NUM2INT(in_res_fmt);
1949
+ nParams = alloc_query_params( &paramsData );
1855
1950
 
1856
- result = PQsendQueryPrepared(conn, StringValuePtr(name), nParams,
1857
- (const char * const *)paramValues, paramLengths, paramFormats,
1951
+ result = gvl_PQsendQueryPrepared(this->pgconn, pg_cstr_enc(name, paramsData.enc_idx), nParams,
1952
+ (const char * const *)paramsData.values, paramsData.lengths, paramsData.formats,
1858
1953
  resultFormat);
1859
1954
 
1860
- rb_gc_unregister_address(&gc_array);
1861
-
1862
- xfree(paramValues);
1863
- xfree(paramLengths);
1864
- xfree(paramFormats);
1955
+ free_query_params( &paramsData );
1865
1956
 
1866
1957
  if(result == 0) {
1867
- error = rb_exc_new2(rb_ePGerror, PQerrorMessage(conn));
1958
+ error = rb_exc_new2(rb_eUnableToSend, PQerrorMessage(this->pgconn));
1868
1959
  rb_iv_set(error, "@connection", self);
1869
1960
  rb_exc_raise(error);
1870
1961
  }
@@ -1882,10 +1973,10 @@ static VALUE
1882
1973
  pgconn_send_describe_prepared(VALUE self, VALUE stmt_name)
1883
1974
  {
1884
1975
  VALUE error;
1885
- PGconn *conn = pg_get_pgconn(self);
1976
+ t_pg_connection *this = pg_get_connection_safe( self );
1886
1977
  /* returns 0 on failure */
1887
- if(PQsendDescribePrepared(conn,StringValuePtr(stmt_name)) == 0) {
1888
- error = rb_exc_new2(rb_ePGerror, PQerrorMessage(conn));
1978
+ if(gvl_PQsendDescribePrepared(this->pgconn, pg_cstr_enc(stmt_name, this->enc_idx)) == 0) {
1979
+ error = rb_exc_new2(rb_eUnableToSend, PQerrorMessage(this->pgconn));
1889
1980
  rb_iv_set(error, "@connection", self);
1890
1981
  rb_exc_raise(error);
1891
1982
  }
@@ -1904,10 +1995,10 @@ static VALUE
1904
1995
  pgconn_send_describe_portal(VALUE self, VALUE portal)
1905
1996
  {
1906
1997
  VALUE error;
1907
- PGconn *conn = pg_get_pgconn(self);
1998
+ t_pg_connection *this = pg_get_connection_safe( self );
1908
1999
  /* returns 0 on failure */
1909
- if(PQsendDescribePortal(conn,StringValuePtr(portal)) == 0) {
1910
- error = rb_exc_new2(rb_ePGerror, PQerrorMessage(conn));
2000
+ if(gvl_PQsendDescribePortal(this->pgconn, pg_cstr_enc(portal, this->enc_idx)) == 0) {
2001
+ error = rb_exc_new2(rb_eUnableToSend, PQerrorMessage(this->pgconn));
1911
2002
  rb_iv_set(error, "@connection", self);
1912
2003
  rb_exc_raise(error);
1913
2004
  }
@@ -1965,7 +2056,7 @@ pgconn_consume_input(self)
1965
2056
  PGconn *conn = pg_get_pgconn(self);
1966
2057
  /* returns 0 on error */
1967
2058
  if(PQconsumeInput(conn) == 0) {
1968
- error = rb_exc_new2(rb_ePGerror, PQerrorMessage(conn));
2059
+ error = rb_exc_new2(rb_eConnectionBad, PQerrorMessage(conn));
1969
2060
  rb_iv_set(error, "@connection", self);
1970
2061
  rb_exc_raise(error);
1971
2062
  }
@@ -1983,7 +2074,7 @@ static VALUE
1983
2074
  pgconn_is_busy(self)
1984
2075
  VALUE self;
1985
2076
  {
1986
- return PQisBusy(pg_get_pgconn(self)) ? Qtrue : Qfalse;
2077
+ return gvl_PQisBusy(pg_get_pgconn(self)) ? Qtrue : Qfalse;
1987
2078
  }
1988
2079
 
1989
2080
  /*
@@ -2078,7 +2169,6 @@ pgconn_flush(self)
2078
2169
  static VALUE
2079
2170
  pgconn_cancel(VALUE self)
2080
2171
  {
2081
- #ifdef HAVE_PQGETCANCEL
2082
2172
  char errbuf[256];
2083
2173
  PGcancel *cancel;
2084
2174
  VALUE retval;
@@ -2088,7 +2178,7 @@ pgconn_cancel(VALUE self)
2088
2178
  if(cancel == NULL)
2089
2179
  rb_raise(rb_ePGerror,"Invalid connection!");
2090
2180
 
2091
- ret = PQcancel(cancel, errbuf, 256);
2181
+ ret = gvl_PQcancel(cancel, errbuf, 256);
2092
2182
  if(ret == 1)
2093
2183
  retval = Qnil;
2094
2184
  else
@@ -2096,9 +2186,6 @@ pgconn_cancel(VALUE self)
2096
2186
 
2097
2187
  PQfreeCancel(cancel);
2098
2188
  return retval;
2099
- #else
2100
- rb_notimplement();
2101
- #endif
2102
2189
  }
2103
2190
 
2104
2191
 
@@ -2112,7 +2199,7 @@ pgconn_cancel(VALUE self)
2112
2199
  static VALUE
2113
2200
  pgconn_notifies(VALUE self)
2114
2201
  {
2115
- PGconn* conn = pg_get_pgconn(self);
2202
+ t_pg_connection *this = pg_get_connection_safe( self );
2116
2203
  PGnotify *notification;
2117
2204
  VALUE hash;
2118
2205
  VALUE sym_relname, sym_be_pid, sym_extra;
@@ -2122,19 +2209,17 @@ pgconn_notifies(VALUE self)
2122
2209
  sym_be_pid = ID2SYM(rb_intern("be_pid"));
2123
2210
  sym_extra = ID2SYM(rb_intern("extra"));
2124
2211
 
2125
- notification = PQnotifies(conn);
2212
+ notification = gvl_PQnotifies(this->pgconn);
2126
2213
  if (notification == NULL) {
2127
2214
  return Qnil;
2128
2215
  }
2129
2216
 
2130
2217
  hash = rb_hash_new();
2131
- relname = rb_tainted_str_new2(notification->relname);
2218
+ relname = rb_str_new2(notification->relname);
2132
2219
  be_pid = INT2NUM(notification->be_pid);
2133
- extra = rb_tainted_str_new2(notification->extra);
2134
- #ifdef M17N_SUPPORTED
2135
- ENCODING_SET( relname, rb_enc_to_index(pg_conn_enc_get( conn )) );
2136
- ENCODING_SET( extra, rb_enc_to_index(pg_conn_enc_get( conn )) );
2137
- #endif
2220
+ extra = rb_str_new2(notification->extra);
2221
+ PG_ENCODING_SET_NOCHECK( relname, this->enc_idx );
2222
+ PG_ENCODING_SET_NOCHECK( extra, this->enc_idx );
2138
2223
 
2139
2224
  rb_hash_aset(hash, sym_relname, relname);
2140
2225
  rb_hash_aset(hash, sym_be_pid, be_pid);
@@ -2144,87 +2229,60 @@ pgconn_notifies(VALUE self)
2144
2229
  return hash;
2145
2230
  }
2146
2231
 
2147
- /* Win32 + Ruby 1.8 */
2148
- #if !defined( HAVE_RUBY_VM_H ) && defined( _WIN32 )
2149
-
2232
+ /* Win32 + Ruby 1.9+ */
2233
+ #if defined( _WIN32 )
2150
2234
  /*
2151
- * Duplicate the sockets from libpq and create temporary CRT FDs
2152
- */
2153
- void create_crt_fd(fd_set *os_set, fd_set *crt_set)
2154
- {
2155
- int i;
2156
- crt_set->fd_count = os_set->fd_count;
2157
- for (i = 0; i < os_set->fd_count; i++) {
2158
- WSAPROTOCOL_INFO wsa_pi;
2159
- /* dupicate the SOCKET */
2160
- int r = WSADuplicateSocket(os_set->fd_array[i], GetCurrentProcessId(), &wsa_pi);
2161
- SOCKET s = WSASocket(wsa_pi.iAddressFamily, wsa_pi.iSocketType, wsa_pi.iProtocol, &wsa_pi, 0, 0);
2162
- /* create the CRT fd so ruby can get back to the SOCKET */
2163
- int fd = _open_osfhandle(s, O_RDWR|O_BINARY);
2164
- os_set->fd_array[i] = s;
2165
- crt_set->fd_array[i] = fd;
2166
- }
2167
- }
2168
-
2169
- /*
2170
- * Clean up the CRT FDs from create_crt_fd()
2171
- */
2172
- void cleanup_crt_fd(fd_set *os_set, fd_set *crt_set)
2173
- {
2174
- int i;
2175
- for (i = 0; i < os_set->fd_count; i++) {
2176
- /* cleanup the CRT fd */
2177
- _close(crt_set->fd_array[i]);
2178
- /* cleanup the duplicated SOCKET */
2179
- closesocket(os_set->fd_array[i]);
2180
- }
2181
- }
2182
- #endif
2183
-
2184
- /* Win32 + Ruby 1.9+ */
2185
- #if defined( HAVE_RUBY_VM_H ) && defined( _WIN32 )
2186
- /*
2187
- * On Windows, use platform-specific strategies to wait for the socket
2188
- * instead of rb_thread_select().
2235
+ * On Windows, use platform-specific strategies to wait for the socket
2236
+ * instead of rb_wait_for_single_fd().
2189
2237
  */
2190
2238
 
2191
2239
  int rb_w32_wait_events( HANDLE *events, int num, DWORD timeout );
2192
2240
 
2193
- /* If WIN32 and Ruby 1.9 do not use rb_thread_select() which sometimes hangs
2194
- * and does not wait (nor sleep) any time even if timeout is given.
2195
- * Instead use the Winsock events and rb_w32_wait_events(). */
2196
-
2197
2241
  static void *
2198
2242
  wait_socket_readable( PGconn *conn, struct timeval *ptimeout, void *(*is_readable)(PGconn *) )
2199
2243
  {
2200
2244
  int sd = PQsocket( conn );
2201
2245
  void *retval;
2246
+ struct timeval aborttime={0,0}, currtime, waittime;
2202
2247
  DWORD timeout_milisec = INFINITE;
2203
2248
  DWORD wait_ret;
2204
2249
  WSAEVENT hEvent;
2205
2250
 
2206
2251
  if ( sd < 0 )
2207
- rb_bug( "PQsocket(conn): couldn't fetch the connection's socket!" );
2252
+ rb_raise(rb_eConnectionBad, "PQsocket() can't get socket descriptor");
2208
2253
 
2209
2254
  hEvent = WSACreateEvent();
2210
2255
 
2211
- if ( ptimeout ) {
2212
- timeout_milisec = (DWORD)( ptimeout->tv_sec * 1e3 + ptimeout->tv_usec / 1e3 );
2213
- }
2214
-
2215
2256
  /* Check for connection errors (PQisBusy is true on connection errors) */
2216
2257
  if( PQconsumeInput(conn) == 0 ) {
2217
2258
  WSACloseEvent( hEvent );
2218
- rb_raise( rb_ePGerror, "%s", PQerrorMessage(conn) );
2259
+ rb_raise( rb_eConnectionBad, "PQconsumeInput() %s", PQerrorMessage(conn) );
2260
+ }
2261
+
2262
+ if ( ptimeout ) {
2263
+ gettimeofday(&currtime, NULL);
2264
+ timeradd(&currtime, ptimeout, &aborttime);
2219
2265
  }
2220
2266
 
2221
2267
  while ( !(retval=is_readable(conn)) ) {
2222
2268
  if ( WSAEventSelect(sd, hEvent, FD_READ|FD_CLOSE) == SOCKET_ERROR ) {
2223
2269
  WSACloseEvent( hEvent );
2224
- rb_raise( rb_ePGerror, "WSAEventSelect socket error: %d", WSAGetLastError() );
2270
+ rb_raise( rb_eConnectionBad, "WSAEventSelect socket error: %d", WSAGetLastError() );
2225
2271
  }
2226
2272
 
2227
- wait_ret = rb_w32_wait_events( &hEvent, 1, timeout_milisec );
2273
+ if ( ptimeout ) {
2274
+ gettimeofday(&currtime, NULL);
2275
+ timersub(&aborttime, &currtime, &waittime);
2276
+ timeout_milisec = (DWORD)( waittime.tv_sec * 1e3 + waittime.tv_usec / 1e3 );
2277
+ }
2278
+
2279
+ /* Is the given timeout valid? */
2280
+ if( !ptimeout || (waittime.tv_sec >= 0 && waittime.tv_usec >= 0) ){
2281
+ /* Wait for the socket to become readable before checking again */
2282
+ wait_ret = rb_w32_wait_events( &hEvent, 1, timeout_milisec );
2283
+ } else {
2284
+ wait_ret = WAIT_TIMEOUT;
2285
+ }
2228
2286
 
2229
2287
  if ( wait_ret == WAIT_TIMEOUT ) {
2230
2288
  WSACloseEvent( hEvent );
@@ -2237,16 +2295,16 @@ wait_socket_readable( PGconn *conn, struct timeval *ptimeout, void *(*is_readabl
2237
2295
  rb_thread_check_ints();
2238
2296
  } else if ( wait_ret == WAIT_FAILED ) {
2239
2297
  WSACloseEvent( hEvent );
2240
- rb_raise( rb_ePGerror, "Wait on socket error (WaitForMultipleObjects): %lu", GetLastError() );
2298
+ rb_raise( rb_eConnectionBad, "Wait on socket error (WaitForMultipleObjects): %lu", GetLastError() );
2241
2299
  } else {
2242
2300
  WSACloseEvent( hEvent );
2243
- rb_raise( rb_ePGerror, "Wait on socket abandoned (WaitForMultipleObjects)" );
2301
+ rb_raise( rb_eConnectionBad, "Wait on socket abandoned (WaitForMultipleObjects)" );
2244
2302
  }
2245
2303
 
2246
2304
  /* Check for connection errors (PQisBusy is true on connection errors) */
2247
2305
  if ( PQconsumeInput(conn) == 0 ) {
2248
2306
  WSACloseEvent( hEvent );
2249
- rb_raise( rb_ePGerror, "%s", PQerrorMessage(conn) );
2307
+ rb_raise( rb_eConnectionBad, "PQconsumeInput() %s", PQerrorMessage(conn) );
2250
2308
  }
2251
2309
  }
2252
2310
 
@@ -2256,7 +2314,7 @@ wait_socket_readable( PGconn *conn, struct timeval *ptimeout, void *(*is_readabl
2256
2314
 
2257
2315
  #else
2258
2316
 
2259
- /* non Win32 or Win32+Ruby-1.8 */
2317
+ /* non Win32 */
2260
2318
 
2261
2319
  static void *
2262
2320
  wait_socket_readable( PGconn *conn, struct timeval *ptimeout, void *(*is_readable)(PGconn *))
@@ -2264,58 +2322,49 @@ wait_socket_readable( PGconn *conn, struct timeval *ptimeout, void *(*is_readabl
2264
2322
  int sd = PQsocket( conn );
2265
2323
  int ret;
2266
2324
  void *retval;
2267
- rb_fdset_t sd_rset;
2268
- #ifdef _WIN32
2269
- rb_fdset_t crt_sd_rset;
2270
- #endif
2325
+ struct timeval aborttime={0,0}, currtime, waittime;
2271
2326
 
2272
2327
  if ( sd < 0 )
2273
- rb_bug( "PQsocket(conn): couldn't fetch the connection's socket!" );
2328
+ rb_raise(rb_eConnectionBad, "PQsocket() can't get socket descriptor");
2274
2329
 
2275
2330
  /* Check for connection errors (PQisBusy is true on connection errors) */
2276
2331
  if ( PQconsumeInput(conn) == 0 )
2277
- rb_raise( rb_ePGerror, "%s", PQerrorMessage(conn) );
2332
+ rb_raise( rb_eConnectionBad, "PQconsumeInput() %s", PQerrorMessage(conn) );
2278
2333
 
2279
- rb_fd_init( &sd_rset );
2334
+ if ( ptimeout ) {
2335
+ gettimeofday(&currtime, NULL);
2336
+ timeradd(&currtime, ptimeout, &aborttime);
2337
+ }
2280
2338
 
2281
2339
  while ( !(retval=is_readable(conn)) ) {
2282
- rb_fd_zero( &sd_rset );
2283
- rb_fd_set( sd, &sd_rset );
2284
-
2285
- #ifdef _WIN32
2286
- /* Ruby's FD_SET is modified on win32 to convert a file descriptor
2287
- * to osfhandle, but we already get a osfhandle from PQsocket().
2288
- * Therefore it's overwritten here. */
2289
- sd_rset.fd_array[0] = sd;
2290
- create_crt_fd(&sd_rset, &crt_sd_rset);
2291
- #endif
2292
-
2293
- /* Wait for the socket to become readable before checking again */
2294
- ret = rb_thread_fd_select( sd+1, &sd_rset, NULL, NULL, ptimeout );
2340
+ if ( ptimeout ) {
2341
+ gettimeofday(&currtime, NULL);
2342
+ timersub(&aborttime, &currtime, &waittime);
2343
+ }
2295
2344
 
2296
- #ifdef _WIN32
2297
- cleanup_crt_fd(&sd_rset, &crt_sd_rset);
2298
- #endif
2345
+ /* Is the given timeout valid? */
2346
+ if( !ptimeout || (waittime.tv_sec >= 0 && waittime.tv_usec >= 0) ){
2347
+ /* Wait for the socket to become readable before checking again */
2348
+ ret = rb_wait_for_single_fd( sd, RB_WAITFD_IN, ptimeout ? &waittime : NULL );
2349
+ } else {
2350
+ ret = 0;
2351
+ }
2299
2352
 
2300
2353
  if ( ret < 0 ){
2301
- rb_fd_term( &sd_rset );
2302
- rb_sys_fail( "rb_thread_select()" );
2354
+ rb_sys_fail( "rb_wait_for_single_fd()" );
2303
2355
  }
2304
2356
 
2305
2357
  /* Return false if the select() timed out */
2306
2358
  if ( ret == 0 ){
2307
- rb_fd_term( &sd_rset );
2308
2359
  return NULL;
2309
2360
  }
2310
2361
 
2311
2362
  /* Check for connection errors (PQisBusy is true on connection errors) */
2312
2363
  if ( PQconsumeInput(conn) == 0 ){
2313
- rb_fd_term( &sd_rset );
2314
- rb_raise( rb_ePGerror, "%s", PQerrorMessage(conn) );
2364
+ rb_raise( rb_eConnectionBad, "PQconsumeInput() %s", PQerrorMessage(conn) );
2315
2365
  }
2316
2366
  }
2317
2367
 
2318
- rb_fd_term( &sd_rset );
2319
2368
  return retval;
2320
2369
  }
2321
2370
 
@@ -2325,32 +2374,25 @@ wait_socket_readable( PGconn *conn, struct timeval *ptimeout, void *(*is_readabl
2325
2374
  static void *
2326
2375
  notify_readable(PGconn *conn)
2327
2376
  {
2328
- return (void*)PQnotifies(conn);
2377
+ return (void*)gvl_PQnotifies(conn);
2329
2378
  }
2330
2379
 
2331
2380
  /*
2332
2381
  * call-seq:
2333
- * conn.wait_for_notify( [ timeout ] ) -> String
2334
- * conn.wait_for_notify( [ timeout ] ) { |event, pid| block }
2335
- * conn.wait_for_notify( [ timeout ] ) { |event, pid, payload| block } # PostgreSQL 9.0
2382
+ * conn.wait_for_notify( [ timeout ] ) { |event, pid, payload| block } -> String
2336
2383
  *
2337
2384
  * Blocks while waiting for notification(s), or until the optional
2338
2385
  * _timeout_ is reached, whichever comes first. _timeout_ is
2339
2386
  * measured in seconds and can be fractional.
2340
2387
  *
2341
- * Returns +nil+ if _timeout_ is reached, the name of the NOTIFY
2342
- * event otherwise. If used in block form, passes the name of the
2343
- * NOTIFY +event+ and the generating +pid+ into the block.
2344
- *
2345
- * Under PostgreSQL 9.0 and later, if the notification is sent with
2346
- * the optional +payload+ string, it will be given to the block as the
2347
- * third argument.
2348
- *
2388
+ * Returns +nil+ if _timeout_ is reached, the name of the NOTIFY event otherwise.
2389
+ * If used in block form, passes the name of the NOTIFY +event+, the generating
2390
+ * +pid+ and the optional +payload+ string into the block.
2349
2391
  */
2350
2392
  static VALUE
2351
2393
  pgconn_wait_for_notify(int argc, VALUE *argv, VALUE self)
2352
2394
  {
2353
- PGconn *conn = pg_get_pgconn( self );
2395
+ t_pg_connection *this = pg_get_connection_safe( self );
2354
2396
  PGnotify *pnotification;
2355
2397
  struct timeval timeout;
2356
2398
  struct timeval *ptimeout = NULL;
@@ -2366,24 +2408,18 @@ pgconn_wait_for_notify(int argc, VALUE *argv, VALUE self)
2366
2408
  ptimeout = &timeout;
2367
2409
  }
2368
2410
 
2369
- pnotification = (PGnotify*) wait_socket_readable( conn, ptimeout, notify_readable);
2411
+ pnotification = (PGnotify*) wait_socket_readable( this->pgconn, ptimeout, notify_readable);
2370
2412
 
2371
2413
  /* Return nil if the select timed out */
2372
2414
  if ( !pnotification ) return Qnil;
2373
2415
 
2374
- relname = rb_tainted_str_new2( pnotification->relname );
2375
- #ifdef M17N_SUPPORTED
2376
- ENCODING_SET( relname, rb_enc_to_index(pg_conn_enc_get( conn )) );
2377
- #endif
2416
+ relname = rb_str_new2( pnotification->relname );
2417
+ PG_ENCODING_SET_NOCHECK( relname, this->enc_idx );
2378
2418
  be_pid = INT2NUM( pnotification->be_pid );
2379
- #ifdef HAVE_ST_NOTIFY_EXTRA
2380
2419
  if ( *pnotification->extra ) {
2381
- extra = rb_tainted_str_new2( pnotification->extra );
2382
- #ifdef M17N_SUPPORTED
2383
- ENCODING_SET( extra, rb_enc_to_index(pg_conn_enc_get( conn )) );
2384
- #endif
2420
+ extra = rb_str_new2( pnotification->extra );
2421
+ PG_ENCODING_SET_NOCHECK( extra, this->enc_idx );
2385
2422
  }
2386
- #endif
2387
2423
  PQfreemem( pnotification );
2388
2424
 
2389
2425
  if ( rb_block_given_p() )
@@ -2395,30 +2431,79 @@ pgconn_wait_for_notify(int argc, VALUE *argv, VALUE self)
2395
2431
 
2396
2432
  /*
2397
2433
  * call-seq:
2398
- * conn.put_copy_data( buffer ) -> Boolean
2434
+ * conn.put_copy_data( buffer [, encoder] ) -> Boolean
2399
2435
  *
2400
2436
  * Transmits _buffer_ as copy data to the server.
2401
2437
  * Returns true if the data was sent, false if it was
2402
2438
  * not sent (false is only possible if the connection
2403
2439
  * is in nonblocking mode, and this command would block).
2404
2440
  *
2441
+ * _encoder_ can be a PG::Coder derivation (typically PG::TextEncoder::CopyRow).
2442
+ * This encodes the data fields given as _buffer_ from an Array of Strings to
2443
+ * PostgreSQL's COPY text format inclusive proper escaping. Optionally
2444
+ * the encoder can type cast the fields from various Ruby types in one step,
2445
+ * if PG::TextEncoder::CopyRow#type_map is set accordingly.
2446
+ *
2405
2447
  * Raises an exception if an error occurs.
2448
+ *
2449
+ * See also #copy_data.
2450
+ *
2406
2451
  */
2407
2452
  static VALUE
2408
- pgconn_put_copy_data(self, buffer)
2409
- VALUE self, buffer;
2453
+ pgconn_put_copy_data(int argc, VALUE *argv, VALUE self)
2410
2454
  {
2411
2455
  int ret;
2412
- VALUE error;
2413
- PGconn *conn = pg_get_pgconn(self);
2456
+ int len;
2457
+ t_pg_connection *this = pg_get_connection_safe( self );
2458
+ VALUE value;
2459
+ VALUE buffer = Qnil;
2460
+ VALUE encoder;
2461
+ VALUE intermediate;
2462
+ t_pg_coder *p_coder = NULL;
2463
+
2464
+ rb_scan_args( argc, argv, "11", &value, &encoder );
2465
+
2466
+ if( NIL_P(encoder) ){
2467
+ if( NIL_P(this->encoder_for_put_copy_data) ){
2468
+ buffer = value;
2469
+ } else {
2470
+ p_coder = DATA_PTR( this->encoder_for_put_copy_data );
2471
+ }
2472
+ } else if( rb_obj_is_kind_of(encoder, rb_cPG_Coder) ) {
2473
+ Data_Get_Struct( encoder, t_pg_coder, p_coder );
2474
+ } else {
2475
+ rb_raise( rb_eTypeError, "wrong encoder type %s (expected some kind of PG::Coder)",
2476
+ rb_obj_classname( encoder ) );
2477
+ }
2478
+
2479
+ if( p_coder ){
2480
+ t_pg_coder_enc_func enc_func;
2481
+ int enc_idx = this->enc_idx;
2482
+
2483
+ enc_func = pg_coder_enc_func( p_coder );
2484
+ len = enc_func( p_coder, value, NULL, &intermediate, enc_idx);
2485
+
2486
+ if( len == -1 ){
2487
+ /* The intermediate value is a String that can be used directly. */
2488
+ buffer = intermediate;
2489
+ } else {
2490
+ buffer = rb_str_new(NULL, len);
2491
+ len = enc_func( p_coder, value, RSTRING_PTR(buffer), &intermediate, enc_idx);
2492
+ rb_str_set_len( buffer, len );
2493
+ }
2494
+ }
2495
+
2414
2496
  Check_Type(buffer, T_STRING);
2415
2497
 
2416
- ret = gvl_PQputCopyData(conn, RSTRING_PTR(buffer), (int)RSTRING_LEN(buffer));
2498
+ ret = gvl_PQputCopyData(this->pgconn, RSTRING_PTR(buffer), RSTRING_LENINT(buffer));
2417
2499
  if(ret == -1) {
2418
- error = rb_exc_new2(rb_ePGerror, PQerrorMessage(conn));
2500
+ VALUE error = rb_exc_new2(rb_ePGerror, PQerrorMessage(this->pgconn));
2419
2501
  rb_iv_set(error, "@connection", self);
2420
2502
  rb_exc_raise(error);
2421
2503
  }
2504
+ RB_GC_GUARD(intermediate);
2505
+ RB_GC_GUARD(buffer);
2506
+
2422
2507
  return (ret) ? Qtrue : Qfalse;
2423
2508
  }
2424
2509
 
@@ -2442,17 +2527,17 @@ pgconn_put_copy_end(int argc, VALUE *argv, VALUE self)
2442
2527
  VALUE str;
2443
2528
  VALUE error;
2444
2529
  int ret;
2445
- char *error_message = NULL;
2446
- PGconn *conn = pg_get_pgconn(self);
2530
+ const char *error_message = NULL;
2531
+ t_pg_connection *this = pg_get_connection_safe( self );
2447
2532
 
2448
2533
  if (rb_scan_args(argc, argv, "01", &str) == 0)
2449
2534
  error_message = NULL;
2450
2535
  else
2451
- error_message = StringValuePtr(str);
2536
+ error_message = pg_cstr_enc(str, this->enc_idx);
2452
2537
 
2453
- ret = gvl_PQputCopyEnd(conn, error_message);
2538
+ ret = gvl_PQputCopyEnd(this->pgconn, error_message);
2454
2539
  if(ret == -1) {
2455
- error = rb_exc_new2(rb_ePGerror, PQerrorMessage(conn));
2540
+ error = rb_exc_new2(rb_ePGerror, PQerrorMessage(this->pgconn));
2456
2541
  rb_iv_set(error, "@connection", self);
2457
2542
  rb_exc_raise(error);
2458
2543
  }
@@ -2461,32 +2546,51 @@ pgconn_put_copy_end(int argc, VALUE *argv, VALUE self)
2461
2546
 
2462
2547
  /*
2463
2548
  * call-seq:
2464
- * conn.get_copy_data( [ async = false ] ) -> String
2549
+ * conn.get_copy_data( [ async = false [, decoder = nil ]] ) -> Object
2465
2550
  *
2466
- * Return a string containing one row of data, +nil+
2551
+ * Return one row of data, +nil+
2467
2552
  * if the copy is done, or +false+ if the call would
2468
2553
  * block (only possible if _async_ is true).
2469
2554
  *
2555
+ * If _decoder_ is not set or +nil+, data is returned as binary string.
2556
+ *
2557
+ * If _decoder_ is set to a PG::Coder derivation, the return type depends on this decoder.
2558
+ * PG::TextDecoder::CopyRow decodes the received data fields from one row of PostgreSQL's
2559
+ * COPY text format to an Array of Strings.
2560
+ * Optionally the decoder can type cast the single fields to various Ruby types in one step,
2561
+ * if PG::TextDecoder::CopyRow#type_map is set accordingly.
2562
+ *
2563
+ * See also #copy_data.
2564
+ *
2470
2565
  */
2471
2566
  static VALUE
2472
2567
  pgconn_get_copy_data(int argc, VALUE *argv, VALUE self )
2473
2568
  {
2474
2569
  VALUE async_in;
2475
2570
  VALUE error;
2476
- VALUE result_str;
2571
+ VALUE result;
2477
2572
  int ret;
2478
- int async;
2479
2573
  char *buffer;
2480
- PGconn *conn = pg_get_pgconn(self);
2574
+ VALUE decoder;
2575
+ t_pg_coder *p_coder = NULL;
2576
+ t_pg_connection *this = pg_get_connection_safe( self );
2481
2577
 
2482
- if (rb_scan_args(argc, argv, "01", &async_in) == 0)
2483
- async = 0;
2484
- else
2485
- async = (async_in == Qfalse || async_in == Qnil) ? 0 : 1;
2578
+ rb_scan_args(argc, argv, "02", &async_in, &decoder);
2579
+
2580
+ if( NIL_P(decoder) ){
2581
+ if( !NIL_P(this->decoder_for_get_copy_data) ){
2582
+ p_coder = DATA_PTR( this->decoder_for_get_copy_data );
2583
+ }
2584
+ } else if( rb_obj_is_kind_of(decoder, rb_cPG_Coder) ) {
2585
+ Data_Get_Struct( decoder, t_pg_coder, p_coder );
2586
+ } else {
2587
+ rb_raise( rb_eTypeError, "wrong decoder type %s (expected some kind of PG::Coder)",
2588
+ rb_obj_classname( decoder ) );
2589
+ }
2486
2590
 
2487
- ret = gvl_PQgetCopyData(conn, &buffer, async);
2591
+ ret = gvl_PQgetCopyData(this->pgconn, &buffer, RTEST(async_in));
2488
2592
  if(ret == -2) { /* error */
2489
- error = rb_exc_new2(rb_ePGerror, PQerrorMessage(conn));
2593
+ error = rb_exc_new2(rb_ePGerror, PQerrorMessage(this->pgconn));
2490
2594
  rb_iv_set(error, "@connection", self);
2491
2595
  rb_exc_raise(error);
2492
2596
  }
@@ -2496,20 +2600,34 @@ pgconn_get_copy_data(int argc, VALUE *argv, VALUE self )
2496
2600
  if(ret == 0) { /* would block */
2497
2601
  return Qfalse;
2498
2602
  }
2499
- result_str = rb_tainted_str_new(buffer, ret);
2603
+
2604
+ if( p_coder ){
2605
+ t_pg_coder_dec_func dec_func = pg_coder_dec_func( p_coder, p_coder->format );
2606
+ result = dec_func( p_coder, buffer, ret, 0, 0, this->enc_idx );
2607
+ } else {
2608
+ result = rb_str_new(buffer, ret);
2609
+ }
2610
+
2500
2611
  PQfreemem(buffer);
2501
- return result_str;
2612
+ return result;
2502
2613
  }
2503
2614
 
2504
2615
  /*
2505
2616
  * call-seq:
2506
- * conn.set_error_verbosity( verbosity ) -> Fixnum
2617
+ * conn.set_error_verbosity( verbosity ) -> Integer
2507
2618
  *
2508
2619
  * Sets connection's verbosity to _verbosity_ and returns
2509
2620
  * the previous setting. Available settings are:
2621
+ *
2510
2622
  * * PQERRORS_TERSE
2511
2623
  * * PQERRORS_DEFAULT
2512
2624
  * * PQERRORS_VERBOSE
2625
+ * * PQERRORS_SQLSTATE
2626
+ *
2627
+ * Changing the verbosity does not affect the messages available from already-existing PG::Result objects, only subsequently-created ones.
2628
+ * (But see PG::Result#verbose_error_message if you want to print a previous error with a different verbosity.)
2629
+ *
2630
+ * See also corresponding {libpq function}[https://www.postgresql.org/docs/current/libpq-control.html#LIBPQ-PQSETERRORVERBOSITY].
2513
2631
  */
2514
2632
  static VALUE
2515
2633
  pgconn_set_error_verbosity(VALUE self, VALUE in_verbosity)
@@ -2519,6 +2637,37 @@ pgconn_set_error_verbosity(VALUE self, VALUE in_verbosity)
2519
2637
  return INT2FIX(PQsetErrorVerbosity(conn, verbosity));
2520
2638
  }
2521
2639
 
2640
+ #ifdef HAVE_PQRESULTVERBOSEERRORMESSAGE
2641
+ /*
2642
+ * call-seq:
2643
+ * conn.set_error_context_visibility( context_visibility ) -> Integer
2644
+ *
2645
+ * Sets connection's context display mode to _context_visibility_ and returns
2646
+ * the previous setting. Available settings are:
2647
+ * * PQSHOW_CONTEXT_NEVER
2648
+ * * PQSHOW_CONTEXT_ERRORS
2649
+ * * PQSHOW_CONTEXT_ALWAYS
2650
+ *
2651
+ * This mode controls whether the CONTEXT field is included in messages (unless the verbosity setting is TERSE, in which case CONTEXT is never shown).
2652
+ * The NEVER mode never includes CONTEXT, while ALWAYS always includes it if available.
2653
+ * In ERRORS mode (the default), CONTEXT fields are included only for error messages, not for notices and warnings.
2654
+ *
2655
+ * Changing this mode does not affect the messages available from already-existing PG::Result objects, only subsequently-created ones.
2656
+ * (But see PG::Result#verbose_error_message if you want to print a previous error with a different display mode.)
2657
+ *
2658
+ * See also corresponding {libpq function}[https://www.postgresql.org/docs/current/libpq-control.html#LIBPQ-PQSETERRORCONTEXTVISIBILITY].
2659
+ *
2660
+ * Available since PostgreSQL-9.6
2661
+ */
2662
+ static VALUE
2663
+ pgconn_set_error_context_visibility(VALUE self, VALUE in_context_visibility)
2664
+ {
2665
+ PGconn *conn = pg_get_pgconn(self);
2666
+ PGContextVisibility context_visibility = NUM2INT(in_context_visibility);
2667
+ return INT2FIX(PQsetErrorContextVisibility(conn, context_visibility));
2668
+ }
2669
+ #endif
2670
+
2522
2671
  /*
2523
2672
  * call-seq:
2524
2673
  * conn.trace( stream ) -> nil
@@ -2535,8 +2684,9 @@ pgconn_trace(VALUE self, VALUE stream)
2535
2684
  FILE *new_fp;
2536
2685
  int old_fd, new_fd;
2537
2686
  VALUE new_file;
2687
+ t_pg_connection *this = pg_get_connection_safe( self );
2538
2688
 
2539
- if(rb_respond_to(stream,rb_intern("fileno")) == Qfalse)
2689
+ if(!rb_respond_to(stream,rb_intern("fileno")))
2540
2690
  rb_raise(rb_eArgError, "stream does not respond to method: fileno");
2541
2691
 
2542
2692
  fileno = rb_funcall(stream, rb_intern("fileno"), 0);
@@ -2557,9 +2707,9 @@ pgconn_trace(VALUE self, VALUE stream)
2557
2707
  rb_raise(rb_eArgError, "stream is not writable");
2558
2708
 
2559
2709
  new_file = rb_funcall(rb_cIO, rb_intern("new"), 1, INT2NUM(new_fd));
2560
- rb_iv_set(self, "@trace_stream", new_file);
2710
+ this->trace_stream = new_file;
2561
2711
 
2562
- PQtrace(pg_get_pgconn(self), new_fp);
2712
+ PQtrace(this->pgconn, new_fp);
2563
2713
  return Qnil;
2564
2714
  }
2565
2715
 
@@ -2572,11 +2722,11 @@ pgconn_trace(VALUE self, VALUE stream)
2572
2722
  static VALUE
2573
2723
  pgconn_untrace(VALUE self)
2574
2724
  {
2575
- VALUE trace_stream;
2576
- PQuntrace(pg_get_pgconn(self));
2577
- trace_stream = rb_iv_get(self, "@trace_stream");
2578
- rb_funcall(trace_stream, rb_intern("close"), 0);
2579
- rb_iv_set(self, "@trace_stream", Qnil);
2725
+ t_pg_connection *this = pg_get_connection_safe( self );
2726
+
2727
+ PQuntrace(this->pgconn);
2728
+ rb_funcall(this->trace_stream, rb_intern("close"), 0);
2729
+ this->trace_stream = Qnil;
2580
2730
  return Qnil;
2581
2731
  }
2582
2732
 
@@ -2586,19 +2736,16 @@ pgconn_untrace(VALUE self)
2586
2736
  * currently-registered Ruby notice_receiver object.
2587
2737
  */
2588
2738
  void
2589
- notice_receiver_proxy(void *arg, const PGresult *result)
2739
+ notice_receiver_proxy(void *arg, const PGresult *pgresult)
2590
2740
  {
2591
- VALUE proc;
2592
2741
  VALUE self = (VALUE)arg;
2742
+ t_pg_connection *this = pg_get_connection( self );
2593
2743
 
2594
- if ((proc = rb_iv_get(self, "@notice_receiver")) != Qnil) {
2595
- VALUE val = Data_Wrap_Struct(rb_cPGresult, NULL, NULL, (PGresult*)result);
2596
- #ifdef M17N_SUPPORTED
2597
- PGconn *conn = pg_get_pgconn( self );
2598
- rb_encoding *enc = pg_conn_enc_get( conn );
2599
- ENCODING_SET( val, rb_enc_to_index(enc) );
2600
- #endif
2601
- rb_funcall(proc, rb_intern("call"), 1, val);
2744
+ if (this->notice_receiver != Qnil) {
2745
+ VALUE result = pg_new_result_autoclear( (PGresult *)pgresult, self );
2746
+
2747
+ rb_funcall(this->notice_receiver, rb_intern("call"), 1, result);
2748
+ pg_result_clear( result );
2602
2749
  }
2603
2750
  return;
2604
2751
  }
@@ -2636,7 +2783,7 @@ static VALUE
2636
2783
  pgconn_set_notice_receiver(VALUE self)
2637
2784
  {
2638
2785
  VALUE proc, old_proc;
2639
- PGconn *conn = pg_get_pgconn(self);
2786
+ t_pg_connection *this = pg_get_connection_safe( self );
2640
2787
 
2641
2788
  /* If default_notice_receiver is unset, assume that the current
2642
2789
  * notice receiver is the default, and save it to a global variable.
@@ -2644,19 +2791,19 @@ pgconn_set_notice_receiver(VALUE self)
2644
2791
  * always the same, so won't vary among connections.
2645
2792
  */
2646
2793
  if(default_notice_receiver == NULL)
2647
- default_notice_receiver = PQsetNoticeReceiver(conn, NULL, NULL);
2794
+ default_notice_receiver = PQsetNoticeReceiver(this->pgconn, NULL, NULL);
2648
2795
 
2649
- old_proc = rb_iv_get(self, "@notice_receiver");
2796
+ old_proc = this->notice_receiver;
2650
2797
  if( rb_block_given_p() ) {
2651
2798
  proc = rb_block_proc();
2652
- PQsetNoticeReceiver(conn, gvl_notice_receiver_proxy, (void *)self);
2799
+ PQsetNoticeReceiver(this->pgconn, gvl_notice_receiver_proxy, (void *)self);
2653
2800
  } else {
2654
2801
  /* if no block is given, set back to default */
2655
2802
  proc = Qnil;
2656
- PQsetNoticeReceiver(conn, default_notice_receiver, NULL);
2803
+ PQsetNoticeReceiver(this->pgconn, default_notice_receiver, NULL);
2657
2804
  }
2658
2805
 
2659
- rb_iv_set(self, "@notice_receiver", proc);
2806
+ this->notice_receiver = proc;
2660
2807
  return old_proc;
2661
2808
  }
2662
2809
 
@@ -2668,17 +2815,13 @@ pgconn_set_notice_receiver(VALUE self)
2668
2815
  void
2669
2816
  notice_processor_proxy(void *arg, const char *message)
2670
2817
  {
2671
- VALUE proc;
2672
2818
  VALUE self = (VALUE)arg;
2819
+ t_pg_connection *this = pg_get_connection( self );
2673
2820
 
2674
- if ((proc = rb_iv_get(self, "@notice_processor")) != Qnil) {
2675
- VALUE message_str = rb_tainted_str_new2(message);
2676
- #ifdef M17N_SUPPORTED
2677
- PGconn *conn = pg_get_pgconn( self );
2678
- rb_encoding *enc = pg_conn_enc_get( conn );
2679
- ENCODING_SET( message_str, rb_enc_to_index(enc) );
2680
- #endif
2681
- rb_funcall(proc, rb_intern("call"), 1, message_str);
2821
+ if (this->notice_receiver != Qnil) {
2822
+ VALUE message_str = rb_str_new2(message);
2823
+ PG_ENCODING_SET_NOCHECK( message_str, this->enc_idx );
2824
+ rb_funcall(this->notice_receiver, rb_intern("call"), 1, message_str);
2682
2825
  }
2683
2826
  return;
2684
2827
  }
@@ -2700,7 +2843,7 @@ static VALUE
2700
2843
  pgconn_set_notice_processor(VALUE self)
2701
2844
  {
2702
2845
  VALUE proc, old_proc;
2703
- PGconn *conn = pg_get_pgconn(self);
2846
+ t_pg_connection *this = pg_get_connection_safe( self );
2704
2847
 
2705
2848
  /* If default_notice_processor is unset, assume that the current
2706
2849
  * notice processor is the default, and save it to a global variable.
@@ -2708,19 +2851,19 @@ pgconn_set_notice_processor(VALUE self)
2708
2851
  * always the same, so won't vary among connections.
2709
2852
  */
2710
2853
  if(default_notice_processor == NULL)
2711
- default_notice_processor = PQsetNoticeProcessor(conn, NULL, NULL);
2854
+ default_notice_processor = PQsetNoticeProcessor(this->pgconn, NULL, NULL);
2712
2855
 
2713
- old_proc = rb_iv_get(self, "@notice_processor");
2856
+ old_proc = this->notice_receiver;
2714
2857
  if( rb_block_given_p() ) {
2715
2858
  proc = rb_block_proc();
2716
- PQsetNoticeProcessor(conn, gvl_notice_processor_proxy, (void *)self);
2859
+ PQsetNoticeProcessor(this->pgconn, gvl_notice_processor_proxy, (void *)self);
2717
2860
  } else {
2718
2861
  /* if no block is given, set back to default */
2719
2862
  proc = Qnil;
2720
- PQsetNoticeProcessor(conn, default_notice_processor, NULL);
2863
+ PQsetNoticeProcessor(this->pgconn, default_notice_processor, NULL);
2721
2864
  }
2722
2865
 
2723
- rb_iv_set(self, "@notice_processor", proc);
2866
+ this->notice_receiver = proc;
2724
2867
  return old_proc;
2725
2868
  }
2726
2869
 
@@ -2735,7 +2878,7 @@ static VALUE
2735
2878
  pgconn_get_client_encoding(VALUE self)
2736
2879
  {
2737
2880
  char *encoding = (char *)pg_encoding_to_char(PQclientEncoding(pg_get_pgconn(self)));
2738
- return rb_tainted_str_new2(encoding);
2881
+ return rb_str_new2(encoding);
2739
2882
  }
2740
2883
 
2741
2884
 
@@ -2752,16 +2895,17 @@ pgconn_set_client_encoding(VALUE self, VALUE str)
2752
2895
 
2753
2896
  Check_Type(str, T_STRING);
2754
2897
 
2755
- if ( (PQsetClientEncoding(conn, StringValuePtr(str))) == -1 ) {
2756
- rb_raise(rb_ePGerror, "invalid encoding name: %s",StringValuePtr(str));
2898
+ if ( (gvl_PQsetClientEncoding(conn, StringValueCStr(str))) == -1 ) {
2899
+ rb_raise(rb_ePGerror, "%s", PQerrorMessage(conn));
2757
2900
  }
2901
+ pgconn_set_internal_encoding_index( self );
2758
2902
 
2759
2903
  return Qnil;
2760
2904
  }
2761
2905
 
2762
2906
  /*
2763
2907
  * call-seq:
2764
- * conn.transaction { |conn| ... } -> nil
2908
+ * conn.transaction { |conn| ... } -> result of the block
2765
2909
  *
2766
2910
  * Executes a +BEGIN+ at the start of the block,
2767
2911
  * and a +COMMIT+ at the end of the block, or
@@ -2773,13 +2917,14 @@ pgconn_transaction(VALUE self)
2773
2917
  PGconn *conn = pg_get_pgconn(self);
2774
2918
  PGresult *result;
2775
2919
  VALUE rb_pgresult;
2920
+ VALUE block_result = Qnil;
2776
2921
  int status;
2777
2922
 
2778
2923
  if (rb_block_given_p()) {
2779
2924
  result = gvl_PQexec(conn, "BEGIN");
2780
2925
  rb_pgresult = pg_new_result(result, self);
2781
2926
  pg_result_check(rb_pgresult);
2782
- rb_protect(rb_yield, self, &status);
2927
+ block_result = rb_protect(rb_yield, self, &status);
2783
2928
  if(status == 0) {
2784
2929
  result = gvl_PQexec(conn, "COMMIT");
2785
2930
  rb_pgresult = pg_new_result(result, self);
@@ -2798,14 +2943,16 @@ pgconn_transaction(VALUE self)
2798
2943
  /* no block supplied? */
2799
2944
  rb_raise(rb_eArgError, "Must supply block for PG::Connection#transaction");
2800
2945
  }
2801
- return Qnil;
2946
+ return block_result;
2802
2947
  }
2803
2948
 
2804
2949
 
2805
2950
  /*
2806
2951
  * call-seq:
2807
- * PG::Connection.quote_ident( str ) -> String
2808
2952
  * conn.quote_ident( str ) -> String
2953
+ * conn.quote_ident( array ) -> String
2954
+ * PG::Connection.quote_ident( str ) -> String
2955
+ * PG::Connection.quote_ident( array ) -> String
2809
2956
  *
2810
2957
  * Returns a string that is safe for inclusion in a SQL query as an
2811
2958
  * identifier. Note: this is not a quote function for values, but for
@@ -2815,40 +2962,40 @@ pgconn_transaction(VALUE self)
2815
2962
  * The identifier <tt>FOO</tt> is folded to lower case, so it actually
2816
2963
  * means <tt>foo</tt>. If you really want to access the case-sensitive
2817
2964
  * field name <tt>FOO</tt>, use this function like
2818
- * <tt>PG::Connection.quote_ident('FOO')</tt>, which will return <tt>"FOO"</tt>
2965
+ * <tt>conn.quote_ident('FOO')</tt>, which will return <tt>"FOO"</tt>
2819
2966
  * (with double-quotes). PostgreSQL will see the double-quotes, and
2820
2967
  * it will not fold to lower case.
2821
2968
  *
2822
2969
  * Similarly, this function also protects against special characters,
2823
2970
  * and other things that might allow SQL injection if the identifier
2824
2971
  * comes from an untrusted source.
2972
+ *
2973
+ * If the parameter is an Array, then all it's values are separately quoted
2974
+ * and then joined by a "." character. This can be used for identifiers in
2975
+ * the form "schema"."table"."column" .
2976
+ *
2977
+ * This method is functional identical to the encoder PG::TextEncoder::Identifier .
2978
+ *
2979
+ * If the instance method form is used and the input string character encoding
2980
+ * is different to the connection encoding, then the string is converted to this
2981
+ * encoding, so that the returned string is always encoded as PG::Connection#internal_encoding .
2982
+ *
2983
+ * In the singleton form (PG::Connection.quote_ident) the character encoding
2984
+ * of the result string is set to the character encoding of the input string.
2825
2985
  */
2826
2986
  static VALUE
2827
- pgconn_s_quote_ident(VALUE self, VALUE in_str)
2987
+ pgconn_s_quote_ident(VALUE self, VALUE str_or_array)
2828
2988
  {
2829
2989
  VALUE ret;
2830
- char *str = StringValuePtr(in_str);
2831
- /* result size at most NAMEDATALEN*2 plus surrounding
2832
- * double-quotes. */
2833
- char buffer[NAMEDATALEN*2+2];
2834
- unsigned int i=0,j=0;
2835
-
2836
- UNUSED( self );
2990
+ int enc_idx;
2837
2991
 
2838
- if(strlen(str) >= NAMEDATALEN) {
2839
- rb_raise(rb_eArgError,
2840
- "Input string is longer than NAMEDATALEN-1 (%d)",
2841
- NAMEDATALEN-1);
2842
- }
2843
- buffer[j++] = '"';
2844
- for(i = 0; i < strlen(str) && str[i]; i++) {
2845
- if(str[i] == '"')
2846
- buffer[j++] = '"';
2847
- buffer[j++] = str[i];
2992
+ if( rb_obj_is_kind_of(self, rb_cPGconn) ){
2993
+ enc_idx = pg_get_connection(self)->enc_idx;
2994
+ }else{
2995
+ enc_idx = RB_TYPE_P(str_or_array, T_STRING) ? ENCODING_GET( str_or_array ) : rb_ascii8bit_encindex();
2848
2996
  }
2849
- buffer[j++] = '"';
2850
- ret = rb_str_new(buffer,j);
2851
- OBJ_INFECT(ret, in_str);
2997
+ pg_text_enc_identifier(NULL, str_or_array, NULL, &ret, enc_idx);
2998
+
2852
2999
  return ret;
2853
3000
  }
2854
3001
 
@@ -2856,7 +3003,7 @@ pgconn_s_quote_ident(VALUE self, VALUE in_str)
2856
3003
  static void *
2857
3004
  get_result_readable(PGconn *conn)
2858
3005
  {
2859
- return PQisBusy(conn) ? NULL : (void*)1;
3006
+ return gvl_PQisBusy(conn) ? NULL : (void*)1;
2860
3007
  }
2861
3008
 
2862
3009
 
@@ -2877,10 +3024,6 @@ static VALUE
2877
3024
  pgconn_block( int argc, VALUE *argv, VALUE self ) {
2878
3025
  PGconn *conn = pg_get_pgconn( self );
2879
3026
 
2880
- /* If WIN32 and Ruby 1.9 do not use rb_thread_select() which sometimes hangs
2881
- * and does not wait (nor sleep) any time even if timeout is given.
2882
- * Instead use the Winsock events and rb_w32_wait_events(). */
2883
-
2884
3027
  struct timeval timeout;
2885
3028
  struct timeval *ptimeout = NULL;
2886
3029
  VALUE timeout_in;
@@ -2945,34 +3088,71 @@ pgconn_get_last_result(VALUE self)
2945
3088
  return rb_pgresult;
2946
3089
  }
2947
3090
 
2948
- #if !defined(HAVE_RB_THREAD_CALL_WITHOUT_GVL)
3091
+ /*
3092
+ * call-seq:
3093
+ * conn.discard_results()
3094
+ *
3095
+ * Silently discard any prior query result that application didn't eat.
3096
+ * This is done prior of Connection#exec and sibling methods and can
3097
+ * be called explicitly when using the async API.
3098
+ */
3099
+ static VALUE
3100
+ pgconn_discard_results(VALUE self)
3101
+ {
3102
+ PGconn *conn = pg_get_pgconn(self);
3103
+
3104
+ PGresult *cur;
3105
+ while ((cur = gvl_PQgetResult(conn)) != NULL) {
3106
+ int status = PQresultStatus(cur);
3107
+ PQclear(cur);
3108
+ if (status == PGRES_COPY_IN){
3109
+ gvl_PQputCopyEnd(conn, "COPY terminated by new PQexec");
3110
+ }
3111
+ if (status == PGRES_COPY_OUT){
3112
+ char *buffer = NULL;
3113
+ while( gvl_PQgetCopyData(conn, &buffer, 0) > 0)
3114
+ PQfreemem(buffer);
3115
+ }
3116
+ }
3117
+
3118
+ return Qnil;
3119
+ }
2949
3120
 
2950
3121
  /*
2951
3122
  * call-seq:
2952
- * conn.async_exec(sql [, params, result_format ] ) -> PG::Result
2953
- * conn.async_exec(sql [, params, result_format ] ) {|pg_result| block }
3123
+ * conn.exec(sql) -> PG::Result
3124
+ * conn.exec(sql) {|pg_result| block }
3125
+ *
3126
+ * Sends SQL query request specified by _sql_ to PostgreSQL.
3127
+ * On success, it returns a PG::Result instance with all result rows and columns.
3128
+ * On failure, it raises a PG::Error.
3129
+ *
3130
+ * For backward compatibility, if you pass more than one parameter to this method,
3131
+ * it will call #exec_params for you. New code should explicitly use #exec_params if
3132
+ * argument placeholders are used.
2954
3133
  *
2955
- * This function has the same behavior as #exec,
2956
- * but ensures that other threads can process while
2957
- * waiting for the server to complete the request.
3134
+ * If the optional code block is given, it will be passed <i>result</i> as an argument,
3135
+ * and the PG::Result object will automatically be cleared when the block terminates.
3136
+ * In this instance, <code>conn.exec</code> returns the value of the block.
2958
3137
  *
2959
- * On Ruby platforms with native threads (MRI-1.9+ and all others)
2960
- * this method is an alias to #exec.
3138
+ * #exec is an alias for #async_exec which is almost identical to #sync_exec .
3139
+ * #sync_exec is implemented on the simpler synchronous command processing API of libpq, whereas
3140
+ * #async_exec is implemented on the asynchronous API and on ruby's IO mechanisms.
3141
+ * Both methods ensure that other threads can process while waiting for the server to
3142
+ * complete the request, but #sync_exec blocks all signals to be processed until the query is finished.
3143
+ * This is most notably visible by a delayed reaction to Control+C.
3144
+ * It's not recommended to use explicit sync or async variants but #exec instead, unless you have a good reason to do so.
2961
3145
  *
2962
- * On MRI-1.8 it's implemented using asynchronous command
2963
- * processing and ruby's +rb_thread_select+ .
3146
+ * See also corresponding {libpq function}[https://www.postgresql.org/docs/current/libpq-exec.html#LIBPQ-PQEXEC].
2964
3147
  */
2965
3148
  static VALUE
2966
3149
  pgconn_async_exec(int argc, VALUE *argv, VALUE self)
2967
3150
  {
2968
3151
  VALUE rb_pgresult = Qnil;
2969
3152
 
2970
- /* remove any remaining results from the queue */
2971
- pgconn_block( 0, NULL, self ); /* wait for input (without blocking) before reading the last result */
2972
- pgconn_get_last_result( self );
2973
-
3153
+ pgconn_discard_results( self );
2974
3154
  pgconn_send_query( argc, argv, self );
2975
- pgconn_block( 0, NULL, self );
3155
+ pgconn_block( 0, NULL, self ); /* wait for input (without blocking) before reading the last result */
2976
3156
  rb_pgresult = pgconn_get_last_result( self );
2977
3157
 
2978
3158
  if ( rb_block_given_p() ) {
@@ -2981,103 +3161,394 @@ pgconn_async_exec(int argc, VALUE *argv, VALUE self)
2981
3161
  return rb_pgresult;
2982
3162
  }
2983
3163
 
2984
- #endif
2985
-
2986
- /**************************************************************************
2987
- * LARGE OBJECT SUPPORT
2988
- **************************************************************************/
2989
3164
 
2990
3165
  /*
2991
3166
  * call-seq:
2992
- * conn.lo_creat( [mode] ) -> Fixnum
3167
+ * conn.exec_params(sql, params [, result_format [, type_map ]] ) -> nil
3168
+ * conn.exec_params(sql, params [, result_format [, type_map ]] ) {|pg_result| block }
2993
3169
  *
2994
- * Creates a large object with mode _mode_. Returns a large object Oid.
2995
- * On failure, it raises PG::Error.
2996
- */
2997
- static VALUE
2998
- pgconn_locreat(int argc, VALUE *argv, VALUE self)
2999
- {
3000
- Oid lo_oid;
3001
- int mode;
3002
- VALUE nmode;
3003
- PGconn *conn = pg_get_pgconn(self);
3004
-
3005
- if (rb_scan_args(argc, argv, "01", &nmode) == 0)
3006
- mode = INV_READ;
3007
- else
3008
- mode = NUM2INT(nmode);
3009
-
3010
- lo_oid = lo_creat(conn, mode);
3011
- if (lo_oid == 0)
3012
- rb_raise(rb_ePGerror, "lo_creat failed");
3013
-
3014
- return INT2FIX(lo_oid);
3015
- }
3016
-
3017
- /*
3018
- * call-seq:
3019
- * conn.lo_create( oid ) -> Fixnum
3170
+ * Sends SQL query request specified by +sql+ to PostgreSQL using placeholders
3171
+ * for parameters.
3020
3172
  *
3021
- * Creates a large object with oid _oid_. Returns the large object Oid.
3022
- * On failure, it raises PG::Error.
3173
+ * Returns a PG::Result instance on success. On failure, it raises a PG::Error.
3174
+ *
3175
+ * +params+ is an array of the bind parameters for the SQL query.
3176
+ * Each element of the +params+ array may be either:
3177
+ * a hash of the form:
3178
+ * {:value => String (value of bind parameter)
3179
+ * :type => Integer (oid of type of bind parameter)
3180
+ * :format => Integer (0 for text, 1 for binary)
3181
+ * }
3182
+ * or, it may be a String. If it is a string, that is equivalent to the hash:
3183
+ * { :value => <string value>, :type => 0, :format => 0 }
3184
+ *
3185
+ * PostgreSQL bind parameters are represented as $1, $1, $2, etc.,
3186
+ * inside the SQL query. The 0th element of the +params+ array is bound
3187
+ * to $1, the 1st element is bound to $2, etc. +nil+ is treated as +NULL+.
3188
+ *
3189
+ * If the types are not specified, they will be inferred by PostgreSQL.
3190
+ * Instead of specifying type oids, it's recommended to simply add
3191
+ * explicit casts in the query to ensure that the right type is used.
3192
+ *
3193
+ * For example: "SELECT $1::int"
3194
+ *
3195
+ * The optional +result_format+ should be 0 for text results, 1
3196
+ * for binary.
3197
+ *
3198
+ * +type_map+ can be a PG::TypeMap derivation (such as PG::BasicTypeMapForQueries).
3199
+ * This will type cast the params from various Ruby types before transmission
3200
+ * based on the encoders defined by the type map. When a type encoder is used
3201
+ * the format and oid of a given bind parameter are retrieved from the encoder
3202
+ * instead out of the hash form described above.
3203
+ *
3204
+ * If the optional code block is given, it will be passed <i>result</i> as an argument,
3205
+ * and the PG::Result object will automatically be cleared when the block terminates.
3206
+ * In this instance, <code>conn.exec</code> returns the value of the block.
3207
+ *
3208
+ * 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.
3209
+ * Unlike #exec, #exec_params allows at most one SQL command in the given string.
3210
+ * (There can be semicolons in it, but not more than one nonempty command.)
3211
+ * This is a limitation of the underlying protocol, but has some usefulness as an extra defense against SQL-injection attacks.
3212
+ *
3213
+ * See also corresponding {libpq function}[https://www.postgresql.org/docs/current/libpq-exec.html#LIBPQ-PQEXECPARAMS].
3023
3214
  */
3024
3215
  static VALUE
3025
- pgconn_locreate(VALUE self, VALUE in_lo_oid)
3216
+ pgconn_async_exec_params(int argc, VALUE *argv, VALUE self)
3026
3217
  {
3027
- Oid ret, lo_oid;
3028
- PGconn *conn = pg_get_pgconn(self);
3029
- lo_oid = NUM2INT(in_lo_oid);
3218
+ VALUE rb_pgresult = Qnil;
3030
3219
 
3031
- ret = lo_create(conn, lo_oid);
3032
- if (ret == InvalidOid)
3033
- rb_raise(rb_ePGerror, "lo_create failed");
3220
+ pgconn_discard_results( self );
3221
+ /* If called with no or nil parameters, use PQsendQuery for compatibility */
3222
+ if ( argc == 1 || (argc >= 2 && argc <= 4 && NIL_P(argv[1]) )) {
3223
+ pg_deprecated(3, ("forwarding async_exec_params to async_exec is deprecated"));
3224
+ pgconn_send_query( argc, argv, self );
3225
+ } else {
3226
+ pgconn_send_query_params( argc, argv, self );
3227
+ }
3228
+ pgconn_block( 0, NULL, self ); /* wait for input (without blocking) before reading the last result */
3229
+ rb_pgresult = pgconn_get_last_result( self );
3034
3230
 
3035
- return INT2FIX(ret);
3231
+ if ( rb_block_given_p() ) {
3232
+ return rb_ensure( rb_yield, rb_pgresult, pg_result_clear, rb_pgresult );
3233
+ }
3234
+ return rb_pgresult;
3036
3235
  }
3037
3236
 
3237
+
3038
3238
  /*
3039
3239
  * call-seq:
3040
- * conn.lo_import(file) -> Fixnum
3041
- *
3042
- * Import a file to a large object. Returns a large object Oid.
3240
+ * conn.prepare(stmt_name, sql [, param_types ] ) -> PG::Result
3043
3241
  *
3242
+ * Prepares statement _sql_ with name _name_ to be executed later.
3243
+ * Returns a PG::Result instance on success.
3044
3244
  * On failure, it raises a PG::Error.
3245
+ *
3246
+ * +param_types+ is an optional parameter to specify the Oids of the
3247
+ * types of the parameters.
3248
+ *
3249
+ * If the types are not specified, they will be inferred by PostgreSQL.
3250
+ * Instead of specifying type oids, it's recommended to simply add
3251
+ * explicit casts in the query to ensure that the right type is used.
3252
+ *
3253
+ * For example: "SELECT $1::int"
3254
+ *
3255
+ * PostgreSQL bind parameters are represented as $1, $1, $2, etc.,
3256
+ * inside the SQL query.
3257
+ *
3258
+ * See also corresponding {libpq function}[https://www.postgresql.org/docs/current/libpq-exec.html#LIBPQ-PQPREPARE].
3045
3259
  */
3046
3260
  static VALUE
3047
- pgconn_loimport(VALUE self, VALUE filename)
3261
+ pgconn_async_prepare(int argc, VALUE *argv, VALUE self)
3048
3262
  {
3049
- Oid lo_oid;
3050
-
3051
- PGconn *conn = pg_get_pgconn(self);
3263
+ VALUE rb_pgresult = Qnil;
3052
3264
 
3053
- Check_Type(filename, T_STRING);
3265
+ pgconn_discard_results( self );
3266
+ pgconn_send_prepare( argc, argv, self );
3267
+ pgconn_block( 0, NULL, self ); /* wait for input (without blocking) before reading the last result */
3268
+ rb_pgresult = pgconn_get_last_result( self );
3054
3269
 
3055
- lo_oid = lo_import(conn, StringValuePtr(filename));
3056
- if (lo_oid == 0) {
3057
- rb_raise(rb_ePGerror, "%s", PQerrorMessage(conn));
3270
+ if ( rb_block_given_p() ) {
3271
+ return rb_ensure( rb_yield, rb_pgresult, pg_result_clear, rb_pgresult );
3058
3272
  }
3059
- return INT2FIX(lo_oid);
3273
+ return rb_pgresult;
3060
3274
  }
3061
3275
 
3276
+
3062
3277
  /*
3063
3278
  * call-seq:
3064
- * conn.lo_export( oid, file ) -> nil
3279
+ * conn.exec_prepared(statement_name [, params, result_format[, type_map]] ) -> PG::Result
3280
+ * conn.exec_prepared(statement_name [, params, result_format[, type_map]] ) {|pg_result| block }
3065
3281
  *
3066
- * Saves a large object of _oid_ to a _file_.
3067
- */
3282
+ * Execute prepared named statement specified by _statement_name_.
3283
+ * Returns a PG::Result instance on success.
3284
+ * On failure, it raises a PG::Error.
3285
+ *
3286
+ * +params+ is an array of the optional bind parameters for the
3287
+ * SQL query. Each element of the +params+ array may be either:
3288
+ * a hash of the form:
3289
+ * {:value => String (value of bind parameter)
3290
+ * :format => Integer (0 for text, 1 for binary)
3291
+ * }
3292
+ * or, it may be a String. If it is a string, that is equivalent to the hash:
3293
+ * { :value => <string value>, :format => 0 }
3294
+ *
3295
+ * PostgreSQL bind parameters are represented as $1, $1, $2, etc.,
3296
+ * inside the SQL query. The 0th element of the +params+ array is bound
3297
+ * to $1, the 1st element is bound to $2, etc. +nil+ is treated as +NULL+.
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_prepared</code> returns the value of the block.
3311
+ *
3312
+ * See also corresponding {libpq function}[https://www.postgresql.org/docs/current/libpq-exec.html#LIBPQ-PQEXECPREPARED].
3313
+ */
3068
3314
  static VALUE
3069
- pgconn_loexport(VALUE self, VALUE lo_oid, VALUE filename)
3315
+ pgconn_async_exec_prepared(int argc, VALUE *argv, VALUE self)
3316
+ {
3317
+ VALUE rb_pgresult = Qnil;
3318
+
3319
+ pgconn_discard_results( self );
3320
+ pgconn_send_query_prepared( argc, argv, self );
3321
+ pgconn_block( 0, NULL, self ); /* wait for input (without blocking) before reading the last result */
3322
+ rb_pgresult = pgconn_get_last_result( self );
3323
+
3324
+ if ( rb_block_given_p() ) {
3325
+ return rb_ensure( rb_yield, rb_pgresult, pg_result_clear, rb_pgresult );
3326
+ }
3327
+ return rb_pgresult;
3328
+ }
3329
+
3330
+
3331
+ /*
3332
+ * call-seq:
3333
+ * conn.describe_portal( portal_name ) -> PG::Result
3334
+ *
3335
+ * Retrieve information about the portal _portal_name_.
3336
+ *
3337
+ * See also corresponding {libpq function}[https://www.postgresql.org/docs/current/libpq-exec.html#LIBPQ-PQDESCRIBEPORTAL].
3338
+ */
3339
+ static VALUE
3340
+ pgconn_async_describe_portal(VALUE self, VALUE portal)
3341
+ {
3342
+ VALUE rb_pgresult = Qnil;
3343
+
3344
+ pgconn_discard_results( self );
3345
+ pgconn_send_describe_portal( self, portal );
3346
+ pgconn_block( 0, NULL, self ); /* wait for input (without blocking) before reading the last result */
3347
+ rb_pgresult = pgconn_get_last_result( self );
3348
+
3349
+ if ( rb_block_given_p() ) {
3350
+ return rb_ensure( rb_yield, rb_pgresult, pg_result_clear, rb_pgresult );
3351
+ }
3352
+ return rb_pgresult;
3353
+ }
3354
+
3355
+
3356
+ /*
3357
+ * call-seq:
3358
+ * conn.describe_prepared( statement_name ) -> PG::Result
3359
+ *
3360
+ * Retrieve information about the prepared statement _statement_name_.
3361
+ *
3362
+ * See also corresponding {libpq function}[https://www.postgresql.org/docs/current/libpq-exec.html#LIBPQ-PQDESCRIBEPREPARED].
3363
+ */
3364
+ static VALUE
3365
+ pgconn_async_describe_prepared(VALUE self, VALUE stmt_name)
3366
+ {
3367
+ VALUE rb_pgresult = Qnil;
3368
+
3369
+ pgconn_discard_results( self );
3370
+ pgconn_send_describe_prepared( self, stmt_name );
3371
+ pgconn_block( 0, NULL, self ); /* wait for input (without blocking) before reading the last result */
3372
+ rb_pgresult = pgconn_get_last_result( self );
3373
+
3374
+ if ( rb_block_given_p() ) {
3375
+ return rb_ensure( rb_yield, rb_pgresult, pg_result_clear, rb_pgresult );
3376
+ }
3377
+ return rb_pgresult;
3378
+ }
3379
+
3380
+
3381
+ #ifdef HAVE_PQSSLATTRIBUTE
3382
+ /*
3383
+ * call-seq:
3384
+ * conn.ssl_in_use? -> Boolean
3385
+ *
3386
+ * Returns +true+ if the connection uses SSL/TLS, +false+ if not.
3387
+ *
3388
+ * Available since PostgreSQL-9.5
3389
+ */
3390
+ static VALUE
3391
+ pgconn_ssl_in_use(VALUE self)
3392
+ {
3393
+ return PQsslInUse(pg_get_pgconn(self)) ? Qtrue : Qfalse;
3394
+ }
3395
+
3396
+
3397
+ /*
3398
+ * call-seq:
3399
+ * conn.ssl_attribute(attribute_name) -> String
3400
+ *
3401
+ * Returns SSL-related information about the connection.
3402
+ *
3403
+ * The list of available attributes varies depending on the SSL library being used,
3404
+ * and the type of connection. If an attribute is not available, returns nil.
3405
+ *
3406
+ * The following attributes are commonly available:
3407
+ *
3408
+ * [+library+]
3409
+ * Name of the SSL implementation in use. (Currently, only "OpenSSL" is implemented)
3410
+ * [+protocol+]
3411
+ * 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.
3412
+ * [+key_bits+]
3413
+ * Number of key bits used by the encryption algorithm.
3414
+ * [+cipher+]
3415
+ * A short name of the ciphersuite used, e.g. "DHE-RSA-DES-CBC3-SHA". The names are specific to each SSL implementation.
3416
+ * [+compression+]
3417
+ * 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".
3418
+ *
3419
+ *
3420
+ * See also #ssl_attribute_names and the {corresponding libpq function}[https://www.postgresql.org/docs/current/libpq-status.html#LIBPQ-PQSSLATTRIBUTE].
3421
+ *
3422
+ * Available since PostgreSQL-9.5
3423
+ */
3424
+ static VALUE
3425
+ pgconn_ssl_attribute(VALUE self, VALUE attribute_name)
3426
+ {
3427
+ const char *p_attr;
3428
+
3429
+ p_attr = PQsslAttribute(pg_get_pgconn(self), StringValueCStr(attribute_name));
3430
+ return p_attr ? rb_str_new_cstr(p_attr) : Qnil;
3431
+ }
3432
+
3433
+ /*
3434
+ * call-seq:
3435
+ * conn.ssl_attribute_names -> Array<String>
3436
+ *
3437
+ * Return an array of SSL attribute names available.
3438
+ *
3439
+ * See also #ssl_attribute
3440
+ *
3441
+ * Available since PostgreSQL-9.5
3442
+ */
3443
+ static VALUE
3444
+ pgconn_ssl_attribute_names(VALUE self)
3445
+ {
3446
+ int i;
3447
+ const char * const * p_list = PQsslAttributeNames(pg_get_pgconn(self));
3448
+ VALUE ary = rb_ary_new();
3449
+
3450
+ for ( i = 0; p_list[i]; i++ ) {
3451
+ rb_ary_push( ary, rb_str_new_cstr( p_list[i] ));
3452
+ }
3453
+ return ary;
3454
+ }
3455
+
3456
+
3457
+ #endif
3458
+
3459
+
3460
+ /**************************************************************************
3461
+ * LARGE OBJECT SUPPORT
3462
+ **************************************************************************/
3463
+
3464
+ /*
3465
+ * call-seq:
3466
+ * conn.lo_creat( [mode] ) -> Integer
3467
+ *
3468
+ * Creates a large object with mode _mode_. Returns a large object Oid.
3469
+ * On failure, it raises PG::Error.
3470
+ */
3471
+ static VALUE
3472
+ pgconn_locreat(int argc, VALUE *argv, VALUE self)
3473
+ {
3474
+ Oid lo_oid;
3475
+ int mode;
3476
+ VALUE nmode;
3477
+ PGconn *conn = pg_get_pgconn(self);
3478
+
3479
+ if (rb_scan_args(argc, argv, "01", &nmode) == 0)
3480
+ mode = INV_READ;
3481
+ else
3482
+ mode = NUM2INT(nmode);
3483
+
3484
+ lo_oid = lo_creat(conn, mode);
3485
+ if (lo_oid == 0)
3486
+ rb_raise(rb_ePGerror, "lo_creat failed");
3487
+
3488
+ return UINT2NUM(lo_oid);
3489
+ }
3490
+
3491
+ /*
3492
+ * call-seq:
3493
+ * conn.lo_create( oid ) -> Integer
3494
+ *
3495
+ * Creates a large object with oid _oid_. Returns the large object Oid.
3496
+ * On failure, it raises PG::Error.
3497
+ */
3498
+ static VALUE
3499
+ pgconn_locreate(VALUE self, VALUE in_lo_oid)
3070
3500
  {
3501
+ Oid ret, lo_oid;
3071
3502
  PGconn *conn = pg_get_pgconn(self);
3072
- int oid;
3503
+ lo_oid = NUM2UINT(in_lo_oid);
3504
+
3505
+ ret = lo_create(conn, lo_oid);
3506
+ if (ret == InvalidOid)
3507
+ rb_raise(rb_ePGerror, "lo_create failed");
3508
+
3509
+ return UINT2NUM(ret);
3510
+ }
3511
+
3512
+ /*
3513
+ * call-seq:
3514
+ * conn.lo_import(file) -> Integer
3515
+ *
3516
+ * Import a file to a large object. Returns a large object Oid.
3517
+ *
3518
+ * On failure, it raises a PG::Error.
3519
+ */
3520
+ static VALUE
3521
+ pgconn_loimport(VALUE self, VALUE filename)
3522
+ {
3523
+ Oid lo_oid;
3524
+
3525
+ PGconn *conn = pg_get_pgconn(self);
3526
+
3073
3527
  Check_Type(filename, T_STRING);
3074
3528
 
3075
- oid = NUM2INT(lo_oid);
3076
- if (oid < 0) {
3077
- rb_raise(rb_ePGerror, "invalid large object oid %d",oid);
3529
+ lo_oid = lo_import(conn, StringValueCStr(filename));
3530
+ if (lo_oid == 0) {
3531
+ rb_raise(rb_ePGerror, "%s", PQerrorMessage(conn));
3078
3532
  }
3533
+ return UINT2NUM(lo_oid);
3534
+ }
3079
3535
 
3080
- if (lo_export(conn, oid, StringValuePtr(filename)) < 0) {
3536
+ /*
3537
+ * call-seq:
3538
+ * conn.lo_export( oid, file ) -> nil
3539
+ *
3540
+ * Saves a large object of _oid_ to a _file_.
3541
+ */
3542
+ static VALUE
3543
+ pgconn_loexport(VALUE self, VALUE lo_oid, VALUE filename)
3544
+ {
3545
+ PGconn *conn = pg_get_pgconn(self);
3546
+ Oid oid;
3547
+ Check_Type(filename, T_STRING);
3548
+
3549
+ oid = NUM2UINT(lo_oid);
3550
+
3551
+ if (lo_export(conn, oid, StringValueCStr(filename)) < 0) {
3081
3552
  rb_raise(rb_ePGerror, "%s", PQerrorMessage(conn));
3082
3553
  }
3083
3554
  return Qnil;
@@ -3085,7 +3556,7 @@ pgconn_loexport(VALUE self, VALUE lo_oid, VALUE filename)
3085
3556
 
3086
3557
  /*
3087
3558
  * call-seq:
3088
- * conn.lo_open( oid, [mode] ) -> Fixnum
3559
+ * conn.lo_open( oid, [mode] ) -> Integer
3089
3560
  *
3090
3561
  * Open a large object of _oid_. Returns a large object descriptor
3091
3562
  * instance on success. The _mode_ argument specifies the mode for
@@ -3102,7 +3573,7 @@ pgconn_loopen(int argc, VALUE *argv, VALUE self)
3102
3573
  PGconn *conn = pg_get_pgconn(self);
3103
3574
 
3104
3575
  rb_scan_args(argc, argv, "11", &selfid, &nmode);
3105
- lo_oid = NUM2INT(selfid);
3576
+ lo_oid = NUM2UINT(selfid);
3106
3577
  if(NIL_P(nmode))
3107
3578
  mode = INV_READ;
3108
3579
  else
@@ -3116,7 +3587,7 @@ pgconn_loopen(int argc, VALUE *argv, VALUE self)
3116
3587
 
3117
3588
  /*
3118
3589
  * call-seq:
3119
- * conn.lo_write( lo_desc, buffer ) -> Fixnum
3590
+ * conn.lo_write( lo_desc, buffer ) -> Integer
3120
3591
  *
3121
3592
  * Writes the string _buffer_ to the large object _lo_desc_.
3122
3593
  * Returns the number of bytes written.
@@ -3174,7 +3645,7 @@ pgconn_loread(VALUE self, VALUE in_lo_desc, VALUE in_len)
3174
3645
  return Qnil;
3175
3646
  }
3176
3647
 
3177
- str = rb_tainted_str_new(buffer, ret);
3648
+ str = rb_str_new(buffer, ret);
3178
3649
  xfree(buffer);
3179
3650
 
3180
3651
  return str;
@@ -3183,7 +3654,7 @@ pgconn_loread(VALUE self, VALUE in_lo_desc, VALUE in_len)
3183
3654
 
3184
3655
  /*
3185
3656
  * call-seq:
3186
- * conn.lo_lseek( lo_desc, offset, whence ) -> Fixnum
3657
+ * conn.lo_lseek( lo_desc, offset, whence ) -> Integer
3187
3658
  *
3188
3659
  * Move the large object pointer _lo_desc_ to offset _offset_.
3189
3660
  * Valid values for _whence_ are +SEEK_SET+, +SEEK_CUR+, and +SEEK_END+.
@@ -3205,7 +3676,7 @@ pgconn_lolseek(VALUE self, VALUE in_lo_desc, VALUE offset, VALUE whence)
3205
3676
 
3206
3677
  /*
3207
3678
  * call-seq:
3208
- * conn.lo_tell( lo_desc ) -> Fixnum
3679
+ * conn.lo_tell( lo_desc ) -> Integer
3209
3680
  *
3210
3681
  * Returns the current position of the large object _lo_desc_.
3211
3682
  */
@@ -3269,10 +3740,7 @@ static VALUE
3269
3740
  pgconn_lounlink(VALUE self, VALUE in_oid)
3270
3741
  {
3271
3742
  PGconn *conn = pg_get_pgconn(self);
3272
- int oid = NUM2INT(in_oid);
3273
-
3274
- if (oid < 0)
3275
- rb_raise(rb_ePGerror, "invalid oid %d",oid);
3743
+ Oid oid = NUM2UINT(in_oid);
3276
3744
 
3277
3745
  if(lo_unlink(conn,oid) < 0)
3278
3746
  rb_raise(rb_ePGerror,"lo_unlink failed");
@@ -3281,7 +3749,16 @@ pgconn_lounlink(VALUE self, VALUE in_oid)
3281
3749
  }
3282
3750
 
3283
3751
 
3284
- #ifdef M17N_SUPPORTED
3752
+ static void
3753
+ pgconn_set_internal_encoding_index( VALUE self )
3754
+ {
3755
+ int enc_idx;
3756
+ t_pg_connection *this = pg_get_connection_safe( self );
3757
+ rb_encoding *enc = pg_conn_enc_get( this->pgconn );
3758
+ enc_idx = rb_enc_to_index(enc);
3759
+ if( enc_idx >= (1<<(PG_ENC_IDX_BITS-1)) ) rb_raise(rb_eArgError, "unsupported encoding index %d", enc_idx);
3760
+ this->enc_idx = enc_idx;
3761
+ }
3285
3762
 
3286
3763
  /*
3287
3764
  * call-seq:
@@ -3327,7 +3804,7 @@ pgconn_internal_encoding_set(VALUE self, VALUE enc)
3327
3804
  pgconn_set_client_encoding( self, rb_usascii_str_new_cstr("SQL_ASCII") );
3328
3805
  return enc;
3329
3806
  }
3330
- else if ( TYPE(enc) == T_STRING && strcasecmp("JOHAB", RSTRING_PTR(enc)) == 0 ) {
3807
+ else if ( TYPE(enc) == T_STRING && strcasecmp("JOHAB", StringValueCStr(enc)) == 0 ) {
3331
3808
  pgconn_set_client_encoding(self, rb_usascii_str_new_cstr("JOHAB"));
3332
3809
  return enc;
3333
3810
  }
@@ -3335,17 +3812,14 @@ pgconn_internal_encoding_set(VALUE self, VALUE enc)
3335
3812
  rb_encoding *rbenc = rb_to_encoding( enc );
3336
3813
  const char *name = pg_get_rb_encoding_as_pg_encoding( rbenc );
3337
3814
 
3338
- if ( PQsetClientEncoding(pg_get_pgconn( self ), name) == -1 ) {
3815
+ if ( gvl_PQsetClientEncoding(pg_get_pgconn( self ), name) == -1 ) {
3339
3816
  VALUE server_encoding = pgconn_external_encoding( self );
3340
3817
  rb_raise( rb_eEncCompatError, "incompatible character encodings: %s and %s",
3341
3818
  rb_enc_name(rb_to_encoding(server_encoding)), name );
3342
3819
  }
3820
+ pgconn_set_internal_encoding_index( self );
3343
3821
  return enc;
3344
3822
  }
3345
-
3346
- rb_raise( rb_ePGerror, "unknown encoding: %s", RSTRING_PTR(rb_inspect(enc)) );
3347
-
3348
- return Qnil;
3349
3823
  }
3350
3824
 
3351
3825
 
@@ -3360,24 +3834,45 @@ pgconn_internal_encoding_set(VALUE self, VALUE enc)
3360
3834
  static VALUE
3361
3835
  pgconn_external_encoding(VALUE self)
3362
3836
  {
3363
- PGconn *conn = pg_get_pgconn( self );
3364
- VALUE encoding = rb_iv_get( self, "@external_encoding" );
3837
+ t_pg_connection *this = pg_get_connection_safe( self );
3365
3838
  rb_encoding *enc = NULL;
3366
3839
  const char *pg_encname = NULL;
3367
3840
 
3368
- /* Use cached value if found */
3369
- if ( RTEST(encoding) ) return encoding;
3370
-
3371
- pg_encname = PQparameterStatus( conn, "server_encoding" );
3841
+ pg_encname = PQparameterStatus( this->pgconn, "server_encoding" );
3372
3842
  enc = pg_get_pg_encname_as_rb_encoding( pg_encname );
3373
- encoding = rb_enc_from_encoding( enc );
3843
+ return rb_enc_from_encoding( enc );
3844
+ }
3845
+
3374
3846
 
3375
- rb_iv_set( self, "@external_encoding", encoding );
3847
+ static VALUE
3848
+ pgconn_set_client_encoding_async1( VALUE args )
3849
+ {
3850
+ VALUE self = ((VALUE*)args)[0];
3851
+ VALUE encname = ((VALUE*)args)[1];
3852
+ VALUE query_format = rb_str_new_cstr("set client_encoding to '%s'");
3853
+ VALUE query = rb_funcall(query_format, rb_intern("%"), 1, encname);
3376
3854
 
3377
- return encoding;
3855
+ pgconn_async_exec(1, &query, self);
3856
+ return 0;
3378
3857
  }
3379
3858
 
3380
3859
 
3860
+ static VALUE
3861
+ pgconn_set_client_encoding_async2( VALUE arg, VALUE ex )
3862
+ {
3863
+ UNUSED(arg);
3864
+ UNUSED(ex);
3865
+ return 1;
3866
+ }
3867
+
3868
+
3869
+ static VALUE
3870
+ pgconn_set_client_encoding_async( VALUE self, const char *encname )
3871
+ {
3872
+ VALUE args[] = { self, rb_str_new_cstr(encname) };
3873
+ return rb_rescue(pgconn_set_client_encoding_async1, (VALUE)&args, pgconn_set_client_encoding_async2, Qnil);
3874
+ }
3875
+
3381
3876
 
3382
3877
  /*
3383
3878
  * call-seq:
@@ -3396,24 +3891,266 @@ pgconn_set_default_encoding( VALUE self )
3396
3891
 
3397
3892
  if (( enc = rb_default_internal_encoding() )) {
3398
3893
  encname = pg_get_rb_encoding_as_pg_encoding( enc );
3399
- if ( PQsetClientEncoding(conn, encname) != 0 )
3400
- rb_warn( "Failed to set the default_internal encoding to %s: '%s'",
3894
+ if ( pgconn_set_client_encoding_async(self, encname) != 0 )
3895
+ rb_warning( "Failed to set the default_internal encoding to %s: '%s'",
3401
3896
  encname, PQerrorMessage(conn) );
3897
+ pgconn_set_internal_encoding_index( self );
3402
3898
  return rb_enc_from_encoding( enc );
3403
3899
  } else {
3900
+ pgconn_set_internal_encoding_index( self );
3404
3901
  return Qnil;
3405
3902
  }
3406
3903
  }
3407
3904
 
3408
3905
 
3409
- #endif /* M17N_SUPPORTED */
3906
+ /*
3907
+ * call-seq:
3908
+ * res.type_map_for_queries = typemap
3909
+ *
3910
+ * Set the default TypeMap that is used for type casts of query bind parameters.
3911
+ *
3912
+ * +typemap+ must be a kind of PG::TypeMap .
3913
+ *
3914
+ */
3915
+ static VALUE
3916
+ pgconn_type_map_for_queries_set(VALUE self, VALUE typemap)
3917
+ {
3918
+ t_pg_connection *this = pg_get_connection( self );
3919
+
3920
+ if ( !rb_obj_is_kind_of(typemap, rb_cTypeMap) ) {
3921
+ rb_raise( rb_eTypeError, "wrong argument type %s (expected kind of PG::TypeMap)",
3922
+ rb_obj_classname( typemap ) );
3923
+ }
3924
+ Check_Type(typemap, T_DATA);
3925
+ this->type_map_for_queries = typemap;
3926
+
3927
+ return typemap;
3928
+ }
3929
+
3930
+ /*
3931
+ * call-seq:
3932
+ * res.type_map_for_queries -> TypeMap
3933
+ *
3934
+ * Returns the default TypeMap that is currently set for type casts of query
3935
+ * bind parameters.
3936
+ *
3937
+ */
3938
+ static VALUE
3939
+ pgconn_type_map_for_queries_get(VALUE self)
3940
+ {
3941
+ t_pg_connection *this = pg_get_connection( self );
3942
+
3943
+ return this->type_map_for_queries;
3944
+ }
3945
+
3946
+ /*
3947
+ * call-seq:
3948
+ * res.type_map_for_results = typemap
3949
+ *
3950
+ * Set the default TypeMap that is used for type casts of result values.
3951
+ *
3952
+ * +typemap+ must be a kind of PG::TypeMap .
3953
+ *
3954
+ */
3955
+ static VALUE
3956
+ pgconn_type_map_for_results_set(VALUE self, VALUE typemap)
3957
+ {
3958
+ t_pg_connection *this = pg_get_connection( self );
3959
+
3960
+ if ( !rb_obj_is_kind_of(typemap, rb_cTypeMap) ) {
3961
+ rb_raise( rb_eTypeError, "wrong argument type %s (expected kind of PG::TypeMap)",
3962
+ rb_obj_classname( typemap ) );
3963
+ }
3964
+ Check_Type(typemap, T_DATA);
3965
+ this->type_map_for_results = typemap;
3966
+
3967
+ return typemap;
3968
+ }
3969
+
3970
+ /*
3971
+ * call-seq:
3972
+ * res.type_map_for_results -> TypeMap
3973
+ *
3974
+ * Returns the default TypeMap that is currently set for type casts of result values.
3975
+ *
3976
+ */
3977
+ static VALUE
3978
+ pgconn_type_map_for_results_get(VALUE self)
3979
+ {
3980
+ t_pg_connection *this = pg_get_connection( self );
3981
+
3982
+ return this->type_map_for_results;
3983
+ }
3410
3984
 
3411
3985
 
3986
+ /*
3987
+ * call-seq:
3988
+ * res.encoder_for_put_copy_data = encoder
3989
+ *
3990
+ * Set the default coder that is used for type casting of parameters
3991
+ * to #put_copy_data .
3992
+ *
3993
+ * +encoder+ can be:
3994
+ * * a kind of PG::Coder
3995
+ * * +nil+ - disable type encoding, data must be a String.
3996
+ *
3997
+ */
3998
+ static VALUE
3999
+ pgconn_encoder_for_put_copy_data_set(VALUE self, VALUE typemap)
4000
+ {
4001
+ t_pg_connection *this = pg_get_connection( self );
3412
4002
 
4003
+ if( typemap != Qnil ){
4004
+ if ( !rb_obj_is_kind_of(typemap, rb_cPG_Coder) ) {
4005
+ rb_raise( rb_eTypeError, "wrong argument type %s (expected kind of PG::Coder)",
4006
+ rb_obj_classname( typemap ) );
4007
+ }
4008
+ Check_Type(typemap, T_DATA);
4009
+ }
4010
+ this->encoder_for_put_copy_data = typemap;
4011
+
4012
+ return typemap;
4013
+ }
4014
+
4015
+ /*
4016
+ * call-seq:
4017
+ * res.encoder_for_put_copy_data -> PG::Coder
4018
+ *
4019
+ * Returns the default coder object that is currently set for type casting of parameters
4020
+ * to #put_copy_data .
4021
+ *
4022
+ * Returns either:
4023
+ * * a kind of PG::Coder
4024
+ * * +nil+ - type encoding is disabled, data must be a String.
4025
+ *
4026
+ */
4027
+ static VALUE
4028
+ pgconn_encoder_for_put_copy_data_get(VALUE self)
4029
+ {
4030
+ t_pg_connection *this = pg_get_connection( self );
4031
+
4032
+ return this->encoder_for_put_copy_data;
4033
+ }
4034
+
4035
+ /*
4036
+ * call-seq:
4037
+ * res.decoder_for_get_copy_data = decoder
4038
+ *
4039
+ * Set the default coder that is used for type casting of received data
4040
+ * by #get_copy_data .
4041
+ *
4042
+ * +decoder+ can be:
4043
+ * * a kind of PG::Coder
4044
+ * * +nil+ - disable type decoding, returned data will be a String.
4045
+ *
4046
+ */
4047
+ static VALUE
4048
+ pgconn_decoder_for_get_copy_data_set(VALUE self, VALUE typemap)
4049
+ {
4050
+ t_pg_connection *this = pg_get_connection( self );
4051
+
4052
+ if( typemap != Qnil ){
4053
+ if ( !rb_obj_is_kind_of(typemap, rb_cPG_Coder) ) {
4054
+ rb_raise( rb_eTypeError, "wrong argument type %s (expected kind of PG::Coder)",
4055
+ rb_obj_classname( typemap ) );
4056
+ }
4057
+ Check_Type(typemap, T_DATA);
4058
+ }
4059
+ this->decoder_for_get_copy_data = typemap;
4060
+
4061
+ return typemap;
4062
+ }
4063
+
4064
+ /*
4065
+ * call-seq:
4066
+ * res.decoder_for_get_copy_data -> PG::Coder
4067
+ *
4068
+ * Returns the default coder object that is currently set for type casting of received
4069
+ * data by #get_copy_data .
4070
+ *
4071
+ * Returns either:
4072
+ * * a kind of PG::Coder
4073
+ * * +nil+ - type encoding is disabled, returned data will be a String.
4074
+ *
4075
+ */
4076
+ static VALUE
4077
+ pgconn_decoder_for_get_copy_data_get(VALUE self)
4078
+ {
4079
+ t_pg_connection *this = pg_get_connection( self );
4080
+
4081
+ return this->decoder_for_get_copy_data;
4082
+ }
4083
+
4084
+ /*
4085
+ * call-seq:
4086
+ * conn.field_name_type = Symbol
4087
+ *
4088
+ * Set default type of field names of results retrieved by this connection.
4089
+ * It can be set to one of:
4090
+ * * +:string+ to use String based field names
4091
+ * * +:symbol+ to use Symbol based field names
4092
+ *
4093
+ * The default is +:string+ .
4094
+ *
4095
+ * Settings the type of field names affects only future results.
4096
+ *
4097
+ * See further description at PG::Result#field_name_type=
4098
+ *
4099
+ */
4100
+ static VALUE
4101
+ pgconn_field_name_type_set(VALUE self, VALUE sym)
4102
+ {
4103
+ t_pg_connection *this = pg_get_connection( self );
4104
+
4105
+ this->flags &= ~PG_RESULT_FIELD_NAMES_MASK;
4106
+ if( sym == sym_symbol ) this->flags |= PG_RESULT_FIELD_NAMES_SYMBOL;
4107
+ else if ( sym == sym_static_symbol ) this->flags |= PG_RESULT_FIELD_NAMES_STATIC_SYMBOL;
4108
+ else if ( sym == sym_string );
4109
+ else rb_raise(rb_eArgError, "invalid argument %+"PRIsVALUE, sym);
4110
+
4111
+ return sym;
4112
+ }
4113
+
4114
+ /*
4115
+ * call-seq:
4116
+ * conn.field_name_type -> Symbol
4117
+ *
4118
+ * Get type of field names.
4119
+ *
4120
+ * See description at #field_name_type=
4121
+ */
4122
+ static VALUE
4123
+ pgconn_field_name_type_get(VALUE self)
4124
+ {
4125
+ t_pg_connection *this = pg_get_connection( self );
4126
+
4127
+ if( this->flags & PG_RESULT_FIELD_NAMES_SYMBOL ){
4128
+ return sym_symbol;
4129
+ } else if( this->flags & PG_RESULT_FIELD_NAMES_STATIC_SYMBOL ){
4130
+ return sym_static_symbol;
4131
+ } else {
4132
+ return sym_string;
4133
+ }
4134
+ }
4135
+
4136
+
4137
+ /*
4138
+ * Document-class: PG::Connection
4139
+ */
3413
4140
  void
3414
4141
  init_pg_connection()
3415
4142
  {
4143
+ s_id_encode = rb_intern("encode");
4144
+ sym_type = ID2SYM(rb_intern("type"));
4145
+ sym_format = ID2SYM(rb_intern("format"));
4146
+ sym_value = ID2SYM(rb_intern("value"));
4147
+ sym_string = ID2SYM(rb_intern("string"));
4148
+ sym_symbol = ID2SYM(rb_intern("symbol"));
4149
+ sym_static_symbol = ID2SYM(rb_intern("static_symbol"));
4150
+
3416
4151
  rb_cPGconn = rb_define_class_under( rb_mPG, "Connection", rb_cObject );
4152
+ /* Help rdoc to known the Constants module */
4153
+ /* rb_mPGconstants = rb_define_module_under( rb_mPG, "Constants" ); */
3417
4154
  rb_include_module(rb_cPGconn, rb_mPGconstants);
3418
4155
 
3419
4156
  /****** PG::Connection CLASS METHODS ******/
@@ -3431,9 +4168,7 @@ init_pg_connection()
3431
4168
  rb_define_singleton_method(rb_cPGconn, "quote_ident", pgconn_s_quote_ident, 1);
3432
4169
  rb_define_singleton_method(rb_cPGconn, "connect_start", pgconn_s_connect_start, -1);
3433
4170
  rb_define_singleton_method(rb_cPGconn, "conndefaults", pgconn_s_conndefaults, 0);
3434
- #ifdef HAVE_PQPING
3435
4171
  rb_define_singleton_method(rb_cPGconn, "ping", pgconn_s_ping, -1);
3436
- #endif
3437
4172
 
3438
4173
  /****** PG::Connection INSTANCE METHODS: Connection Control ******/
3439
4174
  rb_define_method(rb_cPGconn, "initialize", pgconn_init, -1);
@@ -3443,7 +4178,6 @@ init_pg_connection()
3443
4178
  rb_define_method(rb_cPGconn, "reset", pgconn_reset, 0);
3444
4179
  rb_define_method(rb_cPGconn, "reset_start", pgconn_reset_start, 0);
3445
4180
  rb_define_method(rb_cPGconn, "reset_poll", pgconn_reset_poll, 0);
3446
- rb_define_method(rb_cPGconn, "conndefaults", pgconn_s_conndefaults, 0);
3447
4181
  rb_define_alias(rb_cPGconn, "close", "finish");
3448
4182
 
3449
4183
  /****** PG::Connection INSTANCE METHODS: Connection Status ******/
@@ -3453,6 +4187,9 @@ init_pg_connection()
3453
4187
  rb_define_method(rb_cPGconn, "host", pgconn_host, 0);
3454
4188
  rb_define_method(rb_cPGconn, "port", pgconn_port, 0);
3455
4189
  rb_define_method(rb_cPGconn, "tty", pgconn_tty, 0);
4190
+ #ifdef HAVE_PQCONNINFO
4191
+ rb_define_method(rb_cPGconn, "conninfo", pgconn_conninfo, 0);
4192
+ #endif
3456
4193
  rb_define_method(rb_cPGconn, "options", pgconn_options, 0);
3457
4194
  rb_define_method(rb_cPGconn, "status", pgconn_status, 0);
3458
4195
  rb_define_method(rb_cPGconn, "transaction_status", pgconn_transaction_status, 0);
@@ -3461,39 +4198,47 @@ init_pg_connection()
3461
4198
  rb_define_method(rb_cPGconn, "server_version", pgconn_server_version, 0);
3462
4199
  rb_define_method(rb_cPGconn, "error_message", pgconn_error_message, 0);
3463
4200
  rb_define_method(rb_cPGconn, "socket", pgconn_socket, 0);
3464
- #if !defined(_WIN32) || defined(HAVE_RB_W32_WRAP_IO_HANDLE)
3465
4201
  rb_define_method(rb_cPGconn, "socket_io", pgconn_socket_io, 0);
3466
- #endif
3467
4202
  rb_define_method(rb_cPGconn, "backend_pid", pgconn_backend_pid, 0);
3468
4203
  rb_define_method(rb_cPGconn, "connection_needs_password", pgconn_connection_needs_password, 0);
3469
4204
  rb_define_method(rb_cPGconn, "connection_used_password", pgconn_connection_used_password, 0);
3470
4205
  /* rb_define_method(rb_cPGconn, "getssl", pgconn_getssl, 0); */
3471
4206
 
3472
4207
  /****** PG::Connection INSTANCE METHODS: Command Execution ******/
3473
- rb_define_method(rb_cPGconn, "exec", pgconn_exec, -1);
3474
- rb_define_alias(rb_cPGconn, "query", "exec");
3475
- rb_define_method(rb_cPGconn, "exec_params", pgconn_exec_params, -1);
3476
- rb_define_method(rb_cPGconn, "prepare", pgconn_prepare, -1);
3477
- rb_define_method(rb_cPGconn, "exec_prepared", pgconn_exec_prepared, -1);
3478
- rb_define_method(rb_cPGconn, "describe_prepared", pgconn_describe_prepared, 1);
3479
- rb_define_method(rb_cPGconn, "describe_portal", pgconn_describe_portal, 1);
4208
+ rb_define_method(rb_cPGconn, "sync_exec", pgconn_exec, -1);
4209
+ rb_define_method(rb_cPGconn, "sync_exec_params", pgconn_exec_params, -1);
4210
+ rb_define_method(rb_cPGconn, "sync_prepare", pgconn_prepare, -1);
4211
+ rb_define_method(rb_cPGconn, "sync_exec_prepared", pgconn_exec_prepared, -1);
4212
+ rb_define_method(rb_cPGconn, "sync_describe_prepared", pgconn_describe_prepared, 1);
4213
+ rb_define_method(rb_cPGconn, "sync_describe_portal", pgconn_describe_portal, 1);
4214
+
4215
+ rb_define_method(rb_cPGconn, "exec", pgconn_async_exec, -1);
4216
+ rb_define_method(rb_cPGconn, "exec_params", pgconn_async_exec_params, -1);
4217
+ rb_define_method(rb_cPGconn, "prepare", pgconn_async_prepare, -1);
4218
+ rb_define_method(rb_cPGconn, "exec_prepared", pgconn_async_exec_prepared, -1);
4219
+ rb_define_method(rb_cPGconn, "describe_prepared", pgconn_async_describe_prepared, 1);
4220
+ rb_define_method(rb_cPGconn, "describe_portal", pgconn_async_describe_portal, 1);
4221
+
4222
+ rb_define_alias(rb_cPGconn, "async_exec", "exec");
4223
+ rb_define_alias(rb_cPGconn, "async_query", "async_exec");
4224
+ rb_define_alias(rb_cPGconn, "async_exec_params", "exec_params");
4225
+ rb_define_alias(rb_cPGconn, "async_prepare", "prepare");
4226
+ rb_define_alias(rb_cPGconn, "async_exec_prepared", "exec_prepared");
4227
+ rb_define_alias(rb_cPGconn, "async_describe_prepared", "describe_prepared");
4228
+ rb_define_alias(rb_cPGconn, "async_describe_portal", "describe_portal");
4229
+
3480
4230
  rb_define_method(rb_cPGconn, "make_empty_pgresult", pgconn_make_empty_pgresult, 1);
3481
4231
  rb_define_method(rb_cPGconn, "escape_string", pgconn_s_escape, 1);
3482
4232
  rb_define_alias(rb_cPGconn, "escape", "escape_string");
3483
- #ifdef HAVE_PQESCAPELITERAL
3484
4233
  rb_define_method(rb_cPGconn, "escape_literal", pgconn_escape_literal, 1);
3485
- #endif
3486
- #ifdef HAVE_PQESCAPEIDENTIFIER
3487
4234
  rb_define_method(rb_cPGconn, "escape_identifier", pgconn_escape_identifier, 1);
3488
- #endif
3489
4235
  rb_define_method(rb_cPGconn, "escape_bytea", pgconn_s_escape_bytea, 1);
3490
4236
  rb_define_method(rb_cPGconn, "unescape_bytea", pgconn_s_unescape_bytea, 1);
3491
- #ifdef HAVE_PQSETSINGLEROWMODE
3492
4237
  rb_define_method(rb_cPGconn, "set_single_row_mode", pgconn_set_single_row_mode, 0);
3493
- #endif
3494
4238
 
3495
4239
  /****** PG::Connection INSTANCE METHODS: Asynchronous Command Processing ******/
3496
4240
  rb_define_method(rb_cPGconn, "send_query", pgconn_send_query, -1);
4241
+ rb_define_method(rb_cPGconn, "send_query_params", pgconn_send_query_params, -1);
3497
4242
  rb_define_method(rb_cPGconn, "send_prepare", pgconn_send_prepare, -1);
3498
4243
  rb_define_method(rb_cPGconn, "send_query_prepared", pgconn_send_query_prepared, -1);
3499
4244
  rb_define_method(rb_cPGconn, "send_describe_prepared", pgconn_send_describe_prepared, 1);
@@ -3505,6 +4250,7 @@ init_pg_connection()
3505
4250
  rb_define_method(rb_cPGconn, "isnonblocking", pgconn_isnonblocking, 0);
3506
4251
  rb_define_alias(rb_cPGconn, "nonblocking?", "isnonblocking");
3507
4252
  rb_define_method(rb_cPGconn, "flush", pgconn_flush, 0);
4253
+ rb_define_method(rb_cPGconn, "discard_results", pgconn_discard_results, 0);
3508
4254
 
3509
4255
  /****** PG::Connection INSTANCE METHODS: Cancelling Queries in Progress ******/
3510
4256
  rb_define_method(rb_cPGconn, "cancel", pgconn_cancel, 0);
@@ -3513,12 +4259,15 @@ init_pg_connection()
3513
4259
  rb_define_method(rb_cPGconn, "notifies", pgconn_notifies, 0);
3514
4260
 
3515
4261
  /****** PG::Connection INSTANCE METHODS: COPY ******/
3516
- rb_define_method(rb_cPGconn, "put_copy_data", pgconn_put_copy_data, 1);
4262
+ rb_define_method(rb_cPGconn, "put_copy_data", pgconn_put_copy_data, -1);
3517
4263
  rb_define_method(rb_cPGconn, "put_copy_end", pgconn_put_copy_end, -1);
3518
4264
  rb_define_method(rb_cPGconn, "get_copy_data", pgconn_get_copy_data, -1);
3519
4265
 
3520
4266
  /****** PG::Connection INSTANCE METHODS: Control Functions ******/
3521
4267
  rb_define_method(rb_cPGconn, "set_error_verbosity", pgconn_set_error_verbosity, 1);
4268
+ #ifdef HAVE_PQRESULTVERBOSEERRORMESSAGE
4269
+ rb_define_method(rb_cPGconn, "set_error_context_visibility", pgconn_set_error_context_visibility, 1 );
4270
+ #endif
3522
4271
  rb_define_method(rb_cPGconn, "trace", pgconn_trace, 1);
3523
4272
  rb_define_method(rb_cPGconn, "untrace", pgconn_untrace, 0);
3524
4273
 
@@ -3535,13 +4284,16 @@ init_pg_connection()
3535
4284
  rb_define_method(rb_cPGconn, "wait_for_notify", pgconn_wait_for_notify, -1);
3536
4285
  rb_define_alias(rb_cPGconn, "notifies_wait", "wait_for_notify");
3537
4286
  rb_define_method(rb_cPGconn, "quote_ident", pgconn_s_quote_ident, 1);
3538
- #if defined(HAVE_RB_THREAD_CALL_WITHOUT_GVL)
3539
- rb_define_alias(rb_cPGconn, "async_exec", "exec");
3540
- #else
3541
- rb_define_method(rb_cPGconn, "async_exec", pgconn_async_exec, -1);
3542
- #endif
3543
- rb_define_alias(rb_cPGconn, "async_query", "async_exec");
3544
4287
  rb_define_method(rb_cPGconn, "get_last_result", pgconn_get_last_result, 0);
4288
+ #ifdef HAVE_PQENCRYPTPASSWORDCONN
4289
+ rb_define_method(rb_cPGconn, "encrypt_password", pgconn_encrypt_password, -1);
4290
+ #endif
4291
+
4292
+ #ifdef HAVE_PQSSLATTRIBUTE
4293
+ rb_define_method(rb_cPGconn, "ssl_in_use?", pgconn_ssl_in_use, 0);
4294
+ rb_define_method(rb_cPGconn, "ssl_attribute", pgconn_ssl_attribute, 1);
4295
+ rb_define_method(rb_cPGconn, "ssl_attribute_names", pgconn_ssl_attribute_names, 0);
4296
+ #endif
3545
4297
 
3546
4298
  /****** PG::Connection INSTANCE METHODS: Large Object Support ******/
3547
4299
  rb_define_method(rb_cPGconn, "lo_creat", pgconn_locreat, -1);
@@ -3571,12 +4323,20 @@ init_pg_connection()
3571
4323
  rb_define_method(rb_cPGconn, "lo_unlink", pgconn_lounlink, 1);
3572
4324
  rb_define_alias(rb_cPGconn, "lounlink", "lo_unlink");
3573
4325
 
3574
- #ifdef M17N_SUPPORTED
3575
4326
  rb_define_method(rb_cPGconn, "internal_encoding", pgconn_internal_encoding, 0);
3576
4327
  rb_define_method(rb_cPGconn, "internal_encoding=", pgconn_internal_encoding_set, 1);
3577
4328
  rb_define_method(rb_cPGconn, "external_encoding", pgconn_external_encoding, 0);
3578
4329
  rb_define_method(rb_cPGconn, "set_default_encoding", pgconn_set_default_encoding, 0);
3579
- #endif /* M17N_SUPPORTED */
3580
4330
 
4331
+ rb_define_method(rb_cPGconn, "type_map_for_queries=", pgconn_type_map_for_queries_set, 1);
4332
+ rb_define_method(rb_cPGconn, "type_map_for_queries", pgconn_type_map_for_queries_get, 0);
4333
+ rb_define_method(rb_cPGconn, "type_map_for_results=", pgconn_type_map_for_results_set, 1);
4334
+ rb_define_method(rb_cPGconn, "type_map_for_results", pgconn_type_map_for_results_get, 0);
4335
+ rb_define_method(rb_cPGconn, "encoder_for_put_copy_data=", pgconn_encoder_for_put_copy_data_set, 1);
4336
+ rb_define_method(rb_cPGconn, "encoder_for_put_copy_data", pgconn_encoder_for_put_copy_data_get, 0);
4337
+ rb_define_method(rb_cPGconn, "decoder_for_get_copy_data=", pgconn_decoder_for_get_copy_data_set, 1);
4338
+ rb_define_method(rb_cPGconn, "decoder_for_get_copy_data", pgconn_decoder_for_get_copy_data_get, 0);
4339
+
4340
+ rb_define_method(rb_cPGconn, "field_name_type=", pgconn_field_name_type_set, 1 );
4341
+ rb_define_method(rb_cPGconn, "field_name_type", pgconn_field_name_type_get, 0 );
3581
4342
  }
3582
-