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