pg 1.1.3 → 1.5.4
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 +42 -0
- data/.gems +6 -0
- data/.github/workflows/binary-gems.yml +117 -0
- data/.github/workflows/source-gem.yml +141 -0
- data/.gitignore +22 -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.md +884 -0
- data/Manifest.txt +3 -3
- data/README-Windows.rdoc +4 -4
- data/README.ja.md +300 -0
- data/README.md +286 -0
- data/Rakefile +37 -137
- data/Rakefile.cross +62 -62
- data/certs/ged.pem +24 -0
- data/certs/larskanis-2022.pem +26 -0
- data/certs/larskanis-2023.pem +24 -0
- data/ext/errorcodes.def +80 -0
- data/ext/errorcodes.rb +0 -0
- data/ext/errorcodes.txt +22 -2
- data/ext/extconf.rb +105 -26
- data/ext/gvl_wrappers.c +4 -0
- data/ext/gvl_wrappers.h +23 -0
- data/ext/pg.c +204 -152
- data/ext/pg.h +52 -21
- data/ext/pg_binary_decoder.c +100 -17
- data/ext/pg_binary_encoder.c +238 -13
- data/ext/pg_coder.c +109 -34
- data/ext/pg_connection.c +1383 -983
- data/ext/pg_copy_coder.c +356 -35
- data/ext/pg_errors.c +1 -1
- data/ext/pg_record_coder.c +522 -0
- data/ext/pg_result.c +439 -172
- data/ext/pg_text_decoder.c +42 -18
- data/ext/pg_text_encoder.c +201 -56
- data/ext/pg_tuple.c +97 -66
- data/ext/pg_type_map.c +45 -11
- data/ext/pg_type_map_all_strings.c +21 -7
- data/ext/pg_type_map_by_class.c +59 -27
- data/ext/pg_type_map_by_column.c +80 -37
- data/ext/pg_type_map_by_mri_type.c +49 -20
- data/ext/pg_type_map_by_oid.c +62 -29
- data/ext/pg_type_map_in_ruby.c +56 -22
- data/ext/{util.c → pg_util.c} +7 -7
- data/lib/pg/basic_type_map_based_on_result.rb +67 -0
- data/lib/pg/basic_type_map_for_queries.rb +198 -0
- data/lib/pg/basic_type_map_for_results.rb +104 -0
- data/lib/pg/basic_type_registry.rb +299 -0
- data/lib/pg/binary_decoder/date.rb +9 -0
- data/lib/pg/binary_decoder/timestamp.rb +26 -0
- data/lib/pg/binary_encoder/timestamp.rb +20 -0
- data/lib/pg/coder.rb +35 -12
- data/lib/pg/connection.rb +744 -84
- data/lib/pg/exceptions.rb +15 -1
- data/lib/pg/result.rb +13 -1
- data/lib/pg/text_decoder/date.rb +18 -0
- data/lib/pg/text_decoder/inet.rb +9 -0
- data/lib/pg/text_decoder/json.rb +14 -0
- data/lib/pg/text_decoder/numeric.rb +9 -0
- data/lib/pg/text_decoder/timestamp.rb +30 -0
- data/lib/pg/text_encoder/date.rb +12 -0
- data/lib/pg/text_encoder/inet.rb +28 -0
- data/lib/pg/text_encoder/json.rb +14 -0
- data/lib/pg/text_encoder/numeric.rb +9 -0
- data/lib/pg/text_encoder/timestamp.rb +24 -0
- data/lib/pg/type_map_by_column.rb +2 -1
- data/lib/pg/version.rb +4 -0
- data/lib/pg.rb +94 -39
- 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 +34 -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/translation/.po4a-version +7 -0
- data/translation/po/all.pot +936 -0
- data/translation/po/ja.po +1036 -0
- data/translation/po4a.cfg +12 -0
- data.tar.gz.sig +0 -0
- metadata +144 -222
- metadata.gz.sig +0 -0
- data/ChangeLog +0 -6595
- data/History.rdoc +0 -485
- data/README.ja.rdoc +0 -14
- data/README.rdoc +0 -178
- data/lib/pg/basic_type_mapping.rb +0 -459
- data/lib/pg/binary_decoder.rb +0 -22
- data/lib/pg/constants.rb +0 -11
- data/lib/pg/text_decoder.rb +0 -47
- data/lib/pg/text_encoder.rb +0 -69
- 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/{util.h → pg_util.h} +0 -0
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,41 @@
|
|
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;
|
16
|
-
|
17
|
-
static PQnoticeReceiver default_notice_receiver = NULL;
|
18
|
-
static PQnoticeProcessor default_notice_processor = NULL;
|
17
|
+
static VALUE sym_symbol, sym_string, sym_static_symbol;
|
19
18
|
|
20
19
|
static VALUE pgconn_finish( VALUE );
|
21
20
|
static VALUE pgconn_set_default_encoding( VALUE self );
|
22
|
-
|
21
|
+
static VALUE pgconn_wait_for_flush( VALUE self );
|
22
|
+
static void pgconn_set_internal_encoding_index( VALUE );
|
23
|
+
static const rb_data_type_t pg_connection_type;
|
24
|
+
static VALUE pgconn_async_flush(VALUE self);
|
23
25
|
|
24
26
|
/*
|
25
27
|
* Global functions
|
26
28
|
*/
|
27
29
|
|
30
|
+
/*
|
31
|
+
* Convenience function to raise connection errors
|
32
|
+
*/
|
33
|
+
#ifdef __GNUC__
|
34
|
+
__attribute__((format(printf, 3, 4)))
|
35
|
+
#endif
|
36
|
+
static void
|
37
|
+
pg_raise_conn_error( VALUE klass, VALUE self, const char *format, ...)
|
38
|
+
{
|
39
|
+
VALUE msg, error;
|
40
|
+
va_list ap;
|
41
|
+
|
42
|
+
va_start(ap, format);
|
43
|
+
msg = rb_vsprintf(format, ap);
|
44
|
+
va_end(ap);
|
45
|
+
error = rb_exc_new_str(klass, msg);
|
46
|
+
rb_iv_set(error, "@connection", self);
|
47
|
+
rb_exc_raise(error);
|
48
|
+
}
|
49
|
+
|
28
50
|
/*
|
29
51
|
* Fetch the PG::Connection object data pointer.
|
30
52
|
*/
|
@@ -32,7 +54,7 @@ t_pg_connection *
|
|
32
54
|
pg_get_connection( VALUE self )
|
33
55
|
{
|
34
56
|
t_pg_connection *this;
|
35
|
-
|
57
|
+
TypedData_Get_Struct( self, t_pg_connection, &pg_connection_type, this);
|
36
58
|
|
37
59
|
return this;
|
38
60
|
}
|
@@ -45,10 +67,10 @@ static t_pg_connection *
|
|
45
67
|
pg_get_connection_safe( VALUE self )
|
46
68
|
{
|
47
69
|
t_pg_connection *this;
|
48
|
-
|
70
|
+
TypedData_Get_Struct( self, t_pg_connection, &pg_connection_type, this);
|
49
71
|
|
50
72
|
if ( !this->pgconn )
|
51
|
-
|
73
|
+
pg_raise_conn_error( rb_eConnectionBad, self, "connection is closed");
|
52
74
|
|
53
75
|
return this;
|
54
76
|
}
|
@@ -64,10 +86,11 @@ PGconn *
|
|
64
86
|
pg_get_pgconn( VALUE self )
|
65
87
|
{
|
66
88
|
t_pg_connection *this;
|
67
|
-
|
89
|
+
TypedData_Get_Struct( self, t_pg_connection, &pg_connection_type, this);
|
68
90
|
|
69
|
-
if ( !this->pgconn )
|
70
|
-
|
91
|
+
if ( !this->pgconn ){
|
92
|
+
pg_raise_conn_error( rb_eConnectionBad, self, "connection is closed");
|
93
|
+
}
|
71
94
|
|
72
95
|
return this->pgconn;
|
73
96
|
}
|
@@ -85,15 +108,13 @@ pgconn_close_socket_io( VALUE self )
|
|
85
108
|
|
86
109
|
if ( RTEST(socket_io) ) {
|
87
110
|
#if defined(_WIN32)
|
88
|
-
|
89
|
-
|
90
|
-
rb_raise(rb_eConnectionBad, "Could not unwrap win32 socket handle");
|
91
|
-
}
|
111
|
+
if( rb_w32_unwrap_io_handle(this->ruby_sd) )
|
112
|
+
pg_raise_conn_error( rb_eConnectionBad, self, "Could not unwrap win32 socket handle");
|
92
113
|
#endif
|
93
114
|
rb_funcall( socket_io, rb_intern("close"), 0 );
|
94
115
|
}
|
95
116
|
|
96
|
-
this->socket_io
|
117
|
+
RB_OBJ_WRITE(self, &this->socket_io, Qnil);
|
97
118
|
}
|
98
119
|
|
99
120
|
|
@@ -145,17 +166,31 @@ static const char *pg_cstr_enc(VALUE str, int enc_idx){
|
|
145
166
|
* GC Mark function
|
146
167
|
*/
|
147
168
|
static void
|
148
|
-
pgconn_gc_mark(
|
169
|
+
pgconn_gc_mark( void *_this )
|
170
|
+
{
|
171
|
+
t_pg_connection *this = (t_pg_connection *)_this;
|
172
|
+
rb_gc_mark_movable( this->socket_io );
|
173
|
+
rb_gc_mark_movable( this->notice_receiver );
|
174
|
+
rb_gc_mark_movable( this->notice_processor );
|
175
|
+
rb_gc_mark_movable( this->type_map_for_queries );
|
176
|
+
rb_gc_mark_movable( this->type_map_for_results );
|
177
|
+
rb_gc_mark_movable( this->trace_stream );
|
178
|
+
rb_gc_mark_movable( this->encoder_for_put_copy_data );
|
179
|
+
rb_gc_mark_movable( this->decoder_for_get_copy_data );
|
180
|
+
}
|
181
|
+
|
182
|
+
static void
|
183
|
+
pgconn_gc_compact( void *_this )
|
149
184
|
{
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
185
|
+
t_pg_connection *this = (t_pg_connection *)_this;
|
186
|
+
pg_gc_location( this->socket_io );
|
187
|
+
pg_gc_location( this->notice_receiver );
|
188
|
+
pg_gc_location( this->notice_processor );
|
189
|
+
pg_gc_location( this->type_map_for_queries );
|
190
|
+
pg_gc_location( this->type_map_for_results );
|
191
|
+
pg_gc_location( this->trace_stream );
|
192
|
+
pg_gc_location( this->encoder_for_put_copy_data );
|
193
|
+
pg_gc_location( this->decoder_for_get_copy_data );
|
159
194
|
}
|
160
195
|
|
161
196
|
|
@@ -163,14 +198,45 @@ pgconn_gc_mark( t_pg_connection *this )
|
|
163
198
|
* GC Free function
|
164
199
|
*/
|
165
200
|
static void
|
166
|
-
pgconn_gc_free(
|
201
|
+
pgconn_gc_free( void *_this )
|
167
202
|
{
|
203
|
+
t_pg_connection *this = (t_pg_connection *)_this;
|
204
|
+
#if defined(_WIN32)
|
205
|
+
if ( RTEST(this->socket_io) ) {
|
206
|
+
if( rb_w32_unwrap_io_handle(this->ruby_sd) ){
|
207
|
+
rb_warn("pg: Could not unwrap win32 socket handle by garbage collector");
|
208
|
+
}
|
209
|
+
}
|
210
|
+
#endif
|
168
211
|
if (this->pgconn != NULL)
|
169
212
|
PQfinish( this->pgconn );
|
170
213
|
|
171
214
|
xfree(this);
|
172
215
|
}
|
173
216
|
|
217
|
+
/*
|
218
|
+
* Object Size function
|
219
|
+
*/
|
220
|
+
static size_t
|
221
|
+
pgconn_memsize( const void *_this )
|
222
|
+
{
|
223
|
+
const t_pg_connection *this = (const t_pg_connection *)_this;
|
224
|
+
return sizeof(*this);
|
225
|
+
}
|
226
|
+
|
227
|
+
static const rb_data_type_t pg_connection_type = {
|
228
|
+
"PG::Connection",
|
229
|
+
{
|
230
|
+
pgconn_gc_mark,
|
231
|
+
pgconn_gc_free,
|
232
|
+
pgconn_memsize,
|
233
|
+
pg_compact_callback(pgconn_gc_compact),
|
234
|
+
},
|
235
|
+
0,
|
236
|
+
0,
|
237
|
+
RUBY_TYPED_WB_PROTECTED,
|
238
|
+
};
|
239
|
+
|
174
240
|
|
175
241
|
/**************************************************************************
|
176
242
|
* Class Methods
|
@@ -186,100 +252,38 @@ static VALUE
|
|
186
252
|
pgconn_s_allocate( VALUE klass )
|
187
253
|
{
|
188
254
|
t_pg_connection *this;
|
189
|
-
VALUE self =
|
255
|
+
VALUE self = TypedData_Make_Struct( klass, t_pg_connection, &pg_connection_type, this );
|
190
256
|
|
191
257
|
this->pgconn = NULL;
|
192
|
-
this->socket_io
|
193
|
-
this->notice_receiver
|
194
|
-
this->notice_processor
|
195
|
-
this->type_map_for_queries
|
196
|
-
this->type_map_for_results
|
197
|
-
this->encoder_for_put_copy_data
|
198
|
-
this->decoder_for_get_copy_data
|
199
|
-
this->trace_stream
|
200
|
-
|
201
|
-
this->guess_result_memsize = 1;
|
258
|
+
RB_OBJ_WRITE(self, &this->socket_io, Qnil);
|
259
|
+
RB_OBJ_WRITE(self, &this->notice_receiver, Qnil);
|
260
|
+
RB_OBJ_WRITE(self, &this->notice_processor, Qnil);
|
261
|
+
RB_OBJ_WRITE(self, &this->type_map_for_queries, pg_typemap_all_strings);
|
262
|
+
RB_OBJ_WRITE(self, &this->type_map_for_results, pg_typemap_all_strings);
|
263
|
+
RB_OBJ_WRITE(self, &this->encoder_for_put_copy_data, Qnil);
|
264
|
+
RB_OBJ_WRITE(self, &this->decoder_for_get_copy_data, Qnil);
|
265
|
+
RB_OBJ_WRITE(self, &this->trace_stream, Qnil);
|
266
|
+
rb_ivar_set(self, rb_intern("@calls_to_put_copy_data"), INT2FIX(0));
|
202
267
|
|
203
268
|
return self;
|
204
269
|
}
|
205
270
|
|
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
271
|
static VALUE
|
265
|
-
|
272
|
+
pgconn_s_sync_connect(int argc, VALUE *argv, VALUE klass)
|
266
273
|
{
|
267
274
|
t_pg_connection *this;
|
268
275
|
VALUE conninfo;
|
269
|
-
VALUE
|
276
|
+
VALUE self = pgconn_s_allocate( klass );
|
270
277
|
|
271
278
|
this = pg_get_connection( self );
|
272
279
|
conninfo = rb_funcall2( rb_cPGconn, rb_intern("parse_connect_args"), argc, argv );
|
273
280
|
this->pgconn = gvl_PQconnectdb(StringValueCStr(conninfo));
|
274
281
|
|
275
282
|
if(this->pgconn == NULL)
|
276
|
-
rb_raise(rb_ePGerror, "PQconnectdb() unable to allocate structure");
|
283
|
+
rb_raise(rb_ePGerror, "PQconnectdb() unable to allocate PGconn structure");
|
277
284
|
|
278
|
-
if (PQstatus(this->pgconn) == CONNECTION_BAD)
|
279
|
-
|
280
|
-
rb_iv_set(error, "@connection", self);
|
281
|
-
rb_exc_raise(error);
|
282
|
-
}
|
285
|
+
if (PQstatus(this->pgconn) == CONNECTION_BAD)
|
286
|
+
pg_raise_conn_error( rb_eConnectionBad, self, "%s", PQerrorMessage(this->pgconn));
|
283
287
|
|
284
288
|
pgconn_set_default_encoding( self );
|
285
289
|
|
@@ -295,14 +299,16 @@ pgconn_init(int argc, VALUE *argv, VALUE self)
|
|
295
299
|
* PG::Connection.connect_start(connection_string) -> conn
|
296
300
|
* PG::Connection.connect_start(host, port, options, tty, dbname, login, password) -> conn
|
297
301
|
*
|
298
|
-
* This is an asynchronous version of PG::Connection.
|
302
|
+
* This is an asynchronous version of PG::Connection.new.
|
299
303
|
*
|
300
304
|
* Use #connect_poll to poll the status of the connection.
|
301
305
|
*
|
302
306
|
* 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,
|
307
|
+
* +Encoding.default_internal+ is set. To set it after the connection is established,
|
304
308
|
* call #internal_encoding=. You can also set it automatically by setting
|
305
|
-
* ENV['PGCLIENTENCODING']
|
309
|
+
* <code>ENV['PGCLIENTENCODING']</code>, or include the 'options' connection parameter.
|
310
|
+
*
|
311
|
+
* 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
312
|
*
|
307
313
|
*/
|
308
314
|
static VALUE
|
@@ -310,7 +316,6 @@ pgconn_s_connect_start( int argc, VALUE *argv, VALUE klass )
|
|
310
316
|
{
|
311
317
|
VALUE rb_conn;
|
312
318
|
VALUE conninfo;
|
313
|
-
VALUE error;
|
314
319
|
t_pg_connection *this;
|
315
320
|
|
316
321
|
/*
|
@@ -323,13 +328,10 @@ pgconn_s_connect_start( int argc, VALUE *argv, VALUE klass )
|
|
323
328
|
this->pgconn = gvl_PQconnectStart( StringValueCStr(conninfo) );
|
324
329
|
|
325
330
|
if( this->pgconn == NULL )
|
326
|
-
rb_raise(rb_ePGerror, "PQconnectStart() unable to allocate structure");
|
331
|
+
rb_raise(rb_ePGerror, "PQconnectStart() unable to allocate PGconn structure");
|
327
332
|
|
328
|
-
if ( PQstatus(this->pgconn) == CONNECTION_BAD )
|
329
|
-
|
330
|
-
rb_iv_set(error, "@connection", rb_conn);
|
331
|
-
rb_exc_raise(error);
|
332
|
-
}
|
333
|
+
if ( PQstatus(this->pgconn) == CONNECTION_BAD )
|
334
|
+
pg_raise_conn_error( rb_eConnectionBad, rb_conn, "%s", PQerrorMessage(this->pgconn));
|
333
335
|
|
334
336
|
if ( rb_block_given_p() ) {
|
335
337
|
return rb_ensure( rb_yield, rb_conn, pgconn_finish, rb_conn );
|
@@ -337,34 +339,14 @@ pgconn_s_connect_start( int argc, VALUE *argv, VALUE klass )
|
|
337
339
|
return rb_conn;
|
338
340
|
}
|
339
341
|
|
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
342
|
static VALUE
|
361
|
-
|
343
|
+
pgconn_s_sync_ping( int argc, VALUE *argv, VALUE klass )
|
362
344
|
{
|
363
345
|
PGPing ping;
|
364
346
|
VALUE conninfo;
|
365
347
|
|
366
348
|
conninfo = rb_funcall2( klass, rb_intern("parse_connect_args"), argc, argv );
|
367
|
-
ping =
|
349
|
+
ping = gvl_PQping( StringValueCStr(conninfo) );
|
368
350
|
|
369
351
|
return INT2FIX((int)ping);
|
370
352
|
}
|
@@ -405,31 +387,40 @@ pgconn_s_conndefaults(VALUE self)
|
|
405
387
|
return array;
|
406
388
|
}
|
407
389
|
|
408
|
-
|
409
|
-
#ifdef HAVE_PQENCRYPTPASSWORDCONN
|
410
390
|
/*
|
411
|
-
*
|
412
|
-
* conn.encrypt_password( password, username, algorithm=nil ) -> String
|
413
|
-
*
|
414
|
-
* This function is intended to be used by client applications that wish to send commands like <tt>ALTER USER joe PASSWORD 'pwd'</tt>.
|
415
|
-
* It is good practice not to send the original cleartext password in such a command, because it might be exposed in command logs, activity displays, and so on.
|
416
|
-
* Instead, use this function to convert the password to encrypted form before it is sent.
|
391
|
+
* Document-method: PG::Connection.conninfo_parse
|
417
392
|
*
|
418
|
-
*
|
419
|
-
*
|
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.
|
393
|
+
* call-seq:
|
394
|
+
* PG::Connection.conninfo_parse(conninfo_string) -> Array
|
428
395
|
*
|
429
|
-
*
|
396
|
+
* Returns parsed connection options from the provided connection string as an array of hashes.
|
397
|
+
* Each hash has the same keys as PG::Connection.conndefaults() .
|
398
|
+
* The values from the +conninfo_string+ are stored in the +:val+ key.
|
430
399
|
*/
|
431
400
|
static VALUE
|
432
|
-
|
401
|
+
pgconn_s_conninfo_parse(VALUE self, VALUE conninfo)
|
402
|
+
{
|
403
|
+
VALUE array;
|
404
|
+
char *errmsg = NULL;
|
405
|
+
PQconninfoOption *options = PQconninfoParse(StringValueCStr(conninfo), &errmsg);
|
406
|
+
if(errmsg){
|
407
|
+
VALUE error = rb_str_new_cstr(errmsg);
|
408
|
+
PQfreemem(errmsg);
|
409
|
+
rb_raise(rb_ePGerror, "%"PRIsVALUE, error);
|
410
|
+
}
|
411
|
+
array = pgconn_make_conninfo_array( options );
|
412
|
+
|
413
|
+
PQconninfoFree(options);
|
414
|
+
|
415
|
+
UNUSED( self );
|
416
|
+
|
417
|
+
return array;
|
418
|
+
}
|
419
|
+
|
420
|
+
|
421
|
+
#ifdef HAVE_PQENCRYPTPASSWORDCONN
|
422
|
+
static VALUE
|
423
|
+
pgconn_sync_encrypt_password(int argc, VALUE *argv, VALUE self)
|
433
424
|
{
|
434
425
|
char *encrypted = NULL;
|
435
426
|
VALUE rval = Qnil;
|
@@ -445,12 +436,8 @@ pgconn_encrypt_password(int argc, VALUE *argv, VALUE self)
|
|
445
436
|
if ( encrypted ) {
|
446
437
|
rval = rb_str_new2( encrypted );
|
447
438
|
PQfreemem( encrypted );
|
448
|
-
|
449
|
-
OBJ_INFECT( rval, password );
|
450
|
-
OBJ_INFECT( rval, username );
|
451
|
-
OBJ_INFECT( rval, algorithm );
|
452
439
|
} else {
|
453
|
-
|
440
|
+
pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(conn));
|
454
441
|
}
|
455
442
|
|
456
443
|
return rval;
|
@@ -481,9 +468,6 @@ pgconn_s_encrypt_password(VALUE self, VALUE password, VALUE username)
|
|
481
468
|
rval = rb_str_new2( encrypted );
|
482
469
|
PQfreemem( encrypted );
|
483
470
|
|
484
|
-
OBJ_INFECT( rval, password );
|
485
|
-
OBJ_INFECT( rval, username );
|
486
|
-
|
487
471
|
return rval;
|
488
472
|
}
|
489
473
|
|
@@ -507,17 +491,18 @@ pgconn_s_encrypt_password(VALUE self, VALUE password, VALUE username)
|
|
507
491
|
* the asynchronous connection is ready
|
508
492
|
*
|
509
493
|
* Example:
|
510
|
-
*
|
511
|
-
*
|
494
|
+
* require "io/wait"
|
495
|
+
*
|
496
|
+
* conn = PG::Connection.connect_start(dbname: 'mydatabase')
|
512
497
|
* status = conn.connect_poll
|
513
498
|
* while(status != PG::PGRES_POLLING_OK) do
|
514
499
|
* # do some work while waiting for the connection to complete
|
515
500
|
* if(status == PG::PGRES_POLLING_READING)
|
516
|
-
*
|
501
|
+
* unless conn.socket_io.wait_readable(10.0)
|
517
502
|
* raise "Asynchronous connection timed out!"
|
518
503
|
* end
|
519
504
|
* elsif(status == PG::PGRES_POLLING_WRITING)
|
520
|
-
*
|
505
|
+
* unless conn.socket_io.wait_writable(10.0)
|
521
506
|
* raise "Asynchronous connection timed out!"
|
522
507
|
* end
|
523
508
|
* end
|
@@ -531,6 +516,9 @@ pgconn_connect_poll(VALUE self)
|
|
531
516
|
{
|
532
517
|
PostgresPollingStatusType status;
|
533
518
|
status = gvl_PQconnectPoll(pg_get_pgconn(self));
|
519
|
+
|
520
|
+
pgconn_close_socket_io(self);
|
521
|
+
|
534
522
|
return INT2FIX((int)status);
|
535
523
|
}
|
536
524
|
|
@@ -567,15 +555,8 @@ pgconn_finished_p( VALUE self )
|
|
567
555
|
}
|
568
556
|
|
569
557
|
|
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
558
|
static VALUE
|
578
|
-
|
559
|
+
pgconn_sync_reset( VALUE self )
|
579
560
|
{
|
580
561
|
pgconn_close_socket_io( self );
|
581
562
|
gvl_PQreset( pg_get_pgconn(self) );
|
@@ -597,7 +578,7 @@ pgconn_reset_start(VALUE self)
|
|
597
578
|
{
|
598
579
|
pgconn_close_socket_io( self );
|
599
580
|
if(gvl_PQresetStart(pg_get_pgconn(self)) == 0)
|
600
|
-
|
581
|
+
pg_raise_conn_error( rb_eUnableToSend, self, "reset has failed");
|
601
582
|
return Qnil;
|
602
583
|
}
|
603
584
|
|
@@ -614,6 +595,9 @@ pgconn_reset_poll(VALUE self)
|
|
614
595
|
{
|
615
596
|
PostgresPollingStatusType status;
|
616
597
|
status = gvl_PQresetPoll(pg_get_pgconn(self));
|
598
|
+
|
599
|
+
pgconn_close_socket_io(self);
|
600
|
+
|
617
601
|
return INT2FIX((int)status);
|
618
602
|
}
|
619
603
|
|
@@ -629,7 +613,7 @@ pgconn_db(VALUE self)
|
|
629
613
|
{
|
630
614
|
char *db = PQdb(pg_get_pgconn(self));
|
631
615
|
if (!db) return Qnil;
|
632
|
-
return
|
616
|
+
return rb_str_new2(db);
|
633
617
|
}
|
634
618
|
|
635
619
|
/*
|
@@ -643,7 +627,7 @@ pgconn_user(VALUE self)
|
|
643
627
|
{
|
644
628
|
char *user = PQuser(pg_get_pgconn(self));
|
645
629
|
if (!user) return Qnil;
|
646
|
-
return
|
630
|
+
return rb_str_new2(user);
|
647
631
|
}
|
648
632
|
|
649
633
|
/*
|
@@ -657,22 +641,53 @@ pgconn_pass(VALUE self)
|
|
657
641
|
{
|
658
642
|
char *user = PQpass(pg_get_pgconn(self));
|
659
643
|
if (!user) return Qnil;
|
660
|
-
return
|
644
|
+
return rb_str_new2(user);
|
661
645
|
}
|
662
646
|
|
663
647
|
/*
|
664
648
|
* call-seq:
|
665
649
|
* conn.host()
|
666
650
|
*
|
667
|
-
* Returns the
|
651
|
+
* Returns the server host name of the active connection.
|
652
|
+
* This can be a host name, an IP address, or a directory path if the connection is via Unix socket.
|
653
|
+
* (The path case can be distinguished because it will always be an absolute path, beginning with +/+ .)
|
654
|
+
*
|
655
|
+
* If the connection parameters specified both host and hostaddr, then +host+ will return the host information.
|
656
|
+
* If only hostaddr was specified, then that is returned.
|
657
|
+
* If multiple hosts were specified in the connection parameters, +host+ returns the host actually connected to.
|
658
|
+
*
|
659
|
+
* 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.
|
660
|
+
*
|
661
|
+
* 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.
|
662
|
+
* The status of the connection can be checked using the function Connection#status .
|
668
663
|
*/
|
669
664
|
static VALUE
|
670
665
|
pgconn_host(VALUE self)
|
671
666
|
{
|
672
667
|
char *host = PQhost(pg_get_pgconn(self));
|
673
668
|
if (!host) return Qnil;
|
674
|
-
return
|
669
|
+
return rb_str_new2(host);
|
670
|
+
}
|
671
|
+
|
672
|
+
/* PQhostaddr() appeared in PostgreSQL-12 together with PQresultMemorySize() */
|
673
|
+
#if defined(HAVE_PQRESULTMEMORYSIZE)
|
674
|
+
/*
|
675
|
+
* call-seq:
|
676
|
+
* conn.hostaddr()
|
677
|
+
*
|
678
|
+
* Returns the server IP address of the active connection.
|
679
|
+
* This can be the address that a host name resolved to, or an IP address provided through the hostaddr parameter.
|
680
|
+
* 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.
|
681
|
+
*
|
682
|
+
*/
|
683
|
+
static VALUE
|
684
|
+
pgconn_hostaddr(VALUE self)
|
685
|
+
{
|
686
|
+
char *host = PQhostaddr(pg_get_pgconn(self));
|
687
|
+
if (!host) return Qnil;
|
688
|
+
return rb_str_new2(host);
|
675
689
|
}
|
690
|
+
#endif
|
676
691
|
|
677
692
|
/*
|
678
693
|
* call-seq:
|
@@ -684,21 +699,22 @@ static VALUE
|
|
684
699
|
pgconn_port(VALUE self)
|
685
700
|
{
|
686
701
|
char* port = PQport(pg_get_pgconn(self));
|
687
|
-
|
702
|
+
if (!port || port[0] == '\0')
|
703
|
+
return INT2NUM(DEF_PGPORT);
|
704
|
+
else
|
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,24 @@ 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
|
+
* This method returns the status of the last command from memory.
|
767
|
+
* It doesn't do any socket access hence is not suitable to test the connectivity.
|
768
|
+
* See check_socket for a way to verify the socket state.
|
769
|
+
*
|
770
|
+
* Example:
|
771
|
+
* PG.constants.grep(/CONNECTION_/).find{|c| PG.const_get(c) == conn.status} # => :CONNECTION_OK
|
747
772
|
*/
|
748
773
|
static VALUE
|
749
774
|
pgconn_status(VALUE self)
|
@@ -793,7 +818,7 @@ pgconn_parameter_status(VALUE self, VALUE param_name)
|
|
793
818
|
if(ret == NULL)
|
794
819
|
return Qnil;
|
795
820
|
else
|
796
|
-
return
|
821
|
+
return rb_str_new2(ret);
|
797
822
|
}
|
798
823
|
|
799
824
|
/*
|
@@ -831,14 +856,17 @@ pgconn_server_version(VALUE self)
|
|
831
856
|
* call-seq:
|
832
857
|
* conn.error_message -> String
|
833
858
|
*
|
834
|
-
* Returns the error message
|
859
|
+
* Returns the error message most recently generated by an operation on the connection.
|
860
|
+
*
|
861
|
+
* Nearly all libpq functions will set a message for conn.error_message if they fail.
|
862
|
+
* Note that by libpq convention, a nonempty error_message result can consist of multiple lines, and will include a trailing newline.
|
835
863
|
*/
|
836
864
|
static VALUE
|
837
865
|
pgconn_error_message(VALUE self)
|
838
866
|
{
|
839
867
|
char *error = PQerrorMessage(pg_get_pgconn(self));
|
840
868
|
if (!error) return Qnil;
|
841
|
-
return
|
869
|
+
return rb_str_new2(error);
|
842
870
|
}
|
843
871
|
|
844
872
|
/*
|
@@ -862,8 +890,11 @@ static VALUE
|
|
862
890
|
pgconn_socket(VALUE self)
|
863
891
|
{
|
864
892
|
int sd;
|
893
|
+
pg_deprecated(4, ("conn.socket is deprecated and should be replaced by conn.socket_io"));
|
894
|
+
|
865
895
|
if( (sd = PQsocket(pg_get_pgconn(self))) < 0)
|
866
|
-
|
896
|
+
pg_raise_conn_error( rb_eConnectionBad, self, "PQsocket() can't get socket descriptor");
|
897
|
+
|
867
898
|
return INT2NUM(sd);
|
868
899
|
}
|
869
900
|
|
@@ -871,39 +902,47 @@ pgconn_socket(VALUE self)
|
|
871
902
|
* call-seq:
|
872
903
|
* conn.socket_io() -> IO
|
873
904
|
*
|
874
|
-
* Fetch
|
875
|
-
* This object can be used for IO.select to wait for events while running
|
876
|
-
*
|
905
|
+
* Fetch an IO object created from the Connection's underlying socket.
|
906
|
+
* 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.
|
907
|
+
* <tt>IO#wait_*able</tt> is is <tt>Fiber.scheduler</tt> compatible in contrast to <tt>IO.select</tt>.
|
877
908
|
*
|
878
|
-
*
|
879
|
-
*
|
880
|
-
*
|
909
|
+
* The IO object can change while the connection is established, but is memorized afterwards.
|
910
|
+
* So be sure not to cache the IO object, but repeat calling <tt>conn.socket_io</tt> instead.
|
911
|
+
*
|
912
|
+
* Using this method also works on Windows in contrast to using #socket .
|
913
|
+
* 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
914
|
*/
|
882
915
|
static VALUE
|
883
916
|
pgconn_socket_io(VALUE self)
|
884
917
|
{
|
885
918
|
int sd;
|
886
919
|
int ruby_sd;
|
887
|
-
ID id_autoclose = rb_intern("autoclose=");
|
888
920
|
t_pg_connection *this = pg_get_connection_safe( self );
|
921
|
+
VALUE cSocket;
|
889
922
|
VALUE socket_io = this->socket_io;
|
890
923
|
|
891
924
|
if ( !RTEST(socket_io) ) {
|
892
|
-
if( (sd = PQsocket(this->pgconn)) < 0)
|
893
|
-
|
925
|
+
if( (sd = PQsocket(this->pgconn)) < 0){
|
926
|
+
pg_raise_conn_error( rb_eConnectionBad, self, "PQsocket() can't get socket descriptor");
|
927
|
+
}
|
894
928
|
|
895
929
|
#ifdef _WIN32
|
896
930
|
ruby_sd = rb_w32_wrap_io_handle((HANDLE)(intptr_t)sd, O_RDWR|O_BINARY|O_NOINHERIT);
|
931
|
+
if( ruby_sd == -1 )
|
932
|
+
pg_raise_conn_error( rb_eConnectionBad, self, "Could not wrap win32 socket handle");
|
933
|
+
|
934
|
+
this->ruby_sd = ruby_sd;
|
897
935
|
#else
|
898
936
|
ruby_sd = sd;
|
899
937
|
#endif
|
900
938
|
|
901
|
-
|
939
|
+
cSocket = rb_const_get(rb_cObject, rb_intern("BasicSocket"));
|
940
|
+
socket_io = rb_funcall( cSocket, rb_intern("for_fd"), 1, INT2NUM(ruby_sd));
|
902
941
|
|
903
942
|
/* Disable autoclose feature */
|
904
|
-
rb_funcall( socket_io,
|
943
|
+
rb_funcall( socket_io, s_id_autoclose_set, 1, Qfalse );
|
905
944
|
|
906
|
-
this->socket_io
|
945
|
+
RB_OBJ_WRITE(self, &this->socket_io, socket_io);
|
907
946
|
}
|
908
947
|
|
909
948
|
return socket_io;
|
@@ -923,6 +962,51 @@ pgconn_backend_pid(VALUE self)
|
|
923
962
|
return INT2NUM(PQbackendPID(pg_get_pgconn(self)));
|
924
963
|
}
|
925
964
|
|
965
|
+
typedef struct
|
966
|
+
{
|
967
|
+
struct sockaddr_storage addr;
|
968
|
+
socklen_t salen;
|
969
|
+
} SockAddr;
|
970
|
+
|
971
|
+
/* Copy of struct pg_cancel from libpq-int.h
|
972
|
+
*
|
973
|
+
* See https://github.com/postgres/postgres/blame/master/src/interfaces/libpq/libpq-int.h#L577-L586
|
974
|
+
*/
|
975
|
+
struct pg_cancel
|
976
|
+
{
|
977
|
+
SockAddr raddr; /* Remote address */
|
978
|
+
int be_pid; /* PID of backend --- needed for cancels */
|
979
|
+
int be_key; /* key of backend --- needed for cancels */
|
980
|
+
};
|
981
|
+
|
982
|
+
/*
|
983
|
+
* call-seq:
|
984
|
+
* conn.backend_key() -> Integer
|
985
|
+
*
|
986
|
+
* Returns the key of the backend server process for this connection.
|
987
|
+
* This key can be used to cancel queries on the server.
|
988
|
+
*/
|
989
|
+
static VALUE
|
990
|
+
pgconn_backend_key(VALUE self)
|
991
|
+
{
|
992
|
+
int be_key;
|
993
|
+
struct pg_cancel *cancel;
|
994
|
+
PGconn *conn = pg_get_pgconn(self);
|
995
|
+
|
996
|
+
cancel = (struct pg_cancel*)PQgetCancel(conn);
|
997
|
+
if(cancel == NULL)
|
998
|
+
pg_raise_conn_error( rb_ePGerror, self, "Invalid connection!");
|
999
|
+
|
1000
|
+
if( cancel->be_pid != PQbackendPID(conn) )
|
1001
|
+
rb_raise(rb_ePGerror,"Unexpected binary struct layout - please file a bug report at ruby-pg!");
|
1002
|
+
|
1003
|
+
be_key = cancel->be_key;
|
1004
|
+
|
1005
|
+
PQfreeCancel(cancel);
|
1006
|
+
|
1007
|
+
return INT2NUM(be_key);
|
1008
|
+
}
|
1009
|
+
|
926
1010
|
/*
|
927
1011
|
* call-seq:
|
928
1012
|
* conn.connection_needs_password() -> Boolean
|
@@ -953,36 +1037,27 @@ pgconn_connection_used_password(VALUE self)
|
|
953
1037
|
/* :TODO: get_ssl */
|
954
1038
|
|
955
1039
|
|
956
|
-
static VALUE
|
1040
|
+
static VALUE pgconn_sync_exec_params( int, VALUE *, VALUE );
|
957
1041
|
|
958
1042
|
/*
|
959
1043
|
* 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.
|
1044
|
+
* conn.sync_exec(sql) -> PG::Result
|
1045
|
+
* conn.sync_exec(sql) {|pg_result| block }
|
966
1046
|
*
|
967
|
-
*
|
968
|
-
*
|
969
|
-
* argument placeholders are used.
|
1047
|
+
* This function has the same behavior as #async_exec, but is implemented using the synchronous command processing API of libpq.
|
1048
|
+
* It's not recommended to use explicit sync or async variants but #exec instead, unless you have a good reason to do so.
|
970
1049
|
*
|
971
|
-
*
|
972
|
-
*
|
973
|
-
* In this instance, <code>conn.exec</code> returns the value of the block.
|
1050
|
+
* Both #sync_exec and #async_exec release the GVL while waiting for server response, so that concurrent threads will get executed.
|
1051
|
+
* However #async_exec has two advantages:
|
974
1052
|
*
|
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.
|
1053
|
+
* 1. #async_exec can be aborted by signals (like Ctrl-C), while #exec blocks signal processing until the query is answered.
|
1054
|
+
* 2. Ruby VM gets notified about IO blocked operations and can pass them through <tt>Fiber.scheduler</tt>.
|
1055
|
+
* So only <tt>async_*</tt> methods are compatible to event based schedulers like the async gem.
|
981
1056
|
*/
|
982
1057
|
static VALUE
|
983
|
-
|
1058
|
+
pgconn_sync_exec(int argc, VALUE *argv, VALUE self)
|
984
1059
|
{
|
985
|
-
|
1060
|
+
t_pg_connection *this = pg_get_connection_safe( self );
|
986
1061
|
PGresult *result = NULL;
|
987
1062
|
VALUE rb_pgresult;
|
988
1063
|
|
@@ -990,7 +1065,7 @@ pgconn_exec(int argc, VALUE *argv, VALUE self)
|
|
990
1065
|
if ( argc == 1 || (argc >= 2 && argc <= 4 && NIL_P(argv[1]) )) {
|
991
1066
|
VALUE query_str = argv[0];
|
992
1067
|
|
993
|
-
result = gvl_PQexec(
|
1068
|
+
result = gvl_PQexec(this->pgconn, pg_cstr_enc(query_str, this->enc_idx));
|
994
1069
|
rb_pgresult = pg_new_result(result, self);
|
995
1070
|
pg_result_check(rb_pgresult);
|
996
1071
|
if (rb_block_given_p()) {
|
@@ -1001,7 +1076,7 @@ pgconn_exec(int argc, VALUE *argv, VALUE self)
|
|
1001
1076
|
pg_deprecated(0, ("forwarding exec to exec_params is deprecated"));
|
1002
1077
|
|
1003
1078
|
/* Otherwise, just call #exec_params instead for backward-compatibility */
|
1004
|
-
return
|
1079
|
+
return pgconn_sync_exec_params( argc, argv, self );
|
1005
1080
|
|
1006
1081
|
}
|
1007
1082
|
|
@@ -1033,7 +1108,7 @@ struct query_params_data {
|
|
1033
1108
|
* Filled by alloc_query_params()
|
1034
1109
|
*/
|
1035
1110
|
|
1036
|
-
/* Wraps the pointer of allocated memory, if function parameters
|
1111
|
+
/* Wraps the pointer of allocated memory, if function parameters don't
|
1037
1112
|
* fit in the memory_pool below.
|
1038
1113
|
*/
|
1039
1114
|
VALUE heap_pool;
|
@@ -1051,7 +1126,7 @@ struct query_params_data {
|
|
1051
1126
|
Oid *types;
|
1052
1127
|
|
1053
1128
|
/* This array takes the string values for the timeframe of the query,
|
1054
|
-
* if param value
|
1129
|
+
* if param value conversion is required
|
1055
1130
|
*/
|
1056
1131
|
VALUE gc_array;
|
1057
1132
|
|
@@ -1065,8 +1140,9 @@ struct query_params_data {
|
|
1065
1140
|
};
|
1066
1141
|
|
1067
1142
|
static void
|
1068
|
-
free_typecast_heap_chain(
|
1143
|
+
free_typecast_heap_chain(void *_chain_entry)
|
1069
1144
|
{
|
1145
|
+
struct linked_typecast_data *chain_entry = (struct linked_typecast_data *)_chain_entry;
|
1070
1146
|
while(chain_entry){
|
1071
1147
|
struct linked_typecast_data *next = chain_entry->next;
|
1072
1148
|
xfree(chain_entry);
|
@@ -1074,6 +1150,18 @@ free_typecast_heap_chain(struct linked_typecast_data *chain_entry)
|
|
1074
1150
|
}
|
1075
1151
|
}
|
1076
1152
|
|
1153
|
+
static const rb_data_type_t pg_typecast_buffer_type = {
|
1154
|
+
"PG::Connection typecast buffer chain",
|
1155
|
+
{
|
1156
|
+
(RUBY_DATA_FUNC) NULL,
|
1157
|
+
free_typecast_heap_chain,
|
1158
|
+
(size_t (*)(const void *))NULL,
|
1159
|
+
},
|
1160
|
+
0,
|
1161
|
+
0,
|
1162
|
+
RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
|
1163
|
+
};
|
1164
|
+
|
1077
1165
|
static char *
|
1078
1166
|
alloc_typecast_buf( VALUE *typecast_heap_chain, int len )
|
1079
1167
|
{
|
@@ -1084,17 +1172,28 @@ alloc_typecast_buf( VALUE *typecast_heap_chain, int len )
|
|
1084
1172
|
/* Did we already wrap a memory chain per T_DATA object? */
|
1085
1173
|
if( NIL_P( *typecast_heap_chain ) ){
|
1086
1174
|
/* Leave free'ing of the buffer chain to the GC, when paramsData has left the stack */
|
1087
|
-
*typecast_heap_chain =
|
1175
|
+
*typecast_heap_chain = TypedData_Wrap_Struct( rb_cObject, &pg_typecast_buffer_type, allocated );
|
1088
1176
|
allocated->next = NULL;
|
1089
1177
|
} else {
|
1090
1178
|
/* Append to the chain */
|
1091
|
-
allocated->next =
|
1092
|
-
|
1179
|
+
allocated->next = RTYPEDDATA_DATA( *typecast_heap_chain );
|
1180
|
+
RTYPEDDATA_DATA( *typecast_heap_chain ) = allocated;
|
1093
1181
|
}
|
1094
1182
|
|
1095
1183
|
return &allocated->data[0];
|
1096
1184
|
}
|
1097
1185
|
|
1186
|
+
static const rb_data_type_t pg_query_heap_pool_type = {
|
1187
|
+
"PG::Connection query heap pool",
|
1188
|
+
{
|
1189
|
+
(RUBY_DATA_FUNC) NULL,
|
1190
|
+
RUBY_TYPED_DEFAULT_FREE,
|
1191
|
+
(size_t (*)(const void *))NULL,
|
1192
|
+
},
|
1193
|
+
0,
|
1194
|
+
0,
|
1195
|
+
RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
|
1196
|
+
};
|
1098
1197
|
|
1099
1198
|
static int
|
1100
1199
|
alloc_query_params(struct query_params_data *paramsData)
|
@@ -1109,7 +1208,7 @@ alloc_query_params(struct query_params_data *paramsData)
|
|
1109
1208
|
|
1110
1209
|
Check_Type(paramsData->params, T_ARRAY);
|
1111
1210
|
|
1112
|
-
p_typemap =
|
1211
|
+
p_typemap = RTYPEDDATA_DATA( paramsData->typemap );
|
1113
1212
|
p_typemap->funcs.fit_to_query( paramsData->typemap, paramsData->params );
|
1114
1213
|
|
1115
1214
|
paramsData->heap_pool = Qnil;
|
@@ -1128,7 +1227,7 @@ alloc_query_params(struct query_params_data *paramsData)
|
|
1128
1227
|
/* Allocate one combined memory pool for all possible function parameters */
|
1129
1228
|
memory_pool = (char*)xmalloc( required_pool_size );
|
1130
1229
|
/* Leave free'ing of the buffer to the GC, when paramsData has left the stack */
|
1131
|
-
paramsData->heap_pool =
|
1230
|
+
paramsData->heap_pool = TypedData_Wrap_Struct( rb_cObject, &pg_query_heap_pool_type, memory_pool );
|
1132
1231
|
required_pool_size = 0;
|
1133
1232
|
}else{
|
1134
1233
|
/* Use stack memory for function parameters */
|
@@ -1241,68 +1340,33 @@ pgconn_query_assign_typemap( VALUE self, struct query_params_data *paramsData )
|
|
1241
1340
|
/* Use default typemap for queries. It's type is checked when assigned. */
|
1242
1341
|
paramsData->typemap = pg_get_connection(self)->type_map_for_queries;
|
1243
1342
|
}else{
|
1343
|
+
t_typemap *tm;
|
1344
|
+
UNUSED(tm);
|
1345
|
+
|
1244
1346
|
/* 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 );
|
1347
|
+
TypedData_Get_Struct(paramsData->typemap, t_typemap, &pg_typemap_type, tm);
|
1250
1348
|
}
|
1251
1349
|
}
|
1252
1350
|
|
1253
1351
|
/*
|
1254
1352
|
* 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 }
|
1353
|
+
* conn.sync_exec_params(sql, params[, result_format[, type_map]] ) -> PG::Result
|
1354
|
+
* conn.sync_exec_params(sql, params[, result_format[, type_map]] ) {|pg_result| block }
|
1272
1355
|
*
|
1273
|
-
*
|
1274
|
-
*
|
1275
|
-
* to
|
1276
|
-
*
|
1277
|
-
* If the types are not specified, they will be inferred by PostgreSQL.
|
1278
|
-
* Instead of specifying type oids, it's recommended to simply add
|
1279
|
-
* explicit casts in the query to ensure that the right type is used.
|
1280
|
-
*
|
1281
|
-
* For example: "SELECT $1::int"
|
1282
|
-
*
|
1283
|
-
* The optional +result_format+ should be 0 for text results, 1
|
1284
|
-
* for binary.
|
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.
|
1356
|
+
* This function has the same behavior as #async_exec_params, but is implemented using the synchronous command processing API of libpq.
|
1357
|
+
* See #async_exec for the differences between the two API variants.
|
1358
|
+
* 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
1359
|
*/
|
1296
1360
|
static VALUE
|
1297
|
-
|
1361
|
+
pgconn_sync_exec_params( int argc, VALUE *argv, VALUE self )
|
1298
1362
|
{
|
1299
|
-
|
1363
|
+
t_pg_connection *this = pg_get_connection_safe( self );
|
1300
1364
|
PGresult *result = NULL;
|
1301
1365
|
VALUE rb_pgresult;
|
1302
1366
|
VALUE command, in_res_fmt;
|
1303
1367
|
int nParams;
|
1304
1368
|
int resultFormat;
|
1305
|
-
struct query_params_data paramsData = {
|
1369
|
+
struct query_params_data paramsData = { this->enc_idx };
|
1306
1370
|
|
1307
1371
|
/* For compatibility we accept 1 to 4 parameters */
|
1308
1372
|
rb_scan_args(argc, argv, "13", &command, ¶msData.params, &in_res_fmt, ¶msData.typemap);
|
@@ -1314,14 +1378,14 @@ pgconn_exec_params( int argc, VALUE *argv, VALUE self )
|
|
1314
1378
|
*/
|
1315
1379
|
if ( NIL_P(paramsData.params) ) {
|
1316
1380
|
pg_deprecated(1, ("forwarding exec_params to exec is deprecated"));
|
1317
|
-
return
|
1381
|
+
return pgconn_sync_exec( 1, argv, self );
|
1318
1382
|
}
|
1319
1383
|
pgconn_query_assign_typemap( self, ¶msData );
|
1320
1384
|
|
1321
1385
|
resultFormat = NIL_P(in_res_fmt) ? 0 : NUM2INT(in_res_fmt);
|
1322
1386
|
nParams = alloc_query_params( ¶msData );
|
1323
1387
|
|
1324
|
-
result = gvl_PQexecParams(
|
1388
|
+
result = gvl_PQexecParams(this->pgconn, pg_cstr_enc(command, paramsData.enc_idx), nParams, paramsData.types,
|
1325
1389
|
(const char * const *)paramsData.values, paramsData.lengths, paramsData.formats, resultFormat);
|
1326
1390
|
|
1327
1391
|
free_query_params( ¶msData );
|
@@ -1338,28 +1402,16 @@ pgconn_exec_params( int argc, VALUE *argv, VALUE self )
|
|
1338
1402
|
|
1339
1403
|
/*
|
1340
1404
|
* 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.
|
1353
|
-
*
|
1354
|
-
* For example: "SELECT $1::int"
|
1405
|
+
* conn.sync_prepare(stmt_name, sql [, param_types ] ) -> PG::Result
|
1355
1406
|
*
|
1356
|
-
*
|
1357
|
-
*
|
1407
|
+
* This function has the same behavior as #async_prepare, but is implemented using the synchronous command processing API of libpq.
|
1408
|
+
* See #async_exec for the differences between the two API variants.
|
1409
|
+
* It's not recommended to use explicit sync or async variants but #prepare instead, unless you have a good reason to do so.
|
1358
1410
|
*/
|
1359
1411
|
static VALUE
|
1360
|
-
|
1412
|
+
pgconn_sync_prepare(int argc, VALUE *argv, VALUE self)
|
1361
1413
|
{
|
1362
|
-
|
1414
|
+
t_pg_connection *this = pg_get_connection_safe( self );
|
1363
1415
|
PGresult *result = NULL;
|
1364
1416
|
VALUE rb_pgresult;
|
1365
1417
|
VALUE name, command, in_paramtypes;
|
@@ -1369,7 +1421,7 @@ pgconn_prepare(int argc, VALUE *argv, VALUE self)
|
|
1369
1421
|
Oid *paramTypes = NULL;
|
1370
1422
|
const char *name_cstr;
|
1371
1423
|
const char *command_cstr;
|
1372
|
-
int enc_idx =
|
1424
|
+
int enc_idx = this->enc_idx;
|
1373
1425
|
|
1374
1426
|
rb_scan_args(argc, argv, "21", &name, &command, &in_paramtypes);
|
1375
1427
|
name_cstr = pg_cstr_enc(name, enc_idx);
|
@@ -1387,7 +1439,7 @@ pgconn_prepare(int argc, VALUE *argv, VALUE self)
|
|
1387
1439
|
paramTypes[i] = NUM2UINT(param);
|
1388
1440
|
}
|
1389
1441
|
}
|
1390
|
-
result = gvl_PQprepare(
|
1442
|
+
result = gvl_PQprepare(this->pgconn, name_cstr, command_cstr, nParams, paramTypes);
|
1391
1443
|
|
1392
1444
|
xfree(paramTypes);
|
1393
1445
|
|
@@ -1398,49 +1450,23 @@ pgconn_prepare(int argc, VALUE *argv, VALUE self)
|
|
1398
1450
|
|
1399
1451
|
/*
|
1400
1452
|
* 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.
|
1453
|
+
* conn.sync_exec_prepared(statement_name [, params, result_format[, type_map]] ) -> PG::Result
|
1454
|
+
* conn.sync_exec_prepared(statement_name [, params, result_format[, type_map]] ) {|pg_result| block }
|
1429
1455
|
*
|
1430
|
-
*
|
1431
|
-
*
|
1432
|
-
*
|
1456
|
+
* This function has the same behavior as #async_exec_prepared, but is implemented using the synchronous command processing API of libpq.
|
1457
|
+
* See #async_exec for the differences between the two API variants.
|
1458
|
+
* 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
1459
|
*/
|
1434
1460
|
static VALUE
|
1435
|
-
|
1461
|
+
pgconn_sync_exec_prepared(int argc, VALUE *argv, VALUE self)
|
1436
1462
|
{
|
1437
|
-
|
1463
|
+
t_pg_connection *this = pg_get_connection_safe( self );
|
1438
1464
|
PGresult *result = NULL;
|
1439
1465
|
VALUE rb_pgresult;
|
1440
1466
|
VALUE name, in_res_fmt;
|
1441
1467
|
int nParams;
|
1442
1468
|
int resultFormat;
|
1443
|
-
struct query_params_data paramsData = {
|
1469
|
+
struct query_params_data paramsData = { this->enc_idx };
|
1444
1470
|
|
1445
1471
|
rb_scan_args(argc, argv, "13", &name, ¶msData.params, &in_res_fmt, ¶msData.typemap);
|
1446
1472
|
paramsData.with_types = 0;
|
@@ -1453,7 +1479,7 @@ pgconn_exec_prepared(int argc, VALUE *argv, VALUE self)
|
|
1453
1479
|
resultFormat = NIL_P(in_res_fmt) ? 0 : NUM2INT(in_res_fmt);
|
1454
1480
|
nParams = alloc_query_params( ¶msData );
|
1455
1481
|
|
1456
|
-
result = gvl_PQexecPrepared(
|
1482
|
+
result = gvl_PQexecPrepared(this->pgconn, pg_cstr_enc(name, paramsData.enc_idx), nParams,
|
1457
1483
|
(const char * const *)paramsData.values, paramsData.lengths, paramsData.formats,
|
1458
1484
|
resultFormat);
|
1459
1485
|
|
@@ -1470,25 +1496,26 @@ pgconn_exec_prepared(int argc, VALUE *argv, VALUE self)
|
|
1470
1496
|
|
1471
1497
|
/*
|
1472
1498
|
* call-seq:
|
1473
|
-
* conn.
|
1499
|
+
* conn.sync_describe_prepared( statement_name ) -> PG::Result
|
1474
1500
|
*
|
1475
|
-
*
|
1476
|
-
*
|
1501
|
+
* This function has the same behavior as #async_describe_prepared, but is implemented using the synchronous command processing API of libpq.
|
1502
|
+
* See #async_exec for the differences between the two API variants.
|
1503
|
+
* 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
1504
|
*/
|
1478
1505
|
static VALUE
|
1479
|
-
|
1506
|
+
pgconn_sync_describe_prepared(VALUE self, VALUE stmt_name)
|
1480
1507
|
{
|
1481
1508
|
PGresult *result;
|
1482
1509
|
VALUE rb_pgresult;
|
1483
|
-
|
1510
|
+
t_pg_connection *this = pg_get_connection_safe( self );
|
1484
1511
|
const char *stmt;
|
1485
1512
|
if(NIL_P(stmt_name)) {
|
1486
1513
|
stmt = NULL;
|
1487
1514
|
}
|
1488
1515
|
else {
|
1489
|
-
stmt = pg_cstr_enc(stmt_name,
|
1516
|
+
stmt = pg_cstr_enc(stmt_name, this->enc_idx);
|
1490
1517
|
}
|
1491
|
-
result = gvl_PQdescribePrepared(
|
1518
|
+
result = gvl_PQdescribePrepared(this->pgconn, stmt);
|
1492
1519
|
rb_pgresult = pg_new_result(result, self);
|
1493
1520
|
pg_result_check(rb_pgresult);
|
1494
1521
|
return rb_pgresult;
|
@@ -1497,25 +1524,26 @@ pgconn_describe_prepared(VALUE self, VALUE stmt_name)
|
|
1497
1524
|
|
1498
1525
|
/*
|
1499
1526
|
* call-seq:
|
1500
|
-
* conn.
|
1527
|
+
* conn.sync_describe_portal( portal_name ) -> PG::Result
|
1501
1528
|
*
|
1502
|
-
*
|
1529
|
+
* This function has the same behavior as #async_describe_portal, but is implemented using the synchronous command processing API of libpq.
|
1530
|
+
* See #async_exec for the differences between the two API variants.
|
1531
|
+
* 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
1532
|
*/
|
1504
1533
|
static VALUE
|
1505
|
-
|
1506
|
-
VALUE self, stmt_name;
|
1534
|
+
pgconn_sync_describe_portal(VALUE self, VALUE stmt_name)
|
1507
1535
|
{
|
1508
1536
|
PGresult *result;
|
1509
1537
|
VALUE rb_pgresult;
|
1510
|
-
|
1538
|
+
t_pg_connection *this = pg_get_connection_safe( self );
|
1511
1539
|
const char *stmt;
|
1512
1540
|
if(NIL_P(stmt_name)) {
|
1513
1541
|
stmt = NULL;
|
1514
1542
|
}
|
1515
1543
|
else {
|
1516
|
-
stmt = pg_cstr_enc(stmt_name,
|
1544
|
+
stmt = pg_cstr_enc(stmt_name, this->enc_idx);
|
1517
1545
|
}
|
1518
|
-
result = gvl_PQdescribePortal(
|
1546
|
+
result = gvl_PQdescribePortal(this->pgconn, stmt);
|
1519
1547
|
rb_pgresult = pg_new_result(result, self);
|
1520
1548
|
pg_result_check(rb_pgresult);
|
1521
1549
|
return rb_pgresult;
|
@@ -1537,6 +1565,9 @@ pgconn_describe_portal(self, stmt_name)
|
|
1537
1565
|
* * +PGRES_NONFATAL_ERROR+
|
1538
1566
|
* * +PGRES_FATAL_ERROR+
|
1539
1567
|
* * +PGRES_COPY_BOTH+
|
1568
|
+
* * +PGRES_SINGLE_TUPLE+
|
1569
|
+
* * +PGRES_PIPELINE_SYNC+
|
1570
|
+
* * +PGRES_PIPELINE_ABORTED+
|
1540
1571
|
*/
|
1541
1572
|
static VALUE
|
1542
1573
|
pgconn_make_empty_pgresult(VALUE self, VALUE status)
|
@@ -1562,13 +1593,15 @@ pgconn_make_empty_pgresult(VALUE self, VALUE status)
|
|
1562
1593
|
* Consider using exec_params, which avoids the need for passing values
|
1563
1594
|
* inside of SQL commands.
|
1564
1595
|
*
|
1565
|
-
*
|
1596
|
+
* Character encoding of escaped string will be equal to client encoding of connection.
|
1566
1597
|
*
|
1567
1598
|
* NOTE: This class version of this method can only be used safely in client
|
1568
1599
|
* programs that use a single PostgreSQL connection at a time (in this case it can
|
1569
1600
|
* find out what it needs to know "behind the scenes"). It might give the wrong
|
1570
1601
|
* results if used in programs that use multiple database connections; use the
|
1571
1602
|
* same method on the connection object in such cases.
|
1603
|
+
*
|
1604
|
+
* See also convenience functions #escape_literal and #escape_identifier which also add proper quotes around the string.
|
1572
1605
|
*/
|
1573
1606
|
static VALUE
|
1574
1607
|
pgconn_s_escape(VALUE self, VALUE string)
|
@@ -1580,7 +1613,7 @@ pgconn_s_escape(VALUE self, VALUE string)
|
|
1580
1613
|
int singleton = !rb_obj_is_kind_of(self, rb_cPGconn);
|
1581
1614
|
|
1582
1615
|
StringValueCStr(string);
|
1583
|
-
enc_idx =
|
1616
|
+
enc_idx = singleton ? ENCODING_GET(string) : pg_get_connection(self)->enc_idx;
|
1584
1617
|
if( ENCODING_GET(string) != enc_idx ){
|
1585
1618
|
string = rb_str_export_to_enc(string, rb_enc_from_index(enc_idx));
|
1586
1619
|
}
|
@@ -1590,14 +1623,13 @@ pgconn_s_escape(VALUE self, VALUE string)
|
|
1590
1623
|
if( !singleton ) {
|
1591
1624
|
size = PQescapeStringConn(pg_get_pgconn(self), RSTRING_PTR(result),
|
1592
1625
|
RSTRING_PTR(string), RSTRING_LEN(string), &error);
|
1593
|
-
if(error)
|
1594
|
-
|
1595
|
-
|
1626
|
+
if(error)
|
1627
|
+
pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(pg_get_pgconn(self)));
|
1628
|
+
|
1596
1629
|
} else {
|
1597
1630
|
size = PQescapeString(RSTRING_PTR(result), RSTRING_PTR(string), RSTRING_LEN(string));
|
1598
1631
|
}
|
1599
1632
|
rb_str_set_len(result, size);
|
1600
|
-
OBJ_INFECT(result, string);
|
1601
1633
|
|
1602
1634
|
return result;
|
1603
1635
|
}
|
@@ -1643,7 +1675,6 @@ pgconn_s_escape_bytea(VALUE self, VALUE str)
|
|
1643
1675
|
}
|
1644
1676
|
|
1645
1677
|
ret = rb_str_new((char*)to, to_len - 1);
|
1646
|
-
OBJ_INFECT(ret, str);
|
1647
1678
|
PQfreemem(to);
|
1648
1679
|
return ret;
|
1649
1680
|
}
|
@@ -1673,7 +1704,6 @@ pgconn_s_unescape_bytea(VALUE self, VALUE str)
|
|
1673
1704
|
to = PQunescapeBytea(from, &to_len);
|
1674
1705
|
|
1675
1706
|
ret = rb_str_new((char*)to, to_len);
|
1676
|
-
OBJ_INFECT(ret, str);
|
1677
1707
|
PQfreemem(to);
|
1678
1708
|
return ret;
|
1679
1709
|
}
|
@@ -1684,33 +1714,27 @@ pgconn_s_unescape_bytea(VALUE self, VALUE str)
|
|
1684
1714
|
*
|
1685
1715
|
* Escape an arbitrary String +str+ as a literal.
|
1686
1716
|
*
|
1687
|
-
*
|
1717
|
+
* See also PG::TextEncoder::QuotedLiteral for a type cast integrated version of this function.
|
1688
1718
|
*/
|
1689
1719
|
static VALUE
|
1690
1720
|
pgconn_escape_literal(VALUE self, VALUE string)
|
1691
1721
|
{
|
1692
|
-
|
1722
|
+
t_pg_connection *this = pg_get_connection_safe( self );
|
1693
1723
|
char *escaped = NULL;
|
1694
|
-
VALUE error;
|
1695
1724
|
VALUE result = Qnil;
|
1696
|
-
int enc_idx =
|
1725
|
+
int enc_idx = this->enc_idx;
|
1697
1726
|
|
1698
1727
|
StringValueCStr(string);
|
1699
1728
|
if( ENCODING_GET(string) != enc_idx ){
|
1700
1729
|
string = rb_str_export_to_enc(string, rb_enc_from_index(enc_idx));
|
1701
1730
|
}
|
1702
1731
|
|
1703
|
-
escaped = PQescapeLiteral(
|
1732
|
+
escaped = PQescapeLiteral(this->pgconn, RSTRING_PTR(string), RSTRING_LEN(string));
|
1704
1733
|
if (escaped == NULL)
|
1705
|
-
|
1706
|
-
|
1707
|
-
rb_iv_set(error, "@connection", self);
|
1708
|
-
rb_exc_raise(error);
|
1709
|
-
return Qnil;
|
1710
|
-
}
|
1734
|
+
pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(this->pgconn));
|
1735
|
+
|
1711
1736
|
result = rb_str_new2(escaped);
|
1712
1737
|
PQfreemem(escaped);
|
1713
|
-
OBJ_INFECT(result, string);
|
1714
1738
|
PG_ENCODING_SET_NOCHECK(result, enc_idx);
|
1715
1739
|
|
1716
1740
|
return result;
|
@@ -1725,34 +1749,26 @@ pgconn_escape_literal(VALUE self, VALUE string)
|
|
1725
1749
|
* This method does the same as #quote_ident with a String argument,
|
1726
1750
|
* but it doesn't support an Array argument and it makes use of libpq
|
1727
1751
|
* to process the string.
|
1728
|
-
*
|
1729
|
-
* Available since PostgreSQL-9.0
|
1730
1752
|
*/
|
1731
1753
|
static VALUE
|
1732
1754
|
pgconn_escape_identifier(VALUE self, VALUE string)
|
1733
1755
|
{
|
1734
|
-
|
1756
|
+
t_pg_connection *this = pg_get_connection_safe( self );
|
1735
1757
|
char *escaped = NULL;
|
1736
|
-
VALUE error;
|
1737
1758
|
VALUE result = Qnil;
|
1738
|
-
int enc_idx =
|
1759
|
+
int enc_idx = this->enc_idx;
|
1739
1760
|
|
1740
1761
|
StringValueCStr(string);
|
1741
1762
|
if( ENCODING_GET(string) != enc_idx ){
|
1742
1763
|
string = rb_str_export_to_enc(string, rb_enc_from_index(enc_idx));
|
1743
1764
|
}
|
1744
1765
|
|
1745
|
-
escaped = PQescapeIdentifier(
|
1766
|
+
escaped = PQescapeIdentifier(this->pgconn, RSTRING_PTR(string), RSTRING_LEN(string));
|
1746
1767
|
if (escaped == NULL)
|
1747
|
-
|
1748
|
-
|
1749
|
-
rb_iv_set(error, "@connection", self);
|
1750
|
-
rb_exc_raise(error);
|
1751
|
-
return Qnil;
|
1752
|
-
}
|
1768
|
+
pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(this->pgconn));
|
1769
|
+
|
1753
1770
|
result = rb_str_new2(escaped);
|
1754
1771
|
PQfreemem(escaped);
|
1755
|
-
OBJ_INFECT(result, string);
|
1756
1772
|
PG_ENCODING_SET_NOCHECK(result, enc_idx);
|
1757
1773
|
|
1758
1774
|
return result;
|
@@ -1793,21 +1809,15 @@ pgconn_escape_identifier(VALUE self, VALUE string)
|
|
1793
1809
|
* # do something with the received row
|
1794
1810
|
* end
|
1795
1811
|
* end
|
1796
|
-
*
|
1797
|
-
* Available since PostgreSQL-9.2
|
1798
1812
|
*/
|
1799
1813
|
static VALUE
|
1800
1814
|
pgconn_set_single_row_mode(VALUE self)
|
1801
1815
|
{
|
1802
1816
|
PGconn *conn = pg_get_pgconn(self);
|
1803
|
-
VALUE error;
|
1804
1817
|
|
1818
|
+
rb_check_frozen(self);
|
1805
1819
|
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
|
-
}
|
1820
|
+
pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(conn));
|
1811
1821
|
|
1812
1822
|
return self;
|
1813
1823
|
}
|
@@ -1830,16 +1840,14 @@ static VALUE pgconn_send_query_params(int argc, VALUE *argv, VALUE self);
|
|
1830
1840
|
static VALUE
|
1831
1841
|
pgconn_send_query(int argc, VALUE *argv, VALUE self)
|
1832
1842
|
{
|
1833
|
-
|
1834
|
-
VALUE error;
|
1843
|
+
t_pg_connection *this = pg_get_connection_safe( self );
|
1835
1844
|
|
1836
1845
|
/* If called with no or nil parameters, use PQexec for compatibility */
|
1837
1846
|
if ( argc == 1 || (argc >= 2 && argc <= 4 && NIL_P(argv[1]) )) {
|
1838
|
-
if(gvl_PQsendQuery(
|
1839
|
-
|
1840
|
-
|
1841
|
-
|
1842
|
-
}
|
1847
|
+
if(gvl_PQsendQuery(this->pgconn, pg_cstr_enc(argv[0], this->enc_idx)) == 0)
|
1848
|
+
pg_raise_conn_error( rb_eUnableToSend, self, "%s", PQerrorMessage(this->pgconn));
|
1849
|
+
|
1850
|
+
pgconn_wait_for_flush( self );
|
1843
1851
|
return Qnil;
|
1844
1852
|
}
|
1845
1853
|
|
@@ -1869,7 +1877,7 @@ pgconn_send_query(int argc, VALUE *argv, VALUE self)
|
|
1869
1877
|
* or, it may be a String. If it is a string, that is equivalent to the hash:
|
1870
1878
|
* { :value => <string value>, :type => 0, :format => 0 }
|
1871
1879
|
*
|
1872
|
-
* PostgreSQL bind parameters are represented as $1, $
|
1880
|
+
* PostgreSQL bind parameters are represented as $1, $2, $3, etc.,
|
1873
1881
|
* inside the SQL query. The 0th element of the +params+ array is bound
|
1874
1882
|
* to $1, the 1st element is bound to $2, etc. +nil+ is treated as +NULL+.
|
1875
1883
|
*
|
@@ -1882,7 +1890,7 @@ pgconn_send_query(int argc, VALUE *argv, VALUE self)
|
|
1882
1890
|
* The optional +result_format+ should be 0 for text results, 1
|
1883
1891
|
* for binary.
|
1884
1892
|
*
|
1885
|
-
* type_map can be a PG::TypeMap derivation (such as PG::BasicTypeMapForQueries).
|
1893
|
+
* +type_map+ can be a PG::TypeMap derivation (such as PG::BasicTypeMapForQueries).
|
1886
1894
|
* This will type cast the params from various Ruby types before transmission
|
1887
1895
|
* based on the encoders defined by the type map. When a type encoder is used
|
1888
1896
|
* the format and oid of a given bind parameter are retrieved from the encoder
|
@@ -1892,13 +1900,12 @@ pgconn_send_query(int argc, VALUE *argv, VALUE self)
|
|
1892
1900
|
static VALUE
|
1893
1901
|
pgconn_send_query_params(int argc, VALUE *argv, VALUE self)
|
1894
1902
|
{
|
1895
|
-
|
1903
|
+
t_pg_connection *this = pg_get_connection_safe( self );
|
1896
1904
|
int result;
|
1897
1905
|
VALUE command, in_res_fmt;
|
1898
|
-
VALUE error;
|
1899
1906
|
int nParams;
|
1900
1907
|
int resultFormat;
|
1901
|
-
struct query_params_data paramsData = {
|
1908
|
+
struct query_params_data paramsData = { this->enc_idx };
|
1902
1909
|
|
1903
1910
|
rb_scan_args(argc, argv, "22", &command, ¶msData.params, &in_res_fmt, ¶msData.typemap);
|
1904
1911
|
paramsData.with_types = 1;
|
@@ -1907,16 +1914,15 @@ pgconn_send_query_params(int argc, VALUE *argv, VALUE self)
|
|
1907
1914
|
resultFormat = NIL_P(in_res_fmt) ? 0 : NUM2INT(in_res_fmt);
|
1908
1915
|
nParams = alloc_query_params( ¶msData );
|
1909
1916
|
|
1910
|
-
result = gvl_PQsendQueryParams(
|
1917
|
+
result = gvl_PQsendQueryParams(this->pgconn, pg_cstr_enc(command, paramsData.enc_idx), nParams, paramsData.types,
|
1911
1918
|
(const char * const *)paramsData.values, paramsData.lengths, paramsData.formats, resultFormat);
|
1912
1919
|
|
1913
1920
|
free_query_params( ¶msData );
|
1914
1921
|
|
1915
|
-
if(result == 0)
|
1916
|
-
|
1917
|
-
|
1918
|
-
|
1919
|
-
}
|
1922
|
+
if(result == 0)
|
1923
|
+
pg_raise_conn_error( rb_eUnableToSend, self, "%s", PQerrorMessage(this->pgconn));
|
1924
|
+
|
1925
|
+
pgconn_wait_for_flush( self );
|
1920
1926
|
return Qnil;
|
1921
1927
|
}
|
1922
1928
|
|
@@ -1937,23 +1943,22 @@ pgconn_send_query_params(int argc, VALUE *argv, VALUE self)
|
|
1937
1943
|
*
|
1938
1944
|
* For example: "SELECT $1::int"
|
1939
1945
|
*
|
1940
|
-
* PostgreSQL bind parameters are represented as $1, $
|
1946
|
+
* PostgreSQL bind parameters are represented as $1, $2, $3, etc.,
|
1941
1947
|
* inside the SQL query.
|
1942
1948
|
*/
|
1943
1949
|
static VALUE
|
1944
1950
|
pgconn_send_prepare(int argc, VALUE *argv, VALUE self)
|
1945
1951
|
{
|
1946
|
-
|
1952
|
+
t_pg_connection *this = pg_get_connection_safe( self );
|
1947
1953
|
int result;
|
1948
1954
|
VALUE name, command, in_paramtypes;
|
1949
1955
|
VALUE param;
|
1950
|
-
VALUE error;
|
1951
1956
|
int i = 0;
|
1952
1957
|
int nParams = 0;
|
1953
1958
|
Oid *paramTypes = NULL;
|
1954
1959
|
const char *name_cstr;
|
1955
1960
|
const char *command_cstr;
|
1956
|
-
int enc_idx =
|
1961
|
+
int enc_idx = this->enc_idx;
|
1957
1962
|
|
1958
1963
|
rb_scan_args(argc, argv, "21", &name, &command, &in_paramtypes);
|
1959
1964
|
name_cstr = pg_cstr_enc(name, enc_idx);
|
@@ -1971,15 +1976,14 @@ pgconn_send_prepare(int argc, VALUE *argv, VALUE self)
|
|
1971
1976
|
paramTypes[i] = NUM2UINT(param);
|
1972
1977
|
}
|
1973
1978
|
}
|
1974
|
-
result = gvl_PQsendPrepare(
|
1979
|
+
result = gvl_PQsendPrepare(this->pgconn, name_cstr, command_cstr, nParams, paramTypes);
|
1975
1980
|
|
1976
1981
|
xfree(paramTypes);
|
1977
1982
|
|
1978
1983
|
if(result == 0) {
|
1979
|
-
|
1980
|
-
rb_iv_set(error, "@connection", self);
|
1981
|
-
rb_exc_raise(error);
|
1984
|
+
pg_raise_conn_error( rb_eUnableToSend, self, "%s", PQerrorMessage(this->pgconn));
|
1982
1985
|
}
|
1986
|
+
pgconn_wait_for_flush( self );
|
1983
1987
|
return Qnil;
|
1984
1988
|
}
|
1985
1989
|
|
@@ -2001,14 +2005,14 @@ pgconn_send_prepare(int argc, VALUE *argv, VALUE self)
|
|
2001
2005
|
* or, it may be a String. If it is a string, that is equivalent to the hash:
|
2002
2006
|
* { :value => <string value>, :format => 0 }
|
2003
2007
|
*
|
2004
|
-
* PostgreSQL bind parameters are represented as $1, $
|
2008
|
+
* PostgreSQL bind parameters are represented as $1, $2, $3, etc.,
|
2005
2009
|
* inside the SQL query. The 0th element of the +params+ array is bound
|
2006
2010
|
* to $1, the 1st element is bound to $2, etc. +nil+ is treated as +NULL+.
|
2007
2011
|
*
|
2008
2012
|
* The optional +result_format+ should be 0 for text results, 1
|
2009
2013
|
* for binary.
|
2010
2014
|
*
|
2011
|
-
* type_map can be a PG::TypeMap derivation (such as PG::BasicTypeMapForQueries).
|
2015
|
+
* +type_map+ can be a PG::TypeMap derivation (such as PG::BasicTypeMapForQueries).
|
2012
2016
|
* This will type cast the params from various Ruby types before transmission
|
2013
2017
|
* based on the encoders defined by the type map. When a type encoder is used
|
2014
2018
|
* the format and oid of a given bind parameter are retrieved from the encoder
|
@@ -2018,37 +2022,34 @@ pgconn_send_prepare(int argc, VALUE *argv, VALUE self)
|
|
2018
2022
|
static VALUE
|
2019
2023
|
pgconn_send_query_prepared(int argc, VALUE *argv, VALUE self)
|
2020
2024
|
{
|
2021
|
-
|
2025
|
+
t_pg_connection *this = pg_get_connection_safe( self );
|
2022
2026
|
int result;
|
2023
2027
|
VALUE name, in_res_fmt;
|
2024
|
-
VALUE error;
|
2025
2028
|
int nParams;
|
2026
2029
|
int resultFormat;
|
2027
|
-
struct query_params_data paramsData = {
|
2030
|
+
struct query_params_data paramsData = { this->enc_idx };
|
2028
2031
|
|
2029
2032
|
rb_scan_args(argc, argv, "13", &name, ¶msData.params, &in_res_fmt, ¶msData.typemap);
|
2030
2033
|
paramsData.with_types = 0;
|
2031
2034
|
|
2032
2035
|
if(NIL_P(paramsData.params)) {
|
2033
2036
|
paramsData.params = rb_ary_new2(0);
|
2034
|
-
resultFormat = 0;
|
2035
2037
|
}
|
2036
2038
|
pgconn_query_assign_typemap( self, ¶msData );
|
2037
2039
|
|
2038
2040
|
resultFormat = NIL_P(in_res_fmt) ? 0 : NUM2INT(in_res_fmt);
|
2039
2041
|
nParams = alloc_query_params( ¶msData );
|
2040
2042
|
|
2041
|
-
result = gvl_PQsendQueryPrepared(
|
2043
|
+
result = gvl_PQsendQueryPrepared(this->pgconn, pg_cstr_enc(name, paramsData.enc_idx), nParams,
|
2042
2044
|
(const char * const *)paramsData.values, paramsData.lengths, paramsData.formats,
|
2043
2045
|
resultFormat);
|
2044
2046
|
|
2045
2047
|
free_query_params( ¶msData );
|
2046
2048
|
|
2047
|
-
if(result == 0)
|
2048
|
-
|
2049
|
-
|
2050
|
-
|
2051
|
-
}
|
2049
|
+
if(result == 0)
|
2050
|
+
pg_raise_conn_error( rb_eUnableToSend, self, "%s", PQerrorMessage(this->pgconn));
|
2051
|
+
|
2052
|
+
pgconn_wait_for_flush( self );
|
2052
2053
|
return Qnil;
|
2053
2054
|
}
|
2054
2055
|
|
@@ -2062,14 +2063,12 @@ pgconn_send_query_prepared(int argc, VALUE *argv, VALUE self)
|
|
2062
2063
|
static VALUE
|
2063
2064
|
pgconn_send_describe_prepared(VALUE self, VALUE stmt_name)
|
2064
2065
|
{
|
2065
|
-
|
2066
|
-
PGconn *conn = pg_get_pgconn(self);
|
2066
|
+
t_pg_connection *this = pg_get_connection_safe( self );
|
2067
2067
|
/* returns 0 on failure */
|
2068
|
-
if(gvl_PQsendDescribePrepared(
|
2069
|
-
|
2070
|
-
|
2071
|
-
|
2072
|
-
}
|
2068
|
+
if(gvl_PQsendDescribePrepared(this->pgconn, pg_cstr_enc(stmt_name, this->enc_idx)) == 0)
|
2069
|
+
pg_raise_conn_error( rb_eUnableToSend, self, "%s", PQerrorMessage(this->pgconn));
|
2070
|
+
|
2071
|
+
pgconn_wait_for_flush( self );
|
2073
2072
|
return Qnil;
|
2074
2073
|
}
|
2075
2074
|
|
@@ -2084,36 +2083,18 @@ pgconn_send_describe_prepared(VALUE self, VALUE stmt_name)
|
|
2084
2083
|
static VALUE
|
2085
2084
|
pgconn_send_describe_portal(VALUE self, VALUE portal)
|
2086
2085
|
{
|
2087
|
-
|
2088
|
-
PGconn *conn = pg_get_pgconn(self);
|
2086
|
+
t_pg_connection *this = pg_get_connection_safe( self );
|
2089
2087
|
/* returns 0 on failure */
|
2090
|
-
if(gvl_PQsendDescribePortal(
|
2091
|
-
|
2092
|
-
|
2093
|
-
|
2094
|
-
}
|
2088
|
+
if(gvl_PQsendDescribePortal(this->pgconn, pg_cstr_enc(portal, this->enc_idx)) == 0)
|
2089
|
+
pg_raise_conn_error( rb_eUnableToSend, self, "%s", PQerrorMessage(this->pgconn));
|
2090
|
+
|
2091
|
+
pgconn_wait_for_flush( self );
|
2095
2092
|
return Qnil;
|
2096
2093
|
}
|
2097
2094
|
|
2098
2095
|
|
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
2096
|
static VALUE
|
2116
|
-
|
2097
|
+
pgconn_sync_get_result(VALUE self)
|
2117
2098
|
{
|
2118
2099
|
PGconn *conn = pg_get_pgconn(self);
|
2119
2100
|
PGresult *result;
|
@@ -2139,17 +2120,15 @@ pgconn_get_result(VALUE self)
|
|
2139
2120
|
* or *notifies* to see if the state has changed.
|
2140
2121
|
*/
|
2141
2122
|
static VALUE
|
2142
|
-
pgconn_consume_input(self)
|
2143
|
-
VALUE self;
|
2123
|
+
pgconn_consume_input(VALUE self)
|
2144
2124
|
{
|
2145
|
-
VALUE error;
|
2146
2125
|
PGconn *conn = pg_get_pgconn(self);
|
2147
2126
|
/* returns 0 on error */
|
2148
2127
|
if(PQconsumeInput(conn) == 0) {
|
2149
|
-
|
2150
|
-
|
2151
|
-
rb_exc_raise(error);
|
2128
|
+
pgconn_close_socket_io(self);
|
2129
|
+
pg_raise_conn_error( rb_eConnectionBad, self, "%s", PQerrorMessage(conn));
|
2152
2130
|
}
|
2131
|
+
|
2153
2132
|
return Qnil;
|
2154
2133
|
}
|
2155
2134
|
|
@@ -2158,38 +2137,20 @@ pgconn_consume_input(self)
|
|
2158
2137
|
* conn.is_busy() -> Boolean
|
2159
2138
|
*
|
2160
2139
|
* Returns +true+ if a command is busy, that is, if
|
2161
|
-
*
|
2140
|
+
* #get_result would block. Otherwise returns +false+.
|
2162
2141
|
*/
|
2163
2142
|
static VALUE
|
2164
|
-
pgconn_is_busy(self)
|
2165
|
-
VALUE self;
|
2143
|
+
pgconn_is_busy(VALUE self)
|
2166
2144
|
{
|
2167
2145
|
return gvl_PQisBusy(pg_get_pgconn(self)) ? Qtrue : Qfalse;
|
2168
2146
|
}
|
2169
2147
|
|
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
2148
|
static VALUE
|
2187
|
-
|
2188
|
-
VALUE self, state;
|
2149
|
+
pgconn_sync_setnonblocking(VALUE self, VALUE state)
|
2189
2150
|
{
|
2190
2151
|
int arg;
|
2191
|
-
VALUE error;
|
2192
2152
|
PGconn *conn = pg_get_pgconn(self);
|
2153
|
+
rb_check_frozen(self);
|
2193
2154
|
if(state == Qtrue)
|
2194
2155
|
arg = 1;
|
2195
2156
|
else if (state == Qfalse)
|
@@ -2197,67 +2158,32 @@ pgconn_setnonblocking(self, state)
|
|
2197
2158
|
else
|
2198
2159
|
rb_raise(rb_eArgError, "Boolean value expected");
|
2199
2160
|
|
2200
|
-
if(PQsetnonblocking(conn, arg) == -1)
|
2201
|
-
|
2202
|
-
|
2203
|
-
rb_exc_raise(error);
|
2204
|
-
}
|
2161
|
+
if(PQsetnonblocking(conn, arg) == -1)
|
2162
|
+
pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(conn));
|
2163
|
+
|
2205
2164
|
return Qnil;
|
2206
2165
|
}
|
2207
2166
|
|
2208
2167
|
|
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
2168
|
static VALUE
|
2217
|
-
|
2218
|
-
VALUE self;
|
2169
|
+
pgconn_sync_isnonblocking(VALUE self)
|
2219
2170
|
{
|
2220
2171
|
return PQisnonblocking(pg_get_pgconn(self)) ? Qtrue : Qfalse;
|
2221
2172
|
}
|
2222
2173
|
|
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
2174
|
static VALUE
|
2234
|
-
|
2235
|
-
VALUE self;
|
2175
|
+
pgconn_sync_flush(VALUE self)
|
2236
2176
|
{
|
2237
2177
|
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
|
-
}
|
2178
|
+
int ret = PQflush(conn);
|
2179
|
+
if(ret == -1)
|
2180
|
+
pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(conn));
|
2181
|
+
|
2246
2182
|
return (ret) ? Qfalse : Qtrue;
|
2247
2183
|
}
|
2248
2184
|
|
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
2185
|
static VALUE
|
2260
|
-
|
2186
|
+
pgconn_sync_cancel(VALUE self)
|
2261
2187
|
{
|
2262
2188
|
char errbuf[256];
|
2263
2189
|
PGcancel *cancel;
|
@@ -2266,9 +2192,9 @@ pgconn_cancel(VALUE self)
|
|
2266
2192
|
|
2267
2193
|
cancel = PQgetCancel(pg_get_pgconn(self));
|
2268
2194
|
if(cancel == NULL)
|
2269
|
-
|
2195
|
+
pg_raise_conn_error( rb_ePGerror, self, "Invalid connection!");
|
2270
2196
|
|
2271
|
-
ret = gvl_PQcancel(cancel, errbuf,
|
2197
|
+
ret = gvl_PQcancel(cancel, errbuf, sizeof(errbuf));
|
2272
2198
|
if(ret == 1)
|
2273
2199
|
retval = Qnil;
|
2274
2200
|
else
|
@@ -2289,7 +2215,7 @@ pgconn_cancel(VALUE self)
|
|
2289
2215
|
static VALUE
|
2290
2216
|
pgconn_notifies(VALUE self)
|
2291
2217
|
{
|
2292
|
-
|
2218
|
+
t_pg_connection *this = pg_get_connection_safe( self );
|
2293
2219
|
PGnotify *notification;
|
2294
2220
|
VALUE hash;
|
2295
2221
|
VALUE sym_relname, sym_be_pid, sym_extra;
|
@@ -2299,17 +2225,17 @@ pgconn_notifies(VALUE self)
|
|
2299
2225
|
sym_be_pid = ID2SYM(rb_intern("be_pid"));
|
2300
2226
|
sym_extra = ID2SYM(rb_intern("extra"));
|
2301
2227
|
|
2302
|
-
notification = gvl_PQnotifies(
|
2228
|
+
notification = gvl_PQnotifies(this->pgconn);
|
2303
2229
|
if (notification == NULL) {
|
2304
2230
|
return Qnil;
|
2305
2231
|
}
|
2306
2232
|
|
2307
2233
|
hash = rb_hash_new();
|
2308
|
-
relname =
|
2234
|
+
relname = rb_str_new2(notification->relname);
|
2309
2235
|
be_pid = INT2NUM(notification->be_pid);
|
2310
|
-
extra =
|
2311
|
-
PG_ENCODING_SET_NOCHECK( relname,
|
2312
|
-
PG_ENCODING_SET_NOCHECK( extra,
|
2236
|
+
extra = rb_str_new2(notification->extra);
|
2237
|
+
PG_ENCODING_SET_NOCHECK( relname, this->enc_idx );
|
2238
|
+
PG_ENCODING_SET_NOCHECK( extra, this->enc_idx );
|
2313
2239
|
|
2314
2240
|
rb_hash_aset(hash, sym_relname, relname);
|
2315
2241
|
rb_hash_aset(hash, sym_be_pid, be_pid);
|
@@ -2319,55 +2245,63 @@ pgconn_notifies(VALUE self)
|
|
2319
2245
|
return hash;
|
2320
2246
|
}
|
2321
2247
|
|
2322
|
-
|
2323
|
-
|
2324
|
-
/*
|
2325
|
-
*
|
2326
|
-
* instead of rb_wait_for_single_fd().
|
2248
|
+
#if defined(_WIN32)
|
2249
|
+
|
2250
|
+
/* We use a specialized implementation of rb_io_wait() on Windows.
|
2251
|
+
* This is because rb_io_wait() and rb_wait_for_single_fd() are very slow on Windows.
|
2327
2252
|
*/
|
2328
2253
|
|
2254
|
+
#if defined(HAVE_RUBY_FIBER_SCHEDULER_H)
|
2255
|
+
#include <ruby/fiber/scheduler.h>
|
2256
|
+
#endif
|
2257
|
+
|
2258
|
+
typedef enum {
|
2259
|
+
PG_RUBY_IO_READABLE = RB_WAITFD_IN,
|
2260
|
+
PG_RUBY_IO_WRITABLE = RB_WAITFD_OUT,
|
2261
|
+
PG_RUBY_IO_PRIORITY = RB_WAITFD_PRI,
|
2262
|
+
} pg_rb_io_event_t;
|
2263
|
+
|
2329
2264
|
int rb_w32_wait_events( HANDLE *events, int num, DWORD timeout );
|
2330
2265
|
|
2331
|
-
static
|
2332
|
-
|
2333
|
-
|
2334
|
-
|
2335
|
-
|
2266
|
+
static VALUE
|
2267
|
+
pg_rb_thread_io_wait(VALUE io, VALUE events, VALUE timeout) {
|
2268
|
+
rb_io_t *fptr;
|
2269
|
+
struct timeval ptimeout;
|
2270
|
+
|
2336
2271
|
struct timeval aborttime={0,0}, currtime, waittime;
|
2337
2272
|
DWORD timeout_milisec = INFINITE;
|
2338
|
-
|
2339
|
-
WSAEVENT hEvent;
|
2273
|
+
HANDLE hEvent = WSACreateEvent();
|
2340
2274
|
|
2341
|
-
|
2342
|
-
|
2343
|
-
|
2344
|
-
hEvent = WSACreateEvent();
|
2275
|
+
long rb_events = NUM2UINT(events);
|
2276
|
+
long w32_events = 0;
|
2277
|
+
DWORD wait_ret;
|
2345
2278
|
|
2346
|
-
|
2347
|
-
if(
|
2348
|
-
|
2349
|
-
|
2350
|
-
}
|
2279
|
+
GetOpenFile((io), fptr);
|
2280
|
+
if( !NIL_P(timeout) ){
|
2281
|
+
ptimeout.tv_sec = (time_t)(NUM2DBL(timeout));
|
2282
|
+
ptimeout.tv_usec = (time_t)((NUM2DBL(timeout) - (double)ptimeout.tv_sec) * 1e6);
|
2351
2283
|
|
2352
|
-
if ( ptimeout ) {
|
2353
2284
|
gettimeofday(&currtime, NULL);
|
2354
|
-
timeradd(&currtime, ptimeout, &aborttime);
|
2285
|
+
timeradd(&currtime, &ptimeout, &aborttime);
|
2355
2286
|
}
|
2356
2287
|
|
2357
|
-
|
2358
|
-
|
2288
|
+
if(rb_events & PG_RUBY_IO_READABLE) w32_events |= FD_READ | FD_ACCEPT | FD_CLOSE;
|
2289
|
+
if(rb_events & PG_RUBY_IO_WRITABLE) w32_events |= FD_WRITE | FD_CONNECT;
|
2290
|
+
if(rb_events & PG_RUBY_IO_PRIORITY) w32_events |= FD_OOB;
|
2291
|
+
|
2292
|
+
for(;;) {
|
2293
|
+
if ( WSAEventSelect(_get_osfhandle(fptr->fd), hEvent, w32_events) == SOCKET_ERROR ) {
|
2359
2294
|
WSACloseEvent( hEvent );
|
2360
2295
|
rb_raise( rb_eConnectionBad, "WSAEventSelect socket error: %d", WSAGetLastError() );
|
2361
2296
|
}
|
2362
2297
|
|
2363
|
-
if (
|
2298
|
+
if ( !NIL_P(timeout) ) {
|
2364
2299
|
gettimeofday(&currtime, NULL);
|
2365
2300
|
timersub(&aborttime, &currtime, &waittime);
|
2366
2301
|
timeout_milisec = (DWORD)( waittime.tv_sec * 1e3 + waittime.tv_usec / 1e3 );
|
2367
2302
|
}
|
2368
2303
|
|
2369
|
-
|
2370
|
-
if( !ptimeout || (waittime.tv_sec >= 0 && waittime.tv_usec >= 0) ){
|
2304
|
+
if( NIL_P(timeout) || (waittime.tv_sec >= 0 && waittime.tv_usec >= 0) ){
|
2371
2305
|
/* Wait for the socket to become readable before checking again */
|
2372
2306
|
wait_ret = rb_w32_wait_events( &hEvent, 1, timeout_milisec );
|
2373
2307
|
} else {
|
@@ -2376,9 +2310,11 @@ wait_socket_readable( PGconn *conn, struct timeval *ptimeout, void *(*is_readabl
|
|
2376
2310
|
|
2377
2311
|
if ( wait_ret == WAIT_TIMEOUT ) {
|
2378
2312
|
WSACloseEvent( hEvent );
|
2379
|
-
return
|
2313
|
+
return UINT2NUM(0);
|
2380
2314
|
} else if ( wait_ret == WAIT_OBJECT_0 ) {
|
2315
|
+
WSACloseEvent( hEvent );
|
2381
2316
|
/* The event we were waiting for. */
|
2317
|
+
return UINT2NUM(rb_events);
|
2382
2318
|
} else if ( wait_ret == WAIT_OBJECT_0 + 1) {
|
2383
2319
|
/* This indicates interruption from timer thread, GC, exception
|
2384
2320
|
* from other threads etc... */
|
@@ -2390,36 +2326,66 @@ wait_socket_readable( PGconn *conn, struct timeval *ptimeout, void *(*is_readabl
|
|
2390
2326
|
WSACloseEvent( hEvent );
|
2391
2327
|
rb_raise( rb_eConnectionBad, "Wait on socket abandoned (WaitForMultipleObjects)" );
|
2392
2328
|
}
|
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
2329
|
}
|
2330
|
+
}
|
2400
2331
|
|
2401
|
-
|
2402
|
-
|
2332
|
+
static VALUE
|
2333
|
+
pg_rb_io_wait(VALUE io, VALUE events, VALUE timeout) {
|
2334
|
+
#if defined(HAVE_RUBY_FIBER_SCHEDULER_H)
|
2335
|
+
/* We don't support Fiber.scheduler on Windows ruby-3.0 because there is no fast way to check whether a scheduler is active.
|
2336
|
+
* Fortunatelly ruby-3.1 offers a C-API for it.
|
2337
|
+
*/
|
2338
|
+
VALUE scheduler = rb_fiber_scheduler_current();
|
2339
|
+
|
2340
|
+
if (!NIL_P(scheduler)) {
|
2341
|
+
return rb_io_wait(io, events, timeout);
|
2342
|
+
}
|
2343
|
+
#endif
|
2344
|
+
return pg_rb_thread_io_wait(io, events, timeout);
|
2403
2345
|
}
|
2404
2346
|
|
2347
|
+
#elif defined(HAVE_RB_IO_WAIT)
|
2348
|
+
|
2349
|
+
/* Use our own function and constants names, to avoid conflicts with truffleruby-head on its road to ruby-3.0 compatibility. */
|
2350
|
+
#define pg_rb_io_wait rb_io_wait
|
2351
|
+
#define PG_RUBY_IO_READABLE RUBY_IO_READABLE
|
2352
|
+
#define PG_RUBY_IO_WRITABLE RUBY_IO_WRITABLE
|
2353
|
+
#define PG_RUBY_IO_PRIORITY RUBY_IO_PRIORITY
|
2354
|
+
|
2405
2355
|
#else
|
2356
|
+
/* For compat with ruby < 3.0 */
|
2357
|
+
|
2358
|
+
typedef enum {
|
2359
|
+
PG_RUBY_IO_READABLE = RB_WAITFD_IN,
|
2360
|
+
PG_RUBY_IO_WRITABLE = RB_WAITFD_OUT,
|
2361
|
+
PG_RUBY_IO_PRIORITY = RB_WAITFD_PRI,
|
2362
|
+
} pg_rb_io_event_t;
|
2406
2363
|
|
2407
|
-
|
2364
|
+
static VALUE
|
2365
|
+
pg_rb_io_wait(VALUE io, VALUE events, VALUE timeout) {
|
2366
|
+
rb_io_t *fptr;
|
2367
|
+
struct timeval waittime;
|
2368
|
+
int res;
|
2369
|
+
|
2370
|
+
GetOpenFile((io), fptr);
|
2371
|
+
if( !NIL_P(timeout) ){
|
2372
|
+
waittime.tv_sec = (time_t)(NUM2DBL(timeout));
|
2373
|
+
waittime.tv_usec = (time_t)((NUM2DBL(timeout) - (double)waittime.tv_sec) * 1e6);
|
2374
|
+
}
|
2375
|
+
res = rb_wait_for_single_fd(fptr->fd, NUM2UINT(events), NIL_P(timeout) ? NULL : &waittime);
|
2376
|
+
|
2377
|
+
return UINT2NUM(res);
|
2378
|
+
}
|
2379
|
+
#endif
|
2408
2380
|
|
2409
2381
|
static void *
|
2410
|
-
wait_socket_readable(
|
2382
|
+
wait_socket_readable( VALUE self, struct timeval *ptimeout, void *(*is_readable)(PGconn *))
|
2411
2383
|
{
|
2412
|
-
|
2413
|
-
int ret;
|
2384
|
+
VALUE ret;
|
2414
2385
|
void *retval;
|
2415
2386
|
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) );
|
2387
|
+
VALUE wait_timeout = Qnil;
|
2388
|
+
PGconn *conn = pg_get_pgconn(self);
|
2423
2389
|
|
2424
2390
|
if ( ptimeout ) {
|
2425
2391
|
gettimeofday(&currtime, NULL);
|
@@ -2430,36 +2396,81 @@ wait_socket_readable( PGconn *conn, struct timeval *ptimeout, void *(*is_readabl
|
|
2430
2396
|
if ( ptimeout ) {
|
2431
2397
|
gettimeofday(&currtime, NULL);
|
2432
2398
|
timersub(&aborttime, &currtime, &waittime);
|
2399
|
+
wait_timeout = DBL2NUM((double)(waittime.tv_sec) + (double)(waittime.tv_usec) / 1000000.0);
|
2433
2400
|
}
|
2434
2401
|
|
2435
2402
|
/* Is the given timeout valid? */
|
2436
2403
|
if( !ptimeout || (waittime.tv_sec >= 0 && waittime.tv_usec >= 0) ){
|
2404
|
+
VALUE socket_io;
|
2405
|
+
|
2406
|
+
/* before we wait for data, make sure everything has been sent */
|
2407
|
+
pgconn_async_flush(self);
|
2408
|
+
if ((retval=is_readable(conn)))
|
2409
|
+
return retval;
|
2410
|
+
|
2411
|
+
socket_io = pgconn_socket_io(self);
|
2437
2412
|
/* Wait for the socket to become readable before checking again */
|
2438
|
-
ret =
|
2413
|
+
ret = pg_rb_io_wait(socket_io, RB_INT2NUM(PG_RUBY_IO_READABLE), wait_timeout);
|
2439
2414
|
} else {
|
2440
|
-
ret =
|
2441
|
-
}
|
2442
|
-
|
2443
|
-
if ( ret < 0 ){
|
2444
|
-
rb_sys_fail( "rb_wait_for_single_fd()" );
|
2415
|
+
ret = Qfalse;
|
2445
2416
|
}
|
2446
2417
|
|
2447
2418
|
/* Return false if the select() timed out */
|
2448
|
-
if ( ret ==
|
2419
|
+
if ( ret == Qfalse ){
|
2449
2420
|
return NULL;
|
2450
2421
|
}
|
2451
2422
|
|
2452
2423
|
/* Check for connection errors (PQisBusy is true on connection errors) */
|
2453
2424
|
if ( PQconsumeInput(conn) == 0 ){
|
2454
|
-
|
2425
|
+
pgconn_close_socket_io(self);
|
2426
|
+
pg_raise_conn_error(rb_eConnectionBad, self, "PQconsumeInput() %s", PQerrorMessage(conn));
|
2455
2427
|
}
|
2456
2428
|
}
|
2457
2429
|
|
2458
2430
|
return retval;
|
2459
2431
|
}
|
2460
2432
|
|
2433
|
+
/*
|
2434
|
+
* call-seq:
|
2435
|
+
* conn.flush() -> Boolean
|
2436
|
+
*
|
2437
|
+
* Attempts to flush any queued output data to the server.
|
2438
|
+
* Returns +true+ if data is successfully flushed, +false+
|
2439
|
+
* if not. It can only return +false+ if connection is
|
2440
|
+
* in nonblocking mode.
|
2441
|
+
* Raises PG::Error if some other failure occurred.
|
2442
|
+
*/
|
2443
|
+
static VALUE
|
2444
|
+
pgconn_async_flush(VALUE self)
|
2445
|
+
{
|
2446
|
+
while( pgconn_sync_flush(self) == Qfalse ){
|
2447
|
+
/* wait for the socket to become read- or write-ready */
|
2448
|
+
int events;
|
2449
|
+
VALUE socket_io = pgconn_socket_io(self);
|
2450
|
+
events = RB_NUM2INT(pg_rb_io_wait(socket_io, RB_INT2NUM(PG_RUBY_IO_READABLE | PG_RUBY_IO_WRITABLE), Qnil));
|
2451
|
+
|
2452
|
+
if (events & PG_RUBY_IO_READABLE){
|
2453
|
+
pgconn_consume_input(self);
|
2454
|
+
}
|
2455
|
+
}
|
2456
|
+
return Qtrue;
|
2457
|
+
}
|
2458
|
+
|
2459
|
+
static VALUE
|
2460
|
+
pgconn_wait_for_flush( VALUE self ){
|
2461
|
+
if( !pg_get_connection_safe(self)->flush_data )
|
2462
|
+
return Qnil;
|
2463
|
+
|
2464
|
+
return pgconn_async_flush(self);
|
2465
|
+
}
|
2461
2466
|
|
2462
|
-
|
2467
|
+
static VALUE
|
2468
|
+
pgconn_flush_data_set( VALUE self, VALUE enabled ){
|
2469
|
+
t_pg_connection *conn = pg_get_connection(self);
|
2470
|
+
rb_check_frozen(self);
|
2471
|
+
conn->flush_data = RTEST(enabled);
|
2472
|
+
return enabled;
|
2473
|
+
}
|
2463
2474
|
|
2464
2475
|
static void *
|
2465
2476
|
notify_readable(PGconn *conn)
|
@@ -2482,7 +2493,7 @@ notify_readable(PGconn *conn)
|
|
2482
2493
|
static VALUE
|
2483
2494
|
pgconn_wait_for_notify(int argc, VALUE *argv, VALUE self)
|
2484
2495
|
{
|
2485
|
-
|
2496
|
+
t_pg_connection *this = pg_get_connection_safe( self );
|
2486
2497
|
PGnotify *pnotification;
|
2487
2498
|
struct timeval timeout;
|
2488
2499
|
struct timeval *ptimeout = NULL;
|
@@ -2498,17 +2509,17 @@ pgconn_wait_for_notify(int argc, VALUE *argv, VALUE self)
|
|
2498
2509
|
ptimeout = &timeout;
|
2499
2510
|
}
|
2500
2511
|
|
2501
|
-
pnotification = (PGnotify*) wait_socket_readable(
|
2512
|
+
pnotification = (PGnotify*) wait_socket_readable( self, ptimeout, notify_readable);
|
2502
2513
|
|
2503
2514
|
/* Return nil if the select timed out */
|
2504
2515
|
if ( !pnotification ) return Qnil;
|
2505
2516
|
|
2506
|
-
relname =
|
2507
|
-
PG_ENCODING_SET_NOCHECK( relname,
|
2517
|
+
relname = rb_str_new2( pnotification->relname );
|
2518
|
+
PG_ENCODING_SET_NOCHECK( relname, this->enc_idx );
|
2508
2519
|
be_pid = INT2NUM( pnotification->be_pid );
|
2509
2520
|
if ( *pnotification->extra ) {
|
2510
|
-
extra =
|
2511
|
-
PG_ENCODING_SET_NOCHECK( extra,
|
2521
|
+
extra = rb_str_new2( pnotification->extra );
|
2522
|
+
PG_ENCODING_SET_NOCHECK( extra, this->enc_idx );
|
2512
2523
|
}
|
2513
2524
|
PQfreemem( pnotification );
|
2514
2525
|
|
@@ -2519,28 +2530,8 @@ pgconn_wait_for_notify(int argc, VALUE *argv, VALUE self)
|
|
2519
2530
|
}
|
2520
2531
|
|
2521
2532
|
|
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
2533
|
static VALUE
|
2543
|
-
|
2534
|
+
pgconn_sync_put_copy_data(int argc, VALUE *argv, VALUE self)
|
2544
2535
|
{
|
2545
2536
|
int ret;
|
2546
2537
|
int len;
|
@@ -2557,18 +2548,16 @@ pgconn_put_copy_data(int argc, VALUE *argv, VALUE self)
|
|
2557
2548
|
if( NIL_P(this->encoder_for_put_copy_data) ){
|
2558
2549
|
buffer = value;
|
2559
2550
|
} else {
|
2560
|
-
p_coder =
|
2551
|
+
p_coder = RTYPEDDATA_DATA( this->encoder_for_put_copy_data );
|
2561
2552
|
}
|
2562
|
-
} else if( rb_obj_is_kind_of(encoder, rb_cPG_Coder) ) {
|
2563
|
-
Data_Get_Struct( encoder, t_pg_coder, p_coder );
|
2564
2553
|
} else {
|
2565
|
-
|
2566
|
-
|
2554
|
+
/* Check argument type and use argument encoder */
|
2555
|
+
TypedData_Get_Struct(encoder, t_pg_coder, &pg_coder_type, p_coder);
|
2567
2556
|
}
|
2568
2557
|
|
2569
2558
|
if( p_coder ){
|
2570
2559
|
t_pg_coder_enc_func enc_func;
|
2571
|
-
int enc_idx =
|
2560
|
+
int enc_idx = this->enc_idx;
|
2572
2561
|
|
2573
2562
|
enc_func = pg_coder_enc_func( p_coder );
|
2574
2563
|
len = enc_func( p_coder, value, NULL, &intermediate, enc_idx);
|
@@ -2586,78 +2575,39 @@ pgconn_put_copy_data(int argc, VALUE *argv, VALUE self)
|
|
2586
2575
|
Check_Type(buffer, T_STRING);
|
2587
2576
|
|
2588
2577
|
ret = gvl_PQputCopyData(this->pgconn, RSTRING_PTR(buffer), RSTRING_LENINT(buffer));
|
2589
|
-
if(ret == -1)
|
2590
|
-
|
2591
|
-
|
2592
|
-
rb_exc_raise(error);
|
2593
|
-
}
|
2578
|
+
if(ret == -1)
|
2579
|
+
pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(this->pgconn));
|
2580
|
+
|
2594
2581
|
RB_GC_GUARD(intermediate);
|
2595
2582
|
RB_GC_GUARD(buffer);
|
2596
2583
|
|
2597
2584
|
return (ret) ? Qtrue : Qfalse;
|
2598
2585
|
}
|
2599
2586
|
|
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
2587
|
static VALUE
|
2615
|
-
|
2588
|
+
pgconn_sync_put_copy_end(int argc, VALUE *argv, VALUE self)
|
2616
2589
|
{
|
2617
2590
|
VALUE str;
|
2618
|
-
VALUE error;
|
2619
2591
|
int ret;
|
2620
2592
|
const char *error_message = NULL;
|
2621
|
-
|
2593
|
+
t_pg_connection *this = pg_get_connection_safe( self );
|
2622
2594
|
|
2623
2595
|
if (rb_scan_args(argc, argv, "01", &str) == 0)
|
2624
2596
|
error_message = NULL;
|
2625
2597
|
else
|
2626
|
-
error_message = pg_cstr_enc(str,
|
2598
|
+
error_message = pg_cstr_enc(str, this->enc_idx);
|
2599
|
+
|
2600
|
+
ret = gvl_PQputCopyEnd(this->pgconn, error_message);
|
2601
|
+
if(ret == -1)
|
2602
|
+
pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(this->pgconn));
|
2627
2603
|
|
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
2604
|
return (ret) ? Qtrue : Qfalse;
|
2635
2605
|
}
|
2636
2606
|
|
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
2607
|
static VALUE
|
2657
|
-
|
2608
|
+
pgconn_sync_get_copy_data(int argc, VALUE *argv, VALUE self )
|
2658
2609
|
{
|
2659
2610
|
VALUE async_in;
|
2660
|
-
VALUE error;
|
2661
2611
|
VALUE result;
|
2662
2612
|
int ret;
|
2663
2613
|
char *buffer;
|
@@ -2669,20 +2619,16 @@ pgconn_get_copy_data(int argc, VALUE *argv, VALUE self )
|
|
2669
2619
|
|
2670
2620
|
if( NIL_P(decoder) ){
|
2671
2621
|
if( !NIL_P(this->decoder_for_get_copy_data) ){
|
2672
|
-
p_coder =
|
2622
|
+
p_coder = RTYPEDDATA_DATA( this->decoder_for_get_copy_data );
|
2673
2623
|
}
|
2674
|
-
} else if( rb_obj_is_kind_of(decoder, rb_cPG_Coder) ) {
|
2675
|
-
Data_Get_Struct( decoder, t_pg_coder, p_coder );
|
2676
2624
|
} else {
|
2677
|
-
|
2678
|
-
|
2625
|
+
/* Check argument type and use argument decoder */
|
2626
|
+
TypedData_Get_Struct(decoder, t_pg_coder, &pg_coder_type, p_coder);
|
2679
2627
|
}
|
2680
2628
|
|
2681
2629
|
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);
|
2630
|
+
if(ret == -2){ /* error */
|
2631
|
+
pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(this->pgconn));
|
2686
2632
|
}
|
2687
2633
|
if(ret == -1) { /* No data left */
|
2688
2634
|
return Qnil;
|
@@ -2693,9 +2639,9 @@ pgconn_get_copy_data(int argc, VALUE *argv, VALUE self )
|
|
2693
2639
|
|
2694
2640
|
if( p_coder ){
|
2695
2641
|
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,
|
2642
|
+
result = dec_func( p_coder, buffer, ret, 0, 0, this->enc_idx );
|
2697
2643
|
} else {
|
2698
|
-
result =
|
2644
|
+
result = rb_str_new(buffer, ret);
|
2699
2645
|
}
|
2700
2646
|
|
2701
2647
|
PQfreemem(buffer);
|
@@ -2708,9 +2654,16 @@ pgconn_get_copy_data(int argc, VALUE *argv, VALUE self )
|
|
2708
2654
|
*
|
2709
2655
|
* Sets connection's verbosity to _verbosity_ and returns
|
2710
2656
|
* the previous setting. Available settings are:
|
2657
|
+
*
|
2711
2658
|
* * PQERRORS_TERSE
|
2712
2659
|
* * PQERRORS_DEFAULT
|
2713
2660
|
* * PQERRORS_VERBOSE
|
2661
|
+
* * PQERRORS_SQLSTATE
|
2662
|
+
*
|
2663
|
+
* Changing the verbosity does not affect the messages available from already-existing PG::Result objects, only subsequently-created ones.
|
2664
|
+
* (But see PG::Result#verbose_error_message if you want to print a previous error with a different verbosity.)
|
2665
|
+
*
|
2666
|
+
* See also corresponding {libpq function}[https://www.postgresql.org/docs/current/libpq-control.html#LIBPQ-PQSETERRORVERBOSITY].
|
2714
2667
|
*/
|
2715
2668
|
static VALUE
|
2716
2669
|
pgconn_set_error_verbosity(VALUE self, VALUE in_verbosity)
|
@@ -2720,6 +2673,37 @@ pgconn_set_error_verbosity(VALUE self, VALUE in_verbosity)
|
|
2720
2673
|
return INT2FIX(PQsetErrorVerbosity(conn, verbosity));
|
2721
2674
|
}
|
2722
2675
|
|
2676
|
+
#ifdef HAVE_PQRESULTVERBOSEERRORMESSAGE
|
2677
|
+
/*
|
2678
|
+
* call-seq:
|
2679
|
+
* conn.set_error_context_visibility( context_visibility ) -> Integer
|
2680
|
+
*
|
2681
|
+
* Sets connection's context display mode to _context_visibility_ and returns
|
2682
|
+
* the previous setting. Available settings are:
|
2683
|
+
* * PQSHOW_CONTEXT_NEVER
|
2684
|
+
* * PQSHOW_CONTEXT_ERRORS
|
2685
|
+
* * PQSHOW_CONTEXT_ALWAYS
|
2686
|
+
*
|
2687
|
+
* This mode controls whether the CONTEXT field is included in messages (unless the verbosity setting is TERSE, in which case CONTEXT is never shown).
|
2688
|
+
* The NEVER mode never includes CONTEXT, while ALWAYS always includes it if available.
|
2689
|
+
* In ERRORS mode (the default), CONTEXT fields are included only for error messages, not for notices and warnings.
|
2690
|
+
*
|
2691
|
+
* Changing this mode does not affect the messages available from already-existing PG::Result objects, only subsequently-created ones.
|
2692
|
+
* (But see PG::Result#verbose_error_message if you want to print a previous error with a different display mode.)
|
2693
|
+
*
|
2694
|
+
* See also corresponding {libpq function}[https://www.postgresql.org/docs/current/libpq-control.html#LIBPQ-PQSETERRORCONTEXTVISIBILITY].
|
2695
|
+
*
|
2696
|
+
* Available since PostgreSQL-9.6
|
2697
|
+
*/
|
2698
|
+
static VALUE
|
2699
|
+
pgconn_set_error_context_visibility(VALUE self, VALUE in_context_visibility)
|
2700
|
+
{
|
2701
|
+
PGconn *conn = pg_get_pgconn(self);
|
2702
|
+
PGContextVisibility context_visibility = NUM2INT(in_context_visibility);
|
2703
|
+
return INT2FIX(PQsetErrorContextVisibility(conn, context_visibility));
|
2704
|
+
}
|
2705
|
+
#endif
|
2706
|
+
|
2723
2707
|
/*
|
2724
2708
|
* call-seq:
|
2725
2709
|
* conn.trace( stream ) -> nil
|
@@ -2738,7 +2722,8 @@ pgconn_trace(VALUE self, VALUE stream)
|
|
2738
2722
|
VALUE new_file;
|
2739
2723
|
t_pg_connection *this = pg_get_connection_safe( self );
|
2740
2724
|
|
2741
|
-
|
2725
|
+
rb_check_frozen(self);
|
2726
|
+
if(!rb_respond_to(stream,rb_intern("fileno")))
|
2742
2727
|
rb_raise(rb_eArgError, "stream does not respond to method: fileno");
|
2743
2728
|
|
2744
2729
|
fileno = rb_funcall(stream, rb_intern("fileno"), 0);
|
@@ -2759,7 +2744,7 @@ pgconn_trace(VALUE self, VALUE stream)
|
|
2759
2744
|
rb_raise(rb_eArgError, "stream is not writable");
|
2760
2745
|
|
2761
2746
|
new_file = rb_funcall(rb_cIO, rb_intern("new"), 1, INT2NUM(new_fd));
|
2762
|
-
this->trace_stream
|
2747
|
+
RB_OBJ_WRITE(self, &this->trace_stream, new_file);
|
2763
2748
|
|
2764
2749
|
PQtrace(this->pgconn, new_fp);
|
2765
2750
|
return Qnil;
|
@@ -2778,7 +2763,7 @@ pgconn_untrace(VALUE self)
|
|
2778
2763
|
|
2779
2764
|
PQuntrace(this->pgconn);
|
2780
2765
|
rb_funcall(this->trace_stream, rb_intern("close"), 0);
|
2781
|
-
this->trace_stream
|
2766
|
+
RB_OBJ_WRITE(self, &this->trace_stream, Qnil);
|
2782
2767
|
return Qnil;
|
2783
2768
|
}
|
2784
2769
|
|
@@ -2837,13 +2822,14 @@ pgconn_set_notice_receiver(VALUE self)
|
|
2837
2822
|
VALUE proc, old_proc;
|
2838
2823
|
t_pg_connection *this = pg_get_connection_safe( self );
|
2839
2824
|
|
2825
|
+
rb_check_frozen(self);
|
2840
2826
|
/* If default_notice_receiver is unset, assume that the current
|
2841
2827
|
* notice receiver is the default, and save it to a global variable.
|
2842
2828
|
* This should not be a problem because the default receiver is
|
2843
2829
|
* always the same, so won't vary among connections.
|
2844
2830
|
*/
|
2845
|
-
if(default_notice_receiver == NULL)
|
2846
|
-
default_notice_receiver = PQsetNoticeReceiver(this->pgconn, NULL, NULL);
|
2831
|
+
if(this->default_notice_receiver == NULL)
|
2832
|
+
this->default_notice_receiver = PQsetNoticeReceiver(this->pgconn, NULL, NULL);
|
2847
2833
|
|
2848
2834
|
old_proc = this->notice_receiver;
|
2849
2835
|
if( rb_block_given_p() ) {
|
@@ -2852,10 +2838,10 @@ pgconn_set_notice_receiver(VALUE self)
|
|
2852
2838
|
} else {
|
2853
2839
|
/* if no block is given, set back to default */
|
2854
2840
|
proc = Qnil;
|
2855
|
-
PQsetNoticeReceiver(this->pgconn, default_notice_receiver, NULL);
|
2841
|
+
PQsetNoticeReceiver(this->pgconn, this->default_notice_receiver, NULL);
|
2856
2842
|
}
|
2857
2843
|
|
2858
|
-
this->notice_receiver
|
2844
|
+
RB_OBJ_WRITE(self, &this->notice_receiver, proc);
|
2859
2845
|
return old_proc;
|
2860
2846
|
}
|
2861
2847
|
|
@@ -2870,10 +2856,10 @@ notice_processor_proxy(void *arg, const char *message)
|
|
2870
2856
|
VALUE self = (VALUE)arg;
|
2871
2857
|
t_pg_connection *this = pg_get_connection( self );
|
2872
2858
|
|
2873
|
-
if (this->
|
2874
|
-
VALUE message_str =
|
2875
|
-
PG_ENCODING_SET_NOCHECK( message_str,
|
2876
|
-
rb_funcall(this->
|
2859
|
+
if (this->notice_processor != Qnil) {
|
2860
|
+
VALUE message_str = rb_str_new2(message);
|
2861
|
+
PG_ENCODING_SET_NOCHECK( message_str, this->enc_idx );
|
2862
|
+
rb_funcall(this->notice_processor, rb_intern("call"), 1, message_str);
|
2877
2863
|
}
|
2878
2864
|
return;
|
2879
2865
|
}
|
@@ -2882,7 +2868,7 @@ notice_processor_proxy(void *arg, const char *message)
|
|
2882
2868
|
* call-seq:
|
2883
2869
|
* conn.set_notice_processor {|message| ... } -> Proc
|
2884
2870
|
*
|
2885
|
-
* See #set_notice_receiver for the
|
2871
|
+
* See #set_notice_receiver for the description of what this and the
|
2886
2872
|
* notice_processor methods do.
|
2887
2873
|
*
|
2888
2874
|
* This function takes a new block to act as the notice processor and returns
|
@@ -2897,25 +2883,26 @@ pgconn_set_notice_processor(VALUE self)
|
|
2897
2883
|
VALUE proc, old_proc;
|
2898
2884
|
t_pg_connection *this = pg_get_connection_safe( self );
|
2899
2885
|
|
2886
|
+
rb_check_frozen(self);
|
2900
2887
|
/* If default_notice_processor is unset, assume that the current
|
2901
2888
|
* notice processor is the default, and save it to a global variable.
|
2902
2889
|
* This should not be a problem because the default processor is
|
2903
2890
|
* always the same, so won't vary among connections.
|
2904
2891
|
*/
|
2905
|
-
if(default_notice_processor == NULL)
|
2906
|
-
default_notice_processor = PQsetNoticeProcessor(this->pgconn, NULL, NULL);
|
2892
|
+
if(this->default_notice_processor == NULL)
|
2893
|
+
this->default_notice_processor = PQsetNoticeProcessor(this->pgconn, NULL, NULL);
|
2907
2894
|
|
2908
|
-
old_proc = this->
|
2895
|
+
old_proc = this->notice_processor;
|
2909
2896
|
if( rb_block_given_p() ) {
|
2910
2897
|
proc = rb_block_proc();
|
2911
2898
|
PQsetNoticeProcessor(this->pgconn, gvl_notice_processor_proxy, (void *)self);
|
2912
2899
|
} else {
|
2913
2900
|
/* if no block is given, set back to default */
|
2914
2901
|
proc = Qnil;
|
2915
|
-
PQsetNoticeProcessor(this->pgconn, default_notice_processor, NULL);
|
2902
|
+
PQsetNoticeProcessor(this->pgconn, this->default_notice_processor, NULL);
|
2916
2903
|
}
|
2917
2904
|
|
2918
|
-
this->
|
2905
|
+
RB_OBJ_WRITE(self, &this->notice_processor, proc);
|
2919
2906
|
return old_proc;
|
2920
2907
|
}
|
2921
2908
|
|
@@ -2930,74 +2917,34 @@ static VALUE
|
|
2930
2917
|
pgconn_get_client_encoding(VALUE self)
|
2931
2918
|
{
|
2932
2919
|
char *encoding = (char *)pg_encoding_to_char(PQclientEncoding(pg_get_pgconn(self)));
|
2933
|
-
return
|
2920
|
+
return rb_str_new2(encoding);
|
2934
2921
|
}
|
2935
2922
|
|
2936
2923
|
|
2937
2924
|
/*
|
2938
2925
|
* call-seq:
|
2939
|
-
* conn.
|
2926
|
+
* conn.sync_set_client_encoding( encoding )
|
2940
2927
|
*
|
2941
|
-
*
|
2928
|
+
* This function has the same behavior as #async_set_client_encoding, but is implemented using the synchronous command processing API of libpq.
|
2929
|
+
* See #async_exec for the differences between the two API variants.
|
2930
|
+
* 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
2931
|
*/
|
2943
2932
|
static VALUE
|
2944
|
-
|
2933
|
+
pgconn_sync_set_client_encoding(VALUE self, VALUE str)
|
2945
2934
|
{
|
2946
2935
|
PGconn *conn = pg_get_pgconn( self );
|
2947
2936
|
|
2937
|
+
rb_check_frozen(self);
|
2948
2938
|
Check_Type(str, T_STRING);
|
2949
2939
|
|
2950
|
-
if ( (gvl_PQsetClientEncoding(conn, StringValueCStr(str))) == -1 )
|
2951
|
-
|
2952
|
-
|
2940
|
+
if ( (gvl_PQsetClientEncoding(conn, StringValueCStr(str))) == -1 )
|
2941
|
+
pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(conn));
|
2942
|
+
|
2953
2943
|
pgconn_set_internal_encoding_index( self );
|
2954
2944
|
|
2955
2945
|
return Qnil;
|
2956
2946
|
}
|
2957
2947
|
|
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
2948
|
|
3002
2949
|
/*
|
3003
2950
|
* call-seq:
|
@@ -3042,14 +2989,12 @@ pgconn_s_quote_ident(VALUE self, VALUE str_or_array)
|
|
3042
2989
|
int enc_idx;
|
3043
2990
|
|
3044
2991
|
if( rb_obj_is_kind_of(self, rb_cPGconn) ){
|
3045
|
-
enc_idx =
|
2992
|
+
enc_idx = pg_get_connection(self)->enc_idx;
|
3046
2993
|
}else{
|
3047
2994
|
enc_idx = RB_TYPE_P(str_or_array, T_STRING) ? ENCODING_GET( str_or_array ) : rb_ascii8bit_encindex();
|
3048
2995
|
}
|
3049
2996
|
pg_text_enc_identifier(NULL, str_or_array, NULL, &ret, enc_idx);
|
3050
2997
|
|
3051
|
-
OBJ_INFECT(ret, str_or_array);
|
3052
|
-
|
3053
2998
|
return ret;
|
3054
2999
|
}
|
3055
3000
|
|
@@ -3074,10 +3019,8 @@ get_result_readable(PGconn *conn)
|
|
3074
3019
|
* If +true+ is returned, +conn.is_busy+ will return +false+
|
3075
3020
|
* and +conn.get_result+ will not block.
|
3076
3021
|
*/
|
3077
|
-
|
3022
|
+
VALUE
|
3078
3023
|
pgconn_block( int argc, VALUE *argv, VALUE self ) {
|
3079
|
-
PGconn *conn = pg_get_pgconn( self );
|
3080
|
-
|
3081
3024
|
struct timeval timeout;
|
3082
3025
|
struct timeval *ptimeout = NULL;
|
3083
3026
|
VALUE timeout_in;
|
@@ -3091,7 +3034,7 @@ pgconn_block( int argc, VALUE *argv, VALUE self ) {
|
|
3091
3034
|
ptimeout = &timeout;
|
3092
3035
|
}
|
3093
3036
|
|
3094
|
-
ret = wait_socket_readable(
|
3037
|
+
ret = wait_socket_readable( self, ptimeout, get_result_readable);
|
3095
3038
|
|
3096
3039
|
if( !ret )
|
3097
3040
|
return Qfalse;
|
@@ -3102,20 +3045,14 @@ pgconn_block( int argc, VALUE *argv, VALUE self ) {
|
|
3102
3045
|
|
3103
3046
|
/*
|
3104
3047
|
* call-seq:
|
3105
|
-
* conn.
|
3106
|
-
*
|
3107
|
-
* This function retrieves all available results
|
3108
|
-
* on the current connection (from previously issued
|
3109
|
-
* asynchronous commands like +send_query()+) and
|
3110
|
-
* returns the last non-NULL result, or +nil+ if no
|
3111
|
-
* results are available.
|
3048
|
+
* conn.sync_get_last_result( ) -> PG::Result
|
3112
3049
|
*
|
3113
|
-
* This function is
|
3114
|
-
*
|
3115
|
-
*
|
3050
|
+
* This function has the same behavior as #async_get_last_result, but is implemented using the synchronous command processing API of libpq.
|
3051
|
+
* See #async_exec for the differences between the two API variants.
|
3052
|
+
* 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.
|
3116
3053
|
*/
|
3117
3054
|
static VALUE
|
3118
|
-
|
3055
|
+
pgconn_sync_get_last_result(VALUE self)
|
3119
3056
|
{
|
3120
3057
|
PGconn *conn = pg_get_pgconn(self);
|
3121
3058
|
VALUE rb_pgresult = Qnil;
|
@@ -3130,7 +3067,7 @@ pgconn_get_last_result(VALUE self)
|
|
3130
3067
|
prev = cur;
|
3131
3068
|
|
3132
3069
|
status = PQresultStatus(cur);
|
3133
|
-
if (status == PGRES_COPY_OUT || status == PGRES_COPY_IN)
|
3070
|
+
if (status == PGRES_COPY_OUT || status == PGRES_COPY_IN || status == PGRES_COPY_BOTH)
|
3134
3071
|
break;
|
3135
3072
|
}
|
3136
3073
|
|
@@ -3144,49 +3081,174 @@ pgconn_get_last_result(VALUE self)
|
|
3144
3081
|
|
3145
3082
|
/*
|
3146
3083
|
* call-seq:
|
3147
|
-
* conn.
|
3084
|
+
* conn.get_last_result( ) -> PG::Result
|
3148
3085
|
*
|
3149
|
-
*
|
3150
|
-
*
|
3151
|
-
*
|
3086
|
+
* This function retrieves all available results
|
3087
|
+
* on the current connection (from previously issued
|
3088
|
+
* asynchronous commands like +send_query()+) and
|
3089
|
+
* returns the last non-NULL result, or +nil+ if no
|
3090
|
+
* results are available.
|
3091
|
+
*
|
3092
|
+
* If the last result contains a bad result_status, an
|
3093
|
+
* appropriate exception is raised.
|
3094
|
+
*
|
3095
|
+
* This function is similar to #get_result
|
3096
|
+
* except that it is designed to get one and only
|
3097
|
+
* one result and that it checks the result state.
|
3152
3098
|
*/
|
3153
3099
|
static VALUE
|
3154
|
-
|
3100
|
+
pgconn_async_get_last_result(VALUE self)
|
3155
3101
|
{
|
3156
3102
|
PGconn *conn = pg_get_pgconn(self);
|
3103
|
+
VALUE rb_pgresult = Qnil;
|
3104
|
+
PGresult *cur, *prev;
|
3157
3105
|
|
3158
|
-
|
3159
|
-
|
3160
|
-
int status
|
3161
|
-
PQclear(cur);
|
3162
|
-
if (status == PGRES_COPY_IN){
|
3163
|
-
gvl_PQputCopyEnd(conn, "COPY terminated by new PQexec");
|
3164
|
-
}
|
3165
|
-
if (status == PGRES_COPY_OUT){
|
3166
|
-
char *buffer = NULL;
|
3167
|
-
while( gvl_PQgetCopyData(conn, &buffer, 0) > 0)
|
3168
|
-
PQfreemem(buffer);
|
3169
|
-
}
|
3170
|
-
}
|
3106
|
+
cur = prev = NULL;
|
3107
|
+
for(;;) {
|
3108
|
+
int status;
|
3171
3109
|
|
3172
|
-
|
3110
|
+
/* wait for input (without blocking) before reading each result */
|
3111
|
+
wait_socket_readable(self, NULL, get_result_readable);
|
3112
|
+
|
3113
|
+
cur = gvl_PQgetResult(conn);
|
3114
|
+
if (cur == NULL)
|
3115
|
+
break;
|
3116
|
+
|
3117
|
+
if (prev) PQclear(prev);
|
3118
|
+
prev = cur;
|
3119
|
+
|
3120
|
+
status = PQresultStatus(cur);
|
3121
|
+
if (status == PGRES_COPY_OUT || status == PGRES_COPY_IN || status == PGRES_COPY_BOTH)
|
3122
|
+
break;
|
3123
|
+
}
|
3124
|
+
|
3125
|
+
if (prev) {
|
3126
|
+
rb_pgresult = pg_new_result( prev, self );
|
3127
|
+
pg_result_check(rb_pgresult);
|
3128
|
+
}
|
3129
|
+
|
3130
|
+
return rb_pgresult;
|
3173
3131
|
}
|
3174
3132
|
|
3175
3133
|
/*
|
3176
3134
|
* call-seq:
|
3177
|
-
* conn.
|
3178
|
-
* conn.async_exec(sql) {|pg_result| block }
|
3135
|
+
* conn.discard_results()
|
3179
3136
|
*
|
3180
|
-
*
|
3181
|
-
*
|
3182
|
-
*
|
3137
|
+
* Silently discard any prior query result that application didn't eat.
|
3138
|
+
* This is internally used prior to Connection#exec and sibling methods.
|
3139
|
+
* It doesn't raise an exception on connection errors, but returns +false+ instead.
|
3183
3140
|
*
|
3184
|
-
*
|
3185
|
-
*
|
3141
|
+
* Returns:
|
3142
|
+
* * +nil+ when the connection is already idle
|
3143
|
+
* * +true+ when some results have been discarded
|
3144
|
+
* * +false+ when a failure occured and the connection was closed
|
3186
3145
|
*
|
3187
|
-
|
3188
|
-
|
3189
|
-
|
3146
|
+
*/
|
3147
|
+
static VALUE
|
3148
|
+
pgconn_discard_results(VALUE self)
|
3149
|
+
{
|
3150
|
+
PGconn *conn = pg_get_pgconn(self);
|
3151
|
+
VALUE socket_io;
|
3152
|
+
|
3153
|
+
switch( PQtransactionStatus(conn) ) {
|
3154
|
+
case PQTRANS_IDLE:
|
3155
|
+
case PQTRANS_INTRANS:
|
3156
|
+
case PQTRANS_INERROR:
|
3157
|
+
return Qnil;
|
3158
|
+
default:;
|
3159
|
+
}
|
3160
|
+
|
3161
|
+
socket_io = pgconn_socket_io(self);
|
3162
|
+
|
3163
|
+
for(;;) {
|
3164
|
+
PGresult *cur;
|
3165
|
+
int status;
|
3166
|
+
|
3167
|
+
/* pgconn_block() raises an exception in case of errors.
|
3168
|
+
* To avoid this call pg_rb_io_wait() and PQconsumeInput() without rb_raise().
|
3169
|
+
*/
|
3170
|
+
while( gvl_PQisBusy(conn) ){
|
3171
|
+
int events;
|
3172
|
+
|
3173
|
+
switch( PQflush(conn) ) {
|
3174
|
+
case 1:
|
3175
|
+
events = RB_NUM2INT(pg_rb_io_wait(socket_io, RB_INT2NUM(PG_RUBY_IO_READABLE | PG_RUBY_IO_WRITABLE), Qnil));
|
3176
|
+
if (events & PG_RUBY_IO_READABLE){
|
3177
|
+
if ( PQconsumeInput(conn) == 0 ) goto error;
|
3178
|
+
}
|
3179
|
+
break;
|
3180
|
+
case 0:
|
3181
|
+
pg_rb_io_wait(socket_io, RB_INT2NUM(PG_RUBY_IO_READABLE), Qnil);
|
3182
|
+
if ( PQconsumeInput(conn) == 0 ) goto error;
|
3183
|
+
break;
|
3184
|
+
default:
|
3185
|
+
goto error;
|
3186
|
+
}
|
3187
|
+
}
|
3188
|
+
|
3189
|
+
cur = gvl_PQgetResult(conn);
|
3190
|
+
if( cur == NULL) break;
|
3191
|
+
|
3192
|
+
status = PQresultStatus(cur);
|
3193
|
+
PQclear(cur);
|
3194
|
+
if (status == PGRES_COPY_IN){
|
3195
|
+
while( gvl_PQputCopyEnd(conn, "COPY terminated by new query or discard_results") == 0 ){
|
3196
|
+
pgconn_async_flush(self);
|
3197
|
+
}
|
3198
|
+
}
|
3199
|
+
if (status == PGRES_COPY_OUT){
|
3200
|
+
for(;;) {
|
3201
|
+
char *buffer = NULL;
|
3202
|
+
int st = gvl_PQgetCopyData(conn, &buffer, 1);
|
3203
|
+
if( st == 0 ) {
|
3204
|
+
/* would block -> wait for readable data */
|
3205
|
+
pg_rb_io_wait(socket_io, RB_INT2NUM(PG_RUBY_IO_READABLE), Qnil);
|
3206
|
+
if ( PQconsumeInput(conn) == 0 ) goto error;
|
3207
|
+
} else if( st > 0 ) {
|
3208
|
+
/* some data retrieved -> discard it */
|
3209
|
+
PQfreemem(buffer);
|
3210
|
+
} else {
|
3211
|
+
/* no more data */
|
3212
|
+
break;
|
3213
|
+
}
|
3214
|
+
}
|
3215
|
+
}
|
3216
|
+
}
|
3217
|
+
|
3218
|
+
return Qtrue;
|
3219
|
+
|
3220
|
+
error:
|
3221
|
+
pgconn_close_socket_io(self);
|
3222
|
+
return Qfalse;
|
3223
|
+
}
|
3224
|
+
|
3225
|
+
/*
|
3226
|
+
* call-seq:
|
3227
|
+
* conn.exec(sql) -> PG::Result
|
3228
|
+
* conn.exec(sql) {|pg_result| block }
|
3229
|
+
*
|
3230
|
+
* Sends SQL query request specified by _sql_ to PostgreSQL.
|
3231
|
+
* On success, it returns a PG::Result instance with all result rows and columns.
|
3232
|
+
* On failure, it raises a PG::Error.
|
3233
|
+
*
|
3234
|
+
* For backward compatibility, if you pass more than one parameter to this method,
|
3235
|
+
* it will call #exec_params for you. New code should explicitly use #exec_params if
|
3236
|
+
* argument placeholders are used.
|
3237
|
+
*
|
3238
|
+
* If the optional code block is given, it will be passed <i>result</i> as an argument,
|
3239
|
+
* and the PG::Result object will automatically be cleared when the block terminates.
|
3240
|
+
* In this instance, <code>conn.exec</code> returns the value of the block.
|
3241
|
+
*
|
3242
|
+
* #exec is an alias for #async_exec which is almost identical to #sync_exec .
|
3243
|
+
* #sync_exec is implemented on the simpler synchronous command processing API of libpq, whereas
|
3244
|
+
* #async_exec is implemented on the asynchronous API and on ruby's IO mechanisms.
|
3245
|
+
* Only #async_exec is compatible to <tt>Fiber.scheduler</tt> based asynchronous IO processing introduced in ruby-3.0.
|
3246
|
+
* Both methods ensure that other threads can process while waiting for the server to
|
3247
|
+
* complete the request, but #sync_exec blocks all signals to be processed until the query is finished.
|
3248
|
+
* This is most notably visible by a delayed reaction to Control+C.
|
3249
|
+
* It's not recommended to use explicit sync or async variants but #exec instead, unless you have a good reason to do so.
|
3250
|
+
*
|
3251
|
+
* See also corresponding {libpq function}[https://www.postgresql.org/docs/current/libpq-exec.html#LIBPQ-PQEXEC].
|
3190
3252
|
*/
|
3191
3253
|
static VALUE
|
3192
3254
|
pgconn_async_exec(int argc, VALUE *argv, VALUE self)
|
@@ -3195,8 +3257,7 @@ pgconn_async_exec(int argc, VALUE *argv, VALUE self)
|
|
3195
3257
|
|
3196
3258
|
pgconn_discard_results( self );
|
3197
3259
|
pgconn_send_query( argc, argv, self );
|
3198
|
-
|
3199
|
-
rb_pgresult = pgconn_get_last_result( self );
|
3260
|
+
rb_pgresult = pgconn_async_get_last_result( self );
|
3200
3261
|
|
3201
3262
|
if ( rb_block_given_p() ) {
|
3202
3263
|
return rb_ensure( rb_yield, rb_pgresult, pg_result_clear, rb_pgresult );
|
@@ -3207,11 +3268,53 @@ pgconn_async_exec(int argc, VALUE *argv, VALUE self)
|
|
3207
3268
|
|
3208
3269
|
/*
|
3209
3270
|
* call-seq:
|
3210
|
-
* conn.
|
3211
|
-
* conn.
|
3271
|
+
* conn.exec_params(sql, params [, result_format [, type_map ]] ) -> nil
|
3272
|
+
* conn.exec_params(sql, params [, result_format [, type_map ]] ) {|pg_result| block }
|
3212
3273
|
*
|
3213
|
-
*
|
3214
|
-
*
|
3274
|
+
* Sends SQL query request specified by +sql+ to PostgreSQL using placeholders
|
3275
|
+
* for parameters.
|
3276
|
+
*
|
3277
|
+
* Returns a PG::Result instance on success. On failure, it raises a PG::Error.
|
3278
|
+
*
|
3279
|
+
* +params+ is an array of the bind parameters for the SQL query.
|
3280
|
+
* Each element of the +params+ array may be either:
|
3281
|
+
* a hash of the form:
|
3282
|
+
* {:value => String (value of bind parameter)
|
3283
|
+
* :type => Integer (oid of type of bind parameter)
|
3284
|
+
* :format => Integer (0 for text, 1 for binary)
|
3285
|
+
* }
|
3286
|
+
* or, it may be a String. If it is a string, that is equivalent to the hash:
|
3287
|
+
* { :value => <string value>, :type => 0, :format => 0 }
|
3288
|
+
*
|
3289
|
+
* PostgreSQL bind parameters are represented as $1, $2, $3, etc.,
|
3290
|
+
* inside the SQL query. The 0th element of the +params+ array is bound
|
3291
|
+
* to $1, the 1st element is bound to $2, etc. +nil+ is treated as +NULL+.
|
3292
|
+
*
|
3293
|
+
* If the types are not specified, they will be inferred by PostgreSQL.
|
3294
|
+
* Instead of specifying type oids, it's recommended to simply add
|
3295
|
+
* explicit casts in the query to ensure that the right type is used.
|
3296
|
+
*
|
3297
|
+
* For example: "SELECT $1::int"
|
3298
|
+
*
|
3299
|
+
* The optional +result_format+ should be 0 for text results, 1
|
3300
|
+
* for binary.
|
3301
|
+
*
|
3302
|
+
* +type_map+ can be a PG::TypeMap derivation (such as PG::BasicTypeMapForQueries).
|
3303
|
+
* This will type cast the params from various Ruby types before transmission
|
3304
|
+
* based on the encoders defined by the type map. When a type encoder is used
|
3305
|
+
* the format and oid of a given bind parameter are retrieved from the encoder
|
3306
|
+
* instead out of the hash form described above.
|
3307
|
+
*
|
3308
|
+
* If the optional code block is given, it will be passed <i>result</i> as an argument,
|
3309
|
+
* and the PG::Result object will automatically be cleared when the block terminates.
|
3310
|
+
* In this instance, <code>conn.exec</code> returns the value of the block.
|
3311
|
+
*
|
3312
|
+
* 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.
|
3313
|
+
* Unlike #exec, #exec_params allows at most one SQL command in the given string.
|
3314
|
+
* (There can be semicolons in it, but not more than one nonempty command.)
|
3315
|
+
* This is a limitation of the underlying protocol, but has some usefulness as an extra defense against SQL-injection attacks.
|
3316
|
+
*
|
3317
|
+
* See also corresponding {libpq function}[https://www.postgresql.org/docs/current/libpq-exec.html#LIBPQ-PQEXECPARAMS].
|
3215
3318
|
*/
|
3216
3319
|
static VALUE
|
3217
3320
|
pgconn_async_exec_params(int argc, VALUE *argv, VALUE self)
|
@@ -3226,8 +3329,7 @@ pgconn_async_exec_params(int argc, VALUE *argv, VALUE self)
|
|
3226
3329
|
} else {
|
3227
3330
|
pgconn_send_query_params( argc, argv, self );
|
3228
3331
|
}
|
3229
|
-
|
3230
|
-
rb_pgresult = pgconn_get_last_result( self );
|
3332
|
+
rb_pgresult = pgconn_async_get_last_result( self );
|
3231
3333
|
|
3232
3334
|
if ( rb_block_given_p() ) {
|
3233
3335
|
return rb_ensure( rb_yield, rb_pgresult, pg_result_clear, rb_pgresult );
|
@@ -3238,10 +3340,25 @@ pgconn_async_exec_params(int argc, VALUE *argv, VALUE self)
|
|
3238
3340
|
|
3239
3341
|
/*
|
3240
3342
|
* call-seq:
|
3241
|
-
* conn.
|
3343
|
+
* conn.prepare(stmt_name, sql [, param_types ] ) -> PG::Result
|
3242
3344
|
*
|
3243
|
-
*
|
3244
|
-
*
|
3345
|
+
* Prepares statement _sql_ with name _name_ to be executed later.
|
3346
|
+
* Returns a PG::Result instance on success.
|
3347
|
+
* On failure, it raises a PG::Error.
|
3348
|
+
*
|
3349
|
+
* +param_types+ is an optional parameter to specify the Oids of the
|
3350
|
+
* types of the parameters.
|
3351
|
+
*
|
3352
|
+
* If the types are not specified, they will be inferred by PostgreSQL.
|
3353
|
+
* Instead of specifying type oids, it's recommended to simply add
|
3354
|
+
* explicit casts in the query to ensure that the right type is used.
|
3355
|
+
*
|
3356
|
+
* For example: "SELECT $1::int"
|
3357
|
+
*
|
3358
|
+
* PostgreSQL bind parameters are represented as $1, $2, $3, etc.,
|
3359
|
+
* inside the SQL query.
|
3360
|
+
*
|
3361
|
+
* See also corresponding {libpq function}[https://www.postgresql.org/docs/current/libpq-exec.html#LIBPQ-PQPREPARE].
|
3245
3362
|
*/
|
3246
3363
|
static VALUE
|
3247
3364
|
pgconn_async_prepare(int argc, VALUE *argv, VALUE self)
|
@@ -3250,8 +3367,7 @@ pgconn_async_prepare(int argc, VALUE *argv, VALUE self)
|
|
3250
3367
|
|
3251
3368
|
pgconn_discard_results( self );
|
3252
3369
|
pgconn_send_prepare( argc, argv, self );
|
3253
|
-
|
3254
|
-
rb_pgresult = pgconn_get_last_result( self );
|
3370
|
+
rb_pgresult = pgconn_async_get_last_result( self );
|
3255
3371
|
|
3256
3372
|
if ( rb_block_given_p() ) {
|
3257
3373
|
return rb_ensure( rb_yield, rb_pgresult, pg_result_clear, rb_pgresult );
|
@@ -3262,11 +3378,40 @@ pgconn_async_prepare(int argc, VALUE *argv, VALUE self)
|
|
3262
3378
|
|
3263
3379
|
/*
|
3264
3380
|
* call-seq:
|
3265
|
-
* conn.
|
3266
|
-
* conn.
|
3381
|
+
* conn.exec_prepared(statement_name [, params, result_format[, type_map]] ) -> PG::Result
|
3382
|
+
* conn.exec_prepared(statement_name [, params, result_format[, type_map]] ) {|pg_result| block }
|
3267
3383
|
*
|
3268
|
-
*
|
3269
|
-
*
|
3384
|
+
* Execute prepared named statement specified by _statement_name_.
|
3385
|
+
* Returns a PG::Result instance on success.
|
3386
|
+
* On failure, it raises a PG::Error.
|
3387
|
+
*
|
3388
|
+
* +params+ is an array of the optional bind parameters for the
|
3389
|
+
* SQL query. Each element of the +params+ array may be either:
|
3390
|
+
* a hash of the form:
|
3391
|
+
* {:value => String (value of bind parameter)
|
3392
|
+
* :format => Integer (0 for text, 1 for binary)
|
3393
|
+
* }
|
3394
|
+
* or, it may be a String. If it is a string, that is equivalent to the hash:
|
3395
|
+
* { :value => <string value>, :format => 0 }
|
3396
|
+
*
|
3397
|
+
* PostgreSQL bind parameters are represented as $1, $2, $3, etc.,
|
3398
|
+
* inside the SQL query. The 0th element of the +params+ array is bound
|
3399
|
+
* to $1, the 1st element is bound to $2, etc. +nil+ is treated as +NULL+.
|
3400
|
+
*
|
3401
|
+
* The optional +result_format+ should be 0 for text results, 1
|
3402
|
+
* for binary.
|
3403
|
+
*
|
3404
|
+
* +type_map+ can be a PG::TypeMap derivation (such as PG::BasicTypeMapForQueries).
|
3405
|
+
* This will type cast the params from various Ruby types before transmission
|
3406
|
+
* based on the encoders defined by the type map. When a type encoder is used
|
3407
|
+
* the format and oid of a given bind parameter are retrieved from the encoder
|
3408
|
+
* instead out of the hash form described above.
|
3409
|
+
*
|
3410
|
+
* If the optional code block is given, it will be passed <i>result</i> as an argument,
|
3411
|
+
* and the PG::Result object will automatically be cleared when the block terminates.
|
3412
|
+
* In this instance, <code>conn.exec_prepared</code> returns the value of the block.
|
3413
|
+
*
|
3414
|
+
* See also corresponding {libpq function}[https://www.postgresql.org/docs/current/libpq-exec.html#LIBPQ-PQEXECPREPARED].
|
3270
3415
|
*/
|
3271
3416
|
static VALUE
|
3272
3417
|
pgconn_async_exec_prepared(int argc, VALUE *argv, VALUE self)
|
@@ -3275,8 +3420,7 @@ pgconn_async_exec_prepared(int argc, VALUE *argv, VALUE self)
|
|
3275
3420
|
|
3276
3421
|
pgconn_discard_results( self );
|
3277
3422
|
pgconn_send_query_prepared( argc, argv, self );
|
3278
|
-
|
3279
|
-
rb_pgresult = pgconn_get_last_result( self );
|
3423
|
+
rb_pgresult = pgconn_async_get_last_result( self );
|
3280
3424
|
|
3281
3425
|
if ( rb_block_given_p() ) {
|
3282
3426
|
return rb_ensure( rb_yield, rb_pgresult, pg_result_clear, rb_pgresult );
|
@@ -3287,10 +3431,11 @@ pgconn_async_exec_prepared(int argc, VALUE *argv, VALUE self)
|
|
3287
3431
|
|
3288
3432
|
/*
|
3289
3433
|
* call-seq:
|
3290
|
-
* conn.
|
3434
|
+
* conn.describe_portal( portal_name ) -> PG::Result
|
3291
3435
|
*
|
3292
|
-
*
|
3293
|
-
*
|
3436
|
+
* Retrieve information about the portal _portal_name_.
|
3437
|
+
*
|
3438
|
+
* See also corresponding {libpq function}[https://www.postgresql.org/docs/current/libpq-exec.html#LIBPQ-PQDESCRIBEPORTAL].
|
3294
3439
|
*/
|
3295
3440
|
static VALUE
|
3296
3441
|
pgconn_async_describe_portal(VALUE self, VALUE portal)
|
@@ -3299,8 +3444,7 @@ pgconn_async_describe_portal(VALUE self, VALUE portal)
|
|
3299
3444
|
|
3300
3445
|
pgconn_discard_results( self );
|
3301
3446
|
pgconn_send_describe_portal( self, portal );
|
3302
|
-
|
3303
|
-
rb_pgresult = pgconn_get_last_result( self );
|
3447
|
+
rb_pgresult = pgconn_async_get_last_result( self );
|
3304
3448
|
|
3305
3449
|
if ( rb_block_given_p() ) {
|
3306
3450
|
return rb_ensure( rb_yield, rb_pgresult, pg_result_clear, rb_pgresult );
|
@@ -3311,10 +3455,11 @@ pgconn_async_describe_portal(VALUE self, VALUE portal)
|
|
3311
3455
|
|
3312
3456
|
/*
|
3313
3457
|
* call-seq:
|
3314
|
-
* conn.
|
3458
|
+
* conn.describe_prepared( statement_name ) -> PG::Result
|
3315
3459
|
*
|
3316
|
-
*
|
3317
|
-
*
|
3460
|
+
* Retrieve information about the prepared statement _statement_name_.
|
3461
|
+
*
|
3462
|
+
* See also corresponding {libpq function}[https://www.postgresql.org/docs/current/libpq-exec.html#LIBPQ-PQDESCRIBEPREPARED].
|
3318
3463
|
*/
|
3319
3464
|
static VALUE
|
3320
3465
|
pgconn_async_describe_prepared(VALUE self, VALUE stmt_name)
|
@@ -3323,8 +3468,7 @@ pgconn_async_describe_prepared(VALUE self, VALUE stmt_name)
|
|
3323
3468
|
|
3324
3469
|
pgconn_discard_results( self );
|
3325
3470
|
pgconn_send_describe_prepared( self, stmt_name );
|
3326
|
-
|
3327
|
-
rb_pgresult = pgconn_get_last_result( self );
|
3471
|
+
rb_pgresult = pgconn_async_get_last_result( self );
|
3328
3472
|
|
3329
3473
|
if ( rb_block_given_p() ) {
|
3330
3474
|
return rb_ensure( rb_yield, rb_pgresult, pg_result_clear, rb_pgresult );
|
@@ -3338,7 +3482,7 @@ pgconn_async_describe_prepared(VALUE self, VALUE stmt_name)
|
|
3338
3482
|
* call-seq:
|
3339
3483
|
* conn.ssl_in_use? -> Boolean
|
3340
3484
|
*
|
3341
|
-
* Returns +true+ if the connection uses SSL, +false+ if not.
|
3485
|
+
* Returns +true+ if the connection uses SSL/TLS, +false+ if not.
|
3342
3486
|
*
|
3343
3487
|
* Available since PostgreSQL-9.5
|
3344
3488
|
*/
|
@@ -3372,7 +3516,7 @@ pgconn_ssl_in_use(VALUE self)
|
|
3372
3516
|
* 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
3517
|
*
|
3374
3518
|
*
|
3375
|
-
* See also #ssl_attribute_names and
|
3519
|
+
* See also #ssl_attribute_names and the {corresponding libpq function}[https://www.postgresql.org/docs/current/libpq-status.html#LIBPQ-PQSSLATTRIBUTE].
|
3376
3520
|
*
|
3377
3521
|
* Available since PostgreSQL-9.5
|
3378
3522
|
*/
|
@@ -3412,10 +3556,134 @@ pgconn_ssl_attribute_names(VALUE self)
|
|
3412
3556
|
#endif
|
3413
3557
|
|
3414
3558
|
|
3559
|
+
#ifdef HAVE_PQENTERPIPELINEMODE
|
3560
|
+
/*
|
3561
|
+
* call-seq:
|
3562
|
+
* conn.pipeline_status -> Integer
|
3563
|
+
*
|
3564
|
+
* Returns the current pipeline mode status of the libpq connection.
|
3565
|
+
*
|
3566
|
+
* PQpipelineStatus can return one of the following values:
|
3567
|
+
*
|
3568
|
+
* * PQ_PIPELINE_ON - The libpq connection is in pipeline mode.
|
3569
|
+
* * PQ_PIPELINE_OFF - The libpq connection is not in pipeline mode.
|
3570
|
+
* * PQ_PIPELINE_ABORTED - The libpq connection is in pipeline mode and an error occurred while processing the current pipeline.
|
3571
|
+
* The aborted flag is cleared when PQgetResult returns a result of type PGRES_PIPELINE_SYNC.
|
3572
|
+
*
|
3573
|
+
* Available since PostgreSQL-14
|
3574
|
+
*/
|
3575
|
+
static VALUE
|
3576
|
+
pgconn_pipeline_status(VALUE self)
|
3577
|
+
{
|
3578
|
+
int res = PQpipelineStatus(pg_get_pgconn(self));
|
3579
|
+
return INT2FIX(res);
|
3580
|
+
}
|
3581
|
+
|
3582
|
+
|
3583
|
+
/*
|
3584
|
+
* call-seq:
|
3585
|
+
* conn.enter_pipeline_mode -> nil
|
3586
|
+
*
|
3587
|
+
* Causes a connection to enter pipeline mode if it is currently idle or already in pipeline mode.
|
3588
|
+
*
|
3589
|
+
* 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.
|
3590
|
+
* This function does not actually send anything to the server, it just changes the libpq connection state.
|
3591
|
+
*
|
3592
|
+
* Available since PostgreSQL-14
|
3593
|
+
*/
|
3594
|
+
static VALUE
|
3595
|
+
pgconn_enter_pipeline_mode(VALUE self)
|
3596
|
+
{
|
3597
|
+
PGconn *conn = pg_get_pgconn(self);
|
3598
|
+
int res = PQenterPipelineMode(conn);
|
3599
|
+
if( res != 1 )
|
3600
|
+
pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(conn));
|
3601
|
+
|
3602
|
+
return Qnil;
|
3603
|
+
}
|
3604
|
+
|
3605
|
+
/*
|
3606
|
+
* call-seq:
|
3607
|
+
* conn.exit_pipeline_mode -> nil
|
3608
|
+
*
|
3609
|
+
* Causes a connection to exit pipeline mode if it is currently in pipeline mode with an empty queue and no pending results.
|
3610
|
+
*
|
3611
|
+
* Takes no action if not in pipeline mode.
|
3612
|
+
* 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.
|
3613
|
+
*
|
3614
|
+
* Available since PostgreSQL-14
|
3615
|
+
*/
|
3616
|
+
static VALUE
|
3617
|
+
pgconn_exit_pipeline_mode(VALUE self)
|
3618
|
+
{
|
3619
|
+
PGconn *conn = pg_get_pgconn(self);
|
3620
|
+
int res = PQexitPipelineMode(conn);
|
3621
|
+
if( res != 1 )
|
3622
|
+
pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(conn));
|
3623
|
+
|
3624
|
+
return Qnil;
|
3625
|
+
}
|
3626
|
+
|
3627
|
+
|
3628
|
+
/*
|
3629
|
+
* call-seq:
|
3630
|
+
* conn.pipeline_sync -> nil
|
3631
|
+
*
|
3632
|
+
* Marks a synchronization point in a pipeline by sending a sync message and flushing the send buffer.
|
3633
|
+
* This serves as the delimiter of an implicit transaction and an error recovery point; see Section 34.5.1.3 of the PostgreSQL documentation.
|
3634
|
+
*
|
3635
|
+
* Raises PG::Error if the connection is not in pipeline mode or sending a sync message failed.
|
3636
|
+
*
|
3637
|
+
* Available since PostgreSQL-14
|
3638
|
+
*/
|
3639
|
+
static VALUE
|
3640
|
+
pgconn_pipeline_sync(VALUE self)
|
3641
|
+
{
|
3642
|
+
PGconn *conn = pg_get_pgconn(self);
|
3643
|
+
int res = PQpipelineSync(conn);
|
3644
|
+
if( res != 1 )
|
3645
|
+
pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(conn));
|
3646
|
+
|
3647
|
+
return Qnil;
|
3648
|
+
}
|
3649
|
+
|
3650
|
+
/*
|
3651
|
+
* call-seq:
|
3652
|
+
* conn.pipeline_sync -> nil
|
3653
|
+
*
|
3654
|
+
* Sends a request for the server to flush its output buffer.
|
3655
|
+
*
|
3656
|
+
* 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.
|
3657
|
+
* This function is useful to cause the server to flush its output buffer in pipeline mode without establishing a synchronization point.
|
3658
|
+
* Note that the request is not itself flushed to the server automatically; use Connection#flush if necessary.
|
3659
|
+
*
|
3660
|
+
* Available since PostgreSQL-14
|
3661
|
+
*/
|
3662
|
+
static VALUE
|
3663
|
+
pgconn_send_flush_request(VALUE self)
|
3664
|
+
{
|
3665
|
+
PGconn *conn = pg_get_pgconn(self);
|
3666
|
+
int res = PQsendFlushRequest(conn);
|
3667
|
+
if( res != 1 )
|
3668
|
+
pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(conn));
|
3669
|
+
|
3670
|
+
return Qnil;
|
3671
|
+
}
|
3672
|
+
|
3673
|
+
#endif
|
3674
|
+
|
3415
3675
|
/**************************************************************************
|
3416
3676
|
* LARGE OBJECT SUPPORT
|
3417
3677
|
**************************************************************************/
|
3418
3678
|
|
3679
|
+
#define BLOCKING_BEGIN(conn) do { \
|
3680
|
+
int old_nonblocking = PQisnonblocking(conn); \
|
3681
|
+
PQsetnonblocking(conn, 0);
|
3682
|
+
|
3683
|
+
#define BLOCKING_END(th) \
|
3684
|
+
PQsetnonblocking(conn, old_nonblocking); \
|
3685
|
+
} while(0);
|
3686
|
+
|
3419
3687
|
/*
|
3420
3688
|
* call-seq:
|
3421
3689
|
* conn.lo_creat( [mode] ) -> Integer
|
@@ -3436,9 +3704,12 @@ pgconn_locreat(int argc, VALUE *argv, VALUE self)
|
|
3436
3704
|
else
|
3437
3705
|
mode = NUM2INT(nmode);
|
3438
3706
|
|
3439
|
-
|
3707
|
+
BLOCKING_BEGIN(conn)
|
3708
|
+
lo_oid = lo_creat(conn, mode);
|
3709
|
+
BLOCKING_END(conn)
|
3710
|
+
|
3440
3711
|
if (lo_oid == 0)
|
3441
|
-
|
3712
|
+
pg_raise_conn_error( rb_ePGerror, self, "lo_creat failed");
|
3442
3713
|
|
3443
3714
|
return UINT2NUM(lo_oid);
|
3444
3715
|
}
|
@@ -3459,7 +3730,7 @@ pgconn_locreate(VALUE self, VALUE in_lo_oid)
|
|
3459
3730
|
|
3460
3731
|
ret = lo_create(conn, lo_oid);
|
3461
3732
|
if (ret == InvalidOid)
|
3462
|
-
|
3733
|
+
pg_raise_conn_error( rb_ePGerror, self, "lo_create failed");
|
3463
3734
|
|
3464
3735
|
return UINT2NUM(ret);
|
3465
3736
|
}
|
@@ -3481,9 +3752,12 @@ pgconn_loimport(VALUE self, VALUE filename)
|
|
3481
3752
|
|
3482
3753
|
Check_Type(filename, T_STRING);
|
3483
3754
|
|
3484
|
-
|
3755
|
+
BLOCKING_BEGIN(conn)
|
3756
|
+
lo_oid = lo_import(conn, StringValueCStr(filename));
|
3757
|
+
BLOCKING_END(conn)
|
3758
|
+
|
3485
3759
|
if (lo_oid == 0) {
|
3486
|
-
|
3760
|
+
pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(conn));
|
3487
3761
|
}
|
3488
3762
|
return UINT2NUM(lo_oid);
|
3489
3763
|
}
|
@@ -3499,12 +3773,17 @@ pgconn_loexport(VALUE self, VALUE lo_oid, VALUE filename)
|
|
3499
3773
|
{
|
3500
3774
|
PGconn *conn = pg_get_pgconn(self);
|
3501
3775
|
Oid oid;
|
3776
|
+
int ret;
|
3502
3777
|
Check_Type(filename, T_STRING);
|
3503
3778
|
|
3504
3779
|
oid = NUM2UINT(lo_oid);
|
3505
3780
|
|
3506
|
-
|
3507
|
-
|
3781
|
+
BLOCKING_BEGIN(conn)
|
3782
|
+
ret = lo_export(conn, oid, StringValueCStr(filename));
|
3783
|
+
BLOCKING_END(conn)
|
3784
|
+
|
3785
|
+
if (ret < 0) {
|
3786
|
+
pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(conn));
|
3508
3787
|
}
|
3509
3788
|
return Qnil;
|
3510
3789
|
}
|
@@ -3534,8 +3813,12 @@ pgconn_loopen(int argc, VALUE *argv, VALUE self)
|
|
3534
3813
|
else
|
3535
3814
|
mode = NUM2INT(nmode);
|
3536
3815
|
|
3537
|
-
|
3538
|
-
|
3816
|
+
BLOCKING_BEGIN(conn)
|
3817
|
+
fd = lo_open(conn, lo_oid, mode);
|
3818
|
+
BLOCKING_END(conn)
|
3819
|
+
|
3820
|
+
if(fd < 0) {
|
3821
|
+
pg_raise_conn_error( rb_ePGerror, self, "can't open large object: %s", PQerrorMessage(conn));
|
3539
3822
|
}
|
3540
3823
|
return INT2FIX(fd);
|
3541
3824
|
}
|
@@ -3557,11 +3840,15 @@ pgconn_lowrite(VALUE self, VALUE in_lo_desc, VALUE buffer)
|
|
3557
3840
|
Check_Type(buffer, T_STRING);
|
3558
3841
|
|
3559
3842
|
if( RSTRING_LEN(buffer) < 0) {
|
3560
|
-
|
3843
|
+
pg_raise_conn_error( rb_ePGerror, self, "write buffer zero string");
|
3561
3844
|
}
|
3562
|
-
|
3563
|
-
|
3564
|
-
|
3845
|
+
BLOCKING_BEGIN(conn)
|
3846
|
+
n = lo_write(conn, fd, StringValuePtr(buffer),
|
3847
|
+
RSTRING_LEN(buffer));
|
3848
|
+
BLOCKING_END(conn)
|
3849
|
+
|
3850
|
+
if(n < 0) {
|
3851
|
+
pg_raise_conn_error( rb_ePGerror, self, "lo_write failed: %s", PQerrorMessage(conn));
|
3565
3852
|
}
|
3566
3853
|
|
3567
3854
|
return INT2FIX(n);
|
@@ -3584,23 +3871,24 @@ pgconn_loread(VALUE self, VALUE in_lo_desc, VALUE in_len)
|
|
3584
3871
|
VALUE str;
|
3585
3872
|
char *buffer;
|
3586
3873
|
|
3587
|
-
|
3588
|
-
|
3589
|
-
rb_raise(rb_eNoMemError, "ALLOC failed!");
|
3874
|
+
if (len < 0)
|
3875
|
+
pg_raise_conn_error( rb_ePGerror, self, "negative length %d given", len);
|
3590
3876
|
|
3591
|
-
|
3592
|
-
rb_raise(rb_ePGerror,"nagative length %d given", len);
|
3593
|
-
}
|
3877
|
+
buffer = ALLOC_N(char, len);
|
3594
3878
|
|
3595
|
-
|
3596
|
-
|
3879
|
+
BLOCKING_BEGIN(conn)
|
3880
|
+
ret = lo_read(conn, lo_desc, buffer, len);
|
3881
|
+
BLOCKING_END(conn)
|
3882
|
+
|
3883
|
+
if(ret < 0)
|
3884
|
+
pg_raise_conn_error( rb_ePGerror, self, "lo_read failed");
|
3597
3885
|
|
3598
3886
|
if(ret == 0) {
|
3599
3887
|
xfree(buffer);
|
3600
3888
|
return Qnil;
|
3601
3889
|
}
|
3602
3890
|
|
3603
|
-
str =
|
3891
|
+
str = rb_str_new(buffer, ret);
|
3604
3892
|
xfree(buffer);
|
3605
3893
|
|
3606
3894
|
return str;
|
@@ -3622,8 +3910,12 @@ pgconn_lolseek(VALUE self, VALUE in_lo_desc, VALUE offset, VALUE whence)
|
|
3622
3910
|
int lo_desc = NUM2INT(in_lo_desc);
|
3623
3911
|
int ret;
|
3624
3912
|
|
3625
|
-
|
3626
|
-
|
3913
|
+
BLOCKING_BEGIN(conn)
|
3914
|
+
ret = lo_lseek(conn, lo_desc, NUM2INT(offset), NUM2INT(whence));
|
3915
|
+
BLOCKING_END(conn)
|
3916
|
+
|
3917
|
+
if(ret < 0) {
|
3918
|
+
pg_raise_conn_error( rb_ePGerror, self, "lo_lseek failed");
|
3627
3919
|
}
|
3628
3920
|
|
3629
3921
|
return INT2FIX(ret);
|
@@ -3642,8 +3934,12 @@ pgconn_lotell(VALUE self, VALUE in_lo_desc)
|
|
3642
3934
|
PGconn *conn = pg_get_pgconn(self);
|
3643
3935
|
int lo_desc = NUM2INT(in_lo_desc);
|
3644
3936
|
|
3645
|
-
|
3646
|
-
|
3937
|
+
BLOCKING_BEGIN(conn)
|
3938
|
+
position = lo_tell(conn, lo_desc);
|
3939
|
+
BLOCKING_END(conn)
|
3940
|
+
|
3941
|
+
if(position < 0)
|
3942
|
+
pg_raise_conn_error( rb_ePGerror, self, "lo_tell failed");
|
3647
3943
|
|
3648
3944
|
return INT2FIX(position);
|
3649
3945
|
}
|
@@ -3660,9 +3956,14 @@ pgconn_lotruncate(VALUE self, VALUE in_lo_desc, VALUE in_len)
|
|
3660
3956
|
PGconn *conn = pg_get_pgconn(self);
|
3661
3957
|
int lo_desc = NUM2INT(in_lo_desc);
|
3662
3958
|
size_t len = NUM2INT(in_len);
|
3959
|
+
int ret;
|
3960
|
+
|
3961
|
+
BLOCKING_BEGIN(conn)
|
3962
|
+
ret = lo_truncate(conn,lo_desc,len);
|
3963
|
+
BLOCKING_END(conn)
|
3663
3964
|
|
3664
|
-
if(
|
3665
|
-
|
3965
|
+
if(ret < 0)
|
3966
|
+
pg_raise_conn_error( rb_ePGerror, self, "lo_truncate failed");
|
3666
3967
|
|
3667
3968
|
return Qnil;
|
3668
3969
|
}
|
@@ -3678,9 +3979,14 @@ pgconn_loclose(VALUE self, VALUE in_lo_desc)
|
|
3678
3979
|
{
|
3679
3980
|
PGconn *conn = pg_get_pgconn(self);
|
3680
3981
|
int lo_desc = NUM2INT(in_lo_desc);
|
3982
|
+
int ret;
|
3983
|
+
|
3984
|
+
BLOCKING_BEGIN(conn)
|
3985
|
+
ret = lo_close(conn,lo_desc);
|
3986
|
+
BLOCKING_END(conn)
|
3681
3987
|
|
3682
|
-
if(
|
3683
|
-
|
3988
|
+
if(ret < 0)
|
3989
|
+
pg_raise_conn_error( rb_ePGerror, self, "lo_close failed");
|
3684
3990
|
|
3685
3991
|
return Qnil;
|
3686
3992
|
}
|
@@ -3696,20 +4002,28 @@ pgconn_lounlink(VALUE self, VALUE in_oid)
|
|
3696
4002
|
{
|
3697
4003
|
PGconn *conn = pg_get_pgconn(self);
|
3698
4004
|
Oid oid = NUM2UINT(in_oid);
|
4005
|
+
int ret;
|
4006
|
+
|
4007
|
+
BLOCKING_BEGIN(conn)
|
4008
|
+
ret = lo_unlink(conn,oid);
|
4009
|
+
BLOCKING_END(conn)
|
3699
4010
|
|
3700
|
-
if(
|
3701
|
-
|
4011
|
+
if(ret < 0)
|
4012
|
+
pg_raise_conn_error( rb_ePGerror, self, "lo_unlink failed");
|
3702
4013
|
|
3703
4014
|
return Qnil;
|
3704
4015
|
}
|
3705
4016
|
|
3706
4017
|
|
3707
|
-
void
|
4018
|
+
static void
|
3708
4019
|
pgconn_set_internal_encoding_index( VALUE self )
|
3709
4020
|
{
|
3710
|
-
|
3711
|
-
|
3712
|
-
|
4021
|
+
int enc_idx;
|
4022
|
+
t_pg_connection *this = pg_get_connection_safe( self );
|
4023
|
+
rb_encoding *enc = pg_conn_enc_get( this->pgconn );
|
4024
|
+
enc_idx = rb_enc_to_index(enc);
|
4025
|
+
if( enc_idx >= (1<<(PG_ENC_IDX_BITS-1)) ) rb_raise(rb_eArgError, "unsupported encoding index %d", enc_idx);
|
4026
|
+
this->enc_idx = enc_idx;
|
3713
4027
|
}
|
3714
4028
|
|
3715
4029
|
/*
|
@@ -3752,13 +4066,13 @@ static VALUE pgconn_external_encoding(VALUE self);
|
|
3752
4066
|
static VALUE
|
3753
4067
|
pgconn_internal_encoding_set(VALUE self, VALUE enc)
|
3754
4068
|
{
|
3755
|
-
|
4069
|
+
rb_check_frozen(self);
|
3756
4070
|
if (NIL_P(enc)) {
|
3757
|
-
|
4071
|
+
pgconn_sync_set_client_encoding( self, rb_usascii_str_new_cstr("SQL_ASCII") );
|
3758
4072
|
return enc;
|
3759
4073
|
}
|
3760
4074
|
else if ( TYPE(enc) == T_STRING && strcasecmp("JOHAB", StringValueCStr(enc)) == 0 ) {
|
3761
|
-
|
4075
|
+
pgconn_sync_set_client_encoding(self, rb_usascii_str_new_cstr("JOHAB"));
|
3762
4076
|
return enc;
|
3763
4077
|
}
|
3764
4078
|
else {
|
@@ -3773,11 +4087,6 @@ pgconn_internal_encoding_set(VALUE self, VALUE enc)
|
|
3773
4087
|
pgconn_set_internal_encoding_index( self );
|
3774
4088
|
return enc;
|
3775
4089
|
}
|
3776
|
-
|
3777
|
-
enc_inspect = rb_inspect(enc);
|
3778
|
-
rb_raise( rb_ePGerror, "unknown encoding: %s", StringValueCStr(enc_inspect) );
|
3779
|
-
|
3780
|
-
return Qnil;
|
3781
4090
|
}
|
3782
4091
|
|
3783
4092
|
|
@@ -3796,42 +4105,56 @@ pgconn_external_encoding(VALUE self)
|
|
3796
4105
|
rb_encoding *enc = NULL;
|
3797
4106
|
const char *pg_encname = NULL;
|
3798
4107
|
|
3799
|
-
/* Use cached value if found */
|
3800
|
-
if ( RTEST(this->external_encoding) ) return this->external_encoding;
|
3801
|
-
|
3802
4108
|
pg_encname = PQparameterStatus( this->pgconn, "server_encoding" );
|
3803
4109
|
enc = pg_get_pg_encname_as_rb_encoding( pg_encname );
|
3804
|
-
|
3805
|
-
|
3806
|
-
return this->external_encoding;
|
4110
|
+
return rb_enc_from_encoding( enc );
|
3807
4111
|
}
|
3808
4112
|
|
4113
|
+
/*
|
4114
|
+
* call-seq:
|
4115
|
+
* conn.set_client_encoding( encoding )
|
4116
|
+
*
|
4117
|
+
* Sets the client encoding to the _encoding_ String.
|
4118
|
+
*/
|
4119
|
+
static VALUE
|
4120
|
+
pgconn_async_set_client_encoding(VALUE self, VALUE encname)
|
4121
|
+
{
|
4122
|
+
VALUE query_format, query;
|
4123
|
+
|
4124
|
+
rb_check_frozen(self);
|
4125
|
+
Check_Type(encname, T_STRING);
|
4126
|
+
query_format = rb_str_new_cstr("set client_encoding to '%s'");
|
4127
|
+
query = rb_funcall(query_format, rb_intern("%"), 1, encname);
|
4128
|
+
|
4129
|
+
pgconn_async_exec(1, &query, self);
|
4130
|
+
pgconn_set_internal_encoding_index( self );
|
4131
|
+
|
4132
|
+
return Qnil;
|
4133
|
+
}
|
3809
4134
|
|
3810
4135
|
static VALUE
|
3811
4136
|
pgconn_set_client_encoding_async1( VALUE args )
|
3812
4137
|
{
|
3813
4138
|
VALUE self = ((VALUE*)args)[0];
|
3814
4139
|
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);
|
4140
|
+
pgconn_async_set_client_encoding(self, encname);
|
3819
4141
|
return 0;
|
3820
4142
|
}
|
3821
4143
|
|
3822
4144
|
|
3823
4145
|
static VALUE
|
3824
|
-
pgconn_set_client_encoding_async2( VALUE arg )
|
4146
|
+
pgconn_set_client_encoding_async2( VALUE arg, VALUE ex )
|
3825
4147
|
{
|
3826
4148
|
UNUSED(arg);
|
4149
|
+
UNUSED(ex);
|
3827
4150
|
return 1;
|
3828
4151
|
}
|
3829
4152
|
|
3830
4153
|
|
3831
4154
|
static VALUE
|
3832
|
-
pgconn_set_client_encoding_async( VALUE self,
|
4155
|
+
pgconn_set_client_encoding_async( VALUE self, VALUE encname )
|
3833
4156
|
{
|
3834
|
-
VALUE args[] = { self,
|
4157
|
+
VALUE args[] = { self, encname };
|
3835
4158
|
return rb_rescue(pgconn_set_client_encoding_async1, (VALUE)&args, pgconn_set_client_encoding_async2, Qnil);
|
3836
4159
|
}
|
3837
4160
|
|
@@ -3848,16 +4171,23 @@ static VALUE
|
|
3848
4171
|
pgconn_set_default_encoding( VALUE self )
|
3849
4172
|
{
|
3850
4173
|
PGconn *conn = pg_get_pgconn( self );
|
3851
|
-
rb_encoding *
|
3852
|
-
|
3853
|
-
|
3854
|
-
if ((
|
3855
|
-
|
3856
|
-
|
3857
|
-
|
3858
|
-
|
4174
|
+
rb_encoding *rb_enc;
|
4175
|
+
|
4176
|
+
rb_check_frozen(self);
|
4177
|
+
if (( rb_enc = rb_default_internal_encoding() )) {
|
4178
|
+
rb_encoding * conn_encoding = pg_conn_enc_get( conn );
|
4179
|
+
|
4180
|
+
/* Don't set the server encoding, if it's unnecessary.
|
4181
|
+
* This is important for connection proxies, who disallow configuration settings.
|
4182
|
+
*/
|
4183
|
+
if ( conn_encoding != rb_enc ) {
|
4184
|
+
const char *encname = pg_get_rb_encoding_as_pg_encoding( rb_enc );
|
4185
|
+
if ( pgconn_set_client_encoding_async(self, rb_str_new_cstr(encname)) != 0 )
|
4186
|
+
rb_warning( "Failed to set the default_internal encoding to %s: '%s'",
|
4187
|
+
encname, PQerrorMessage(conn) );
|
4188
|
+
}
|
3859
4189
|
pgconn_set_internal_encoding_index( self );
|
3860
|
-
return rb_enc_from_encoding(
|
4190
|
+
return rb_enc_from_encoding( rb_enc );
|
3861
4191
|
} else {
|
3862
4192
|
pgconn_set_internal_encoding_index( self );
|
3863
4193
|
return Qnil;
|
@@ -3878,13 +4208,14 @@ static VALUE
|
|
3878
4208
|
pgconn_type_map_for_queries_set(VALUE self, VALUE typemap)
|
3879
4209
|
{
|
3880
4210
|
t_pg_connection *this = pg_get_connection( self );
|
4211
|
+
t_typemap *tm;
|
4212
|
+
UNUSED(tm);
|
3881
4213
|
|
3882
|
-
|
3883
|
-
|
3884
|
-
|
3885
|
-
|
3886
|
-
|
3887
|
-
this->type_map_for_queries = typemap;
|
4214
|
+
rb_check_frozen(self);
|
4215
|
+
/* Check type of method param */
|
4216
|
+
TypedData_Get_Struct(typemap, t_typemap, &pg_typemap_type, tm);
|
4217
|
+
|
4218
|
+
RB_OBJ_WRITE(self, &this->type_map_for_queries, typemap);
|
3888
4219
|
|
3889
4220
|
return typemap;
|
3890
4221
|
}
|
@@ -3918,13 +4249,12 @@ static VALUE
|
|
3918
4249
|
pgconn_type_map_for_results_set(VALUE self, VALUE typemap)
|
3919
4250
|
{
|
3920
4251
|
t_pg_connection *this = pg_get_connection( self );
|
4252
|
+
t_typemap *tm;
|
4253
|
+
UNUSED(tm);
|
3921
4254
|
|
3922
|
-
|
3923
|
-
|
3924
|
-
|
3925
|
-
}
|
3926
|
-
Check_Type(typemap, T_DATA);
|
3927
|
-
this->type_map_for_results = typemap;
|
4255
|
+
rb_check_frozen(self);
|
4256
|
+
TypedData_Get_Struct(typemap, t_typemap, &pg_typemap_type, tm);
|
4257
|
+
RB_OBJ_WRITE(self, &this->type_map_for_results, typemap);
|
3928
4258
|
|
3929
4259
|
return typemap;
|
3930
4260
|
}
|
@@ -3958,20 +4288,20 @@ pgconn_type_map_for_results_get(VALUE self)
|
|
3958
4288
|
*
|
3959
4289
|
*/
|
3960
4290
|
static VALUE
|
3961
|
-
pgconn_encoder_for_put_copy_data_set(VALUE self, VALUE
|
4291
|
+
pgconn_encoder_for_put_copy_data_set(VALUE self, VALUE encoder)
|
3962
4292
|
{
|
3963
4293
|
t_pg_connection *this = pg_get_connection( self );
|
3964
4294
|
|
3965
|
-
|
3966
|
-
|
3967
|
-
|
3968
|
-
|
3969
|
-
|
3970
|
-
|
4295
|
+
rb_check_frozen(self);
|
4296
|
+
if( encoder != Qnil ){
|
4297
|
+
t_pg_coder *co;
|
4298
|
+
UNUSED(co);
|
4299
|
+
/* Check argument type */
|
4300
|
+
TypedData_Get_Struct(encoder, t_pg_coder, &pg_coder_type, co);
|
3971
4301
|
}
|
3972
|
-
this->encoder_for_put_copy_data
|
4302
|
+
RB_OBJ_WRITE(self, &this->encoder_for_put_copy_data, encoder);
|
3973
4303
|
|
3974
|
-
return
|
4304
|
+
return encoder;
|
3975
4305
|
}
|
3976
4306
|
|
3977
4307
|
/*
|
@@ -4007,20 +4337,20 @@ pgconn_encoder_for_put_copy_data_get(VALUE self)
|
|
4007
4337
|
*
|
4008
4338
|
*/
|
4009
4339
|
static VALUE
|
4010
|
-
pgconn_decoder_for_get_copy_data_set(VALUE self, VALUE
|
4340
|
+
pgconn_decoder_for_get_copy_data_set(VALUE self, VALUE decoder)
|
4011
4341
|
{
|
4012
4342
|
t_pg_connection *this = pg_get_connection( self );
|
4013
4343
|
|
4014
|
-
|
4015
|
-
|
4016
|
-
|
4017
|
-
|
4018
|
-
|
4019
|
-
|
4344
|
+
rb_check_frozen(self);
|
4345
|
+
if( decoder != Qnil ){
|
4346
|
+
t_pg_coder *co;
|
4347
|
+
UNUSED(co);
|
4348
|
+
/* Check argument type */
|
4349
|
+
TypedData_Get_Struct(decoder, t_pg_coder, &pg_coder_type, co);
|
4020
4350
|
}
|
4021
|
-
this->decoder_for_get_copy_data
|
4351
|
+
RB_OBJ_WRITE(self, &this->decoder_for_get_copy_data, decoder);
|
4022
4352
|
|
4023
|
-
return
|
4353
|
+
return decoder;
|
4024
4354
|
}
|
4025
4355
|
|
4026
4356
|
/*
|
@@ -4045,16 +4375,55 @@ pgconn_decoder_for_get_copy_data_get(VALUE self)
|
|
4045
4375
|
|
4046
4376
|
/*
|
4047
4377
|
* call-seq:
|
4048
|
-
*
|
4378
|
+
* conn.field_name_type = Symbol
|
4379
|
+
*
|
4380
|
+
* Set default type of field names of results retrieved by this connection.
|
4381
|
+
* It can be set to one of:
|
4382
|
+
* * +:string+ to use String based field names
|
4383
|
+
* * +:symbol+ to use Symbol based field names
|
4384
|
+
*
|
4385
|
+
* The default is +:string+ .
|
4386
|
+
*
|
4387
|
+
* Settings the type of field names affects only future results.
|
4388
|
+
*
|
4389
|
+
* See further description at PG::Result#field_name_type=
|
4049
4390
|
*
|
4050
|
-
* This method is for testing only and will probably be removed in the future.
|
4051
4391
|
*/
|
4052
4392
|
static VALUE
|
4053
|
-
|
4393
|
+
pgconn_field_name_type_set(VALUE self, VALUE sym)
|
4054
4394
|
{
|
4055
4395
|
t_pg_connection *this = pg_get_connection( self );
|
4056
|
-
|
4057
|
-
|
4396
|
+
|
4397
|
+
rb_check_frozen(self);
|
4398
|
+
this->flags &= ~PG_RESULT_FIELD_NAMES_MASK;
|
4399
|
+
if( sym == sym_symbol ) this->flags |= PG_RESULT_FIELD_NAMES_SYMBOL;
|
4400
|
+
else if ( sym == sym_static_symbol ) this->flags |= PG_RESULT_FIELD_NAMES_STATIC_SYMBOL;
|
4401
|
+
else if ( sym == sym_string );
|
4402
|
+
else rb_raise(rb_eArgError, "invalid argument %+"PRIsVALUE, sym);
|
4403
|
+
|
4404
|
+
return sym;
|
4405
|
+
}
|
4406
|
+
|
4407
|
+
/*
|
4408
|
+
* call-seq:
|
4409
|
+
* conn.field_name_type -> Symbol
|
4410
|
+
*
|
4411
|
+
* Get type of field names.
|
4412
|
+
*
|
4413
|
+
* See description at #field_name_type=
|
4414
|
+
*/
|
4415
|
+
static VALUE
|
4416
|
+
pgconn_field_name_type_get(VALUE self)
|
4417
|
+
{
|
4418
|
+
t_pg_connection *this = pg_get_connection( self );
|
4419
|
+
|
4420
|
+
if( this->flags & PG_RESULT_FIELD_NAMES_SYMBOL ){
|
4421
|
+
return sym_symbol;
|
4422
|
+
} else if( this->flags & PG_RESULT_FIELD_NAMES_STATIC_SYMBOL ){
|
4423
|
+
return sym_static_symbol;
|
4424
|
+
} else {
|
4425
|
+
return sym_string;
|
4426
|
+
}
|
4058
4427
|
}
|
4059
4428
|
|
4060
4429
|
|
@@ -4062,23 +4431,25 @@ pgconn_guess_result_memsize_set(VALUE self, VALUE enable)
|
|
4062
4431
|
* Document-class: PG::Connection
|
4063
4432
|
*/
|
4064
4433
|
void
|
4065
|
-
init_pg_connection()
|
4434
|
+
init_pg_connection(void)
|
4066
4435
|
{
|
4067
4436
|
s_id_encode = rb_intern("encode");
|
4437
|
+
s_id_autoclose_set = rb_intern("autoclose=");
|
4068
4438
|
sym_type = ID2SYM(rb_intern("type"));
|
4069
4439
|
sym_format = ID2SYM(rb_intern("format"));
|
4070
4440
|
sym_value = ID2SYM(rb_intern("value"));
|
4441
|
+
sym_string = ID2SYM(rb_intern("string"));
|
4442
|
+
sym_symbol = ID2SYM(rb_intern("symbol"));
|
4443
|
+
sym_static_symbol = ID2SYM(rb_intern("static_symbol"));
|
4071
4444
|
|
4072
4445
|
rb_cPGconn = rb_define_class_under( rb_mPG, "Connection", rb_cObject );
|
4446
|
+
/* Help rdoc to known the Constants module */
|
4447
|
+
/* rb_mPGconstants = rb_define_module_under( rb_mPG, "Constants" ); */
|
4073
4448
|
rb_include_module(rb_cPGconn, rb_mPGconstants);
|
4074
4449
|
|
4075
4450
|
/****** PG::Connection CLASS METHODS ******/
|
4076
4451
|
rb_define_alloc_func( rb_cPGconn, pgconn_s_allocate );
|
4077
4452
|
|
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
4453
|
rb_define_singleton_method(rb_cPGconn, "escape_string", pgconn_s_escape, 1);
|
4083
4454
|
SINGLETON_ALIAS(rb_cPGconn, "escape", "escape_string");
|
4084
4455
|
rb_define_singleton_method(rb_cPGconn, "escape_bytea", pgconn_s_escape_bytea, 1);
|
@@ -4087,14 +4458,15 @@ init_pg_connection()
|
|
4087
4458
|
rb_define_singleton_method(rb_cPGconn, "quote_ident", pgconn_s_quote_ident, 1);
|
4088
4459
|
rb_define_singleton_method(rb_cPGconn, "connect_start", pgconn_s_connect_start, -1);
|
4089
4460
|
rb_define_singleton_method(rb_cPGconn, "conndefaults", pgconn_s_conndefaults, 0);
|
4090
|
-
rb_define_singleton_method(rb_cPGconn, "
|
4461
|
+
rb_define_singleton_method(rb_cPGconn, "conninfo_parse", pgconn_s_conninfo_parse, 1);
|
4462
|
+
rb_define_singleton_method(rb_cPGconn, "sync_ping", pgconn_s_sync_ping, -1);
|
4463
|
+
rb_define_singleton_method(rb_cPGconn, "sync_connect", pgconn_s_sync_connect, -1);
|
4091
4464
|
|
4092
4465
|
/****** PG::Connection INSTANCE METHODS: Connection Control ******/
|
4093
|
-
rb_define_method(rb_cPGconn, "initialize", pgconn_init, -1);
|
4094
4466
|
rb_define_method(rb_cPGconn, "connect_poll", pgconn_connect_poll, 0);
|
4095
4467
|
rb_define_method(rb_cPGconn, "finish", pgconn_finish, 0);
|
4096
4468
|
rb_define_method(rb_cPGconn, "finished?", pgconn_finished_p, 0);
|
4097
|
-
rb_define_method(rb_cPGconn, "
|
4469
|
+
rb_define_method(rb_cPGconn, "sync_reset", pgconn_sync_reset, 0);
|
4098
4470
|
rb_define_method(rb_cPGconn, "reset_start", pgconn_reset_start, 0);
|
4099
4471
|
rb_define_method(rb_cPGconn, "reset_poll", pgconn_reset_poll, 0);
|
4100
4472
|
rb_define_alias(rb_cPGconn, "close", "finish");
|
@@ -4104,11 +4476,12 @@ init_pg_connection()
|
|
4104
4476
|
rb_define_method(rb_cPGconn, "user", pgconn_user, 0);
|
4105
4477
|
rb_define_method(rb_cPGconn, "pass", pgconn_pass, 0);
|
4106
4478
|
rb_define_method(rb_cPGconn, "host", pgconn_host, 0);
|
4479
|
+
#if defined(HAVE_PQRESULTMEMORYSIZE)
|
4480
|
+
rb_define_method(rb_cPGconn, "hostaddr", pgconn_hostaddr, 0);
|
4481
|
+
#endif
|
4107
4482
|
rb_define_method(rb_cPGconn, "port", pgconn_port, 0);
|
4108
4483
|
rb_define_method(rb_cPGconn, "tty", pgconn_tty, 0);
|
4109
|
-
#ifdef HAVE_PQCONNINFO
|
4110
4484
|
rb_define_method(rb_cPGconn, "conninfo", pgconn_conninfo, 0);
|
4111
|
-
#endif
|
4112
4485
|
rb_define_method(rb_cPGconn, "options", pgconn_options, 0);
|
4113
4486
|
rb_define_method(rb_cPGconn, "status", pgconn_status, 0);
|
4114
4487
|
rb_define_method(rb_cPGconn, "transaction_status", pgconn_transaction_status, 0);
|
@@ -4119,17 +4492,34 @@ init_pg_connection()
|
|
4119
4492
|
rb_define_method(rb_cPGconn, "socket", pgconn_socket, 0);
|
4120
4493
|
rb_define_method(rb_cPGconn, "socket_io", pgconn_socket_io, 0);
|
4121
4494
|
rb_define_method(rb_cPGconn, "backend_pid", pgconn_backend_pid, 0);
|
4495
|
+
rb_define_method(rb_cPGconn, "backend_key", pgconn_backend_key, 0);
|
4122
4496
|
rb_define_method(rb_cPGconn, "connection_needs_password", pgconn_connection_needs_password, 0);
|
4123
4497
|
rb_define_method(rb_cPGconn, "connection_used_password", pgconn_connection_used_password, 0);
|
4124
4498
|
/* rb_define_method(rb_cPGconn, "getssl", pgconn_getssl, 0); */
|
4125
4499
|
|
4126
4500
|
/****** 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",
|
4501
|
+
rb_define_method(rb_cPGconn, "sync_exec", pgconn_sync_exec, -1);
|
4502
|
+
rb_define_method(rb_cPGconn, "sync_exec_params", pgconn_sync_exec_params, -1);
|
4503
|
+
rb_define_method(rb_cPGconn, "sync_prepare", pgconn_sync_prepare, -1);
|
4504
|
+
rb_define_method(rb_cPGconn, "sync_exec_prepared", pgconn_sync_exec_prepared, -1);
|
4505
|
+
rb_define_method(rb_cPGconn, "sync_describe_prepared", pgconn_sync_describe_prepared, 1);
|
4506
|
+
rb_define_method(rb_cPGconn, "sync_describe_portal", pgconn_sync_describe_portal, 1);
|
4507
|
+
|
4508
|
+
rb_define_method(rb_cPGconn, "exec", pgconn_async_exec, -1);
|
4509
|
+
rb_define_method(rb_cPGconn, "exec_params", pgconn_async_exec_params, -1);
|
4510
|
+
rb_define_method(rb_cPGconn, "prepare", pgconn_async_prepare, -1);
|
4511
|
+
rb_define_method(rb_cPGconn, "exec_prepared", pgconn_async_exec_prepared, -1);
|
4512
|
+
rb_define_method(rb_cPGconn, "describe_prepared", pgconn_async_describe_prepared, 1);
|
4513
|
+
rb_define_method(rb_cPGconn, "describe_portal", pgconn_async_describe_portal, 1);
|
4514
|
+
|
4515
|
+
rb_define_alias(rb_cPGconn, "async_exec", "exec");
|
4516
|
+
rb_define_alias(rb_cPGconn, "async_query", "async_exec");
|
4517
|
+
rb_define_alias(rb_cPGconn, "async_exec_params", "exec_params");
|
4518
|
+
rb_define_alias(rb_cPGconn, "async_prepare", "prepare");
|
4519
|
+
rb_define_alias(rb_cPGconn, "async_exec_prepared", "exec_prepared");
|
4520
|
+
rb_define_alias(rb_cPGconn, "async_describe_prepared", "describe_prepared");
|
4521
|
+
rb_define_alias(rb_cPGconn, "async_describe_portal", "describe_portal");
|
4522
|
+
|
4133
4523
|
rb_define_method(rb_cPGconn, "make_empty_pgresult", pgconn_make_empty_pgresult, 1);
|
4134
4524
|
rb_define_method(rb_cPGconn, "escape_string", pgconn_s_escape, 1);
|
4135
4525
|
rb_define_alias(rb_cPGconn, "escape", "escape_string");
|
@@ -4142,42 +4532,38 @@ init_pg_connection()
|
|
4142
4532
|
/****** PG::Connection INSTANCE METHODS: Asynchronous Command Processing ******/
|
4143
4533
|
rb_define_method(rb_cPGconn, "send_query", pgconn_send_query, -1);
|
4144
4534
|
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
4535
|
rb_define_method(rb_cPGconn, "send_prepare", pgconn_send_prepare, -1);
|
4149
|
-
rb_define_method(rb_cPGconn, "async_prepare", pgconn_async_prepare, -1);
|
4150
4536
|
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
4537
|
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
4538
|
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);
|
4539
|
+
rb_define_method(rb_cPGconn, "sync_get_result", pgconn_sync_get_result, 0);
|
4157
4540
|
rb_define_method(rb_cPGconn, "consume_input", pgconn_consume_input, 0);
|
4158
4541
|
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",
|
4542
|
+
rb_define_method(rb_cPGconn, "sync_setnonblocking", pgconn_sync_setnonblocking, 1);
|
4543
|
+
rb_define_method(rb_cPGconn, "sync_isnonblocking", pgconn_sync_isnonblocking, 0);
|
4544
|
+
rb_define_method(rb_cPGconn, "sync_flush", pgconn_sync_flush, 0);
|
4545
|
+
rb_define_method(rb_cPGconn, "flush", pgconn_async_flush, 0);
|
4546
|
+
rb_define_alias(rb_cPGconn, "async_flush", "flush");
|
4163
4547
|
rb_define_method(rb_cPGconn, "discard_results", pgconn_discard_results, 0);
|
4164
4548
|
|
4165
4549
|
/****** PG::Connection INSTANCE METHODS: Cancelling Queries in Progress ******/
|
4166
|
-
rb_define_method(rb_cPGconn, "
|
4550
|
+
rb_define_method(rb_cPGconn, "sync_cancel", pgconn_sync_cancel, 0);
|
4167
4551
|
|
4168
4552
|
/****** PG::Connection INSTANCE METHODS: NOTIFY ******/
|
4169
4553
|
rb_define_method(rb_cPGconn, "notifies", pgconn_notifies, 0);
|
4170
4554
|
|
4171
4555
|
/****** PG::Connection INSTANCE METHODS: COPY ******/
|
4172
|
-
rb_define_method(rb_cPGconn, "
|
4173
|
-
rb_define_method(rb_cPGconn, "
|
4174
|
-
rb_define_method(rb_cPGconn, "
|
4556
|
+
rb_define_method(rb_cPGconn, "sync_put_copy_data", pgconn_sync_put_copy_data, -1);
|
4557
|
+
rb_define_method(rb_cPGconn, "sync_put_copy_end", pgconn_sync_put_copy_end, -1);
|
4558
|
+
rb_define_method(rb_cPGconn, "sync_get_copy_data", pgconn_sync_get_copy_data, -1);
|
4175
4559
|
|
4176
4560
|
/****** PG::Connection INSTANCE METHODS: Control Functions ******/
|
4177
4561
|
rb_define_method(rb_cPGconn, "set_error_verbosity", pgconn_set_error_verbosity, 1);
|
4562
|
+
#ifdef HAVE_PQRESULTVERBOSEERRORMESSAGE
|
4563
|
+
rb_define_method(rb_cPGconn, "set_error_context_visibility", pgconn_set_error_context_visibility, 1 );
|
4564
|
+
#endif
|
4178
4565
|
rb_define_method(rb_cPGconn, "trace", pgconn_trace, 1);
|
4179
4566
|
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
4567
|
|
4182
4568
|
/****** PG::Connection INSTANCE METHODS: Notice Processing ******/
|
4183
4569
|
rb_define_method(rb_cPGconn, "set_notice_receiver", pgconn_set_notice_receiver, 0);
|
@@ -4185,16 +4571,20 @@ init_pg_connection()
|
|
4185
4571
|
|
4186
4572
|
/****** PG::Connection INSTANCE METHODS: Other ******/
|
4187
4573
|
rb_define_method(rb_cPGconn, "get_client_encoding", pgconn_get_client_encoding, 0);
|
4188
|
-
rb_define_method(rb_cPGconn, "
|
4574
|
+
rb_define_method(rb_cPGconn, "sync_set_client_encoding", pgconn_sync_set_client_encoding, 1);
|
4575
|
+
rb_define_method(rb_cPGconn, "set_client_encoding", pgconn_async_set_client_encoding, 1);
|
4576
|
+
rb_define_alias(rb_cPGconn, "async_set_client_encoding", "set_client_encoding");
|
4189
4577
|
rb_define_alias(rb_cPGconn, "client_encoding=", "set_client_encoding");
|
4190
|
-
rb_define_method(rb_cPGconn, "transaction", pgconn_transaction, 0);
|
4191
4578
|
rb_define_method(rb_cPGconn, "block", pgconn_block, -1);
|
4579
|
+
rb_define_private_method(rb_cPGconn, "flush_data=", pgconn_flush_data_set, 1);
|
4192
4580
|
rb_define_method(rb_cPGconn, "wait_for_notify", pgconn_wait_for_notify, -1);
|
4193
4581
|
rb_define_alias(rb_cPGconn, "notifies_wait", "wait_for_notify");
|
4194
4582
|
rb_define_method(rb_cPGconn, "quote_ident", pgconn_s_quote_ident, 1);
|
4195
|
-
rb_define_method(rb_cPGconn, "
|
4583
|
+
rb_define_method(rb_cPGconn, "sync_get_last_result", pgconn_sync_get_last_result, 0);
|
4584
|
+
rb_define_method(rb_cPGconn, "get_last_result", pgconn_async_get_last_result, 0);
|
4585
|
+
rb_define_alias(rb_cPGconn, "async_get_last_result", "get_last_result");
|
4196
4586
|
#ifdef HAVE_PQENCRYPTPASSWORDCONN
|
4197
|
-
rb_define_method(rb_cPGconn, "
|
4587
|
+
rb_define_method(rb_cPGconn, "sync_encrypt_password", pgconn_sync_encrypt_password, -1);
|
4198
4588
|
#endif
|
4199
4589
|
|
4200
4590
|
#ifdef HAVE_PQSSLATTRIBUTE
|
@@ -4203,6 +4593,14 @@ init_pg_connection()
|
|
4203
4593
|
rb_define_method(rb_cPGconn, "ssl_attribute_names", pgconn_ssl_attribute_names, 0);
|
4204
4594
|
#endif
|
4205
4595
|
|
4596
|
+
#ifdef HAVE_PQENTERPIPELINEMODE
|
4597
|
+
rb_define_method(rb_cPGconn, "pipeline_status", pgconn_pipeline_status, 0);
|
4598
|
+
rb_define_method(rb_cPGconn, "enter_pipeline_mode", pgconn_enter_pipeline_mode, 0);
|
4599
|
+
rb_define_method(rb_cPGconn, "exit_pipeline_mode", pgconn_exit_pipeline_mode, 0);
|
4600
|
+
rb_define_method(rb_cPGconn, "pipeline_sync", pgconn_pipeline_sync, 0);
|
4601
|
+
rb_define_method(rb_cPGconn, "send_flush_request", pgconn_send_flush_request, 0);
|
4602
|
+
#endif
|
4603
|
+
|
4206
4604
|
/****** PG::Connection INSTANCE METHODS: Large Object Support ******/
|
4207
4605
|
rb_define_method(rb_cPGconn, "lo_creat", pgconn_locreat, -1);
|
4208
4606
|
rb_define_alias(rb_cPGconn, "locreat", "lo_creat");
|
@@ -4244,5 +4642,7 @@ init_pg_connection()
|
|
4244
4642
|
rb_define_method(rb_cPGconn, "encoder_for_put_copy_data", pgconn_encoder_for_put_copy_data_get, 0);
|
4245
4643
|
rb_define_method(rb_cPGconn, "decoder_for_get_copy_data=", pgconn_decoder_for_get_copy_data_set, 1);
|
4246
4644
|
rb_define_method(rb_cPGconn, "decoder_for_get_copy_data", pgconn_decoder_for_get_copy_data_get, 0);
|
4247
|
-
}
|
4248
4645
|
|
4646
|
+
rb_define_method(rb_cPGconn, "field_name_type=", pgconn_field_name_type_set, 1 );
|
4647
|
+
rb_define_method(rb_cPGconn, "field_name_type", pgconn_field_name_type_get, 0 );
|
4648
|
+
}
|