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