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