pg 1.1.3 → 1.3.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- checksums.yaml.gz.sig +0 -0
- data/.appveyor.yml +36 -0
- data/.gems +6 -0
- data/.github/workflows/binary-gems.yml +86 -0
- data/.github/workflows/source-gem.yml +129 -0
- data/.gitignore +13 -0
- data/.hgsigs +34 -0
- data/.hgtags +41 -0
- data/.irbrc +23 -0
- data/.pryrc +23 -0
- data/.tm_properties +21 -0
- data/.travis.yml +49 -0
- data/Gemfile +14 -0
- data/History.rdoc +210 -6
- data/Manifest.txt +3 -3
- data/README-Windows.rdoc +4 -4
- data/README.ja.rdoc +1 -2
- data/README.rdoc +51 -15
- data/Rakefile +31 -140
- data/Rakefile.cross +60 -56
- data/certs/ged.pem +24 -0
- data/certs/larskanis-2022.pem +26 -0
- data/ext/errorcodes.def +76 -0
- data/ext/errorcodes.txt +21 -2
- data/ext/extconf.rb +101 -26
- data/ext/gvl_wrappers.c +4 -0
- data/ext/gvl_wrappers.h +23 -0
- data/ext/pg.c +190 -98
- data/ext/pg.h +42 -17
- data/ext/pg_binary_decoder.c +20 -16
- data/ext/pg_binary_encoder.c +13 -12
- data/ext/pg_coder.c +95 -29
- data/ext/pg_connection.c +1043 -769
- data/ext/pg_copy_coder.c +50 -18
- data/ext/pg_record_coder.c +519 -0
- data/ext/pg_result.c +326 -142
- data/ext/pg_text_decoder.c +15 -9
- data/ext/pg_text_encoder.c +185 -53
- data/ext/pg_tuple.c +61 -27
- data/ext/pg_type_map.c +42 -9
- data/ext/pg_type_map_all_strings.c +19 -5
- data/ext/pg_type_map_by_class.c +54 -24
- data/ext/pg_type_map_by_column.c +73 -34
- data/ext/pg_type_map_by_mri_type.c +48 -19
- data/ext/pg_type_map_by_oid.c +55 -25
- data/ext/pg_type_map_in_ruby.c +51 -20
- data/ext/{util.c → pg_util.c} +7 -7
- data/ext/{util.h → pg_util.h} +0 -0
- data/lib/pg/basic_type_map_based_on_result.rb +47 -0
- data/lib/pg/basic_type_map_for_queries.rb +193 -0
- data/lib/pg/basic_type_map_for_results.rb +81 -0
- data/lib/pg/basic_type_registry.rb +296 -0
- data/lib/pg/binary_decoder.rb +1 -0
- data/lib/pg/coder.rb +23 -2
- data/lib/pg/connection.rb +589 -59
- data/lib/pg/constants.rb +1 -0
- data/lib/pg/exceptions.rb +1 -0
- data/lib/pg/result.rb +13 -1
- data/lib/pg/text_decoder.rb +2 -3
- data/lib/pg/text_encoder.rb +8 -18
- data/lib/pg/type_map_by_column.rb +2 -1
- data/lib/pg/version.rb +4 -0
- data/lib/pg.rb +48 -33
- data/misc/openssl-pg-segfault.rb +31 -0
- data/misc/postgres/History.txt +9 -0
- data/misc/postgres/Manifest.txt +5 -0
- data/misc/postgres/README.txt +21 -0
- data/misc/postgres/Rakefile +21 -0
- data/misc/postgres/lib/postgres.rb +16 -0
- data/misc/ruby-pg/History.txt +9 -0
- data/misc/ruby-pg/Manifest.txt +5 -0
- data/misc/ruby-pg/README.txt +21 -0
- data/misc/ruby-pg/Rakefile +21 -0
- data/misc/ruby-pg/lib/ruby/pg.rb +16 -0
- data/pg.gemspec +32 -0
- data/rakelib/task_extension.rb +46 -0
- data/sample/array_insert.rb +20 -0
- data/sample/async_api.rb +106 -0
- data/sample/async_copyto.rb +39 -0
- data/sample/async_mixed.rb +56 -0
- data/sample/check_conn.rb +21 -0
- data/sample/copydata.rb +71 -0
- data/sample/copyfrom.rb +81 -0
- data/sample/copyto.rb +19 -0
- data/sample/cursor.rb +21 -0
- data/sample/disk_usage_report.rb +177 -0
- data/sample/issue-119.rb +94 -0
- data/sample/losample.rb +69 -0
- data/sample/minimal-testcase.rb +17 -0
- data/sample/notify_wait.rb +72 -0
- data/sample/pg_statistics.rb +285 -0
- data/sample/replication_monitor.rb +222 -0
- data/sample/test_binary_values.rb +33 -0
- data/sample/wal_shipper.rb +434 -0
- data/sample/warehouse_partitions.rb +311 -0
- data.tar.gz.sig +0 -0
- metadata +94 -237
- metadata.gz.sig +0 -0
- data/ChangeLog +0 -6595
- data/lib/pg/basic_type_mapping.rb +0 -459
- data/spec/data/expected_trace.out +0 -26
- data/spec/data/random_binary_data +0 -0
- data/spec/helpers.rb +0 -381
- data/spec/pg/basic_type_mapping_spec.rb +0 -508
- data/spec/pg/connection_spec.rb +0 -1849
- data/spec/pg/connection_sync_spec.rb +0 -41
- data/spec/pg/result_spec.rb +0 -491
- data/spec/pg/tuple_spec.rb +0 -280
- data/spec/pg/type_map_by_class_spec.rb +0 -138
- data/spec/pg/type_map_by_column_spec.rb +0 -222
- data/spec/pg/type_map_by_mri_type_spec.rb +0 -136
- data/spec/pg/type_map_by_oid_spec.rb +0 -149
- data/spec/pg/type_map_in_ruby_spec.rb +0 -164
- data/spec/pg/type_map_spec.rb +0 -22
- data/spec/pg/type_spec.rb +0 -949
- data/spec/pg_spec.rb +0 -50
data/ext/pg_connection.c
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
/*
|
2
2
|
* pg_connection.c - PG::Connection class extension
|
3
|
-
* $Id
|
3
|
+
* $Id$
|
4
4
|
*
|
5
5
|
*/
|
6
6
|
|
@@ -12,14 +12,18 @@
|
|
12
12
|
|
13
13
|
VALUE rb_cPGconn;
|
14
14
|
static ID s_id_encode;
|
15
|
+
static ID s_id_autoclose_set;
|
15
16
|
static VALUE sym_type, sym_format, sym_value;
|
17
|
+
static VALUE sym_symbol, sym_string, sym_static_symbol;
|
16
18
|
|
17
19
|
static PQnoticeReceiver default_notice_receiver = NULL;
|
18
20
|
static PQnoticeProcessor default_notice_processor = NULL;
|
19
21
|
|
20
22
|
static VALUE pgconn_finish( VALUE );
|
21
23
|
static VALUE pgconn_set_default_encoding( VALUE self );
|
22
|
-
|
24
|
+
static VALUE pgconn_wait_for_flush( VALUE self );
|
25
|
+
static void pgconn_set_internal_encoding_index( VALUE );
|
26
|
+
static const rb_data_type_t pg_connection_type;
|
23
27
|
|
24
28
|
/*
|
25
29
|
* Global functions
|
@@ -32,7 +36,7 @@ t_pg_connection *
|
|
32
36
|
pg_get_connection( VALUE self )
|
33
37
|
{
|
34
38
|
t_pg_connection *this;
|
35
|
-
|
39
|
+
TypedData_Get_Struct( self, t_pg_connection, &pg_connection_type, this);
|
36
40
|
|
37
41
|
return this;
|
38
42
|
}
|
@@ -45,7 +49,7 @@ static t_pg_connection *
|
|
45
49
|
pg_get_connection_safe( VALUE self )
|
46
50
|
{
|
47
51
|
t_pg_connection *this;
|
48
|
-
|
52
|
+
TypedData_Get_Struct( self, t_pg_connection, &pg_connection_type, this);
|
49
53
|
|
50
54
|
if ( !this->pgconn )
|
51
55
|
rb_raise( rb_eConnectionBad, "connection is closed" );
|
@@ -64,7 +68,7 @@ PGconn *
|
|
64
68
|
pg_get_pgconn( VALUE self )
|
65
69
|
{
|
66
70
|
t_pg_connection *this;
|
67
|
-
|
71
|
+
TypedData_Get_Struct( self, t_pg_connection, &pg_connection_type, this);
|
68
72
|
|
69
73
|
if ( !this->pgconn )
|
70
74
|
rb_raise( rb_eConnectionBad, "connection is closed" );
|
@@ -85,8 +89,7 @@ pgconn_close_socket_io( VALUE self )
|
|
85
89
|
|
86
90
|
if ( RTEST(socket_io) ) {
|
87
91
|
#if defined(_WIN32)
|
88
|
-
|
89
|
-
if( rb_w32_unwrap_io_handle(ruby_sd) ){
|
92
|
+
if( rb_w32_unwrap_io_handle(this->ruby_sd) ){
|
90
93
|
rb_raise(rb_eConnectionBad, "Could not unwrap win32 socket handle");
|
91
94
|
}
|
92
95
|
#endif
|
@@ -145,17 +148,31 @@ static const char *pg_cstr_enc(VALUE str, int enc_idx){
|
|
145
148
|
* GC Mark function
|
146
149
|
*/
|
147
150
|
static void
|
148
|
-
pgconn_gc_mark(
|
151
|
+
pgconn_gc_mark( void *_this )
|
149
152
|
{
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
153
|
+
t_pg_connection *this = (t_pg_connection *)_this;
|
154
|
+
rb_gc_mark_movable( this->socket_io );
|
155
|
+
rb_gc_mark_movable( this->notice_receiver );
|
156
|
+
rb_gc_mark_movable( this->notice_processor );
|
157
|
+
rb_gc_mark_movable( this->type_map_for_queries );
|
158
|
+
rb_gc_mark_movable( this->type_map_for_results );
|
159
|
+
rb_gc_mark_movable( this->trace_stream );
|
160
|
+
rb_gc_mark_movable( this->encoder_for_put_copy_data );
|
161
|
+
rb_gc_mark_movable( this->decoder_for_get_copy_data );
|
162
|
+
}
|
163
|
+
|
164
|
+
static void
|
165
|
+
pgconn_gc_compact( void *_this )
|
166
|
+
{
|
167
|
+
t_pg_connection *this = (t_pg_connection *)_this;
|
168
|
+
pg_gc_location( this->socket_io );
|
169
|
+
pg_gc_location( this->notice_receiver );
|
170
|
+
pg_gc_location( this->notice_processor );
|
171
|
+
pg_gc_location( this->type_map_for_queries );
|
172
|
+
pg_gc_location( this->type_map_for_results );
|
173
|
+
pg_gc_location( this->trace_stream );
|
174
|
+
pg_gc_location( this->encoder_for_put_copy_data );
|
175
|
+
pg_gc_location( this->decoder_for_get_copy_data );
|
159
176
|
}
|
160
177
|
|
161
178
|
|
@@ -163,14 +180,45 @@ pgconn_gc_mark( t_pg_connection *this )
|
|
163
180
|
* GC Free function
|
164
181
|
*/
|
165
182
|
static void
|
166
|
-
pgconn_gc_free(
|
183
|
+
pgconn_gc_free( void *_this )
|
167
184
|
{
|
185
|
+
t_pg_connection *this = (t_pg_connection *)_this;
|
186
|
+
#if defined(_WIN32)
|
187
|
+
if ( RTEST(this->socket_io) ) {
|
188
|
+
if( rb_w32_unwrap_io_handle(this->ruby_sd) ){
|
189
|
+
rb_warn("pg: Could not unwrap win32 socket handle by garbage collector");
|
190
|
+
}
|
191
|
+
}
|
192
|
+
#endif
|
168
193
|
if (this->pgconn != NULL)
|
169
194
|
PQfinish( this->pgconn );
|
170
195
|
|
171
196
|
xfree(this);
|
172
197
|
}
|
173
198
|
|
199
|
+
/*
|
200
|
+
* Object Size function
|
201
|
+
*/
|
202
|
+
static size_t
|
203
|
+
pgconn_memsize( const void *_this )
|
204
|
+
{
|
205
|
+
const t_pg_connection *this = (const t_pg_connection *)_this;
|
206
|
+
return sizeof(*this);
|
207
|
+
}
|
208
|
+
|
209
|
+
static const rb_data_type_t pg_connection_type = {
|
210
|
+
"PG::Connection",
|
211
|
+
{
|
212
|
+
pgconn_gc_mark,
|
213
|
+
pgconn_gc_free,
|
214
|
+
pgconn_memsize,
|
215
|
+
pg_compact_callback(pgconn_gc_compact),
|
216
|
+
},
|
217
|
+
0,
|
218
|
+
0,
|
219
|
+
0,
|
220
|
+
};
|
221
|
+
|
174
222
|
|
175
223
|
/**************************************************************************
|
176
224
|
* Class Methods
|
@@ -186,7 +234,7 @@ static VALUE
|
|
186
234
|
pgconn_s_allocate( VALUE klass )
|
187
235
|
{
|
188
236
|
t_pg_connection *this;
|
189
|
-
VALUE self =
|
237
|
+
VALUE self = TypedData_Make_Struct( klass, t_pg_connection, &pg_connection_type, this );
|
190
238
|
|
191
239
|
this->pgconn = NULL;
|
192
240
|
this->socket_io = Qnil;
|
@@ -197,76 +245,17 @@ pgconn_s_allocate( VALUE klass )
|
|
197
245
|
this->encoder_for_put_copy_data = Qnil;
|
198
246
|
this->decoder_for_get_copy_data = Qnil;
|
199
247
|
this->trace_stream = Qnil;
|
200
|
-
this->external_encoding = Qnil;
|
201
|
-
this->guess_result_memsize = 1;
|
202
248
|
|
203
249
|
return self;
|
204
250
|
}
|
205
251
|
|
206
|
-
|
207
|
-
/*
|
208
|
-
* Document-method: new
|
209
|
-
*
|
210
|
-
* call-seq:
|
211
|
-
* PG::Connection.new -> conn
|
212
|
-
* PG::Connection.new(connection_hash) -> conn
|
213
|
-
* PG::Connection.new(connection_string) -> conn
|
214
|
-
* PG::Connection.new(host, port, options, tty, dbname, user, password) -> conn
|
215
|
-
*
|
216
|
-
* Create a connection to the specified server.
|
217
|
-
*
|
218
|
-
* [+host+]
|
219
|
-
* server hostname
|
220
|
-
* [+hostaddr+]
|
221
|
-
* server address (avoids hostname lookup, overrides +host+)
|
222
|
-
* [+port+]
|
223
|
-
* server port number
|
224
|
-
* [+dbname+]
|
225
|
-
* connecting database name
|
226
|
-
* [+user+]
|
227
|
-
* login user name
|
228
|
-
* [+password+]
|
229
|
-
* login password
|
230
|
-
* [+connect_timeout+]
|
231
|
-
* maximum time to wait for connection to succeed
|
232
|
-
* [+options+]
|
233
|
-
* backend options
|
234
|
-
* [+tty+]
|
235
|
-
* (ignored in newer versions of PostgreSQL)
|
236
|
-
* [+sslmode+]
|
237
|
-
* (disable|allow|prefer|require)
|
238
|
-
* [+krbsrvname+]
|
239
|
-
* kerberos service name
|
240
|
-
* [+gsslib+]
|
241
|
-
* GSS library to use for GSSAPI authentication
|
242
|
-
* [+service+]
|
243
|
-
* service name to use for additional parameters
|
244
|
-
*
|
245
|
-
* Examples:
|
246
|
-
*
|
247
|
-
* # Connect using all defaults
|
248
|
-
* PG::Connection.new
|
249
|
-
*
|
250
|
-
* # As a Hash
|
251
|
-
* PG::Connection.new( :dbname => 'test', :port => 5432 )
|
252
|
-
*
|
253
|
-
* # As a String
|
254
|
-
* PG::Connection.new( "dbname=test port=5432" )
|
255
|
-
*
|
256
|
-
* # As an Array
|
257
|
-
* PG::Connection.new( nil, 5432, nil, nil, 'test', nil, nil )
|
258
|
-
*
|
259
|
-
* If the Ruby default internal encoding is set (i.e., Encoding.default_internal != nil), the
|
260
|
-
* connection will have its +client_encoding+ set accordingly.
|
261
|
-
*
|
262
|
-
* Raises a PG::Error if the connection fails.
|
263
|
-
*/
|
264
252
|
static VALUE
|
265
|
-
|
253
|
+
pgconn_s_sync_connect(int argc, VALUE *argv, VALUE klass)
|
266
254
|
{
|
267
255
|
t_pg_connection *this;
|
268
256
|
VALUE conninfo;
|
269
257
|
VALUE error;
|
258
|
+
VALUE self = pgconn_s_allocate( klass );
|
270
259
|
|
271
260
|
this = pg_get_connection( self );
|
272
261
|
conninfo = rb_funcall2( rb_cPGconn, rb_intern("parse_connect_args"), argc, argv );
|
@@ -295,14 +284,16 @@ pgconn_init(int argc, VALUE *argv, VALUE self)
|
|
295
284
|
* PG::Connection.connect_start(connection_string) -> conn
|
296
285
|
* PG::Connection.connect_start(host, port, options, tty, dbname, login, password) -> conn
|
297
286
|
*
|
298
|
-
* This is an asynchronous version of PG::Connection.
|
287
|
+
* This is an asynchronous version of PG::Connection.new.
|
299
288
|
*
|
300
289
|
* Use #connect_poll to poll the status of the connection.
|
301
290
|
*
|
302
291
|
* NOTE: this does *not* set the connection's +client_encoding+ for you if
|
303
|
-
* Encoding.default_internal is set. To set it after the connection is established,
|
292
|
+
* +Encoding.default_internal+ is set. To set it after the connection is established,
|
304
293
|
* call #internal_encoding=. You can also set it automatically by setting
|
305
|
-
* ENV['PGCLIENTENCODING']
|
294
|
+
* <code>ENV['PGCLIENTENCODING']</code>, or include the 'options' connection parameter.
|
295
|
+
*
|
296
|
+
* See also the 'sample' directory of this gem and the corresponding {libpq functions}[https://www.postgresql.org/docs/current/libpq-connect.html#LIBPQ-PQCONNECTSTARTPARAMS].
|
306
297
|
*
|
307
298
|
*/
|
308
299
|
static VALUE
|
@@ -337,34 +328,14 @@ pgconn_s_connect_start( int argc, VALUE *argv, VALUE klass )
|
|
337
328
|
return rb_conn;
|
338
329
|
}
|
339
330
|
|
340
|
-
/*
|
341
|
-
* call-seq:
|
342
|
-
* PG::Connection.ping(connection_hash) -> Integer
|
343
|
-
* PG::Connection.ping(connection_string) -> Integer
|
344
|
-
* PG::Connection.ping(host, port, options, tty, dbname, login, password) -> Integer
|
345
|
-
*
|
346
|
-
* Check server status.
|
347
|
-
*
|
348
|
-
* Returns one of:
|
349
|
-
* [+PQPING_OK+]
|
350
|
-
* server is accepting connections
|
351
|
-
* [+PQPING_REJECT+]
|
352
|
-
* server is alive but rejecting connections
|
353
|
-
* [+PQPING_NO_RESPONSE+]
|
354
|
-
* could not establish connection
|
355
|
-
* [+PQPING_NO_ATTEMPT+]
|
356
|
-
* connection not attempted (bad params)
|
357
|
-
*
|
358
|
-
* Available since PostgreSQL-9.1
|
359
|
-
*/
|
360
331
|
static VALUE
|
361
|
-
|
332
|
+
pgconn_s_sync_ping( int argc, VALUE *argv, VALUE klass )
|
362
333
|
{
|
363
334
|
PGPing ping;
|
364
335
|
VALUE conninfo;
|
365
336
|
|
366
337
|
conninfo = rb_funcall2( klass, rb_intern("parse_connect_args"), argc, argv );
|
367
|
-
ping =
|
338
|
+
ping = gvl_PQping( StringValueCStr(conninfo) );
|
368
339
|
|
369
340
|
return INT2FIX((int)ping);
|
370
341
|
}
|
@@ -407,29 +378,8 @@ pgconn_s_conndefaults(VALUE self)
|
|
407
378
|
|
408
379
|
|
409
380
|
#ifdef HAVE_PQENCRYPTPASSWORDCONN
|
410
|
-
/*
|
411
|
-
* call-seq:
|
412
|
-
* conn.encrypt_password( password, username, algorithm=nil ) -> String
|
413
|
-
*
|
414
|
-
* This function is intended to be used by client applications that wish to send commands like <tt>ALTER USER joe PASSWORD 'pwd'</tt>.
|
415
|
-
* 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.
|
416
|
-
* Instead, use this function to convert the password to encrypted form before it is sent.
|
417
|
-
*
|
418
|
-
* The +password+ and +username+ arguments are the cleartext password, and the SQL name of the user it is for.
|
419
|
-
* +algorithm+ specifies the encryption algorithm to use to encrypt the password.
|
420
|
-
* 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).
|
421
|
-
* Note that support for +scram-sha-256+ was introduced in PostgreSQL version 10, and will not work correctly with older server versions.
|
422
|
-
* If algorithm is omitted or +nil+, this function will query the server for the current value of the +password_encryption+ setting.
|
423
|
-
* That can block, and will fail if the current transaction is aborted, or if the connection is busy executing another query.
|
424
|
-
* 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.
|
425
|
-
*
|
426
|
-
* Return value is the encrypted password.
|
427
|
-
* The caller can assume the string doesn't contain any special characters that would require escaping.
|
428
|
-
*
|
429
|
-
* Available since PostgreSQL-10
|
430
|
-
*/
|
431
381
|
static VALUE
|
432
|
-
|
382
|
+
pgconn_sync_encrypt_password(int argc, VALUE *argv, VALUE self)
|
433
383
|
{
|
434
384
|
char *encrypted = NULL;
|
435
385
|
VALUE rval = Qnil;
|
@@ -445,10 +395,6 @@ pgconn_encrypt_password(int argc, VALUE *argv, VALUE self)
|
|
445
395
|
if ( encrypted ) {
|
446
396
|
rval = rb_str_new2( encrypted );
|
447
397
|
PQfreemem( encrypted );
|
448
|
-
|
449
|
-
OBJ_INFECT( rval, password );
|
450
|
-
OBJ_INFECT( rval, username );
|
451
|
-
OBJ_INFECT( rval, algorithm );
|
452
398
|
} else {
|
453
399
|
rb_raise(rb_ePGerror, "%s", PQerrorMessage(conn));
|
454
400
|
}
|
@@ -481,9 +427,6 @@ pgconn_s_encrypt_password(VALUE self, VALUE password, VALUE username)
|
|
481
427
|
rval = rb_str_new2( encrypted );
|
482
428
|
PQfreemem( encrypted );
|
483
429
|
|
484
|
-
OBJ_INFECT( rval, password );
|
485
|
-
OBJ_INFECT( rval, username );
|
486
|
-
|
487
430
|
return rval;
|
488
431
|
}
|
489
432
|
|
@@ -531,6 +474,11 @@ pgconn_connect_poll(VALUE self)
|
|
531
474
|
{
|
532
475
|
PostgresPollingStatusType status;
|
533
476
|
status = gvl_PQconnectPoll(pg_get_pgconn(self));
|
477
|
+
|
478
|
+
if ( status == PGRES_POLLING_FAILED ) {
|
479
|
+
pgconn_close_socket_io(self);
|
480
|
+
}
|
481
|
+
|
534
482
|
return INT2FIX((int)status);
|
535
483
|
}
|
536
484
|
|
@@ -567,15 +515,8 @@ pgconn_finished_p( VALUE self )
|
|
567
515
|
}
|
568
516
|
|
569
517
|
|
570
|
-
/*
|
571
|
-
* call-seq:
|
572
|
-
* conn.reset()
|
573
|
-
*
|
574
|
-
* Resets the backend connection. This method closes the
|
575
|
-
* backend connection and tries to re-connect.
|
576
|
-
*/
|
577
518
|
static VALUE
|
578
|
-
|
519
|
+
pgconn_sync_reset( VALUE self )
|
579
520
|
{
|
580
521
|
pgconn_close_socket_io( self );
|
581
522
|
gvl_PQreset( pg_get_pgconn(self) );
|
@@ -614,6 +555,11 @@ pgconn_reset_poll(VALUE self)
|
|
614
555
|
{
|
615
556
|
PostgresPollingStatusType status;
|
616
557
|
status = gvl_PQresetPoll(pg_get_pgconn(self));
|
558
|
+
|
559
|
+
if ( status == PGRES_POLLING_FAILED ) {
|
560
|
+
pgconn_close_socket_io(self);
|
561
|
+
}
|
562
|
+
|
617
563
|
return INT2FIX((int)status);
|
618
564
|
}
|
619
565
|
|
@@ -629,7 +575,7 @@ pgconn_db(VALUE self)
|
|
629
575
|
{
|
630
576
|
char *db = PQdb(pg_get_pgconn(self));
|
631
577
|
if (!db) return Qnil;
|
632
|
-
return
|
578
|
+
return rb_str_new2(db);
|
633
579
|
}
|
634
580
|
|
635
581
|
/*
|
@@ -643,7 +589,7 @@ pgconn_user(VALUE self)
|
|
643
589
|
{
|
644
590
|
char *user = PQuser(pg_get_pgconn(self));
|
645
591
|
if (!user) return Qnil;
|
646
|
-
return
|
592
|
+
return rb_str_new2(user);
|
647
593
|
}
|
648
594
|
|
649
595
|
/*
|
@@ -657,7 +603,7 @@ pgconn_pass(VALUE self)
|
|
657
603
|
{
|
658
604
|
char *user = PQpass(pg_get_pgconn(self));
|
659
605
|
if (!user) return Qnil;
|
660
|
-
return
|
606
|
+
return rb_str_new2(user);
|
661
607
|
}
|
662
608
|
|
663
609
|
/*
|
@@ -671,7 +617,7 @@ pgconn_host(VALUE self)
|
|
671
617
|
{
|
672
618
|
char *host = PQhost(pg_get_pgconn(self));
|
673
619
|
if (!host) return Qnil;
|
674
|
-
return
|
620
|
+
return rb_str_new2(host);
|
675
621
|
}
|
676
622
|
|
677
623
|
/*
|
@@ -684,21 +630,19 @@ static VALUE
|
|
684
630
|
pgconn_port(VALUE self)
|
685
631
|
{
|
686
632
|
char* port = PQport(pg_get_pgconn(self));
|
687
|
-
return INT2NUM(
|
633
|
+
return INT2NUM(atoi(port));
|
688
634
|
}
|
689
635
|
|
690
636
|
/*
|
691
637
|
* call-seq:
|
692
638
|
* conn.tty()
|
693
639
|
*
|
694
|
-
*
|
640
|
+
* Obsolete function.
|
695
641
|
*/
|
696
642
|
static VALUE
|
697
643
|
pgconn_tty(VALUE self)
|
698
644
|
{
|
699
|
-
|
700
|
-
if (!tty) return Qnil;
|
701
|
-
return rb_tainted_str_new2(tty);
|
645
|
+
return rb_str_new2("");
|
702
646
|
}
|
703
647
|
|
704
648
|
/*
|
@@ -712,11 +656,10 @@ pgconn_options(VALUE self)
|
|
712
656
|
{
|
713
657
|
char *options = PQoptions(pg_get_pgconn(self));
|
714
658
|
if (!options) return Qnil;
|
715
|
-
return
|
659
|
+
return rb_str_new2(options);
|
716
660
|
}
|
717
661
|
|
718
662
|
|
719
|
-
#ifdef HAVE_PQCONNINFO
|
720
663
|
/*
|
721
664
|
* call-seq:
|
722
665
|
* conn.conninfo -> hash
|
@@ -736,14 +679,17 @@ pgconn_conninfo( VALUE self )
|
|
736
679
|
|
737
680
|
return array;
|
738
681
|
}
|
739
|
-
#endif
|
740
682
|
|
741
683
|
|
742
684
|
/*
|
743
685
|
* call-seq:
|
744
686
|
* conn.status()
|
745
687
|
*
|
746
|
-
* Returns status of connection
|
688
|
+
* Returns the status of the connection, which is one:
|
689
|
+
* PG::Constants::CONNECTION_OK
|
690
|
+
* PG::Constants::CONNECTION_BAD
|
691
|
+
*
|
692
|
+
* ... and other constants of kind PG::Constants::CONNECTION_*
|
747
693
|
*/
|
748
694
|
static VALUE
|
749
695
|
pgconn_status(VALUE self)
|
@@ -793,7 +739,7 @@ pgconn_parameter_status(VALUE self, VALUE param_name)
|
|
793
739
|
if(ret == NULL)
|
794
740
|
return Qnil;
|
795
741
|
else
|
796
|
-
return
|
742
|
+
return rb_str_new2(ret);
|
797
743
|
}
|
798
744
|
|
799
745
|
/*
|
@@ -831,14 +777,17 @@ pgconn_server_version(VALUE self)
|
|
831
777
|
* call-seq:
|
832
778
|
* conn.error_message -> String
|
833
779
|
*
|
834
|
-
* Returns the error message
|
780
|
+
* Returns the error message most recently generated by an operation on the connection.
|
781
|
+
*
|
782
|
+
* Nearly all libpq functions will set a message for conn.error_message if they fail.
|
783
|
+
* Note that by libpq convention, a nonempty error_message result can consist of multiple lines, and will include a trailing newline.
|
835
784
|
*/
|
836
785
|
static VALUE
|
837
786
|
pgconn_error_message(VALUE self)
|
838
787
|
{
|
839
788
|
char *error = PQerrorMessage(pg_get_pgconn(self));
|
840
789
|
if (!error) return Qnil;
|
841
|
-
return
|
790
|
+
return rb_str_new2(error);
|
842
791
|
}
|
843
792
|
|
844
793
|
/*
|
@@ -862,6 +811,8 @@ static VALUE
|
|
862
811
|
pgconn_socket(VALUE self)
|
863
812
|
{
|
864
813
|
int sd;
|
814
|
+
pg_deprecated(4, ("conn.socket is deprecated and should be replaced by conn.socket_io"));
|
815
|
+
|
865
816
|
if( (sd = PQsocket(pg_get_pgconn(self))) < 0)
|
866
817
|
rb_raise(rb_eConnectionBad, "PQsocket() can't get socket descriptor");
|
867
818
|
return INT2NUM(sd);
|
@@ -884,8 +835,8 @@ pgconn_socket_io(VALUE self)
|
|
884
835
|
{
|
885
836
|
int sd;
|
886
837
|
int ruby_sd;
|
887
|
-
ID id_autoclose = rb_intern("autoclose=");
|
888
838
|
t_pg_connection *this = pg_get_connection_safe( self );
|
839
|
+
VALUE cSocket;
|
889
840
|
VALUE socket_io = this->socket_io;
|
890
841
|
|
891
842
|
if ( !RTEST(socket_io) ) {
|
@@ -894,14 +845,19 @@ pgconn_socket_io(VALUE self)
|
|
894
845
|
|
895
846
|
#ifdef _WIN32
|
896
847
|
ruby_sd = rb_w32_wrap_io_handle((HANDLE)(intptr_t)sd, O_RDWR|O_BINARY|O_NOINHERIT);
|
848
|
+
if( ruby_sd == -1 ){
|
849
|
+
rb_raise(rb_eConnectionBad, "Could not wrap win32 socket handle");
|
850
|
+
}
|
851
|
+
this->ruby_sd = ruby_sd;
|
897
852
|
#else
|
898
853
|
ruby_sd = sd;
|
899
854
|
#endif
|
900
855
|
|
901
|
-
|
856
|
+
cSocket = rb_const_get(rb_cObject, rb_intern("BasicSocket"));
|
857
|
+
socket_io = rb_funcall( cSocket, rb_intern("for_fd"), 1, INT2NUM(ruby_sd));
|
902
858
|
|
903
859
|
/* Disable autoclose feature */
|
904
|
-
rb_funcall( socket_io,
|
860
|
+
rb_funcall( socket_io, s_id_autoclose_set, 1, Qfalse );
|
905
861
|
|
906
862
|
this->socket_io = socket_io;
|
907
863
|
}
|
@@ -923,6 +879,51 @@ pgconn_backend_pid(VALUE self)
|
|
923
879
|
return INT2NUM(PQbackendPID(pg_get_pgconn(self)));
|
924
880
|
}
|
925
881
|
|
882
|
+
typedef struct
|
883
|
+
{
|
884
|
+
struct sockaddr_storage addr;
|
885
|
+
socklen_t salen;
|
886
|
+
} SockAddr;
|
887
|
+
|
888
|
+
/* Copy of struct pg_cancel from libpq-int.h
|
889
|
+
*
|
890
|
+
* See https://github.com/postgres/postgres/blame/master/src/interfaces/libpq/libpq-int.h#L577-L586
|
891
|
+
*/
|
892
|
+
struct pg_cancel
|
893
|
+
{
|
894
|
+
SockAddr raddr; /* Remote address */
|
895
|
+
int be_pid; /* PID of backend --- needed for cancels */
|
896
|
+
int be_key; /* key of backend --- needed for cancels */
|
897
|
+
};
|
898
|
+
|
899
|
+
/*
|
900
|
+
* call-seq:
|
901
|
+
* conn.backend_key() -> Integer
|
902
|
+
*
|
903
|
+
* Returns the key of the backend server process for this connection.
|
904
|
+
* This key can be used to cancel queries on the server.
|
905
|
+
*/
|
906
|
+
static VALUE
|
907
|
+
pgconn_backend_key(VALUE self)
|
908
|
+
{
|
909
|
+
int be_key;
|
910
|
+
struct pg_cancel *cancel;
|
911
|
+
PGconn *conn = pg_get_pgconn(self);
|
912
|
+
|
913
|
+
cancel = (struct pg_cancel*)PQgetCancel(conn);
|
914
|
+
if(cancel == NULL)
|
915
|
+
rb_raise(rb_ePGerror,"Invalid connection!");
|
916
|
+
|
917
|
+
if( cancel->be_pid != PQbackendPID(conn) )
|
918
|
+
rb_raise(rb_ePGerror,"Unexpected binary struct layout - please file a bug report at ruby-pg!");
|
919
|
+
|
920
|
+
be_key = cancel->be_key;
|
921
|
+
|
922
|
+
PQfreeCancel(cancel);
|
923
|
+
|
924
|
+
return INT2NUM(be_key);
|
925
|
+
}
|
926
|
+
|
926
927
|
/*
|
927
928
|
* call-seq:
|
928
929
|
* conn.connection_needs_password() -> Boolean
|
@@ -953,36 +954,27 @@ pgconn_connection_used_password(VALUE self)
|
|
953
954
|
/* :TODO: get_ssl */
|
954
955
|
|
955
956
|
|
956
|
-
static VALUE
|
957
|
+
static VALUE pgconn_sync_exec_params( int, VALUE *, VALUE );
|
957
958
|
|
958
959
|
/*
|
959
960
|
* call-seq:
|
960
|
-
* conn.
|
961
|
-
* conn.
|
962
|
-
*
|
963
|
-
* Sends SQL query request specified by _sql_ to PostgreSQL.
|
964
|
-
* Returns a PG::Result instance on success.
|
965
|
-
* On failure, it raises a PG::Error.
|
961
|
+
* conn.sync_exec(sql) -> PG::Result
|
962
|
+
* conn.sync_exec(sql) {|pg_result| block }
|
966
963
|
*
|
967
|
-
*
|
968
|
-
*
|
969
|
-
* argument placeholders are used.
|
964
|
+
* This function has the same behavior as #async_exec, but is implemented using the synchronous command processing API of libpq.
|
965
|
+
* It's not recommended to use explicit sync or async variants but #exec instead, unless you have a good reason to do so.
|
970
966
|
*
|
971
|
-
*
|
972
|
-
*
|
973
|
-
* In this instance, <code>conn.exec</code> returns the value of the block.
|
967
|
+
* Both #sync_exec and #async_exec release the GVL while waiting for server response, so that concurrent threads will get executed.
|
968
|
+
* However #async_exec has two advantages:
|
974
969
|
*
|
975
|
-
* #
|
976
|
-
*
|
977
|
-
*
|
978
|
-
* the query is finished. This is most notably visible by a delayed reaction to Control+C.
|
979
|
-
* Both methods ensure that other threads can process while waiting for the server to
|
980
|
-
* complete the request.
|
970
|
+
* 1. #async_exec can be aborted by signals (like Ctrl-C), while #exec blocks signal processing until the query is answered.
|
971
|
+
* 2. Ruby VM gets notified about IO blocked operations and can pass them through <tt>Fiber.scheduler</tt>.
|
972
|
+
* So only <tt>async_*</tt> methods are compatible to event based schedulers like the async gem.
|
981
973
|
*/
|
982
974
|
static VALUE
|
983
|
-
|
975
|
+
pgconn_sync_exec(int argc, VALUE *argv, VALUE self)
|
984
976
|
{
|
985
|
-
|
977
|
+
t_pg_connection *this = pg_get_connection_safe( self );
|
986
978
|
PGresult *result = NULL;
|
987
979
|
VALUE rb_pgresult;
|
988
980
|
|
@@ -990,7 +982,7 @@ pgconn_exec(int argc, VALUE *argv, VALUE self)
|
|
990
982
|
if ( argc == 1 || (argc >= 2 && argc <= 4 && NIL_P(argv[1]) )) {
|
991
983
|
VALUE query_str = argv[0];
|
992
984
|
|
993
|
-
result = gvl_PQexec(
|
985
|
+
result = gvl_PQexec(this->pgconn, pg_cstr_enc(query_str, this->enc_idx));
|
994
986
|
rb_pgresult = pg_new_result(result, self);
|
995
987
|
pg_result_check(rb_pgresult);
|
996
988
|
if (rb_block_given_p()) {
|
@@ -1001,7 +993,7 @@ pgconn_exec(int argc, VALUE *argv, VALUE self)
|
|
1001
993
|
pg_deprecated(0, ("forwarding exec to exec_params is deprecated"));
|
1002
994
|
|
1003
995
|
/* Otherwise, just call #exec_params instead for backward-compatibility */
|
1004
|
-
return
|
996
|
+
return pgconn_sync_exec_params( argc, argv, self );
|
1005
997
|
|
1006
998
|
}
|
1007
999
|
|
@@ -1033,7 +1025,7 @@ struct query_params_data {
|
|
1033
1025
|
* Filled by alloc_query_params()
|
1034
1026
|
*/
|
1035
1027
|
|
1036
|
-
/* Wraps the pointer of allocated memory, if function parameters
|
1028
|
+
/* Wraps the pointer of allocated memory, if function parameters don't
|
1037
1029
|
* fit in the memory_pool below.
|
1038
1030
|
*/
|
1039
1031
|
VALUE heap_pool;
|
@@ -1051,7 +1043,7 @@ struct query_params_data {
|
|
1051
1043
|
Oid *types;
|
1052
1044
|
|
1053
1045
|
/* This array takes the string values for the timeframe of the query,
|
1054
|
-
* if param value
|
1046
|
+
* if param value conversion is required
|
1055
1047
|
*/
|
1056
1048
|
VALUE gc_array;
|
1057
1049
|
|
@@ -1065,8 +1057,9 @@ struct query_params_data {
|
|
1065
1057
|
};
|
1066
1058
|
|
1067
1059
|
static void
|
1068
|
-
free_typecast_heap_chain(
|
1060
|
+
free_typecast_heap_chain(void *_chain_entry)
|
1069
1061
|
{
|
1062
|
+
struct linked_typecast_data *chain_entry = (struct linked_typecast_data *)_chain_entry;
|
1070
1063
|
while(chain_entry){
|
1071
1064
|
struct linked_typecast_data *next = chain_entry->next;
|
1072
1065
|
xfree(chain_entry);
|
@@ -1074,6 +1067,18 @@ free_typecast_heap_chain(struct linked_typecast_data *chain_entry)
|
|
1074
1067
|
}
|
1075
1068
|
}
|
1076
1069
|
|
1070
|
+
static const rb_data_type_t pg_typecast_buffer_type = {
|
1071
|
+
"PG::Connection typecast buffer chain",
|
1072
|
+
{
|
1073
|
+
(RUBY_DATA_FUNC) NULL,
|
1074
|
+
free_typecast_heap_chain,
|
1075
|
+
(size_t (*)(const void *))NULL,
|
1076
|
+
},
|
1077
|
+
0,
|
1078
|
+
0,
|
1079
|
+
RUBY_TYPED_FREE_IMMEDIATELY,
|
1080
|
+
};
|
1081
|
+
|
1077
1082
|
static char *
|
1078
1083
|
alloc_typecast_buf( VALUE *typecast_heap_chain, int len )
|
1079
1084
|
{
|
@@ -1084,17 +1089,28 @@ alloc_typecast_buf( VALUE *typecast_heap_chain, int len )
|
|
1084
1089
|
/* Did we already wrap a memory chain per T_DATA object? */
|
1085
1090
|
if( NIL_P( *typecast_heap_chain ) ){
|
1086
1091
|
/* Leave free'ing of the buffer chain to the GC, when paramsData has left the stack */
|
1087
|
-
*typecast_heap_chain =
|
1092
|
+
*typecast_heap_chain = TypedData_Wrap_Struct( rb_cObject, &pg_typecast_buffer_type, allocated );
|
1088
1093
|
allocated->next = NULL;
|
1089
1094
|
} else {
|
1090
1095
|
/* Append to the chain */
|
1091
|
-
allocated->next =
|
1092
|
-
|
1096
|
+
allocated->next = RTYPEDDATA_DATA( *typecast_heap_chain );
|
1097
|
+
RTYPEDDATA_DATA( *typecast_heap_chain ) = allocated;
|
1093
1098
|
}
|
1094
1099
|
|
1095
1100
|
return &allocated->data[0];
|
1096
1101
|
}
|
1097
1102
|
|
1103
|
+
static const rb_data_type_t pg_query_heap_pool_type = {
|
1104
|
+
"PG::Connection query heap pool",
|
1105
|
+
{
|
1106
|
+
(RUBY_DATA_FUNC) NULL,
|
1107
|
+
RUBY_TYPED_DEFAULT_FREE,
|
1108
|
+
(size_t (*)(const void *))NULL,
|
1109
|
+
},
|
1110
|
+
0,
|
1111
|
+
0,
|
1112
|
+
RUBY_TYPED_FREE_IMMEDIATELY,
|
1113
|
+
};
|
1098
1114
|
|
1099
1115
|
static int
|
1100
1116
|
alloc_query_params(struct query_params_data *paramsData)
|
@@ -1109,7 +1125,7 @@ alloc_query_params(struct query_params_data *paramsData)
|
|
1109
1125
|
|
1110
1126
|
Check_Type(paramsData->params, T_ARRAY);
|
1111
1127
|
|
1112
|
-
p_typemap =
|
1128
|
+
p_typemap = RTYPEDDATA_DATA( paramsData->typemap );
|
1113
1129
|
p_typemap->funcs.fit_to_query( paramsData->typemap, paramsData->params );
|
1114
1130
|
|
1115
1131
|
paramsData->heap_pool = Qnil;
|
@@ -1128,7 +1144,7 @@ alloc_query_params(struct query_params_data *paramsData)
|
|
1128
1144
|
/* Allocate one combined memory pool for all possible function parameters */
|
1129
1145
|
memory_pool = (char*)xmalloc( required_pool_size );
|
1130
1146
|
/* Leave free'ing of the buffer to the GC, when paramsData has left the stack */
|
1131
|
-
paramsData->heap_pool =
|
1147
|
+
paramsData->heap_pool = TypedData_Wrap_Struct( rb_cObject, &pg_query_heap_pool_type, memory_pool );
|
1132
1148
|
required_pool_size = 0;
|
1133
1149
|
}else{
|
1134
1150
|
/* Use stack memory for function parameters */
|
@@ -1241,68 +1257,33 @@ pgconn_query_assign_typemap( VALUE self, struct query_params_data *paramsData )
|
|
1241
1257
|
/* Use default typemap for queries. It's type is checked when assigned. */
|
1242
1258
|
paramsData->typemap = pg_get_connection(self)->type_map_for_queries;
|
1243
1259
|
}else{
|
1260
|
+
t_typemap *tm;
|
1261
|
+
UNUSED(tm);
|
1262
|
+
|
1244
1263
|
/* Check type of method param */
|
1245
|
-
|
1246
|
-
rb_raise( rb_eTypeError, "wrong argument type %s (expected kind of PG::TypeMap)",
|
1247
|
-
rb_obj_classname( paramsData->typemap ) );
|
1248
|
-
}
|
1249
|
-
Check_Type( paramsData->typemap, T_DATA );
|
1264
|
+
TypedData_Get_Struct(paramsData->typemap, t_typemap, &pg_typemap_type, tm);
|
1250
1265
|
}
|
1251
1266
|
}
|
1252
1267
|
|
1253
1268
|
/*
|
1254
1269
|
* call-seq:
|
1255
|
-
* conn.
|
1256
|
-
* conn.
|
1257
|
-
*
|
1258
|
-
* Sends SQL query request specified by +sql+ to PostgreSQL using placeholders
|
1259
|
-
* for parameters.
|
1260
|
-
*
|
1261
|
-
* Returns a PG::Result instance on success. On failure, it raises a PG::Error.
|
1262
|
-
*
|
1263
|
-
* +params+ is an array of the bind parameters for the SQL query.
|
1264
|
-
* Each element of the +params+ array may be either:
|
1265
|
-
* a hash of the form:
|
1266
|
-
* {:value => String (value of bind parameter)
|
1267
|
-
* :type => Integer (oid of type of bind parameter)
|
1268
|
-
* :format => Integer (0 for text, 1 for binary)
|
1269
|
-
* }
|
1270
|
-
* or, it may be a String. If it is a string, that is equivalent to the hash:
|
1271
|
-
* { :value => <string value>, :type => 0, :format => 0 }
|
1272
|
-
*
|
1273
|
-
* PostgreSQL bind parameters are represented as $1, $1, $2, etc.,
|
1274
|
-
* inside the SQL query. The 0th element of the +params+ array is bound
|
1275
|
-
* to $1, the 1st element is bound to $2, etc. +nil+ is treated as +NULL+.
|
1276
|
-
*
|
1277
|
-
* If the types are not specified, they will be inferred by PostgreSQL.
|
1278
|
-
* Instead of specifying type oids, it's recommended to simply add
|
1279
|
-
* explicit casts in the query to ensure that the right type is used.
|
1280
|
-
*
|
1281
|
-
* For example: "SELECT $1::int"
|
1282
|
-
*
|
1283
|
-
* The optional +result_format+ should be 0 for text results, 1
|
1284
|
-
* for binary.
|
1270
|
+
* conn.sync_exec_params(sql, params[, result_format[, type_map]] ) -> PG::Result
|
1271
|
+
* conn.sync_exec_params(sql, params[, result_format[, type_map]] ) {|pg_result| block }
|
1285
1272
|
*
|
1286
|
-
*
|
1287
|
-
*
|
1288
|
-
*
|
1289
|
-
* the format and oid of a given bind parameter are retrieved from the encoder
|
1290
|
-
* instead out of the hash form described above.
|
1291
|
-
*
|
1292
|
-
* If the optional code block is given, it will be passed <i>result</i> as an argument,
|
1293
|
-
* and the PG::Result object will automatically be cleared when the block terminates.
|
1294
|
-
* In this instance, <code>conn.exec</code> returns the value of the block.
|
1273
|
+
* This function has the same behavior as #async_exec_params, but is implemented using the synchronous command processing API of libpq.
|
1274
|
+
* See #async_exec for the differences between the two API variants.
|
1275
|
+
* It's not recommended to use explicit sync or async variants but #exec_params instead, unless you have a good reason to do so.
|
1295
1276
|
*/
|
1296
1277
|
static VALUE
|
1297
|
-
|
1278
|
+
pgconn_sync_exec_params( int argc, VALUE *argv, VALUE self )
|
1298
1279
|
{
|
1299
|
-
|
1280
|
+
t_pg_connection *this = pg_get_connection_safe( self );
|
1300
1281
|
PGresult *result = NULL;
|
1301
1282
|
VALUE rb_pgresult;
|
1302
1283
|
VALUE command, in_res_fmt;
|
1303
1284
|
int nParams;
|
1304
1285
|
int resultFormat;
|
1305
|
-
struct query_params_data paramsData = {
|
1286
|
+
struct query_params_data paramsData = { this->enc_idx };
|
1306
1287
|
|
1307
1288
|
/* For compatibility we accept 1 to 4 parameters */
|
1308
1289
|
rb_scan_args(argc, argv, "13", &command, ¶msData.params, &in_res_fmt, ¶msData.typemap);
|
@@ -1314,14 +1295,14 @@ pgconn_exec_params( int argc, VALUE *argv, VALUE self )
|
|
1314
1295
|
*/
|
1315
1296
|
if ( NIL_P(paramsData.params) ) {
|
1316
1297
|
pg_deprecated(1, ("forwarding exec_params to exec is deprecated"));
|
1317
|
-
return
|
1298
|
+
return pgconn_sync_exec( 1, argv, self );
|
1318
1299
|
}
|
1319
1300
|
pgconn_query_assign_typemap( self, ¶msData );
|
1320
1301
|
|
1321
1302
|
resultFormat = NIL_P(in_res_fmt) ? 0 : NUM2INT(in_res_fmt);
|
1322
1303
|
nParams = alloc_query_params( ¶msData );
|
1323
1304
|
|
1324
|
-
result = gvl_PQexecParams(
|
1305
|
+
result = gvl_PQexecParams(this->pgconn, pg_cstr_enc(command, paramsData.enc_idx), nParams, paramsData.types,
|
1325
1306
|
(const char * const *)paramsData.values, paramsData.lengths, paramsData.formats, resultFormat);
|
1326
1307
|
|
1327
1308
|
free_query_params( ¶msData );
|
@@ -1338,28 +1319,16 @@ pgconn_exec_params( int argc, VALUE *argv, VALUE self )
|
|
1338
1319
|
|
1339
1320
|
/*
|
1340
1321
|
* call-seq:
|
1341
|
-
* conn.
|
1342
|
-
*
|
1343
|
-
* Prepares statement _sql_ with name _name_ to be executed later.
|
1344
|
-
* Returns a PG::Result instance on success.
|
1345
|
-
* On failure, it raises a PG::Error.
|
1322
|
+
* conn.sync_prepare(stmt_name, sql [, param_types ] ) -> PG::Result
|
1346
1323
|
*
|
1347
|
-
*
|
1348
|
-
*
|
1349
|
-
*
|
1350
|
-
* If the types are not specified, they will be inferred by PostgreSQL.
|
1351
|
-
* Instead of specifying type oids, it's recommended to simply add
|
1352
|
-
* explicit casts in the query to ensure that the right type is used.
|
1353
|
-
*
|
1354
|
-
* For example: "SELECT $1::int"
|
1355
|
-
*
|
1356
|
-
* PostgreSQL bind parameters are represented as $1, $1, $2, etc.,
|
1357
|
-
* inside the SQL query.
|
1324
|
+
* This function has the same behavior as #async_prepare, but is implemented using the synchronous command processing API of libpq.
|
1325
|
+
* See #async_exec for the differences between the two API variants.
|
1326
|
+
* It's not recommended to use explicit sync or async variants but #prepare instead, unless you have a good reason to do so.
|
1358
1327
|
*/
|
1359
1328
|
static VALUE
|
1360
|
-
|
1329
|
+
pgconn_sync_prepare(int argc, VALUE *argv, VALUE self)
|
1361
1330
|
{
|
1362
|
-
|
1331
|
+
t_pg_connection *this = pg_get_connection_safe( self );
|
1363
1332
|
PGresult *result = NULL;
|
1364
1333
|
VALUE rb_pgresult;
|
1365
1334
|
VALUE name, command, in_paramtypes;
|
@@ -1369,7 +1338,7 @@ pgconn_prepare(int argc, VALUE *argv, VALUE self)
|
|
1369
1338
|
Oid *paramTypes = NULL;
|
1370
1339
|
const char *name_cstr;
|
1371
1340
|
const char *command_cstr;
|
1372
|
-
int enc_idx =
|
1341
|
+
int enc_idx = this->enc_idx;
|
1373
1342
|
|
1374
1343
|
rb_scan_args(argc, argv, "21", &name, &command, &in_paramtypes);
|
1375
1344
|
name_cstr = pg_cstr_enc(name, enc_idx);
|
@@ -1387,7 +1356,7 @@ pgconn_prepare(int argc, VALUE *argv, VALUE self)
|
|
1387
1356
|
paramTypes[i] = NUM2UINT(param);
|
1388
1357
|
}
|
1389
1358
|
}
|
1390
|
-
result = gvl_PQprepare(
|
1359
|
+
result = gvl_PQprepare(this->pgconn, name_cstr, command_cstr, nParams, paramTypes);
|
1391
1360
|
|
1392
1361
|
xfree(paramTypes);
|
1393
1362
|
|
@@ -1398,49 +1367,23 @@ pgconn_prepare(int argc, VALUE *argv, VALUE self)
|
|
1398
1367
|
|
1399
1368
|
/*
|
1400
1369
|
* call-seq:
|
1401
|
-
* conn.
|
1402
|
-
* conn.
|
1403
|
-
*
|
1404
|
-
* Execute prepared named statement specified by _statement_name_.
|
1405
|
-
* Returns a PG::Result instance on success.
|
1406
|
-
* On failure, it raises a PG::Error.
|
1407
|
-
*
|
1408
|
-
* +params+ is an array of the optional bind parameters for the
|
1409
|
-
* SQL query. Each element of the +params+ array may be either:
|
1410
|
-
* a hash of the form:
|
1411
|
-
* {:value => String (value of bind parameter)
|
1412
|
-
* :format => Integer (0 for text, 1 for binary)
|
1413
|
-
* }
|
1414
|
-
* or, it may be a String. If it is a string, that is equivalent to the hash:
|
1415
|
-
* { :value => <string value>, :format => 0 }
|
1416
|
-
*
|
1417
|
-
* PostgreSQL bind parameters are represented as $1, $1, $2, etc.,
|
1418
|
-
* inside the SQL query. The 0th element of the +params+ array is bound
|
1419
|
-
* to $1, the 1st element is bound to $2, etc. +nil+ is treated as +NULL+.
|
1420
|
-
*
|
1421
|
-
* The optional +result_format+ should be 0 for text results, 1
|
1422
|
-
* for binary.
|
1423
|
-
*
|
1424
|
-
* type_map can be a PG::TypeMap derivation (such as PG::BasicTypeMapForQueries).
|
1425
|
-
* This will type cast the params from various Ruby types before transmission
|
1426
|
-
* based on the encoders defined by the type map. When a type encoder is used
|
1427
|
-
* the format and oid of a given bind parameter are retrieved from the encoder
|
1428
|
-
* instead out of the hash form described above.
|
1370
|
+
* conn.sync_exec_prepared(statement_name [, params, result_format[, type_map]] ) -> PG::Result
|
1371
|
+
* conn.sync_exec_prepared(statement_name [, params, result_format[, type_map]] ) {|pg_result| block }
|
1429
1372
|
*
|
1430
|
-
*
|
1431
|
-
*
|
1432
|
-
*
|
1373
|
+
* This function has the same behavior as #async_exec_prepared, but is implemented using the synchronous command processing API of libpq.
|
1374
|
+
* See #async_exec for the differences between the two API variants.
|
1375
|
+
* It's not recommended to use explicit sync or async variants but #exec_prepared instead, unless you have a good reason to do so.
|
1433
1376
|
*/
|
1434
1377
|
static VALUE
|
1435
|
-
|
1378
|
+
pgconn_sync_exec_prepared(int argc, VALUE *argv, VALUE self)
|
1436
1379
|
{
|
1437
|
-
|
1380
|
+
t_pg_connection *this = pg_get_connection_safe( self );
|
1438
1381
|
PGresult *result = NULL;
|
1439
1382
|
VALUE rb_pgresult;
|
1440
1383
|
VALUE name, in_res_fmt;
|
1441
1384
|
int nParams;
|
1442
1385
|
int resultFormat;
|
1443
|
-
struct query_params_data paramsData = {
|
1386
|
+
struct query_params_data paramsData = { this->enc_idx };
|
1444
1387
|
|
1445
1388
|
rb_scan_args(argc, argv, "13", &name, ¶msData.params, &in_res_fmt, ¶msData.typemap);
|
1446
1389
|
paramsData.with_types = 0;
|
@@ -1453,7 +1396,7 @@ pgconn_exec_prepared(int argc, VALUE *argv, VALUE self)
|
|
1453
1396
|
resultFormat = NIL_P(in_res_fmt) ? 0 : NUM2INT(in_res_fmt);
|
1454
1397
|
nParams = alloc_query_params( ¶msData );
|
1455
1398
|
|
1456
|
-
result = gvl_PQexecPrepared(
|
1399
|
+
result = gvl_PQexecPrepared(this->pgconn, pg_cstr_enc(name, paramsData.enc_idx), nParams,
|
1457
1400
|
(const char * const *)paramsData.values, paramsData.lengths, paramsData.formats,
|
1458
1401
|
resultFormat);
|
1459
1402
|
|
@@ -1470,25 +1413,26 @@ pgconn_exec_prepared(int argc, VALUE *argv, VALUE self)
|
|
1470
1413
|
|
1471
1414
|
/*
|
1472
1415
|
* call-seq:
|
1473
|
-
* conn.
|
1416
|
+
* conn.sync_describe_prepared( statement_name ) -> PG::Result
|
1474
1417
|
*
|
1475
|
-
*
|
1476
|
-
*
|
1418
|
+
* This function has the same behavior as #async_describe_prepared, but is implemented using the synchronous command processing API of libpq.
|
1419
|
+
* See #async_exec for the differences between the two API variants.
|
1420
|
+
* It's not recommended to use explicit sync or async variants but #describe_prepared instead, unless you have a good reason to do so.
|
1477
1421
|
*/
|
1478
1422
|
static VALUE
|
1479
|
-
|
1423
|
+
pgconn_sync_describe_prepared(VALUE self, VALUE stmt_name)
|
1480
1424
|
{
|
1481
1425
|
PGresult *result;
|
1482
1426
|
VALUE rb_pgresult;
|
1483
|
-
|
1427
|
+
t_pg_connection *this = pg_get_connection_safe( self );
|
1484
1428
|
const char *stmt;
|
1485
1429
|
if(NIL_P(stmt_name)) {
|
1486
1430
|
stmt = NULL;
|
1487
1431
|
}
|
1488
1432
|
else {
|
1489
|
-
stmt = pg_cstr_enc(stmt_name,
|
1433
|
+
stmt = pg_cstr_enc(stmt_name, this->enc_idx);
|
1490
1434
|
}
|
1491
|
-
result = gvl_PQdescribePrepared(
|
1435
|
+
result = gvl_PQdescribePrepared(this->pgconn, stmt);
|
1492
1436
|
rb_pgresult = pg_new_result(result, self);
|
1493
1437
|
pg_result_check(rb_pgresult);
|
1494
1438
|
return rb_pgresult;
|
@@ -1497,25 +1441,27 @@ pgconn_describe_prepared(VALUE self, VALUE stmt_name)
|
|
1497
1441
|
|
1498
1442
|
/*
|
1499
1443
|
* call-seq:
|
1500
|
-
* conn.
|
1444
|
+
* conn.sync_describe_portal( portal_name ) -> PG::Result
|
1501
1445
|
*
|
1502
|
-
*
|
1446
|
+
* This function has the same behavior as #async_describe_portal, but is implemented using the synchronous command processing API of libpq.
|
1447
|
+
* See #async_exec for the differences between the two API variants.
|
1448
|
+
* It's not recommended to use explicit sync or async variants but #describe_portal instead, unless you have a good reason to do so.
|
1503
1449
|
*/
|
1504
1450
|
static VALUE
|
1505
|
-
|
1451
|
+
pgconn_sync_describe_portal(self, stmt_name)
|
1506
1452
|
VALUE self, stmt_name;
|
1507
1453
|
{
|
1508
1454
|
PGresult *result;
|
1509
1455
|
VALUE rb_pgresult;
|
1510
|
-
|
1456
|
+
t_pg_connection *this = pg_get_connection_safe( self );
|
1511
1457
|
const char *stmt;
|
1512
1458
|
if(NIL_P(stmt_name)) {
|
1513
1459
|
stmt = NULL;
|
1514
1460
|
}
|
1515
1461
|
else {
|
1516
|
-
stmt = pg_cstr_enc(stmt_name,
|
1462
|
+
stmt = pg_cstr_enc(stmt_name, this->enc_idx);
|
1517
1463
|
}
|
1518
|
-
result = gvl_PQdescribePortal(
|
1464
|
+
result = gvl_PQdescribePortal(this->pgconn, stmt);
|
1519
1465
|
rb_pgresult = pg_new_result(result, self);
|
1520
1466
|
pg_result_check(rb_pgresult);
|
1521
1467
|
return rb_pgresult;
|
@@ -1537,6 +1483,9 @@ pgconn_describe_portal(self, stmt_name)
|
|
1537
1483
|
* * +PGRES_NONFATAL_ERROR+
|
1538
1484
|
* * +PGRES_FATAL_ERROR+
|
1539
1485
|
* * +PGRES_COPY_BOTH+
|
1486
|
+
* * +PGRES_SINGLE_TUPLE+
|
1487
|
+
* * +PGRES_PIPELINE_SYNC+
|
1488
|
+
* * +PGRES_PIPELINE_ABORTED+
|
1540
1489
|
*/
|
1541
1490
|
static VALUE
|
1542
1491
|
pgconn_make_empty_pgresult(VALUE self, VALUE status)
|
@@ -1562,13 +1511,15 @@ pgconn_make_empty_pgresult(VALUE self, VALUE status)
|
|
1562
1511
|
* Consider using exec_params, which avoids the need for passing values
|
1563
1512
|
* inside of SQL commands.
|
1564
1513
|
*
|
1565
|
-
*
|
1514
|
+
* Character encoding of escaped string will be equal to client encoding of connection.
|
1566
1515
|
*
|
1567
1516
|
* NOTE: This class version of this method can only be used safely in client
|
1568
1517
|
* programs that use a single PostgreSQL connection at a time (in this case it can
|
1569
1518
|
* find out what it needs to know "behind the scenes"). It might give the wrong
|
1570
1519
|
* results if used in programs that use multiple database connections; use the
|
1571
1520
|
* same method on the connection object in such cases.
|
1521
|
+
*
|
1522
|
+
* See also convenience functions #escape_literal and #escape_identifier which also add proper quotes around the string.
|
1572
1523
|
*/
|
1573
1524
|
static VALUE
|
1574
1525
|
pgconn_s_escape(VALUE self, VALUE string)
|
@@ -1580,7 +1531,7 @@ pgconn_s_escape(VALUE self, VALUE string)
|
|
1580
1531
|
int singleton = !rb_obj_is_kind_of(self, rb_cPGconn);
|
1581
1532
|
|
1582
1533
|
StringValueCStr(string);
|
1583
|
-
enc_idx =
|
1534
|
+
enc_idx = singleton ? ENCODING_GET(string) : pg_get_connection(self)->enc_idx;
|
1584
1535
|
if( ENCODING_GET(string) != enc_idx ){
|
1585
1536
|
string = rb_str_export_to_enc(string, rb_enc_from_index(enc_idx));
|
1586
1537
|
}
|
@@ -1597,7 +1548,6 @@ pgconn_s_escape(VALUE self, VALUE string)
|
|
1597
1548
|
size = PQescapeString(RSTRING_PTR(result), RSTRING_PTR(string), RSTRING_LEN(string));
|
1598
1549
|
}
|
1599
1550
|
rb_str_set_len(result, size);
|
1600
|
-
OBJ_INFECT(result, string);
|
1601
1551
|
|
1602
1552
|
return result;
|
1603
1553
|
}
|
@@ -1643,7 +1593,6 @@ pgconn_s_escape_bytea(VALUE self, VALUE str)
|
|
1643
1593
|
}
|
1644
1594
|
|
1645
1595
|
ret = rb_str_new((char*)to, to_len - 1);
|
1646
|
-
OBJ_INFECT(ret, str);
|
1647
1596
|
PQfreemem(to);
|
1648
1597
|
return ret;
|
1649
1598
|
}
|
@@ -1673,7 +1622,6 @@ pgconn_s_unescape_bytea(VALUE self, VALUE str)
|
|
1673
1622
|
to = PQunescapeBytea(from, &to_len);
|
1674
1623
|
|
1675
1624
|
ret = rb_str_new((char*)to, to_len);
|
1676
|
-
OBJ_INFECT(ret, str);
|
1677
1625
|
PQfreemem(to);
|
1678
1626
|
return ret;
|
1679
1627
|
}
|
@@ -1684,33 +1632,32 @@ pgconn_s_unescape_bytea(VALUE self, VALUE str)
|
|
1684
1632
|
*
|
1685
1633
|
* Escape an arbitrary String +str+ as a literal.
|
1686
1634
|
*
|
1687
|
-
*
|
1635
|
+
* See also PG::TextEncoder::QuotedLiteral for a type cast integrated version of this function.
|
1688
1636
|
*/
|
1689
1637
|
static VALUE
|
1690
1638
|
pgconn_escape_literal(VALUE self, VALUE string)
|
1691
1639
|
{
|
1692
|
-
|
1640
|
+
t_pg_connection *this = pg_get_connection_safe( self );
|
1693
1641
|
char *escaped = NULL;
|
1694
1642
|
VALUE error;
|
1695
1643
|
VALUE result = Qnil;
|
1696
|
-
int enc_idx =
|
1644
|
+
int enc_idx = this->enc_idx;
|
1697
1645
|
|
1698
1646
|
StringValueCStr(string);
|
1699
1647
|
if( ENCODING_GET(string) != enc_idx ){
|
1700
1648
|
string = rb_str_export_to_enc(string, rb_enc_from_index(enc_idx));
|
1701
1649
|
}
|
1702
1650
|
|
1703
|
-
escaped = PQescapeLiteral(
|
1651
|
+
escaped = PQescapeLiteral(this->pgconn, RSTRING_PTR(string), RSTRING_LEN(string));
|
1704
1652
|
if (escaped == NULL)
|
1705
1653
|
{
|
1706
|
-
error = rb_exc_new2(rb_ePGerror, PQerrorMessage(
|
1654
|
+
error = rb_exc_new2(rb_ePGerror, PQerrorMessage(this->pgconn));
|
1707
1655
|
rb_iv_set(error, "@connection", self);
|
1708
1656
|
rb_exc_raise(error);
|
1709
1657
|
return Qnil;
|
1710
1658
|
}
|
1711
1659
|
result = rb_str_new2(escaped);
|
1712
1660
|
PQfreemem(escaped);
|
1713
|
-
OBJ_INFECT(result, string);
|
1714
1661
|
PG_ENCODING_SET_NOCHECK(result, enc_idx);
|
1715
1662
|
|
1716
1663
|
return result;
|
@@ -1725,34 +1672,31 @@ pgconn_escape_literal(VALUE self, VALUE string)
|
|
1725
1672
|
* This method does the same as #quote_ident with a String argument,
|
1726
1673
|
* but it doesn't support an Array argument and it makes use of libpq
|
1727
1674
|
* to process the string.
|
1728
|
-
*
|
1729
|
-
* Available since PostgreSQL-9.0
|
1730
1675
|
*/
|
1731
1676
|
static VALUE
|
1732
1677
|
pgconn_escape_identifier(VALUE self, VALUE string)
|
1733
1678
|
{
|
1734
|
-
|
1679
|
+
t_pg_connection *this = pg_get_connection_safe( self );
|
1735
1680
|
char *escaped = NULL;
|
1736
1681
|
VALUE error;
|
1737
1682
|
VALUE result = Qnil;
|
1738
|
-
int enc_idx =
|
1683
|
+
int enc_idx = this->enc_idx;
|
1739
1684
|
|
1740
1685
|
StringValueCStr(string);
|
1741
1686
|
if( ENCODING_GET(string) != enc_idx ){
|
1742
1687
|
string = rb_str_export_to_enc(string, rb_enc_from_index(enc_idx));
|
1743
1688
|
}
|
1744
1689
|
|
1745
|
-
escaped = PQescapeIdentifier(
|
1690
|
+
escaped = PQescapeIdentifier(this->pgconn, RSTRING_PTR(string), RSTRING_LEN(string));
|
1746
1691
|
if (escaped == NULL)
|
1747
1692
|
{
|
1748
|
-
error = rb_exc_new2(rb_ePGerror, PQerrorMessage(
|
1693
|
+
error = rb_exc_new2(rb_ePGerror, PQerrorMessage(this->pgconn));
|
1749
1694
|
rb_iv_set(error, "@connection", self);
|
1750
1695
|
rb_exc_raise(error);
|
1751
1696
|
return Qnil;
|
1752
1697
|
}
|
1753
1698
|
result = rb_str_new2(escaped);
|
1754
1699
|
PQfreemem(escaped);
|
1755
|
-
OBJ_INFECT(result, string);
|
1756
1700
|
PG_ENCODING_SET_NOCHECK(result, enc_idx);
|
1757
1701
|
|
1758
1702
|
return result;
|
@@ -1793,8 +1737,6 @@ pgconn_escape_identifier(VALUE self, VALUE string)
|
|
1793
1737
|
* # do something with the received row
|
1794
1738
|
* end
|
1795
1739
|
* end
|
1796
|
-
*
|
1797
|
-
* Available since PostgreSQL-9.2
|
1798
1740
|
*/
|
1799
1741
|
static VALUE
|
1800
1742
|
pgconn_set_single_row_mode(VALUE self)
|
@@ -1830,16 +1772,17 @@ static VALUE pgconn_send_query_params(int argc, VALUE *argv, VALUE self);
|
|
1830
1772
|
static VALUE
|
1831
1773
|
pgconn_send_query(int argc, VALUE *argv, VALUE self)
|
1832
1774
|
{
|
1833
|
-
|
1775
|
+
t_pg_connection *this = pg_get_connection_safe( self );
|
1834
1776
|
VALUE error;
|
1835
1777
|
|
1836
1778
|
/* If called with no or nil parameters, use PQexec for compatibility */
|
1837
1779
|
if ( argc == 1 || (argc >= 2 && argc <= 4 && NIL_P(argv[1]) )) {
|
1838
|
-
if(gvl_PQsendQuery(
|
1839
|
-
error = rb_exc_new2(rb_eUnableToSend, PQerrorMessage(
|
1780
|
+
if(gvl_PQsendQuery(this->pgconn, pg_cstr_enc(argv[0], this->enc_idx)) == 0) {
|
1781
|
+
error = rb_exc_new2(rb_eUnableToSend, PQerrorMessage(this->pgconn));
|
1840
1782
|
rb_iv_set(error, "@connection", self);
|
1841
1783
|
rb_exc_raise(error);
|
1842
1784
|
}
|
1785
|
+
pgconn_wait_for_flush( self );
|
1843
1786
|
return Qnil;
|
1844
1787
|
}
|
1845
1788
|
|
@@ -1869,7 +1812,7 @@ pgconn_send_query(int argc, VALUE *argv, VALUE self)
|
|
1869
1812
|
* or, it may be a String. If it is a string, that is equivalent to the hash:
|
1870
1813
|
* { :value => <string value>, :type => 0, :format => 0 }
|
1871
1814
|
*
|
1872
|
-
* PostgreSQL bind parameters are represented as $1, $
|
1815
|
+
* PostgreSQL bind parameters are represented as $1, $2, $3, etc.,
|
1873
1816
|
* inside the SQL query. The 0th element of the +params+ array is bound
|
1874
1817
|
* to $1, the 1st element is bound to $2, etc. +nil+ is treated as +NULL+.
|
1875
1818
|
*
|
@@ -1882,7 +1825,7 @@ pgconn_send_query(int argc, VALUE *argv, VALUE self)
|
|
1882
1825
|
* The optional +result_format+ should be 0 for text results, 1
|
1883
1826
|
* for binary.
|
1884
1827
|
*
|
1885
|
-
* type_map can be a PG::TypeMap derivation (such as PG::BasicTypeMapForQueries).
|
1828
|
+
* +type_map+ can be a PG::TypeMap derivation (such as PG::BasicTypeMapForQueries).
|
1886
1829
|
* This will type cast the params from various Ruby types before transmission
|
1887
1830
|
* based on the encoders defined by the type map. When a type encoder is used
|
1888
1831
|
* the format and oid of a given bind parameter are retrieved from the encoder
|
@@ -1892,13 +1835,13 @@ pgconn_send_query(int argc, VALUE *argv, VALUE self)
|
|
1892
1835
|
static VALUE
|
1893
1836
|
pgconn_send_query_params(int argc, VALUE *argv, VALUE self)
|
1894
1837
|
{
|
1895
|
-
|
1838
|
+
t_pg_connection *this = pg_get_connection_safe( self );
|
1896
1839
|
int result;
|
1897
1840
|
VALUE command, in_res_fmt;
|
1898
1841
|
VALUE error;
|
1899
1842
|
int nParams;
|
1900
1843
|
int resultFormat;
|
1901
|
-
struct query_params_data paramsData = {
|
1844
|
+
struct query_params_data paramsData = { this->enc_idx };
|
1902
1845
|
|
1903
1846
|
rb_scan_args(argc, argv, "22", &command, ¶msData.params, &in_res_fmt, ¶msData.typemap);
|
1904
1847
|
paramsData.with_types = 1;
|
@@ -1907,16 +1850,17 @@ pgconn_send_query_params(int argc, VALUE *argv, VALUE self)
|
|
1907
1850
|
resultFormat = NIL_P(in_res_fmt) ? 0 : NUM2INT(in_res_fmt);
|
1908
1851
|
nParams = alloc_query_params( ¶msData );
|
1909
1852
|
|
1910
|
-
result = gvl_PQsendQueryParams(
|
1853
|
+
result = gvl_PQsendQueryParams(this->pgconn, pg_cstr_enc(command, paramsData.enc_idx), nParams, paramsData.types,
|
1911
1854
|
(const char * const *)paramsData.values, paramsData.lengths, paramsData.formats, resultFormat);
|
1912
1855
|
|
1913
1856
|
free_query_params( ¶msData );
|
1914
1857
|
|
1915
1858
|
if(result == 0) {
|
1916
|
-
error = rb_exc_new2(rb_eUnableToSend, PQerrorMessage(
|
1859
|
+
error = rb_exc_new2(rb_eUnableToSend, PQerrorMessage(this->pgconn));
|
1917
1860
|
rb_iv_set(error, "@connection", self);
|
1918
1861
|
rb_exc_raise(error);
|
1919
1862
|
}
|
1863
|
+
pgconn_wait_for_flush( self );
|
1920
1864
|
return Qnil;
|
1921
1865
|
}
|
1922
1866
|
|
@@ -1937,13 +1881,13 @@ pgconn_send_query_params(int argc, VALUE *argv, VALUE self)
|
|
1937
1881
|
*
|
1938
1882
|
* For example: "SELECT $1::int"
|
1939
1883
|
*
|
1940
|
-
* PostgreSQL bind parameters are represented as $1, $
|
1884
|
+
* PostgreSQL bind parameters are represented as $1, $2, $3, etc.,
|
1941
1885
|
* inside the SQL query.
|
1942
1886
|
*/
|
1943
1887
|
static VALUE
|
1944
1888
|
pgconn_send_prepare(int argc, VALUE *argv, VALUE self)
|
1945
1889
|
{
|
1946
|
-
|
1890
|
+
t_pg_connection *this = pg_get_connection_safe( self );
|
1947
1891
|
int result;
|
1948
1892
|
VALUE name, command, in_paramtypes;
|
1949
1893
|
VALUE param;
|
@@ -1953,7 +1897,7 @@ pgconn_send_prepare(int argc, VALUE *argv, VALUE self)
|
|
1953
1897
|
Oid *paramTypes = NULL;
|
1954
1898
|
const char *name_cstr;
|
1955
1899
|
const char *command_cstr;
|
1956
|
-
int enc_idx =
|
1900
|
+
int enc_idx = this->enc_idx;
|
1957
1901
|
|
1958
1902
|
rb_scan_args(argc, argv, "21", &name, &command, &in_paramtypes);
|
1959
1903
|
name_cstr = pg_cstr_enc(name, enc_idx);
|
@@ -1971,15 +1915,16 @@ pgconn_send_prepare(int argc, VALUE *argv, VALUE self)
|
|
1971
1915
|
paramTypes[i] = NUM2UINT(param);
|
1972
1916
|
}
|
1973
1917
|
}
|
1974
|
-
result = gvl_PQsendPrepare(
|
1918
|
+
result = gvl_PQsendPrepare(this->pgconn, name_cstr, command_cstr, nParams, paramTypes);
|
1975
1919
|
|
1976
1920
|
xfree(paramTypes);
|
1977
1921
|
|
1978
1922
|
if(result == 0) {
|
1979
|
-
error = rb_exc_new2(rb_eUnableToSend, PQerrorMessage(
|
1923
|
+
error = rb_exc_new2(rb_eUnableToSend, PQerrorMessage(this->pgconn));
|
1980
1924
|
rb_iv_set(error, "@connection", self);
|
1981
1925
|
rb_exc_raise(error);
|
1982
1926
|
}
|
1927
|
+
pgconn_wait_for_flush( self );
|
1983
1928
|
return Qnil;
|
1984
1929
|
}
|
1985
1930
|
|
@@ -2001,14 +1946,14 @@ pgconn_send_prepare(int argc, VALUE *argv, VALUE self)
|
|
2001
1946
|
* or, it may be a String. If it is a string, that is equivalent to the hash:
|
2002
1947
|
* { :value => <string value>, :format => 0 }
|
2003
1948
|
*
|
2004
|
-
* PostgreSQL bind parameters are represented as $1, $
|
1949
|
+
* PostgreSQL bind parameters are represented as $1, $2, $3, etc.,
|
2005
1950
|
* inside the SQL query. The 0th element of the +params+ array is bound
|
2006
1951
|
* to $1, the 1st element is bound to $2, etc. +nil+ is treated as +NULL+.
|
2007
1952
|
*
|
2008
1953
|
* The optional +result_format+ should be 0 for text results, 1
|
2009
1954
|
* for binary.
|
2010
1955
|
*
|
2011
|
-
* type_map can be a PG::TypeMap derivation (such as PG::BasicTypeMapForQueries).
|
1956
|
+
* +type_map+ can be a PG::TypeMap derivation (such as PG::BasicTypeMapForQueries).
|
2012
1957
|
* This will type cast the params from various Ruby types before transmission
|
2013
1958
|
* based on the encoders defined by the type map. When a type encoder is used
|
2014
1959
|
* the format and oid of a given bind parameter are retrieved from the encoder
|
@@ -2018,37 +1963,37 @@ pgconn_send_prepare(int argc, VALUE *argv, VALUE self)
|
|
2018
1963
|
static VALUE
|
2019
1964
|
pgconn_send_query_prepared(int argc, VALUE *argv, VALUE self)
|
2020
1965
|
{
|
2021
|
-
|
1966
|
+
t_pg_connection *this = pg_get_connection_safe( self );
|
2022
1967
|
int result;
|
2023
1968
|
VALUE name, in_res_fmt;
|
2024
1969
|
VALUE error;
|
2025
1970
|
int nParams;
|
2026
1971
|
int resultFormat;
|
2027
|
-
struct query_params_data paramsData = {
|
1972
|
+
struct query_params_data paramsData = { this->enc_idx };
|
2028
1973
|
|
2029
1974
|
rb_scan_args(argc, argv, "13", &name, ¶msData.params, &in_res_fmt, ¶msData.typemap);
|
2030
1975
|
paramsData.with_types = 0;
|
2031
1976
|
|
2032
1977
|
if(NIL_P(paramsData.params)) {
|
2033
1978
|
paramsData.params = rb_ary_new2(0);
|
2034
|
-
resultFormat = 0;
|
2035
1979
|
}
|
2036
1980
|
pgconn_query_assign_typemap( self, ¶msData );
|
2037
1981
|
|
2038
1982
|
resultFormat = NIL_P(in_res_fmt) ? 0 : NUM2INT(in_res_fmt);
|
2039
1983
|
nParams = alloc_query_params( ¶msData );
|
2040
1984
|
|
2041
|
-
result = gvl_PQsendQueryPrepared(
|
1985
|
+
result = gvl_PQsendQueryPrepared(this->pgconn, pg_cstr_enc(name, paramsData.enc_idx), nParams,
|
2042
1986
|
(const char * const *)paramsData.values, paramsData.lengths, paramsData.formats,
|
2043
1987
|
resultFormat);
|
2044
1988
|
|
2045
1989
|
free_query_params( ¶msData );
|
2046
1990
|
|
2047
1991
|
if(result == 0) {
|
2048
|
-
error = rb_exc_new2(rb_eUnableToSend, PQerrorMessage(
|
1992
|
+
error = rb_exc_new2(rb_eUnableToSend, PQerrorMessage(this->pgconn));
|
2049
1993
|
rb_iv_set(error, "@connection", self);
|
2050
1994
|
rb_exc_raise(error);
|
2051
1995
|
}
|
1996
|
+
pgconn_wait_for_flush( self );
|
2052
1997
|
return Qnil;
|
2053
1998
|
}
|
2054
1999
|
|
@@ -2063,13 +2008,14 @@ static VALUE
|
|
2063
2008
|
pgconn_send_describe_prepared(VALUE self, VALUE stmt_name)
|
2064
2009
|
{
|
2065
2010
|
VALUE error;
|
2066
|
-
|
2011
|
+
t_pg_connection *this = pg_get_connection_safe( self );
|
2067
2012
|
/* returns 0 on failure */
|
2068
|
-
if(gvl_PQsendDescribePrepared(
|
2069
|
-
error = rb_exc_new2(rb_eUnableToSend, PQerrorMessage(
|
2013
|
+
if(gvl_PQsendDescribePrepared(this->pgconn, pg_cstr_enc(stmt_name, this->enc_idx)) == 0) {
|
2014
|
+
error = rb_exc_new2(rb_eUnableToSend, PQerrorMessage(this->pgconn));
|
2070
2015
|
rb_iv_set(error, "@connection", self);
|
2071
2016
|
rb_exc_raise(error);
|
2072
2017
|
}
|
2018
|
+
pgconn_wait_for_flush( self );
|
2073
2019
|
return Qnil;
|
2074
2020
|
}
|
2075
2021
|
|
@@ -2085,35 +2031,20 @@ static VALUE
|
|
2085
2031
|
pgconn_send_describe_portal(VALUE self, VALUE portal)
|
2086
2032
|
{
|
2087
2033
|
VALUE error;
|
2088
|
-
|
2034
|
+
t_pg_connection *this = pg_get_connection_safe( self );
|
2089
2035
|
/* returns 0 on failure */
|
2090
|
-
if(gvl_PQsendDescribePortal(
|
2091
|
-
error = rb_exc_new2(rb_eUnableToSend, PQerrorMessage(
|
2036
|
+
if(gvl_PQsendDescribePortal(this->pgconn, pg_cstr_enc(portal, this->enc_idx)) == 0) {
|
2037
|
+
error = rb_exc_new2(rb_eUnableToSend, PQerrorMessage(this->pgconn));
|
2092
2038
|
rb_iv_set(error, "@connection", self);
|
2093
2039
|
rb_exc_raise(error);
|
2094
2040
|
}
|
2041
|
+
pgconn_wait_for_flush( self );
|
2095
2042
|
return Qnil;
|
2096
2043
|
}
|
2097
2044
|
|
2098
2045
|
|
2099
|
-
/*
|
2100
|
-
* call-seq:
|
2101
|
-
* conn.get_result() -> PG::Result
|
2102
|
-
* conn.get_result() {|pg_result| block }
|
2103
|
-
*
|
2104
|
-
* Blocks waiting for the next result from a call to
|
2105
|
-
* #send_query (or another asynchronous command), and returns
|
2106
|
-
* it. Returns +nil+ if no more results are available.
|
2107
|
-
*
|
2108
|
-
* Note: call this function repeatedly until it returns +nil+, or else
|
2109
|
-
* you will not be able to issue further commands.
|
2110
|
-
*
|
2111
|
-
* If the optional code block is given, it will be passed <i>result</i> as an argument,
|
2112
|
-
* and the PG::Result object will automatically be cleared when the block terminates.
|
2113
|
-
* In this instance, <code>conn.exec</code> returns the value of the block.
|
2114
|
-
*/
|
2115
2046
|
static VALUE
|
2116
|
-
|
2047
|
+
pgconn_sync_get_result(VALUE self)
|
2117
2048
|
{
|
2118
2049
|
PGconn *conn = pg_get_pgconn(self);
|
2119
2050
|
PGresult *result;
|
@@ -2146,6 +2077,7 @@ pgconn_consume_input(self)
|
|
2146
2077
|
PGconn *conn = pg_get_pgconn(self);
|
2147
2078
|
/* returns 0 on error */
|
2148
2079
|
if(PQconsumeInput(conn) == 0) {
|
2080
|
+
pgconn_close_socket_io(self);
|
2149
2081
|
error = rb_exc_new2(rb_eConnectionBad, PQerrorMessage(conn));
|
2150
2082
|
rb_iv_set(error, "@connection", self);
|
2151
2083
|
rb_exc_raise(error);
|
@@ -2158,7 +2090,7 @@ pgconn_consume_input(self)
|
|
2158
2090
|
* conn.is_busy() -> Boolean
|
2159
2091
|
*
|
2160
2092
|
* Returns +true+ if a command is busy, that is, if
|
2161
|
-
*
|
2093
|
+
* #get_result would block. Otherwise returns +false+.
|
2162
2094
|
*/
|
2163
2095
|
static VALUE
|
2164
2096
|
pgconn_is_busy(self)
|
@@ -2167,24 +2099,8 @@ pgconn_is_busy(self)
|
|
2167
2099
|
return gvl_PQisBusy(pg_get_pgconn(self)) ? Qtrue : Qfalse;
|
2168
2100
|
}
|
2169
2101
|
|
2170
|
-
/*
|
2171
|
-
* call-seq:
|
2172
|
-
* conn.setnonblocking(Boolean) -> nil
|
2173
|
-
*
|
2174
|
-
* Sets the nonblocking status of the connection.
|
2175
|
-
* In the blocking state, calls to #send_query
|
2176
|
-
* will block until the message is sent to the server,
|
2177
|
-
* but will not wait for the query results.
|
2178
|
-
* In the nonblocking state, calls to #send_query
|
2179
|
-
* will return an error if the socket is not ready for
|
2180
|
-
* writing.
|
2181
|
-
* Note: This function does not affect #exec, because
|
2182
|
-
* that function doesn't return until the server has
|
2183
|
-
* processed the query and returned the results.
|
2184
|
-
* Returns +nil+.
|
2185
|
-
*/
|
2186
2102
|
static VALUE
|
2187
|
-
|
2103
|
+
pgconn_sync_setnonblocking(self, state)
|
2188
2104
|
VALUE self, state;
|
2189
2105
|
{
|
2190
2106
|
int arg;
|
@@ -2206,33 +2122,15 @@ pgconn_setnonblocking(self, state)
|
|
2206
2122
|
}
|
2207
2123
|
|
2208
2124
|
|
2209
|
-
/*
|
2210
|
-
* call-seq:
|
2211
|
-
* conn.isnonblocking() -> Boolean
|
2212
|
-
*
|
2213
|
-
* Returns +true+ if a command is busy, that is, if
|
2214
|
-
* PQgetResult would block. Otherwise returns +false+.
|
2215
|
-
*/
|
2216
2125
|
static VALUE
|
2217
|
-
|
2126
|
+
pgconn_sync_isnonblocking(self)
|
2218
2127
|
VALUE self;
|
2219
2128
|
{
|
2220
2129
|
return PQisnonblocking(pg_get_pgconn(self)) ? Qtrue : Qfalse;
|
2221
2130
|
}
|
2222
2131
|
|
2223
|
-
/*
|
2224
|
-
* call-seq:
|
2225
|
-
* conn.flush() -> Boolean
|
2226
|
-
*
|
2227
|
-
* Attempts to flush any queued output data to the server.
|
2228
|
-
* Returns +true+ if data is successfully flushed, +false+
|
2229
|
-
* if not (can only return +false+ if connection is
|
2230
|
-
* nonblocking.
|
2231
|
-
* Raises PG::Error if some other failure occurred.
|
2232
|
-
*/
|
2233
2132
|
static VALUE
|
2234
|
-
|
2235
|
-
VALUE self;
|
2133
|
+
pgconn_sync_flush(VALUE self)
|
2236
2134
|
{
|
2237
2135
|
PGconn *conn = pg_get_pgconn(self);
|
2238
2136
|
int ret;
|
@@ -2246,18 +2144,8 @@ pgconn_flush(self)
|
|
2246
2144
|
return (ret) ? Qfalse : Qtrue;
|
2247
2145
|
}
|
2248
2146
|
|
2249
|
-
/*
|
2250
|
-
* call-seq:
|
2251
|
-
* conn.cancel() -> String
|
2252
|
-
*
|
2253
|
-
* Requests cancellation of the command currently being
|
2254
|
-
* processed. (Only implemented in PostgreSQL >= 8.0)
|
2255
|
-
*
|
2256
|
-
* Returns +nil+ on success, or a string containing the
|
2257
|
-
* error message if a failure occurs.
|
2258
|
-
*/
|
2259
2147
|
static VALUE
|
2260
|
-
|
2148
|
+
pgconn_sync_cancel(VALUE self)
|
2261
2149
|
{
|
2262
2150
|
char errbuf[256];
|
2263
2151
|
PGcancel *cancel;
|
@@ -2268,7 +2156,7 @@ pgconn_cancel(VALUE self)
|
|
2268
2156
|
if(cancel == NULL)
|
2269
2157
|
rb_raise(rb_ePGerror,"Invalid connection!");
|
2270
2158
|
|
2271
|
-
ret = gvl_PQcancel(cancel, errbuf,
|
2159
|
+
ret = gvl_PQcancel(cancel, errbuf, sizeof(errbuf));
|
2272
2160
|
if(ret == 1)
|
2273
2161
|
retval = Qnil;
|
2274
2162
|
else
|
@@ -2289,7 +2177,7 @@ pgconn_cancel(VALUE self)
|
|
2289
2177
|
static VALUE
|
2290
2178
|
pgconn_notifies(VALUE self)
|
2291
2179
|
{
|
2292
|
-
|
2180
|
+
t_pg_connection *this = pg_get_connection_safe( self );
|
2293
2181
|
PGnotify *notification;
|
2294
2182
|
VALUE hash;
|
2295
2183
|
VALUE sym_relname, sym_be_pid, sym_extra;
|
@@ -2299,17 +2187,17 @@ pgconn_notifies(VALUE self)
|
|
2299
2187
|
sym_be_pid = ID2SYM(rb_intern("be_pid"));
|
2300
2188
|
sym_extra = ID2SYM(rb_intern("extra"));
|
2301
2189
|
|
2302
|
-
notification = gvl_PQnotifies(
|
2190
|
+
notification = gvl_PQnotifies(this->pgconn);
|
2303
2191
|
if (notification == NULL) {
|
2304
2192
|
return Qnil;
|
2305
2193
|
}
|
2306
2194
|
|
2307
2195
|
hash = rb_hash_new();
|
2308
|
-
relname =
|
2196
|
+
relname = rb_str_new2(notification->relname);
|
2309
2197
|
be_pid = INT2NUM(notification->be_pid);
|
2310
|
-
extra =
|
2311
|
-
PG_ENCODING_SET_NOCHECK( relname,
|
2312
|
-
PG_ENCODING_SET_NOCHECK( extra,
|
2198
|
+
extra = rb_str_new2(notification->extra);
|
2199
|
+
PG_ENCODING_SET_NOCHECK( relname, this->enc_idx );
|
2200
|
+
PG_ENCODING_SET_NOCHECK( extra, this->enc_idx );
|
2313
2201
|
|
2314
2202
|
rb_hash_aset(hash, sym_relname, relname);
|
2315
2203
|
rb_hash_aset(hash, sym_be_pid, be_pid);
|
@@ -2319,55 +2207,63 @@ pgconn_notifies(VALUE self)
|
|
2319
2207
|
return hash;
|
2320
2208
|
}
|
2321
2209
|
|
2322
|
-
|
2323
|
-
|
2324
|
-
/*
|
2325
|
-
*
|
2326
|
-
* instead of rb_wait_for_single_fd().
|
2210
|
+
#if defined(_WIN32)
|
2211
|
+
|
2212
|
+
/* We use a specialized implementation of rb_io_wait() on Windows.
|
2213
|
+
* This is because rb_io_wait() and rb_wait_for_single_fd() are very slow on Windows.
|
2327
2214
|
*/
|
2328
2215
|
|
2216
|
+
#if defined(HAVE_RUBY_FIBER_SCHEDULER_H)
|
2217
|
+
#include <ruby/fiber/scheduler.h>
|
2218
|
+
#endif
|
2219
|
+
|
2220
|
+
typedef enum {
|
2221
|
+
PG_RUBY_IO_READABLE = RB_WAITFD_IN,
|
2222
|
+
PG_RUBY_IO_WRITABLE = RB_WAITFD_OUT,
|
2223
|
+
PG_RUBY_IO_PRIORITY = RB_WAITFD_PRI,
|
2224
|
+
} pg_rb_io_event_t;
|
2225
|
+
|
2329
2226
|
int rb_w32_wait_events( HANDLE *events, int num, DWORD timeout );
|
2330
2227
|
|
2331
|
-
static
|
2332
|
-
|
2333
|
-
|
2334
|
-
|
2335
|
-
|
2228
|
+
static VALUE
|
2229
|
+
pg_rb_thread_io_wait(VALUE io, VALUE events, VALUE timeout) {
|
2230
|
+
rb_io_t *fptr;
|
2231
|
+
struct timeval ptimeout;
|
2232
|
+
|
2336
2233
|
struct timeval aborttime={0,0}, currtime, waittime;
|
2337
2234
|
DWORD timeout_milisec = INFINITE;
|
2338
|
-
|
2339
|
-
WSAEVENT hEvent;
|
2235
|
+
HANDLE hEvent = WSACreateEvent();
|
2340
2236
|
|
2341
|
-
|
2342
|
-
|
2237
|
+
long rb_events = NUM2UINT(events);
|
2238
|
+
long w32_events = 0;
|
2239
|
+
DWORD wait_ret;
|
2343
2240
|
|
2344
|
-
|
2241
|
+
GetOpenFile((io), fptr);
|
2242
|
+
if( !NIL_P(timeout) ){
|
2243
|
+
ptimeout.tv_sec = (time_t)(NUM2DBL(timeout));
|
2244
|
+
ptimeout.tv_usec = (time_t)((NUM2DBL(timeout) - (double)ptimeout.tv_sec) * 1e6);
|
2345
2245
|
|
2346
|
-
/* Check for connection errors (PQisBusy is true on connection errors) */
|
2347
|
-
if( PQconsumeInput(conn) == 0 ) {
|
2348
|
-
WSACloseEvent( hEvent );
|
2349
|
-
rb_raise( rb_eConnectionBad, "PQconsumeInput() %s", PQerrorMessage(conn) );
|
2350
|
-
}
|
2351
|
-
|
2352
|
-
if ( ptimeout ) {
|
2353
2246
|
gettimeofday(&currtime, NULL);
|
2354
|
-
timeradd(&currtime, ptimeout, &aborttime);
|
2247
|
+
timeradd(&currtime, &ptimeout, &aborttime);
|
2355
2248
|
}
|
2356
2249
|
|
2357
|
-
|
2358
|
-
|
2250
|
+
if(rb_events & PG_RUBY_IO_READABLE) w32_events |= FD_READ | FD_ACCEPT | FD_CLOSE;
|
2251
|
+
if(rb_events & PG_RUBY_IO_WRITABLE) w32_events |= FD_WRITE | FD_CONNECT;
|
2252
|
+
if(rb_events & PG_RUBY_IO_PRIORITY) w32_events |= FD_OOB;
|
2253
|
+
|
2254
|
+
for(;;) {
|
2255
|
+
if ( WSAEventSelect(_get_osfhandle(fptr->fd), hEvent, w32_events) == SOCKET_ERROR ) {
|
2359
2256
|
WSACloseEvent( hEvent );
|
2360
2257
|
rb_raise( rb_eConnectionBad, "WSAEventSelect socket error: %d", WSAGetLastError() );
|
2361
2258
|
}
|
2362
2259
|
|
2363
|
-
if (
|
2260
|
+
if ( !NIL_P(timeout) ) {
|
2364
2261
|
gettimeofday(&currtime, NULL);
|
2365
2262
|
timersub(&aborttime, &currtime, &waittime);
|
2366
2263
|
timeout_milisec = (DWORD)( waittime.tv_sec * 1e3 + waittime.tv_usec / 1e3 );
|
2367
2264
|
}
|
2368
2265
|
|
2369
|
-
|
2370
|
-
if( !ptimeout || (waittime.tv_sec >= 0 && waittime.tv_usec >= 0) ){
|
2266
|
+
if( NIL_P(timeout) || (waittime.tv_sec >= 0 && waittime.tv_usec >= 0) ){
|
2371
2267
|
/* Wait for the socket to become readable before checking again */
|
2372
2268
|
wait_ret = rb_w32_wait_events( &hEvent, 1, timeout_milisec );
|
2373
2269
|
} else {
|
@@ -2376,9 +2272,11 @@ wait_socket_readable( PGconn *conn, struct timeval *ptimeout, void *(*is_readabl
|
|
2376
2272
|
|
2377
2273
|
if ( wait_ret == WAIT_TIMEOUT ) {
|
2378
2274
|
WSACloseEvent( hEvent );
|
2379
|
-
return
|
2275
|
+
return UINT2NUM(0);
|
2380
2276
|
} else if ( wait_ret == WAIT_OBJECT_0 ) {
|
2277
|
+
WSACloseEvent( hEvent );
|
2381
2278
|
/* The event we were waiting for. */
|
2279
|
+
return UINT2NUM(rb_events);
|
2382
2280
|
} else if ( wait_ret == WAIT_OBJECT_0 + 1) {
|
2383
2281
|
/* This indicates interruption from timer thread, GC, exception
|
2384
2282
|
* from other threads etc... */
|
@@ -2390,36 +2288,75 @@ wait_socket_readable( PGconn *conn, struct timeval *ptimeout, void *(*is_readabl
|
|
2390
2288
|
WSACloseEvent( hEvent );
|
2391
2289
|
rb_raise( rb_eConnectionBad, "Wait on socket abandoned (WaitForMultipleObjects)" );
|
2392
2290
|
}
|
2393
|
-
|
2394
|
-
/* Check for connection errors (PQisBusy is true on connection errors) */
|
2395
|
-
if ( PQconsumeInput(conn) == 0 ) {
|
2396
|
-
WSACloseEvent( hEvent );
|
2397
|
-
rb_raise( rb_eConnectionBad, "PQconsumeInput() %s", PQerrorMessage(conn) );
|
2398
|
-
}
|
2399
2291
|
}
|
2292
|
+
}
|
2400
2293
|
|
2401
|
-
|
2402
|
-
|
2294
|
+
static VALUE
|
2295
|
+
pg_rb_io_wait(VALUE io, VALUE events, VALUE timeout) {
|
2296
|
+
#if defined(HAVE_RUBY_FIBER_SCHEDULER_H)
|
2297
|
+
/* We don't support Fiber.scheduler on Windows ruby-3.0 because there is no fast way to check whether a scheduler is active.
|
2298
|
+
* Fortunatelly ruby-3.1 offers a C-API for it.
|
2299
|
+
*/
|
2300
|
+
VALUE scheduler = rb_fiber_scheduler_current();
|
2301
|
+
|
2302
|
+
if (!NIL_P(scheduler)) {
|
2303
|
+
return rb_io_wait(io, events, timeout);
|
2304
|
+
}
|
2305
|
+
#endif
|
2306
|
+
return pg_rb_thread_io_wait(io, events, timeout);
|
2403
2307
|
}
|
2404
2308
|
|
2309
|
+
#elif defined(HAVE_RB_IO_WAIT)
|
2310
|
+
|
2311
|
+
/* Use our own function and constants names, to avoid conflicts with truffleruby-head on its road to ruby-3.0 compatibility. */
|
2312
|
+
#define pg_rb_io_wait rb_io_wait
|
2313
|
+
#define PG_RUBY_IO_READABLE RUBY_IO_READABLE
|
2314
|
+
#define PG_RUBY_IO_WRITABLE RUBY_IO_WRITABLE
|
2315
|
+
#define PG_RUBY_IO_PRIORITY RUBY_IO_PRIORITY
|
2316
|
+
|
2405
2317
|
#else
|
2318
|
+
/* For compat with ruby < 3.0 */
|
2319
|
+
|
2320
|
+
typedef enum {
|
2321
|
+
PG_RUBY_IO_READABLE = RB_WAITFD_IN,
|
2322
|
+
PG_RUBY_IO_WRITABLE = RB_WAITFD_OUT,
|
2323
|
+
PG_RUBY_IO_PRIORITY = RB_WAITFD_PRI,
|
2324
|
+
} pg_rb_io_event_t;
|
2325
|
+
|
2326
|
+
static VALUE
|
2327
|
+
pg_rb_io_wait(VALUE io, VALUE events, VALUE timeout) {
|
2328
|
+
rb_io_t *fptr;
|
2329
|
+
struct timeval waittime;
|
2330
|
+
int res;
|
2331
|
+
|
2332
|
+
GetOpenFile((io), fptr);
|
2333
|
+
if( !NIL_P(timeout) ){
|
2334
|
+
waittime.tv_sec = (time_t)(NUM2DBL(timeout));
|
2335
|
+
waittime.tv_usec = (time_t)((NUM2DBL(timeout) - (double)waittime.tv_sec) * 1e6);
|
2336
|
+
}
|
2337
|
+
res = rb_wait_for_single_fd(fptr->fd, NUM2UINT(events), NIL_P(timeout) ? NULL : &waittime);
|
2406
2338
|
|
2407
|
-
|
2339
|
+
return UINT2NUM(res);
|
2340
|
+
}
|
2341
|
+
#endif
|
2408
2342
|
|
2409
2343
|
static void *
|
2410
|
-
wait_socket_readable(
|
2344
|
+
wait_socket_readable( VALUE self, struct timeval *ptimeout, void *(*is_readable)(PGconn *))
|
2411
2345
|
{
|
2412
|
-
|
2413
|
-
|
2346
|
+
VALUE socket_io;
|
2347
|
+
VALUE ret;
|
2414
2348
|
void *retval;
|
2415
2349
|
struct timeval aborttime={0,0}, currtime, waittime;
|
2350
|
+
VALUE wait_timeout = Qnil;
|
2351
|
+
PGconn *conn = pg_get_pgconn(self);
|
2416
2352
|
|
2417
|
-
|
2418
|
-
rb_raise(rb_eConnectionBad, "PQsocket() can't get socket descriptor");
|
2353
|
+
socket_io = pgconn_socket_io(self);
|
2419
2354
|
|
2420
2355
|
/* Check for connection errors (PQisBusy is true on connection errors) */
|
2421
|
-
if ( PQconsumeInput(conn) == 0 )
|
2356
|
+
if ( PQconsumeInput(conn) == 0 ) {
|
2357
|
+
pgconn_close_socket_io(self);
|
2422
2358
|
rb_raise( rb_eConnectionBad, "PQconsumeInput() %s", PQerrorMessage(conn) );
|
2359
|
+
}
|
2423
2360
|
|
2424
2361
|
if ( ptimeout ) {
|
2425
2362
|
gettimeofday(&currtime, NULL);
|
@@ -2430,27 +2367,25 @@ wait_socket_readable( PGconn *conn, struct timeval *ptimeout, void *(*is_readabl
|
|
2430
2367
|
if ( ptimeout ) {
|
2431
2368
|
gettimeofday(&currtime, NULL);
|
2432
2369
|
timersub(&aborttime, &currtime, &waittime);
|
2370
|
+
wait_timeout = DBL2NUM((double)(waittime.tv_sec) + (double)(waittime.tv_usec) / 1000000.0);
|
2433
2371
|
}
|
2434
2372
|
|
2435
2373
|
/* Is the given timeout valid? */
|
2436
2374
|
if( !ptimeout || (waittime.tv_sec >= 0 && waittime.tv_usec >= 0) ){
|
2437
2375
|
/* Wait for the socket to become readable before checking again */
|
2438
|
-
ret =
|
2376
|
+
ret = pg_rb_io_wait(socket_io, RB_INT2NUM(PG_RUBY_IO_READABLE), wait_timeout);
|
2439
2377
|
} else {
|
2440
|
-
ret =
|
2441
|
-
}
|
2442
|
-
|
2443
|
-
if ( ret < 0 ){
|
2444
|
-
rb_sys_fail( "rb_wait_for_single_fd()" );
|
2378
|
+
ret = Qfalse;
|
2445
2379
|
}
|
2446
2380
|
|
2447
2381
|
/* Return false if the select() timed out */
|
2448
|
-
if ( ret ==
|
2382
|
+
if ( ret == Qfalse ){
|
2449
2383
|
return NULL;
|
2450
2384
|
}
|
2451
2385
|
|
2452
2386
|
/* Check for connection errors (PQisBusy is true on connection errors) */
|
2453
2387
|
if ( PQconsumeInput(conn) == 0 ){
|
2388
|
+
pgconn_close_socket_io(self);
|
2454
2389
|
rb_raise( rb_eConnectionBad, "PQconsumeInput() %s", PQerrorMessage(conn) );
|
2455
2390
|
}
|
2456
2391
|
}
|
@@ -2458,8 +2393,45 @@ wait_socket_readable( PGconn *conn, struct timeval *ptimeout, void *(*is_readabl
|
|
2458
2393
|
return retval;
|
2459
2394
|
}
|
2460
2395
|
|
2396
|
+
/*
|
2397
|
+
* call-seq:
|
2398
|
+
* conn.flush() -> Boolean
|
2399
|
+
*
|
2400
|
+
* Attempts to flush any queued output data to the server.
|
2401
|
+
* Returns +true+ if data is successfully flushed, +false+
|
2402
|
+
* if not (can only return +false+ if connection is
|
2403
|
+
* nonblocking.
|
2404
|
+
* Raises PG::Error if some other failure occurred.
|
2405
|
+
*/
|
2406
|
+
static VALUE
|
2407
|
+
pgconn_async_flush(VALUE self)
|
2408
|
+
{
|
2409
|
+
while( pgconn_sync_flush(self) == Qfalse ){
|
2410
|
+
/* wait for the socket to become read- or write-ready */
|
2411
|
+
int events;
|
2412
|
+
VALUE socket_io = pgconn_socket_io(self);
|
2413
|
+
events = RB_NUM2INT(pg_rb_io_wait(socket_io, RB_INT2NUM(PG_RUBY_IO_READABLE | PG_RUBY_IO_WRITABLE), Qnil));
|
2414
|
+
|
2415
|
+
if (events & PG_RUBY_IO_READABLE)
|
2416
|
+
pgconn_consume_input(self);
|
2417
|
+
}
|
2418
|
+
return Qtrue;
|
2419
|
+
}
|
2420
|
+
|
2421
|
+
static VALUE
|
2422
|
+
pgconn_wait_for_flush( VALUE self ){
|
2423
|
+
if( !pg_get_connection_safe(self)->flush_data )
|
2424
|
+
return Qnil;
|
2461
2425
|
|
2462
|
-
|
2426
|
+
return pgconn_async_flush(self);
|
2427
|
+
}
|
2428
|
+
|
2429
|
+
static VALUE
|
2430
|
+
pgconn_flush_data_set( VALUE self, VALUE enabled ){
|
2431
|
+
t_pg_connection *conn = pg_get_connection(self);
|
2432
|
+
conn->flush_data = RTEST(enabled);
|
2433
|
+
return enabled;
|
2434
|
+
}
|
2463
2435
|
|
2464
2436
|
static void *
|
2465
2437
|
notify_readable(PGconn *conn)
|
@@ -2482,7 +2454,7 @@ notify_readable(PGconn *conn)
|
|
2482
2454
|
static VALUE
|
2483
2455
|
pgconn_wait_for_notify(int argc, VALUE *argv, VALUE self)
|
2484
2456
|
{
|
2485
|
-
|
2457
|
+
t_pg_connection *this = pg_get_connection_safe( self );
|
2486
2458
|
PGnotify *pnotification;
|
2487
2459
|
struct timeval timeout;
|
2488
2460
|
struct timeval *ptimeout = NULL;
|
@@ -2498,17 +2470,17 @@ pgconn_wait_for_notify(int argc, VALUE *argv, VALUE self)
|
|
2498
2470
|
ptimeout = &timeout;
|
2499
2471
|
}
|
2500
2472
|
|
2501
|
-
pnotification = (PGnotify*) wait_socket_readable(
|
2473
|
+
pnotification = (PGnotify*) wait_socket_readable( self, ptimeout, notify_readable);
|
2502
2474
|
|
2503
2475
|
/* Return nil if the select timed out */
|
2504
2476
|
if ( !pnotification ) return Qnil;
|
2505
2477
|
|
2506
|
-
relname =
|
2507
|
-
PG_ENCODING_SET_NOCHECK( relname,
|
2478
|
+
relname = rb_str_new2( pnotification->relname );
|
2479
|
+
PG_ENCODING_SET_NOCHECK( relname, this->enc_idx );
|
2508
2480
|
be_pid = INT2NUM( pnotification->be_pid );
|
2509
2481
|
if ( *pnotification->extra ) {
|
2510
|
-
extra =
|
2511
|
-
PG_ENCODING_SET_NOCHECK( extra,
|
2482
|
+
extra = rb_str_new2( pnotification->extra );
|
2483
|
+
PG_ENCODING_SET_NOCHECK( extra, this->enc_idx );
|
2512
2484
|
}
|
2513
2485
|
PQfreemem( pnotification );
|
2514
2486
|
|
@@ -2519,28 +2491,8 @@ pgconn_wait_for_notify(int argc, VALUE *argv, VALUE self)
|
|
2519
2491
|
}
|
2520
2492
|
|
2521
2493
|
|
2522
|
-
/*
|
2523
|
-
* call-seq:
|
2524
|
-
* conn.put_copy_data( buffer [, encoder] ) -> Boolean
|
2525
|
-
*
|
2526
|
-
* Transmits _buffer_ as copy data to the server.
|
2527
|
-
* Returns true if the data was sent, false if it was
|
2528
|
-
* not sent (false is only possible if the connection
|
2529
|
-
* is in nonblocking mode, and this command would block).
|
2530
|
-
*
|
2531
|
-
* _encoder_ can be a PG::Coder derivation (typically PG::TextEncoder::CopyRow).
|
2532
|
-
* This encodes the data fields given as _buffer_ from an Array of Strings to
|
2533
|
-
* PostgreSQL's COPY text format inclusive proper escaping. Optionally
|
2534
|
-
* the encoder can type cast the fields from various Ruby types in one step,
|
2535
|
-
* if PG::TextEncoder::CopyRow#type_map is set accordingly.
|
2536
|
-
*
|
2537
|
-
* Raises an exception if an error occurs.
|
2538
|
-
*
|
2539
|
-
* See also #copy_data.
|
2540
|
-
*
|
2541
|
-
*/
|
2542
2494
|
static VALUE
|
2543
|
-
|
2495
|
+
pgconn_sync_put_copy_data(int argc, VALUE *argv, VALUE self)
|
2544
2496
|
{
|
2545
2497
|
int ret;
|
2546
2498
|
int len;
|
@@ -2557,18 +2509,16 @@ pgconn_put_copy_data(int argc, VALUE *argv, VALUE self)
|
|
2557
2509
|
if( NIL_P(this->encoder_for_put_copy_data) ){
|
2558
2510
|
buffer = value;
|
2559
2511
|
} else {
|
2560
|
-
p_coder =
|
2512
|
+
p_coder = RTYPEDDATA_DATA( this->encoder_for_put_copy_data );
|
2561
2513
|
}
|
2562
|
-
} else if( rb_obj_is_kind_of(encoder, rb_cPG_Coder) ) {
|
2563
|
-
Data_Get_Struct( encoder, t_pg_coder, p_coder );
|
2564
2514
|
} else {
|
2565
|
-
|
2566
|
-
|
2515
|
+
/* Check argument type and use argument encoder */
|
2516
|
+
TypedData_Get_Struct(encoder, t_pg_coder, &pg_coder_type, p_coder);
|
2567
2517
|
}
|
2568
2518
|
|
2569
2519
|
if( p_coder ){
|
2570
2520
|
t_pg_coder_enc_func enc_func;
|
2571
|
-
int enc_idx =
|
2521
|
+
int enc_idx = this->enc_idx;
|
2572
2522
|
|
2573
2523
|
enc_func = pg_coder_enc_func( p_coder );
|
2574
2524
|
len = enc_func( p_coder, value, NULL, &intermediate, enc_idx);
|
@@ -2597,64 +2547,31 @@ pgconn_put_copy_data(int argc, VALUE *argv, VALUE self)
|
|
2597
2547
|
return (ret) ? Qtrue : Qfalse;
|
2598
2548
|
}
|
2599
2549
|
|
2600
|
-
/*
|
2601
|
-
* call-seq:
|
2602
|
-
* conn.put_copy_end( [ error_message ] ) -> Boolean
|
2603
|
-
*
|
2604
|
-
* Sends end-of-data indication to the server.
|
2605
|
-
*
|
2606
|
-
* _error_message_ is an optional parameter, and if set,
|
2607
|
-
* forces the COPY command to fail with the string
|
2608
|
-
* _error_message_.
|
2609
|
-
*
|
2610
|
-
* Returns true if the end-of-data was sent, false if it was
|
2611
|
-
* not sent (false is only possible if the connection
|
2612
|
-
* is in nonblocking mode, and this command would block).
|
2613
|
-
*/
|
2614
2550
|
static VALUE
|
2615
|
-
|
2551
|
+
pgconn_sync_put_copy_end(int argc, VALUE *argv, VALUE self)
|
2616
2552
|
{
|
2617
2553
|
VALUE str;
|
2618
2554
|
VALUE error;
|
2619
2555
|
int ret;
|
2620
2556
|
const char *error_message = NULL;
|
2621
|
-
|
2557
|
+
t_pg_connection *this = pg_get_connection_safe( self );
|
2622
2558
|
|
2623
2559
|
if (rb_scan_args(argc, argv, "01", &str) == 0)
|
2624
2560
|
error_message = NULL;
|
2625
2561
|
else
|
2626
|
-
error_message = pg_cstr_enc(str,
|
2562
|
+
error_message = pg_cstr_enc(str, this->enc_idx);
|
2627
2563
|
|
2628
|
-
ret = gvl_PQputCopyEnd(
|
2564
|
+
ret = gvl_PQputCopyEnd(this->pgconn, error_message);
|
2629
2565
|
if(ret == -1) {
|
2630
|
-
error = rb_exc_new2(rb_ePGerror, PQerrorMessage(
|
2566
|
+
error = rb_exc_new2(rb_ePGerror, PQerrorMessage(this->pgconn));
|
2631
2567
|
rb_iv_set(error, "@connection", self);
|
2632
2568
|
rb_exc_raise(error);
|
2633
2569
|
}
|
2634
2570
|
return (ret) ? Qtrue : Qfalse;
|
2635
2571
|
}
|
2636
2572
|
|
2637
|
-
/*
|
2638
|
-
* call-seq:
|
2639
|
-
* conn.get_copy_data( [ async = false [, decoder = nil ]] ) -> Object
|
2640
|
-
*
|
2641
|
-
* Return one row of data, +nil+
|
2642
|
-
* if the copy is done, or +false+ if the call would
|
2643
|
-
* block (only possible if _async_ is true).
|
2644
|
-
*
|
2645
|
-
* If _decoder_ is not set or +nil+, data is returned as binary string.
|
2646
|
-
*
|
2647
|
-
* If _decoder_ is set to a PG::Coder derivation, the return type depends on this decoder.
|
2648
|
-
* PG::TextDecoder::CopyRow decodes the received data fields from one row of PostgreSQL's
|
2649
|
-
* COPY text format to an Array of Strings.
|
2650
|
-
* Optionally the decoder can type cast the single fields to various Ruby types in one step,
|
2651
|
-
* if PG::TextDecoder::CopyRow#type_map is set accordingly.
|
2652
|
-
*
|
2653
|
-
* See also #copy_data.
|
2654
|
-
*
|
2655
|
-
*/
|
2656
2573
|
static VALUE
|
2657
|
-
|
2574
|
+
pgconn_sync_get_copy_data(int argc, VALUE *argv, VALUE self )
|
2658
2575
|
{
|
2659
2576
|
VALUE async_in;
|
2660
2577
|
VALUE error;
|
@@ -2669,13 +2586,11 @@ pgconn_get_copy_data(int argc, VALUE *argv, VALUE self )
|
|
2669
2586
|
|
2670
2587
|
if( NIL_P(decoder) ){
|
2671
2588
|
if( !NIL_P(this->decoder_for_get_copy_data) ){
|
2672
|
-
p_coder =
|
2589
|
+
p_coder = RTYPEDDATA_DATA( this->decoder_for_get_copy_data );
|
2673
2590
|
}
|
2674
|
-
} else if( rb_obj_is_kind_of(decoder, rb_cPG_Coder) ) {
|
2675
|
-
Data_Get_Struct( decoder, t_pg_coder, p_coder );
|
2676
2591
|
} else {
|
2677
|
-
|
2678
|
-
|
2592
|
+
/* Check argument type and use argument decoder */
|
2593
|
+
TypedData_Get_Struct(decoder, t_pg_coder, &pg_coder_type, p_coder);
|
2679
2594
|
}
|
2680
2595
|
|
2681
2596
|
ret = gvl_PQgetCopyData(this->pgconn, &buffer, RTEST(async_in));
|
@@ -2693,9 +2608,9 @@ pgconn_get_copy_data(int argc, VALUE *argv, VALUE self )
|
|
2693
2608
|
|
2694
2609
|
if( p_coder ){
|
2695
2610
|
t_pg_coder_dec_func dec_func = pg_coder_dec_func( p_coder, p_coder->format );
|
2696
|
-
result = dec_func( p_coder, buffer, ret, 0, 0,
|
2611
|
+
result = dec_func( p_coder, buffer, ret, 0, 0, this->enc_idx );
|
2697
2612
|
} else {
|
2698
|
-
result =
|
2613
|
+
result = rb_str_new(buffer, ret);
|
2699
2614
|
}
|
2700
2615
|
|
2701
2616
|
PQfreemem(buffer);
|
@@ -2708,9 +2623,16 @@ pgconn_get_copy_data(int argc, VALUE *argv, VALUE self )
|
|
2708
2623
|
*
|
2709
2624
|
* Sets connection's verbosity to _verbosity_ and returns
|
2710
2625
|
* the previous setting. Available settings are:
|
2626
|
+
*
|
2711
2627
|
* * PQERRORS_TERSE
|
2712
2628
|
* * PQERRORS_DEFAULT
|
2713
2629
|
* * PQERRORS_VERBOSE
|
2630
|
+
* * PQERRORS_SQLSTATE
|
2631
|
+
*
|
2632
|
+
* Changing the verbosity does not affect the messages available from already-existing PG::Result objects, only subsequently-created ones.
|
2633
|
+
* (But see PG::Result#verbose_error_message if you want to print a previous error with a different verbosity.)
|
2634
|
+
*
|
2635
|
+
* See also corresponding {libpq function}[https://www.postgresql.org/docs/current/libpq-control.html#LIBPQ-PQSETERRORVERBOSITY].
|
2714
2636
|
*/
|
2715
2637
|
static VALUE
|
2716
2638
|
pgconn_set_error_verbosity(VALUE self, VALUE in_verbosity)
|
@@ -2720,6 +2642,37 @@ pgconn_set_error_verbosity(VALUE self, VALUE in_verbosity)
|
|
2720
2642
|
return INT2FIX(PQsetErrorVerbosity(conn, verbosity));
|
2721
2643
|
}
|
2722
2644
|
|
2645
|
+
#ifdef HAVE_PQRESULTVERBOSEERRORMESSAGE
|
2646
|
+
/*
|
2647
|
+
* call-seq:
|
2648
|
+
* conn.set_error_context_visibility( context_visibility ) -> Integer
|
2649
|
+
*
|
2650
|
+
* Sets connection's context display mode to _context_visibility_ and returns
|
2651
|
+
* the previous setting. Available settings are:
|
2652
|
+
* * PQSHOW_CONTEXT_NEVER
|
2653
|
+
* * PQSHOW_CONTEXT_ERRORS
|
2654
|
+
* * PQSHOW_CONTEXT_ALWAYS
|
2655
|
+
*
|
2656
|
+
* This mode controls whether the CONTEXT field is included in messages (unless the verbosity setting is TERSE, in which case CONTEXT is never shown).
|
2657
|
+
* The NEVER mode never includes CONTEXT, while ALWAYS always includes it if available.
|
2658
|
+
* In ERRORS mode (the default), CONTEXT fields are included only for error messages, not for notices and warnings.
|
2659
|
+
*
|
2660
|
+
* Changing this mode does not affect the messages available from already-existing PG::Result objects, only subsequently-created ones.
|
2661
|
+
* (But see PG::Result#verbose_error_message if you want to print a previous error with a different display mode.)
|
2662
|
+
*
|
2663
|
+
* See also corresponding {libpq function}[https://www.postgresql.org/docs/current/libpq-control.html#LIBPQ-PQSETERRORCONTEXTVISIBILITY].
|
2664
|
+
*
|
2665
|
+
* Available since PostgreSQL-9.6
|
2666
|
+
*/
|
2667
|
+
static VALUE
|
2668
|
+
pgconn_set_error_context_visibility(VALUE self, VALUE in_context_visibility)
|
2669
|
+
{
|
2670
|
+
PGconn *conn = pg_get_pgconn(self);
|
2671
|
+
PGContextVisibility context_visibility = NUM2INT(in_context_visibility);
|
2672
|
+
return INT2FIX(PQsetErrorContextVisibility(conn, context_visibility));
|
2673
|
+
}
|
2674
|
+
#endif
|
2675
|
+
|
2723
2676
|
/*
|
2724
2677
|
* call-seq:
|
2725
2678
|
* conn.trace( stream ) -> nil
|
@@ -2738,7 +2691,7 @@ pgconn_trace(VALUE self, VALUE stream)
|
|
2738
2691
|
VALUE new_file;
|
2739
2692
|
t_pg_connection *this = pg_get_connection_safe( self );
|
2740
2693
|
|
2741
|
-
if(rb_respond_to(stream,rb_intern("fileno"))
|
2694
|
+
if(!rb_respond_to(stream,rb_intern("fileno")))
|
2742
2695
|
rb_raise(rb_eArgError, "stream does not respond to method: fileno");
|
2743
2696
|
|
2744
2697
|
fileno = rb_funcall(stream, rb_intern("fileno"), 0);
|
@@ -2871,8 +2824,8 @@ notice_processor_proxy(void *arg, const char *message)
|
|
2871
2824
|
t_pg_connection *this = pg_get_connection( self );
|
2872
2825
|
|
2873
2826
|
if (this->notice_receiver != Qnil) {
|
2874
|
-
VALUE message_str =
|
2875
|
-
PG_ENCODING_SET_NOCHECK( message_str,
|
2827
|
+
VALUE message_str = rb_str_new2(message);
|
2828
|
+
PG_ENCODING_SET_NOCHECK( message_str, this->enc_idx );
|
2876
2829
|
rb_funcall(this->notice_receiver, rb_intern("call"), 1, message_str);
|
2877
2830
|
}
|
2878
2831
|
return;
|
@@ -2882,7 +2835,7 @@ notice_processor_proxy(void *arg, const char *message)
|
|
2882
2835
|
* call-seq:
|
2883
2836
|
* conn.set_notice_processor {|message| ... } -> Proc
|
2884
2837
|
*
|
2885
|
-
* See #set_notice_receiver for the
|
2838
|
+
* See #set_notice_receiver for the description of what this and the
|
2886
2839
|
* notice_processor methods do.
|
2887
2840
|
*
|
2888
2841
|
* This function takes a new block to act as the notice processor and returns
|
@@ -2930,18 +2883,20 @@ static VALUE
|
|
2930
2883
|
pgconn_get_client_encoding(VALUE self)
|
2931
2884
|
{
|
2932
2885
|
char *encoding = (char *)pg_encoding_to_char(PQclientEncoding(pg_get_pgconn(self)));
|
2933
|
-
return
|
2886
|
+
return rb_str_new2(encoding);
|
2934
2887
|
}
|
2935
2888
|
|
2936
2889
|
|
2937
2890
|
/*
|
2938
2891
|
* call-seq:
|
2939
|
-
* conn.
|
2892
|
+
* conn.sync_set_client_encoding( encoding )
|
2940
2893
|
*
|
2941
|
-
*
|
2894
|
+
* This function has the same behavior as #async_set_client_encoding, but is implemented using the synchronous command processing API of libpq.
|
2895
|
+
* See #async_exec for the differences between the two API variants.
|
2896
|
+
* It's not recommended to use explicit sync or async variants but #set_client_encoding instead, unless you have a good reason to do so.
|
2942
2897
|
*/
|
2943
2898
|
static VALUE
|
2944
|
-
|
2899
|
+
pgconn_sync_set_client_encoding(VALUE self, VALUE str)
|
2945
2900
|
{
|
2946
2901
|
PGconn *conn = pg_get_pgconn( self );
|
2947
2902
|
|
@@ -2955,49 +2910,6 @@ pgconn_set_client_encoding(VALUE self, VALUE str)
|
|
2955
2910
|
return Qnil;
|
2956
2911
|
}
|
2957
2912
|
|
2958
|
-
/*
|
2959
|
-
* call-seq:
|
2960
|
-
* conn.transaction { |conn| ... } -> result of the block
|
2961
|
-
*
|
2962
|
-
* Executes a +BEGIN+ at the start of the block,
|
2963
|
-
* and a +COMMIT+ at the end of the block, or
|
2964
|
-
* +ROLLBACK+ if any exception occurs.
|
2965
|
-
*/
|
2966
|
-
static VALUE
|
2967
|
-
pgconn_transaction(VALUE self)
|
2968
|
-
{
|
2969
|
-
PGconn *conn = pg_get_pgconn(self);
|
2970
|
-
PGresult *result;
|
2971
|
-
VALUE rb_pgresult;
|
2972
|
-
VALUE block_result = Qnil;
|
2973
|
-
int status;
|
2974
|
-
|
2975
|
-
if (rb_block_given_p()) {
|
2976
|
-
result = gvl_PQexec(conn, "BEGIN");
|
2977
|
-
rb_pgresult = pg_new_result(result, self);
|
2978
|
-
pg_result_check(rb_pgresult);
|
2979
|
-
block_result = rb_protect(rb_yield, self, &status);
|
2980
|
-
if(status == 0) {
|
2981
|
-
result = gvl_PQexec(conn, "COMMIT");
|
2982
|
-
rb_pgresult = pg_new_result(result, self);
|
2983
|
-
pg_result_check(rb_pgresult);
|
2984
|
-
}
|
2985
|
-
else {
|
2986
|
-
/* exception occurred, ROLLBACK and re-raise */
|
2987
|
-
result = gvl_PQexec(conn, "ROLLBACK");
|
2988
|
-
rb_pgresult = pg_new_result(result, self);
|
2989
|
-
pg_result_check(rb_pgresult);
|
2990
|
-
rb_jump_tag(status);
|
2991
|
-
}
|
2992
|
-
|
2993
|
-
}
|
2994
|
-
else {
|
2995
|
-
/* no block supplied? */
|
2996
|
-
rb_raise(rb_eArgError, "Must supply block for PG::Connection#transaction");
|
2997
|
-
}
|
2998
|
-
return block_result;
|
2999
|
-
}
|
3000
|
-
|
3001
2913
|
|
3002
2914
|
/*
|
3003
2915
|
* call-seq:
|
@@ -3042,14 +2954,12 @@ pgconn_s_quote_ident(VALUE self, VALUE str_or_array)
|
|
3042
2954
|
int enc_idx;
|
3043
2955
|
|
3044
2956
|
if( rb_obj_is_kind_of(self, rb_cPGconn) ){
|
3045
|
-
enc_idx =
|
2957
|
+
enc_idx = pg_get_connection(self)->enc_idx;
|
3046
2958
|
}else{
|
3047
2959
|
enc_idx = RB_TYPE_P(str_or_array, T_STRING) ? ENCODING_GET( str_or_array ) : rb_ascii8bit_encindex();
|
3048
2960
|
}
|
3049
2961
|
pg_text_enc_identifier(NULL, str_or_array, NULL, &ret, enc_idx);
|
3050
2962
|
|
3051
|
-
OBJ_INFECT(ret, str_or_array);
|
3052
|
-
|
3053
2963
|
return ret;
|
3054
2964
|
}
|
3055
2965
|
|
@@ -3076,8 +2986,6 @@ get_result_readable(PGconn *conn)
|
|
3076
2986
|
*/
|
3077
2987
|
static VALUE
|
3078
2988
|
pgconn_block( int argc, VALUE *argv, VALUE self ) {
|
3079
|
-
PGconn *conn = pg_get_pgconn( self );
|
3080
|
-
|
3081
2989
|
struct timeval timeout;
|
3082
2990
|
struct timeval *ptimeout = NULL;
|
3083
2991
|
VALUE timeout_in;
|
@@ -3091,7 +2999,7 @@ pgconn_block( int argc, VALUE *argv, VALUE self ) {
|
|
3091
2999
|
ptimeout = &timeout;
|
3092
3000
|
}
|
3093
3001
|
|
3094
|
-
ret = wait_socket_readable(
|
3002
|
+
ret = wait_socket_readable( self, ptimeout, get_result_readable);
|
3095
3003
|
|
3096
3004
|
if( !ret )
|
3097
3005
|
return Qfalse;
|
@@ -3100,6 +3008,42 @@ pgconn_block( int argc, VALUE *argv, VALUE self ) {
|
|
3100
3008
|
}
|
3101
3009
|
|
3102
3010
|
|
3011
|
+
/*
|
3012
|
+
* call-seq:
|
3013
|
+
* conn.sync_get_last_result( ) -> PG::Result
|
3014
|
+
*
|
3015
|
+
* This function has the same behavior as #async_get_last_result, but is implemented using the synchronous command processing API of libpq.
|
3016
|
+
* See #async_exec for the differences between the two API variants.
|
3017
|
+
* It's not recommended to use explicit sync or async variants but #get_last_result instead, unless you have a good reason to do so.
|
3018
|
+
*/
|
3019
|
+
static VALUE
|
3020
|
+
pgconn_sync_get_last_result(VALUE self)
|
3021
|
+
{
|
3022
|
+
PGconn *conn = pg_get_pgconn(self);
|
3023
|
+
VALUE rb_pgresult = Qnil;
|
3024
|
+
PGresult *cur, *prev;
|
3025
|
+
|
3026
|
+
|
3027
|
+
cur = prev = NULL;
|
3028
|
+
while ((cur = gvl_PQgetResult(conn)) != NULL) {
|
3029
|
+
int status;
|
3030
|
+
|
3031
|
+
if (prev) PQclear(prev);
|
3032
|
+
prev = cur;
|
3033
|
+
|
3034
|
+
status = PQresultStatus(cur);
|
3035
|
+
if (status == PGRES_COPY_OUT || status == PGRES_COPY_IN || status == PGRES_COPY_BOTH)
|
3036
|
+
break;
|
3037
|
+
}
|
3038
|
+
|
3039
|
+
if (prev) {
|
3040
|
+
rb_pgresult = pg_new_result( prev, self );
|
3041
|
+
pg_result_check(rb_pgresult);
|
3042
|
+
}
|
3043
|
+
|
3044
|
+
return rb_pgresult;
|
3045
|
+
}
|
3046
|
+
|
3103
3047
|
/*
|
3104
3048
|
* call-seq:
|
3105
3049
|
* conn.get_last_result( ) -> PG::Result
|
@@ -3110,27 +3054,35 @@ pgconn_block( int argc, VALUE *argv, VALUE self ) {
|
|
3110
3054
|
* returns the last non-NULL result, or +nil+ if no
|
3111
3055
|
* results are available.
|
3112
3056
|
*
|
3057
|
+
* If the last result contains a bad result_status, an
|
3058
|
+
* appropriate exception is raised.
|
3059
|
+
*
|
3113
3060
|
* This function is similar to #get_result
|
3114
3061
|
* except that it is designed to get one and only
|
3115
|
-
* one result.
|
3062
|
+
* one result and that it checks the result state.
|
3116
3063
|
*/
|
3117
3064
|
static VALUE
|
3118
|
-
|
3065
|
+
pgconn_async_get_last_result(VALUE self)
|
3119
3066
|
{
|
3120
3067
|
PGconn *conn = pg_get_pgconn(self);
|
3121
3068
|
VALUE rb_pgresult = Qnil;
|
3122
3069
|
PGresult *cur, *prev;
|
3123
3070
|
|
3124
|
-
|
3125
|
-
|
3126
|
-
while ((cur = gvl_PQgetResult(conn)) != NULL) {
|
3071
|
+
cur = prev = NULL;
|
3072
|
+
for(;;) {
|
3127
3073
|
int status;
|
3128
3074
|
|
3075
|
+
pgconn_block( 0, NULL, self ); /* wait for input (without blocking) before reading the last result */
|
3076
|
+
|
3077
|
+
cur = gvl_PQgetResult(conn);
|
3078
|
+
if (cur == NULL)
|
3079
|
+
break;
|
3080
|
+
|
3129
3081
|
if (prev) PQclear(prev);
|
3130
3082
|
prev = cur;
|
3131
3083
|
|
3132
3084
|
status = PQresultStatus(cur);
|
3133
|
-
if (status == PGRES_COPY_OUT || status == PGRES_COPY_IN)
|
3085
|
+
if (status == PGRES_COPY_OUT || status == PGRES_COPY_IN || status == PGRES_COPY_BOTH)
|
3134
3086
|
break;
|
3135
3087
|
}
|
3136
3088
|
|
@@ -3154,39 +3106,89 @@ static VALUE
|
|
3154
3106
|
pgconn_discard_results(VALUE self)
|
3155
3107
|
{
|
3156
3108
|
PGconn *conn = pg_get_pgconn(self);
|
3109
|
+
VALUE socket_io;
|
3157
3110
|
|
3158
|
-
|
3159
|
-
|
3160
|
-
|
3111
|
+
if( PQtransactionStatus(conn) == PQTRANS_IDLE ) {
|
3112
|
+
return Qnil;
|
3113
|
+
}
|
3114
|
+
|
3115
|
+
socket_io = pgconn_socket_io(self);
|
3116
|
+
|
3117
|
+
for(;;) {
|
3118
|
+
PGresult *cur;
|
3119
|
+
int status;
|
3120
|
+
|
3121
|
+
/* pgconn_block() raises an exception in case of errors.
|
3122
|
+
* To avoid this call pg_rb_io_wait() and PQconsumeInput() without rb_raise().
|
3123
|
+
*/
|
3124
|
+
while( gvl_PQisBusy(conn) ){
|
3125
|
+
pg_rb_io_wait(socket_io, RB_INT2NUM(PG_RUBY_IO_READABLE), Qnil);
|
3126
|
+
if ( PQconsumeInput(conn) == 0 ) {
|
3127
|
+
pgconn_close_socket_io(self);
|
3128
|
+
return Qfalse;
|
3129
|
+
}
|
3130
|
+
}
|
3131
|
+
|
3132
|
+
cur = gvl_PQgetResult(conn);
|
3133
|
+
if( cur == NULL) break;
|
3134
|
+
|
3135
|
+
status = PQresultStatus(cur);
|
3161
3136
|
PQclear(cur);
|
3162
3137
|
if (status == PGRES_COPY_IN){
|
3163
3138
|
gvl_PQputCopyEnd(conn, "COPY terminated by new PQexec");
|
3164
3139
|
}
|
3165
3140
|
if (status == PGRES_COPY_OUT){
|
3166
|
-
|
3167
|
-
|
3168
|
-
|
3141
|
+
for(;;) {
|
3142
|
+
char *buffer = NULL;
|
3143
|
+
int st = gvl_PQgetCopyData(conn, &buffer, 1);
|
3144
|
+
if( st == 0 ) {
|
3145
|
+
/* would block -> wait for readable data */
|
3146
|
+
pg_rb_io_wait(socket_io, RB_INT2NUM(PG_RUBY_IO_READABLE), Qnil);
|
3147
|
+
if ( PQconsumeInput(conn) == 0 ) {
|
3148
|
+
pgconn_close_socket_io(self);
|
3149
|
+
return Qfalse;
|
3150
|
+
}
|
3151
|
+
} else if( st > 0 ) {
|
3152
|
+
/* some data retrieved -> discard it */
|
3153
|
+
PQfreemem(buffer);
|
3154
|
+
} else {
|
3155
|
+
/* no more data */
|
3156
|
+
break;
|
3157
|
+
}
|
3158
|
+
}
|
3169
3159
|
}
|
3170
3160
|
}
|
3171
3161
|
|
3172
|
-
return
|
3162
|
+
return Qtrue;
|
3173
3163
|
}
|
3174
3164
|
|
3175
3165
|
/*
|
3176
3166
|
* call-seq:
|
3177
|
-
* conn.
|
3178
|
-
* conn.
|
3167
|
+
* conn.exec(sql) -> PG::Result
|
3168
|
+
* conn.exec(sql) {|pg_result| block }
|
3179
3169
|
*
|
3180
|
-
*
|
3181
|
-
*
|
3182
|
-
*
|
3170
|
+
* Sends SQL query request specified by _sql_ to PostgreSQL.
|
3171
|
+
* On success, it returns a PG::Result instance with all result rows and columns.
|
3172
|
+
* On failure, it raises a PG::Error.
|
3183
3173
|
*
|
3184
|
-
*
|
3185
|
-
*
|
3174
|
+
* For backward compatibility, if you pass more than one parameter to this method,
|
3175
|
+
* it will call #exec_params for you. New code should explicitly use #exec_params if
|
3176
|
+
* argument placeholders are used.
|
3186
3177
|
*
|
3187
|
-
*
|
3188
|
-
*
|
3189
|
-
*
|
3178
|
+
* If the optional code block is given, it will be passed <i>result</i> as an argument,
|
3179
|
+
* and the PG::Result object will automatically be cleared when the block terminates.
|
3180
|
+
* In this instance, <code>conn.exec</code> returns the value of the block.
|
3181
|
+
*
|
3182
|
+
* #exec is an alias for #async_exec which is almost identical to #sync_exec .
|
3183
|
+
* #sync_exec is implemented on the simpler synchronous command processing API of libpq, whereas
|
3184
|
+
* #async_exec is implemented on the asynchronous API and on ruby's IO mechanisms.
|
3185
|
+
* Only #async_exec is compatible to <tt>Fiber.scheduler</tt> based asynchronous IO processing introduced in ruby-3.0.
|
3186
|
+
* Both methods ensure that other threads can process while waiting for the server to
|
3187
|
+
* complete the request, but #sync_exec blocks all signals to be processed until the query is finished.
|
3188
|
+
* This is most notably visible by a delayed reaction to Control+C.
|
3189
|
+
* It's not recommended to use explicit sync or async variants but #exec instead, unless you have a good reason to do so.
|
3190
|
+
*
|
3191
|
+
* See also corresponding {libpq function}[https://www.postgresql.org/docs/current/libpq-exec.html#LIBPQ-PQEXEC].
|
3190
3192
|
*/
|
3191
3193
|
static VALUE
|
3192
3194
|
pgconn_async_exec(int argc, VALUE *argv, VALUE self)
|
@@ -3195,8 +3197,7 @@ pgconn_async_exec(int argc, VALUE *argv, VALUE self)
|
|
3195
3197
|
|
3196
3198
|
pgconn_discard_results( self );
|
3197
3199
|
pgconn_send_query( argc, argv, self );
|
3198
|
-
|
3199
|
-
rb_pgresult = pgconn_get_last_result( self );
|
3200
|
+
rb_pgresult = pgconn_async_get_last_result( self );
|
3200
3201
|
|
3201
3202
|
if ( rb_block_given_p() ) {
|
3202
3203
|
return rb_ensure( rb_yield, rb_pgresult, pg_result_clear, rb_pgresult );
|
@@ -3207,11 +3208,53 @@ pgconn_async_exec(int argc, VALUE *argv, VALUE self)
|
|
3207
3208
|
|
3208
3209
|
/*
|
3209
3210
|
* call-seq:
|
3210
|
-
* conn.
|
3211
|
-
* conn.
|
3211
|
+
* conn.exec_params(sql, params [, result_format [, type_map ]] ) -> nil
|
3212
|
+
* conn.exec_params(sql, params [, result_format [, type_map ]] ) {|pg_result| block }
|
3212
3213
|
*
|
3213
|
-
*
|
3214
|
-
*
|
3214
|
+
* Sends SQL query request specified by +sql+ to PostgreSQL using placeholders
|
3215
|
+
* for parameters.
|
3216
|
+
*
|
3217
|
+
* Returns a PG::Result instance on success. On failure, it raises a PG::Error.
|
3218
|
+
*
|
3219
|
+
* +params+ is an array of the bind parameters for the SQL query.
|
3220
|
+
* Each element of the +params+ array may be either:
|
3221
|
+
* a hash of the form:
|
3222
|
+
* {:value => String (value of bind parameter)
|
3223
|
+
* :type => Integer (oid of type of bind parameter)
|
3224
|
+
* :format => Integer (0 for text, 1 for binary)
|
3225
|
+
* }
|
3226
|
+
* or, it may be a String. If it is a string, that is equivalent to the hash:
|
3227
|
+
* { :value => <string value>, :type => 0, :format => 0 }
|
3228
|
+
*
|
3229
|
+
* PostgreSQL bind parameters are represented as $1, $2, $3, etc.,
|
3230
|
+
* inside the SQL query. The 0th element of the +params+ array is bound
|
3231
|
+
* to $1, the 1st element is bound to $2, etc. +nil+ is treated as +NULL+.
|
3232
|
+
*
|
3233
|
+
* If the types are not specified, they will be inferred by PostgreSQL.
|
3234
|
+
* Instead of specifying type oids, it's recommended to simply add
|
3235
|
+
* explicit casts in the query to ensure that the right type is used.
|
3236
|
+
*
|
3237
|
+
* For example: "SELECT $1::int"
|
3238
|
+
*
|
3239
|
+
* The optional +result_format+ should be 0 for text results, 1
|
3240
|
+
* for binary.
|
3241
|
+
*
|
3242
|
+
* +type_map+ can be a PG::TypeMap derivation (such as PG::BasicTypeMapForQueries).
|
3243
|
+
* This will type cast the params from various Ruby types before transmission
|
3244
|
+
* based on the encoders defined by the type map. When a type encoder is used
|
3245
|
+
* the format and oid of a given bind parameter are retrieved from the encoder
|
3246
|
+
* instead out of the hash form described above.
|
3247
|
+
*
|
3248
|
+
* If the optional code block is given, it will be passed <i>result</i> as an argument,
|
3249
|
+
* and the PG::Result object will automatically be cleared when the block terminates.
|
3250
|
+
* In this instance, <code>conn.exec</code> returns the value of the block.
|
3251
|
+
*
|
3252
|
+
* 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.
|
3253
|
+
* Unlike #exec, #exec_params allows at most one SQL command in the given string.
|
3254
|
+
* (There can be semicolons in it, but not more than one nonempty command.)
|
3255
|
+
* This is a limitation of the underlying protocol, but has some usefulness as an extra defense against SQL-injection attacks.
|
3256
|
+
*
|
3257
|
+
* See also corresponding {libpq function}[https://www.postgresql.org/docs/current/libpq-exec.html#LIBPQ-PQEXECPARAMS].
|
3215
3258
|
*/
|
3216
3259
|
static VALUE
|
3217
3260
|
pgconn_async_exec_params(int argc, VALUE *argv, VALUE self)
|
@@ -3226,8 +3269,7 @@ pgconn_async_exec_params(int argc, VALUE *argv, VALUE self)
|
|
3226
3269
|
} else {
|
3227
3270
|
pgconn_send_query_params( argc, argv, self );
|
3228
3271
|
}
|
3229
|
-
|
3230
|
-
rb_pgresult = pgconn_get_last_result( self );
|
3272
|
+
rb_pgresult = pgconn_async_get_last_result( self );
|
3231
3273
|
|
3232
3274
|
if ( rb_block_given_p() ) {
|
3233
3275
|
return rb_ensure( rb_yield, rb_pgresult, pg_result_clear, rb_pgresult );
|
@@ -3238,10 +3280,25 @@ pgconn_async_exec_params(int argc, VALUE *argv, VALUE self)
|
|
3238
3280
|
|
3239
3281
|
/*
|
3240
3282
|
* call-seq:
|
3241
|
-
* conn.
|
3283
|
+
* conn.prepare(stmt_name, sql [, param_types ] ) -> PG::Result
|
3242
3284
|
*
|
3243
|
-
*
|
3244
|
-
*
|
3285
|
+
* Prepares statement _sql_ with name _name_ to be executed later.
|
3286
|
+
* Returns a PG::Result instance on success.
|
3287
|
+
* On failure, it raises a PG::Error.
|
3288
|
+
*
|
3289
|
+
* +param_types+ is an optional parameter to specify the Oids of the
|
3290
|
+
* types of the parameters.
|
3291
|
+
*
|
3292
|
+
* If the types are not specified, they will be inferred by PostgreSQL.
|
3293
|
+
* Instead of specifying type oids, it's recommended to simply add
|
3294
|
+
* explicit casts in the query to ensure that the right type is used.
|
3295
|
+
*
|
3296
|
+
* For example: "SELECT $1::int"
|
3297
|
+
*
|
3298
|
+
* PostgreSQL bind parameters are represented as $1, $2, $3, etc.,
|
3299
|
+
* inside the SQL query.
|
3300
|
+
*
|
3301
|
+
* See also corresponding {libpq function}[https://www.postgresql.org/docs/current/libpq-exec.html#LIBPQ-PQPREPARE].
|
3245
3302
|
*/
|
3246
3303
|
static VALUE
|
3247
3304
|
pgconn_async_prepare(int argc, VALUE *argv, VALUE self)
|
@@ -3250,8 +3307,7 @@ pgconn_async_prepare(int argc, VALUE *argv, VALUE self)
|
|
3250
3307
|
|
3251
3308
|
pgconn_discard_results( self );
|
3252
3309
|
pgconn_send_prepare( argc, argv, self );
|
3253
|
-
|
3254
|
-
rb_pgresult = pgconn_get_last_result( self );
|
3310
|
+
rb_pgresult = pgconn_async_get_last_result( self );
|
3255
3311
|
|
3256
3312
|
if ( rb_block_given_p() ) {
|
3257
3313
|
return rb_ensure( rb_yield, rb_pgresult, pg_result_clear, rb_pgresult );
|
@@ -3262,11 +3318,40 @@ pgconn_async_prepare(int argc, VALUE *argv, VALUE self)
|
|
3262
3318
|
|
3263
3319
|
/*
|
3264
3320
|
* call-seq:
|
3265
|
-
* conn.
|
3266
|
-
* conn.
|
3321
|
+
* conn.exec_prepared(statement_name [, params, result_format[, type_map]] ) -> PG::Result
|
3322
|
+
* conn.exec_prepared(statement_name [, params, result_format[, type_map]] ) {|pg_result| block }
|
3267
3323
|
*
|
3268
|
-
*
|
3269
|
-
*
|
3324
|
+
* Execute prepared named statement specified by _statement_name_.
|
3325
|
+
* Returns a PG::Result instance on success.
|
3326
|
+
* On failure, it raises a PG::Error.
|
3327
|
+
*
|
3328
|
+
* +params+ is an array of the optional bind parameters for the
|
3329
|
+
* SQL query. Each element of the +params+ array may be either:
|
3330
|
+
* a hash of the form:
|
3331
|
+
* {:value => String (value of bind parameter)
|
3332
|
+
* :format => Integer (0 for text, 1 for binary)
|
3333
|
+
* }
|
3334
|
+
* or, it may be a String. If it is a string, that is equivalent to the hash:
|
3335
|
+
* { :value => <string value>, :format => 0 }
|
3336
|
+
*
|
3337
|
+
* PostgreSQL bind parameters are represented as $1, $2, $3, etc.,
|
3338
|
+
* inside the SQL query. The 0th element of the +params+ array is bound
|
3339
|
+
* to $1, the 1st element is bound to $2, etc. +nil+ is treated as +NULL+.
|
3340
|
+
*
|
3341
|
+
* The optional +result_format+ should be 0 for text results, 1
|
3342
|
+
* for binary.
|
3343
|
+
*
|
3344
|
+
* +type_map+ can be a PG::TypeMap derivation (such as PG::BasicTypeMapForQueries).
|
3345
|
+
* This will type cast the params from various Ruby types before transmission
|
3346
|
+
* based on the encoders defined by the type map. When a type encoder is used
|
3347
|
+
* the format and oid of a given bind parameter are retrieved from the encoder
|
3348
|
+
* instead out of the hash form described above.
|
3349
|
+
*
|
3350
|
+
* If the optional code block is given, it will be passed <i>result</i> as an argument,
|
3351
|
+
* and the PG::Result object will automatically be cleared when the block terminates.
|
3352
|
+
* In this instance, <code>conn.exec_prepared</code> returns the value of the block.
|
3353
|
+
*
|
3354
|
+
* See also corresponding {libpq function}[https://www.postgresql.org/docs/current/libpq-exec.html#LIBPQ-PQEXECPREPARED].
|
3270
3355
|
*/
|
3271
3356
|
static VALUE
|
3272
3357
|
pgconn_async_exec_prepared(int argc, VALUE *argv, VALUE self)
|
@@ -3275,8 +3360,7 @@ pgconn_async_exec_prepared(int argc, VALUE *argv, VALUE self)
|
|
3275
3360
|
|
3276
3361
|
pgconn_discard_results( self );
|
3277
3362
|
pgconn_send_query_prepared( argc, argv, self );
|
3278
|
-
|
3279
|
-
rb_pgresult = pgconn_get_last_result( self );
|
3363
|
+
rb_pgresult = pgconn_async_get_last_result( self );
|
3280
3364
|
|
3281
3365
|
if ( rb_block_given_p() ) {
|
3282
3366
|
return rb_ensure( rb_yield, rb_pgresult, pg_result_clear, rb_pgresult );
|
@@ -3287,10 +3371,11 @@ pgconn_async_exec_prepared(int argc, VALUE *argv, VALUE self)
|
|
3287
3371
|
|
3288
3372
|
/*
|
3289
3373
|
* call-seq:
|
3290
|
-
* conn.
|
3374
|
+
* conn.describe_portal( portal_name ) -> PG::Result
|
3291
3375
|
*
|
3292
|
-
*
|
3293
|
-
*
|
3376
|
+
* Retrieve information about the portal _portal_name_.
|
3377
|
+
*
|
3378
|
+
* See also corresponding {libpq function}[https://www.postgresql.org/docs/current/libpq-exec.html#LIBPQ-PQDESCRIBEPORTAL].
|
3294
3379
|
*/
|
3295
3380
|
static VALUE
|
3296
3381
|
pgconn_async_describe_portal(VALUE self, VALUE portal)
|
@@ -3299,8 +3384,7 @@ pgconn_async_describe_portal(VALUE self, VALUE portal)
|
|
3299
3384
|
|
3300
3385
|
pgconn_discard_results( self );
|
3301
3386
|
pgconn_send_describe_portal( self, portal );
|
3302
|
-
|
3303
|
-
rb_pgresult = pgconn_get_last_result( self );
|
3387
|
+
rb_pgresult = pgconn_async_get_last_result( self );
|
3304
3388
|
|
3305
3389
|
if ( rb_block_given_p() ) {
|
3306
3390
|
return rb_ensure( rb_yield, rb_pgresult, pg_result_clear, rb_pgresult );
|
@@ -3311,10 +3395,11 @@ pgconn_async_describe_portal(VALUE self, VALUE portal)
|
|
3311
3395
|
|
3312
3396
|
/*
|
3313
3397
|
* call-seq:
|
3314
|
-
* conn.
|
3398
|
+
* conn.describe_prepared( statement_name ) -> PG::Result
|
3315
3399
|
*
|
3316
|
-
*
|
3317
|
-
*
|
3400
|
+
* Retrieve information about the prepared statement _statement_name_.
|
3401
|
+
*
|
3402
|
+
* See also corresponding {libpq function}[https://www.postgresql.org/docs/current/libpq-exec.html#LIBPQ-PQDESCRIBEPREPARED].
|
3318
3403
|
*/
|
3319
3404
|
static VALUE
|
3320
3405
|
pgconn_async_describe_prepared(VALUE self, VALUE stmt_name)
|
@@ -3323,8 +3408,7 @@ pgconn_async_describe_prepared(VALUE self, VALUE stmt_name)
|
|
3323
3408
|
|
3324
3409
|
pgconn_discard_results( self );
|
3325
3410
|
pgconn_send_describe_prepared( self, stmt_name );
|
3326
|
-
|
3327
|
-
rb_pgresult = pgconn_get_last_result( self );
|
3411
|
+
rb_pgresult = pgconn_async_get_last_result( self );
|
3328
3412
|
|
3329
3413
|
if ( rb_block_given_p() ) {
|
3330
3414
|
return rb_ensure( rb_yield, rb_pgresult, pg_result_clear, rb_pgresult );
|
@@ -3338,7 +3422,7 @@ pgconn_async_describe_prepared(VALUE self, VALUE stmt_name)
|
|
3338
3422
|
* call-seq:
|
3339
3423
|
* conn.ssl_in_use? -> Boolean
|
3340
3424
|
*
|
3341
|
-
* Returns +true+ if the connection uses SSL, +false+ if not.
|
3425
|
+
* Returns +true+ if the connection uses SSL/TLS, +false+ if not.
|
3342
3426
|
*
|
3343
3427
|
* Available since PostgreSQL-9.5
|
3344
3428
|
*/
|
@@ -3372,7 +3456,7 @@ pgconn_ssl_in_use(VALUE self)
|
|
3372
3456
|
* 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".
|
3373
3457
|
*
|
3374
3458
|
*
|
3375
|
-
* See also #ssl_attribute_names and
|
3459
|
+
* See also #ssl_attribute_names and the {corresponding libpq function}[https://www.postgresql.org/docs/current/libpq-status.html#LIBPQ-PQSSLATTRIBUTE].
|
3376
3460
|
*
|
3377
3461
|
* Available since PostgreSQL-9.5
|
3378
3462
|
*/
|
@@ -3412,6 +3496,126 @@ pgconn_ssl_attribute_names(VALUE self)
|
|
3412
3496
|
#endif
|
3413
3497
|
|
3414
3498
|
|
3499
|
+
#ifdef HAVE_PQENTERPIPELINEMODE
|
3500
|
+
/*
|
3501
|
+
* call-seq:
|
3502
|
+
* conn.pipeline_status -> Integer
|
3503
|
+
*
|
3504
|
+
* Returns the current pipeline mode status of the libpq connection.
|
3505
|
+
*
|
3506
|
+
* PQpipelineStatus can return one of the following values:
|
3507
|
+
*
|
3508
|
+
* * PQ_PIPELINE_ON - The libpq connection is in pipeline mode.
|
3509
|
+
* * PQ_PIPELINE_OFF - The libpq connection is not in pipeline mode.
|
3510
|
+
* * PQ_PIPELINE_ABORTED - The libpq connection is in pipeline mode and an error occurred while processing the current pipeline.
|
3511
|
+
* The aborted flag is cleared when PQgetResult returns a result of type PGRES_PIPELINE_SYNC.
|
3512
|
+
*
|
3513
|
+
* Available since PostgreSQL-14
|
3514
|
+
*/
|
3515
|
+
static VALUE
|
3516
|
+
pgconn_pipeline_status(VALUE self)
|
3517
|
+
{
|
3518
|
+
int res = PQpipelineStatus(pg_get_pgconn(self));
|
3519
|
+
return INT2FIX(res);
|
3520
|
+
}
|
3521
|
+
|
3522
|
+
|
3523
|
+
/*
|
3524
|
+
* call-seq:
|
3525
|
+
* conn.enter_pipeline_mode -> nil
|
3526
|
+
*
|
3527
|
+
* Causes a connection to enter pipeline mode if it is currently idle or already in pipeline mode.
|
3528
|
+
*
|
3529
|
+
* Raises PG::Error and has no effect if the connection is not currently idle, i.e., it has a result ready, or it is waiting for more input from the server, etc.
|
3530
|
+
* This function does not actually send anything to the server, it just changes the libpq connection state.
|
3531
|
+
*
|
3532
|
+
* Available since PostgreSQL-14
|
3533
|
+
*/
|
3534
|
+
static VALUE
|
3535
|
+
pgconn_enter_pipeline_mode(VALUE self)
|
3536
|
+
{
|
3537
|
+
PGconn *conn = pg_get_pgconn(self);
|
3538
|
+
int res = PQenterPipelineMode(conn);
|
3539
|
+
if( res == 1 ) {
|
3540
|
+
return Qnil;
|
3541
|
+
} else {
|
3542
|
+
rb_raise(rb_ePGerror, "%s", PQerrorMessage(conn));
|
3543
|
+
}
|
3544
|
+
}
|
3545
|
+
|
3546
|
+
/*
|
3547
|
+
* call-seq:
|
3548
|
+
* conn.exit_pipeline_mode -> nil
|
3549
|
+
*
|
3550
|
+
* Causes a connection to exit pipeline mode if it is currently in pipeline mode with an empty queue and no pending results.
|
3551
|
+
*
|
3552
|
+
* Takes no action if not in pipeline mode.
|
3553
|
+
* Raises PG::Error if the current statement isn't finished processing, or PQgetResult has not been called to collect results from all previously sent query.
|
3554
|
+
*
|
3555
|
+
* Available since PostgreSQL-14
|
3556
|
+
*/
|
3557
|
+
static VALUE
|
3558
|
+
pgconn_exit_pipeline_mode(VALUE self)
|
3559
|
+
{
|
3560
|
+
PGconn *conn = pg_get_pgconn(self);
|
3561
|
+
int res = PQexitPipelineMode(conn);
|
3562
|
+
if( res == 1 ) {
|
3563
|
+
return Qnil;
|
3564
|
+
} else {
|
3565
|
+
rb_raise(rb_ePGerror, "%s", PQerrorMessage(conn));
|
3566
|
+
}
|
3567
|
+
}
|
3568
|
+
|
3569
|
+
|
3570
|
+
/*
|
3571
|
+
* call-seq:
|
3572
|
+
* conn.pipeline_sync -> nil
|
3573
|
+
*
|
3574
|
+
* Marks a synchronization point in a pipeline by sending a sync message and flushing the send buffer.
|
3575
|
+
* This serves as the delimiter of an implicit transaction and an error recovery point; see Section 34.5.1.3 of the PostgreSQL documentation.
|
3576
|
+
*
|
3577
|
+
* Raises PG::Error if the connection is not in pipeline mode or sending a sync message failed.
|
3578
|
+
*
|
3579
|
+
* Available since PostgreSQL-14
|
3580
|
+
*/
|
3581
|
+
static VALUE
|
3582
|
+
pgconn_pipeline_sync(VALUE self)
|
3583
|
+
{
|
3584
|
+
PGconn *conn = pg_get_pgconn(self);
|
3585
|
+
int res = PQpipelineSync(conn);
|
3586
|
+
if( res == 1 ) {
|
3587
|
+
return Qnil;
|
3588
|
+
} else {
|
3589
|
+
rb_raise(rb_ePGerror, "%s", PQerrorMessage(conn));
|
3590
|
+
}
|
3591
|
+
}
|
3592
|
+
|
3593
|
+
/*
|
3594
|
+
* call-seq:
|
3595
|
+
* conn.pipeline_sync -> nil
|
3596
|
+
*
|
3597
|
+
* Sends a request for the server to flush its output buffer.
|
3598
|
+
*
|
3599
|
+
* The server flushes its output buffer automatically as a result of Connection#pipeline_sync being called, or on any request when not in pipeline mode.
|
3600
|
+
* This function is useful to cause the server to flush its output buffer in pipeline mode without establishing a synchronization point.
|
3601
|
+
* Note that the request is not itself flushed to the server automatically; use Connection#flush if necessary.
|
3602
|
+
*
|
3603
|
+
* Available since PostgreSQL-14
|
3604
|
+
*/
|
3605
|
+
static VALUE
|
3606
|
+
pgconn_send_flush_request(VALUE self)
|
3607
|
+
{
|
3608
|
+
PGconn *conn = pg_get_pgconn(self);
|
3609
|
+
int res = PQsendFlushRequest(conn);
|
3610
|
+
if( res == 1 ) {
|
3611
|
+
return Qnil;
|
3612
|
+
} else {
|
3613
|
+
rb_raise(rb_ePGerror, "%s", PQerrorMessage(conn));
|
3614
|
+
}
|
3615
|
+
}
|
3616
|
+
|
3617
|
+
#endif
|
3618
|
+
|
3415
3619
|
/**************************************************************************
|
3416
3620
|
* LARGE OBJECT SUPPORT
|
3417
3621
|
**************************************************************************/
|
@@ -3600,7 +3804,7 @@ pgconn_loread(VALUE self, VALUE in_lo_desc, VALUE in_len)
|
|
3600
3804
|
return Qnil;
|
3601
3805
|
}
|
3602
3806
|
|
3603
|
-
str =
|
3807
|
+
str = rb_str_new(buffer, ret);
|
3604
3808
|
xfree(buffer);
|
3605
3809
|
|
3606
3810
|
return str;
|
@@ -3704,12 +3908,15 @@ pgconn_lounlink(VALUE self, VALUE in_oid)
|
|
3704
3908
|
}
|
3705
3909
|
|
3706
3910
|
|
3707
|
-
void
|
3911
|
+
static void
|
3708
3912
|
pgconn_set_internal_encoding_index( VALUE self )
|
3709
3913
|
{
|
3710
|
-
|
3711
|
-
|
3712
|
-
|
3914
|
+
int enc_idx;
|
3915
|
+
t_pg_connection *this = pg_get_connection_safe( self );
|
3916
|
+
rb_encoding *enc = pg_conn_enc_get( this->pgconn );
|
3917
|
+
enc_idx = rb_enc_to_index(enc);
|
3918
|
+
if( enc_idx >= (1<<(PG_ENC_IDX_BITS-1)) ) rb_raise(rb_eArgError, "unsupported encoding index %d", enc_idx);
|
3919
|
+
this->enc_idx = enc_idx;
|
3713
3920
|
}
|
3714
3921
|
|
3715
3922
|
/*
|
@@ -3752,13 +3959,12 @@ static VALUE pgconn_external_encoding(VALUE self);
|
|
3752
3959
|
static VALUE
|
3753
3960
|
pgconn_internal_encoding_set(VALUE self, VALUE enc)
|
3754
3961
|
{
|
3755
|
-
VALUE enc_inspect;
|
3756
3962
|
if (NIL_P(enc)) {
|
3757
|
-
|
3963
|
+
pgconn_sync_set_client_encoding( self, rb_usascii_str_new_cstr("SQL_ASCII") );
|
3758
3964
|
return enc;
|
3759
3965
|
}
|
3760
3966
|
else if ( TYPE(enc) == T_STRING && strcasecmp("JOHAB", StringValueCStr(enc)) == 0 ) {
|
3761
|
-
|
3967
|
+
pgconn_sync_set_client_encoding(self, rb_usascii_str_new_cstr("JOHAB"));
|
3762
3968
|
return enc;
|
3763
3969
|
}
|
3764
3970
|
else {
|
@@ -3773,11 +3979,6 @@ pgconn_internal_encoding_set(VALUE self, VALUE enc)
|
|
3773
3979
|
pgconn_set_internal_encoding_index( self );
|
3774
3980
|
return enc;
|
3775
3981
|
}
|
3776
|
-
|
3777
|
-
enc_inspect = rb_inspect(enc);
|
3778
|
-
rb_raise( rb_ePGerror, "unknown encoding: %s", StringValueCStr(enc_inspect) );
|
3779
|
-
|
3780
|
-
return Qnil;
|
3781
3982
|
}
|
3782
3983
|
|
3783
3984
|
|
@@ -3796,42 +3997,55 @@ pgconn_external_encoding(VALUE self)
|
|
3796
3997
|
rb_encoding *enc = NULL;
|
3797
3998
|
const char *pg_encname = NULL;
|
3798
3999
|
|
3799
|
-
/* Use cached value if found */
|
3800
|
-
if ( RTEST(this->external_encoding) ) return this->external_encoding;
|
3801
|
-
|
3802
4000
|
pg_encname = PQparameterStatus( this->pgconn, "server_encoding" );
|
3803
4001
|
enc = pg_get_pg_encname_as_rb_encoding( pg_encname );
|
3804
|
-
|
3805
|
-
|
3806
|
-
return this->external_encoding;
|
4002
|
+
return rb_enc_from_encoding( enc );
|
3807
4003
|
}
|
3808
4004
|
|
4005
|
+
/*
|
4006
|
+
* call-seq:
|
4007
|
+
* conn.set_client_encoding( encoding )
|
4008
|
+
*
|
4009
|
+
* Sets the client encoding to the _encoding_ String.
|
4010
|
+
*/
|
4011
|
+
static VALUE
|
4012
|
+
pgconn_async_set_client_encoding(VALUE self, VALUE encname)
|
4013
|
+
{
|
4014
|
+
VALUE query_format, query;
|
4015
|
+
|
4016
|
+
Check_Type(encname, T_STRING);
|
4017
|
+
query_format = rb_str_new_cstr("set client_encoding to '%s'");
|
4018
|
+
query = rb_funcall(query_format, rb_intern("%"), 1, encname);
|
4019
|
+
|
4020
|
+
pgconn_async_exec(1, &query, self);
|
4021
|
+
pgconn_set_internal_encoding_index( self );
|
4022
|
+
|
4023
|
+
return Qnil;
|
4024
|
+
}
|
3809
4025
|
|
3810
4026
|
static VALUE
|
3811
4027
|
pgconn_set_client_encoding_async1( VALUE args )
|
3812
4028
|
{
|
3813
4029
|
VALUE self = ((VALUE*)args)[0];
|
3814
4030
|
VALUE encname = ((VALUE*)args)[1];
|
3815
|
-
|
3816
|
-
VALUE query = rb_funcall(query_format, rb_intern("%"), 1, encname);
|
3817
|
-
|
3818
|
-
pgconn_async_exec(1, &query, self);
|
4031
|
+
pgconn_async_set_client_encoding(self, encname);
|
3819
4032
|
return 0;
|
3820
4033
|
}
|
3821
4034
|
|
3822
4035
|
|
3823
4036
|
static VALUE
|
3824
|
-
pgconn_set_client_encoding_async2( VALUE arg )
|
4037
|
+
pgconn_set_client_encoding_async2( VALUE arg, VALUE ex )
|
3825
4038
|
{
|
3826
4039
|
UNUSED(arg);
|
4040
|
+
UNUSED(ex);
|
3827
4041
|
return 1;
|
3828
4042
|
}
|
3829
4043
|
|
3830
4044
|
|
3831
4045
|
static VALUE
|
3832
|
-
pgconn_set_client_encoding_async( VALUE self,
|
4046
|
+
pgconn_set_client_encoding_async( VALUE self, VALUE encname )
|
3833
4047
|
{
|
3834
|
-
VALUE args[] = { self,
|
4048
|
+
VALUE args[] = { self, encname };
|
3835
4049
|
return rb_rescue(pgconn_set_client_encoding_async1, (VALUE)&args, pgconn_set_client_encoding_async2, Qnil);
|
3836
4050
|
}
|
3837
4051
|
|
@@ -3853,10 +4067,9 @@ pgconn_set_default_encoding( VALUE self )
|
|
3853
4067
|
|
3854
4068
|
if (( enc = rb_default_internal_encoding() )) {
|
3855
4069
|
encname = pg_get_rb_encoding_as_pg_encoding( enc );
|
3856
|
-
if ( pgconn_set_client_encoding_async(self, encname) != 0 )
|
4070
|
+
if ( pgconn_set_client_encoding_async(self, rb_str_new_cstr(encname)) != 0 )
|
3857
4071
|
rb_warning( "Failed to set the default_internal encoding to %s: '%s'",
|
3858
4072
|
encname, PQerrorMessage(conn) );
|
3859
|
-
pgconn_set_internal_encoding_index( self );
|
3860
4073
|
return rb_enc_from_encoding( enc );
|
3861
4074
|
} else {
|
3862
4075
|
pgconn_set_internal_encoding_index( self );
|
@@ -3878,12 +4091,12 @@ static VALUE
|
|
3878
4091
|
pgconn_type_map_for_queries_set(VALUE self, VALUE typemap)
|
3879
4092
|
{
|
3880
4093
|
t_pg_connection *this = pg_get_connection( self );
|
4094
|
+
t_typemap *tm;
|
4095
|
+
UNUSED(tm);
|
4096
|
+
|
4097
|
+
/* Check type of method param */
|
4098
|
+
TypedData_Get_Struct(typemap, t_typemap, &pg_typemap_type, tm);
|
3881
4099
|
|
3882
|
-
if ( !rb_obj_is_kind_of(typemap, rb_cTypeMap) ) {
|
3883
|
-
rb_raise( rb_eTypeError, "wrong argument type %s (expected kind of PG::TypeMap)",
|
3884
|
-
rb_obj_classname( typemap ) );
|
3885
|
-
}
|
3886
|
-
Check_Type(typemap, T_DATA);
|
3887
4100
|
this->type_map_for_queries = typemap;
|
3888
4101
|
|
3889
4102
|
return typemap;
|
@@ -3918,12 +4131,10 @@ static VALUE
|
|
3918
4131
|
pgconn_type_map_for_results_set(VALUE self, VALUE typemap)
|
3919
4132
|
{
|
3920
4133
|
t_pg_connection *this = pg_get_connection( self );
|
4134
|
+
t_typemap *tm;
|
4135
|
+
UNUSED(tm);
|
3921
4136
|
|
3922
|
-
|
3923
|
-
rb_raise( rb_eTypeError, "wrong argument type %s (expected kind of PG::TypeMap)",
|
3924
|
-
rb_obj_classname( typemap ) );
|
3925
|
-
}
|
3926
|
-
Check_Type(typemap, T_DATA);
|
4137
|
+
TypedData_Get_Struct(typemap, t_typemap, &pg_typemap_type, tm);
|
3927
4138
|
this->type_map_for_results = typemap;
|
3928
4139
|
|
3929
4140
|
return typemap;
|
@@ -3958,20 +4169,19 @@ pgconn_type_map_for_results_get(VALUE self)
|
|
3958
4169
|
*
|
3959
4170
|
*/
|
3960
4171
|
static VALUE
|
3961
|
-
pgconn_encoder_for_put_copy_data_set(VALUE self, VALUE
|
4172
|
+
pgconn_encoder_for_put_copy_data_set(VALUE self, VALUE encoder)
|
3962
4173
|
{
|
3963
4174
|
t_pg_connection *this = pg_get_connection( self );
|
3964
4175
|
|
3965
|
-
if(
|
3966
|
-
|
3967
|
-
|
3968
|
-
|
3969
|
-
|
3970
|
-
Check_Type(typemap, T_DATA);
|
4176
|
+
if( encoder != Qnil ){
|
4177
|
+
t_pg_coder *co;
|
4178
|
+
UNUSED(co);
|
4179
|
+
/* Check argument type */
|
4180
|
+
TypedData_Get_Struct(encoder, t_pg_coder, &pg_coder_type, co);
|
3971
4181
|
}
|
3972
|
-
this->encoder_for_put_copy_data =
|
4182
|
+
this->encoder_for_put_copy_data = encoder;
|
3973
4183
|
|
3974
|
-
return
|
4184
|
+
return encoder;
|
3975
4185
|
}
|
3976
4186
|
|
3977
4187
|
/*
|
@@ -4007,20 +4217,19 @@ pgconn_encoder_for_put_copy_data_get(VALUE self)
|
|
4007
4217
|
*
|
4008
4218
|
*/
|
4009
4219
|
static VALUE
|
4010
|
-
pgconn_decoder_for_get_copy_data_set(VALUE self, VALUE
|
4220
|
+
pgconn_decoder_for_get_copy_data_set(VALUE self, VALUE decoder)
|
4011
4221
|
{
|
4012
4222
|
t_pg_connection *this = pg_get_connection( self );
|
4013
4223
|
|
4014
|
-
if(
|
4015
|
-
|
4016
|
-
|
4017
|
-
|
4018
|
-
|
4019
|
-
Check_Type(typemap, T_DATA);
|
4224
|
+
if( decoder != Qnil ){
|
4225
|
+
t_pg_coder *co;
|
4226
|
+
UNUSED(co);
|
4227
|
+
/* Check argument type */
|
4228
|
+
TypedData_Get_Struct(decoder, t_pg_coder, &pg_coder_type, co);
|
4020
4229
|
}
|
4021
|
-
this->decoder_for_get_copy_data =
|
4230
|
+
this->decoder_for_get_copy_data = decoder;
|
4022
4231
|
|
4023
|
-
return
|
4232
|
+
return decoder;
|
4024
4233
|
}
|
4025
4234
|
|
4026
4235
|
/*
|
@@ -4045,16 +4254,54 @@ pgconn_decoder_for_get_copy_data_get(VALUE self)
|
|
4045
4254
|
|
4046
4255
|
/*
|
4047
4256
|
* call-seq:
|
4048
|
-
*
|
4257
|
+
* conn.field_name_type = Symbol
|
4049
4258
|
*
|
4050
|
-
*
|
4259
|
+
* Set default type of field names of results retrieved by this connection.
|
4260
|
+
* It can be set to one of:
|
4261
|
+
* * +:string+ to use String based field names
|
4262
|
+
* * +:symbol+ to use Symbol based field names
|
4263
|
+
*
|
4264
|
+
* The default is +:string+ .
|
4265
|
+
*
|
4266
|
+
* Settings the type of field names affects only future results.
|
4267
|
+
*
|
4268
|
+
* See further description at PG::Result#field_name_type=
|
4269
|
+
*
|
4270
|
+
*/
|
4271
|
+
static VALUE
|
4272
|
+
pgconn_field_name_type_set(VALUE self, VALUE sym)
|
4273
|
+
{
|
4274
|
+
t_pg_connection *this = pg_get_connection( self );
|
4275
|
+
|
4276
|
+
this->flags &= ~PG_RESULT_FIELD_NAMES_MASK;
|
4277
|
+
if( sym == sym_symbol ) this->flags |= PG_RESULT_FIELD_NAMES_SYMBOL;
|
4278
|
+
else if ( sym == sym_static_symbol ) this->flags |= PG_RESULT_FIELD_NAMES_STATIC_SYMBOL;
|
4279
|
+
else if ( sym == sym_string );
|
4280
|
+
else rb_raise(rb_eArgError, "invalid argument %+"PRIsVALUE, sym);
|
4281
|
+
|
4282
|
+
return sym;
|
4283
|
+
}
|
4284
|
+
|
4285
|
+
/*
|
4286
|
+
* call-seq:
|
4287
|
+
* conn.field_name_type -> Symbol
|
4288
|
+
*
|
4289
|
+
* Get type of field names.
|
4290
|
+
*
|
4291
|
+
* See description at #field_name_type=
|
4051
4292
|
*/
|
4052
4293
|
static VALUE
|
4053
|
-
|
4294
|
+
pgconn_field_name_type_get(VALUE self)
|
4054
4295
|
{
|
4055
4296
|
t_pg_connection *this = pg_get_connection( self );
|
4056
|
-
|
4057
|
-
|
4297
|
+
|
4298
|
+
if( this->flags & PG_RESULT_FIELD_NAMES_SYMBOL ){
|
4299
|
+
return sym_symbol;
|
4300
|
+
} else if( this->flags & PG_RESULT_FIELD_NAMES_STATIC_SYMBOL ){
|
4301
|
+
return sym_static_symbol;
|
4302
|
+
} else {
|
4303
|
+
return sym_string;
|
4304
|
+
}
|
4058
4305
|
}
|
4059
4306
|
|
4060
4307
|
|
@@ -4065,20 +4312,22 @@ void
|
|
4065
4312
|
init_pg_connection()
|
4066
4313
|
{
|
4067
4314
|
s_id_encode = rb_intern("encode");
|
4315
|
+
s_id_autoclose_set = rb_intern("autoclose=");
|
4068
4316
|
sym_type = ID2SYM(rb_intern("type"));
|
4069
4317
|
sym_format = ID2SYM(rb_intern("format"));
|
4070
4318
|
sym_value = ID2SYM(rb_intern("value"));
|
4319
|
+
sym_string = ID2SYM(rb_intern("string"));
|
4320
|
+
sym_symbol = ID2SYM(rb_intern("symbol"));
|
4321
|
+
sym_static_symbol = ID2SYM(rb_intern("static_symbol"));
|
4071
4322
|
|
4072
4323
|
rb_cPGconn = rb_define_class_under( rb_mPG, "Connection", rb_cObject );
|
4324
|
+
/* Help rdoc to known the Constants module */
|
4325
|
+
/* rb_mPGconstants = rb_define_module_under( rb_mPG, "Constants" ); */
|
4073
4326
|
rb_include_module(rb_cPGconn, rb_mPGconstants);
|
4074
4327
|
|
4075
4328
|
/****** PG::Connection CLASS METHODS ******/
|
4076
4329
|
rb_define_alloc_func( rb_cPGconn, pgconn_s_allocate );
|
4077
4330
|
|
4078
|
-
SINGLETON_ALIAS(rb_cPGconn, "connect", "new");
|
4079
|
-
SINGLETON_ALIAS(rb_cPGconn, "open", "new");
|
4080
|
-
SINGLETON_ALIAS(rb_cPGconn, "setdb", "new");
|
4081
|
-
SINGLETON_ALIAS(rb_cPGconn, "setdblogin", "new");
|
4082
4331
|
rb_define_singleton_method(rb_cPGconn, "escape_string", pgconn_s_escape, 1);
|
4083
4332
|
SINGLETON_ALIAS(rb_cPGconn, "escape", "escape_string");
|
4084
4333
|
rb_define_singleton_method(rb_cPGconn, "escape_bytea", pgconn_s_escape_bytea, 1);
|
@@ -4087,14 +4336,14 @@ init_pg_connection()
|
|
4087
4336
|
rb_define_singleton_method(rb_cPGconn, "quote_ident", pgconn_s_quote_ident, 1);
|
4088
4337
|
rb_define_singleton_method(rb_cPGconn, "connect_start", pgconn_s_connect_start, -1);
|
4089
4338
|
rb_define_singleton_method(rb_cPGconn, "conndefaults", pgconn_s_conndefaults, 0);
|
4090
|
-
rb_define_singleton_method(rb_cPGconn, "
|
4339
|
+
rb_define_singleton_method(rb_cPGconn, "sync_ping", pgconn_s_sync_ping, -1);
|
4340
|
+
rb_define_singleton_method(rb_cPGconn, "sync_connect", pgconn_s_sync_connect, -1);
|
4091
4341
|
|
4092
4342
|
/****** PG::Connection INSTANCE METHODS: Connection Control ******/
|
4093
|
-
rb_define_method(rb_cPGconn, "initialize", pgconn_init, -1);
|
4094
4343
|
rb_define_method(rb_cPGconn, "connect_poll", pgconn_connect_poll, 0);
|
4095
4344
|
rb_define_method(rb_cPGconn, "finish", pgconn_finish, 0);
|
4096
4345
|
rb_define_method(rb_cPGconn, "finished?", pgconn_finished_p, 0);
|
4097
|
-
rb_define_method(rb_cPGconn, "
|
4346
|
+
rb_define_method(rb_cPGconn, "sync_reset", pgconn_sync_reset, 0);
|
4098
4347
|
rb_define_method(rb_cPGconn, "reset_start", pgconn_reset_start, 0);
|
4099
4348
|
rb_define_method(rb_cPGconn, "reset_poll", pgconn_reset_poll, 0);
|
4100
4349
|
rb_define_alias(rb_cPGconn, "close", "finish");
|
@@ -4106,9 +4355,7 @@ init_pg_connection()
|
|
4106
4355
|
rb_define_method(rb_cPGconn, "host", pgconn_host, 0);
|
4107
4356
|
rb_define_method(rb_cPGconn, "port", pgconn_port, 0);
|
4108
4357
|
rb_define_method(rb_cPGconn, "tty", pgconn_tty, 0);
|
4109
|
-
#ifdef HAVE_PQCONNINFO
|
4110
4358
|
rb_define_method(rb_cPGconn, "conninfo", pgconn_conninfo, 0);
|
4111
|
-
#endif
|
4112
4359
|
rb_define_method(rb_cPGconn, "options", pgconn_options, 0);
|
4113
4360
|
rb_define_method(rb_cPGconn, "status", pgconn_status, 0);
|
4114
4361
|
rb_define_method(rb_cPGconn, "transaction_status", pgconn_transaction_status, 0);
|
@@ -4119,17 +4366,34 @@ init_pg_connection()
|
|
4119
4366
|
rb_define_method(rb_cPGconn, "socket", pgconn_socket, 0);
|
4120
4367
|
rb_define_method(rb_cPGconn, "socket_io", pgconn_socket_io, 0);
|
4121
4368
|
rb_define_method(rb_cPGconn, "backend_pid", pgconn_backend_pid, 0);
|
4369
|
+
rb_define_method(rb_cPGconn, "backend_key", pgconn_backend_key, 0);
|
4122
4370
|
rb_define_method(rb_cPGconn, "connection_needs_password", pgconn_connection_needs_password, 0);
|
4123
4371
|
rb_define_method(rb_cPGconn, "connection_used_password", pgconn_connection_used_password, 0);
|
4124
4372
|
/* rb_define_method(rb_cPGconn, "getssl", pgconn_getssl, 0); */
|
4125
4373
|
|
4126
4374
|
/****** PG::Connection INSTANCE METHODS: Command Execution ******/
|
4127
|
-
rb_define_method(rb_cPGconn, "sync_exec",
|
4128
|
-
rb_define_method(rb_cPGconn, "sync_exec_params",
|
4129
|
-
rb_define_method(rb_cPGconn, "sync_prepare",
|
4130
|
-
rb_define_method(rb_cPGconn, "sync_exec_prepared",
|
4131
|
-
rb_define_method(rb_cPGconn, "sync_describe_prepared",
|
4132
|
-
rb_define_method(rb_cPGconn, "sync_describe_portal",
|
4375
|
+
rb_define_method(rb_cPGconn, "sync_exec", pgconn_sync_exec, -1);
|
4376
|
+
rb_define_method(rb_cPGconn, "sync_exec_params", pgconn_sync_exec_params, -1);
|
4377
|
+
rb_define_method(rb_cPGconn, "sync_prepare", pgconn_sync_prepare, -1);
|
4378
|
+
rb_define_method(rb_cPGconn, "sync_exec_prepared", pgconn_sync_exec_prepared, -1);
|
4379
|
+
rb_define_method(rb_cPGconn, "sync_describe_prepared", pgconn_sync_describe_prepared, 1);
|
4380
|
+
rb_define_method(rb_cPGconn, "sync_describe_portal", pgconn_sync_describe_portal, 1);
|
4381
|
+
|
4382
|
+
rb_define_method(rb_cPGconn, "exec", pgconn_async_exec, -1);
|
4383
|
+
rb_define_method(rb_cPGconn, "exec_params", pgconn_async_exec_params, -1);
|
4384
|
+
rb_define_method(rb_cPGconn, "prepare", pgconn_async_prepare, -1);
|
4385
|
+
rb_define_method(rb_cPGconn, "exec_prepared", pgconn_async_exec_prepared, -1);
|
4386
|
+
rb_define_method(rb_cPGconn, "describe_prepared", pgconn_async_describe_prepared, 1);
|
4387
|
+
rb_define_method(rb_cPGconn, "describe_portal", pgconn_async_describe_portal, 1);
|
4388
|
+
|
4389
|
+
rb_define_alias(rb_cPGconn, "async_exec", "exec");
|
4390
|
+
rb_define_alias(rb_cPGconn, "async_query", "async_exec");
|
4391
|
+
rb_define_alias(rb_cPGconn, "async_exec_params", "exec_params");
|
4392
|
+
rb_define_alias(rb_cPGconn, "async_prepare", "prepare");
|
4393
|
+
rb_define_alias(rb_cPGconn, "async_exec_prepared", "exec_prepared");
|
4394
|
+
rb_define_alias(rb_cPGconn, "async_describe_prepared", "describe_prepared");
|
4395
|
+
rb_define_alias(rb_cPGconn, "async_describe_portal", "describe_portal");
|
4396
|
+
|
4133
4397
|
rb_define_method(rb_cPGconn, "make_empty_pgresult", pgconn_make_empty_pgresult, 1);
|
4134
4398
|
rb_define_method(rb_cPGconn, "escape_string", pgconn_s_escape, 1);
|
4135
4399
|
rb_define_alias(rb_cPGconn, "escape", "escape_string");
|
@@ -4142,42 +4406,38 @@ init_pg_connection()
|
|
4142
4406
|
/****** PG::Connection INSTANCE METHODS: Asynchronous Command Processing ******/
|
4143
4407
|
rb_define_method(rb_cPGconn, "send_query", pgconn_send_query, -1);
|
4144
4408
|
rb_define_method(rb_cPGconn, "send_query_params", pgconn_send_query_params, -1);
|
4145
|
-
rb_define_method(rb_cPGconn, "async_exec", pgconn_async_exec, -1);
|
4146
|
-
rb_define_method(rb_cPGconn, "async_exec_params", pgconn_async_exec_params, -1);
|
4147
|
-
rb_define_alias(rb_cPGconn, "async_query", "async_exec");
|
4148
4409
|
rb_define_method(rb_cPGconn, "send_prepare", pgconn_send_prepare, -1);
|
4149
|
-
rb_define_method(rb_cPGconn, "async_prepare", pgconn_async_prepare, -1);
|
4150
4410
|
rb_define_method(rb_cPGconn, "send_query_prepared", pgconn_send_query_prepared, -1);
|
4151
|
-
rb_define_method(rb_cPGconn, "async_exec_prepared", pgconn_async_exec_prepared, -1);
|
4152
4411
|
rb_define_method(rb_cPGconn, "send_describe_prepared", pgconn_send_describe_prepared, 1);
|
4153
|
-
rb_define_method(rb_cPGconn, "async_describe_prepared", pgconn_async_describe_prepared, 1);
|
4154
4412
|
rb_define_method(rb_cPGconn, "send_describe_portal", pgconn_send_describe_portal, 1);
|
4155
|
-
rb_define_method(rb_cPGconn, "
|
4156
|
-
rb_define_method(rb_cPGconn, "get_result", pgconn_get_result, 0);
|
4413
|
+
rb_define_method(rb_cPGconn, "sync_get_result", pgconn_sync_get_result, 0);
|
4157
4414
|
rb_define_method(rb_cPGconn, "consume_input", pgconn_consume_input, 0);
|
4158
4415
|
rb_define_method(rb_cPGconn, "is_busy", pgconn_is_busy, 0);
|
4159
|
-
rb_define_method(rb_cPGconn, "
|
4160
|
-
rb_define_method(rb_cPGconn, "
|
4161
|
-
|
4162
|
-
rb_define_method(rb_cPGconn, "flush",
|
4416
|
+
rb_define_method(rb_cPGconn, "sync_setnonblocking", pgconn_sync_setnonblocking, 1);
|
4417
|
+
rb_define_method(rb_cPGconn, "sync_isnonblocking", pgconn_sync_isnonblocking, 0);
|
4418
|
+
rb_define_method(rb_cPGconn, "sync_flush", pgconn_sync_flush, 0);
|
4419
|
+
rb_define_method(rb_cPGconn, "flush", pgconn_async_flush, 0);
|
4420
|
+
rb_define_alias(rb_cPGconn, "async_flush", "flush");
|
4163
4421
|
rb_define_method(rb_cPGconn, "discard_results", pgconn_discard_results, 0);
|
4164
4422
|
|
4165
4423
|
/****** PG::Connection INSTANCE METHODS: Cancelling Queries in Progress ******/
|
4166
|
-
rb_define_method(rb_cPGconn, "
|
4424
|
+
rb_define_method(rb_cPGconn, "sync_cancel", pgconn_sync_cancel, 0);
|
4167
4425
|
|
4168
4426
|
/****** PG::Connection INSTANCE METHODS: NOTIFY ******/
|
4169
4427
|
rb_define_method(rb_cPGconn, "notifies", pgconn_notifies, 0);
|
4170
4428
|
|
4171
4429
|
/****** PG::Connection INSTANCE METHODS: COPY ******/
|
4172
|
-
rb_define_method(rb_cPGconn, "
|
4173
|
-
rb_define_method(rb_cPGconn, "
|
4174
|
-
rb_define_method(rb_cPGconn, "
|
4430
|
+
rb_define_method(rb_cPGconn, "sync_put_copy_data", pgconn_sync_put_copy_data, -1);
|
4431
|
+
rb_define_method(rb_cPGconn, "sync_put_copy_end", pgconn_sync_put_copy_end, -1);
|
4432
|
+
rb_define_method(rb_cPGconn, "sync_get_copy_data", pgconn_sync_get_copy_data, -1);
|
4175
4433
|
|
4176
4434
|
/****** PG::Connection INSTANCE METHODS: Control Functions ******/
|
4177
4435
|
rb_define_method(rb_cPGconn, "set_error_verbosity", pgconn_set_error_verbosity, 1);
|
4436
|
+
#ifdef HAVE_PQRESULTVERBOSEERRORMESSAGE
|
4437
|
+
rb_define_method(rb_cPGconn, "set_error_context_visibility", pgconn_set_error_context_visibility, 1 );
|
4438
|
+
#endif
|
4178
4439
|
rb_define_method(rb_cPGconn, "trace", pgconn_trace, 1);
|
4179
4440
|
rb_define_method(rb_cPGconn, "untrace", pgconn_untrace, 0);
|
4180
|
-
rb_define_method(rb_cPGconn, "guess_result_memsize=", pgconn_guess_result_memsize_set, 1);
|
4181
4441
|
|
4182
4442
|
/****** PG::Connection INSTANCE METHODS: Notice Processing ******/
|
4183
4443
|
rb_define_method(rb_cPGconn, "set_notice_receiver", pgconn_set_notice_receiver, 0);
|
@@ -4185,16 +4445,20 @@ init_pg_connection()
|
|
4185
4445
|
|
4186
4446
|
/****** PG::Connection INSTANCE METHODS: Other ******/
|
4187
4447
|
rb_define_method(rb_cPGconn, "get_client_encoding", pgconn_get_client_encoding, 0);
|
4188
|
-
rb_define_method(rb_cPGconn, "
|
4448
|
+
rb_define_method(rb_cPGconn, "sync_set_client_encoding", pgconn_sync_set_client_encoding, 1);
|
4449
|
+
rb_define_method(rb_cPGconn, "set_client_encoding", pgconn_async_set_client_encoding, 1);
|
4450
|
+
rb_define_alias(rb_cPGconn, "async_set_client_encoding", "set_client_encoding");
|
4189
4451
|
rb_define_alias(rb_cPGconn, "client_encoding=", "set_client_encoding");
|
4190
|
-
rb_define_method(rb_cPGconn, "transaction", pgconn_transaction, 0);
|
4191
4452
|
rb_define_method(rb_cPGconn, "block", pgconn_block, -1);
|
4453
|
+
rb_define_private_method(rb_cPGconn, "flush_data=", pgconn_flush_data_set, 1);
|
4192
4454
|
rb_define_method(rb_cPGconn, "wait_for_notify", pgconn_wait_for_notify, -1);
|
4193
4455
|
rb_define_alias(rb_cPGconn, "notifies_wait", "wait_for_notify");
|
4194
4456
|
rb_define_method(rb_cPGconn, "quote_ident", pgconn_s_quote_ident, 1);
|
4195
|
-
rb_define_method(rb_cPGconn, "
|
4457
|
+
rb_define_method(rb_cPGconn, "sync_get_last_result", pgconn_sync_get_last_result, 0);
|
4458
|
+
rb_define_method(rb_cPGconn, "get_last_result", pgconn_async_get_last_result, 0);
|
4459
|
+
rb_define_alias(rb_cPGconn, "async_get_last_result", "get_last_result");
|
4196
4460
|
#ifdef HAVE_PQENCRYPTPASSWORDCONN
|
4197
|
-
rb_define_method(rb_cPGconn, "
|
4461
|
+
rb_define_method(rb_cPGconn, "sync_encrypt_password", pgconn_sync_encrypt_password, -1);
|
4198
4462
|
#endif
|
4199
4463
|
|
4200
4464
|
#ifdef HAVE_PQSSLATTRIBUTE
|
@@ -4203,6 +4467,14 @@ init_pg_connection()
|
|
4203
4467
|
rb_define_method(rb_cPGconn, "ssl_attribute_names", pgconn_ssl_attribute_names, 0);
|
4204
4468
|
#endif
|
4205
4469
|
|
4470
|
+
#ifdef HAVE_PQENTERPIPELINEMODE
|
4471
|
+
rb_define_method(rb_cPGconn, "pipeline_status", pgconn_pipeline_status, 0);
|
4472
|
+
rb_define_method(rb_cPGconn, "enter_pipeline_mode", pgconn_enter_pipeline_mode, 0);
|
4473
|
+
rb_define_method(rb_cPGconn, "exit_pipeline_mode", pgconn_exit_pipeline_mode, 0);
|
4474
|
+
rb_define_method(rb_cPGconn, "pipeline_sync", pgconn_pipeline_sync, 0);
|
4475
|
+
rb_define_method(rb_cPGconn, "send_flush_request", pgconn_send_flush_request, 0);
|
4476
|
+
#endif
|
4477
|
+
|
4206
4478
|
/****** PG::Connection INSTANCE METHODS: Large Object Support ******/
|
4207
4479
|
rb_define_method(rb_cPGconn, "lo_creat", pgconn_locreat, -1);
|
4208
4480
|
rb_define_alias(rb_cPGconn, "locreat", "lo_creat");
|
@@ -4244,5 +4516,7 @@ init_pg_connection()
|
|
4244
4516
|
rb_define_method(rb_cPGconn, "encoder_for_put_copy_data", pgconn_encoder_for_put_copy_data_get, 0);
|
4245
4517
|
rb_define_method(rb_cPGconn, "decoder_for_get_copy_data=", pgconn_decoder_for_get_copy_data_set, 1);
|
4246
4518
|
rb_define_method(rb_cPGconn, "decoder_for_get_copy_data", pgconn_decoder_for_get_copy_data_get, 0);
|
4247
|
-
}
|
4248
4519
|
|
4520
|
+
rb_define_method(rb_cPGconn, "field_name_type=", pgconn_field_name_type_set, 1 );
|
4521
|
+
rb_define_method(rb_cPGconn, "field_name_type", pgconn_field_name_type_get, 0 );
|
4522
|
+
}
|