pg 1.0.0 → 1.5.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- checksums.yaml.gz.sig +0 -0
- data/Gemfile +20 -0
- data/History.md +932 -0
- data/Manifest.txt +8 -3
- data/README-Windows.rdoc +4 -4
- data/README.ja.md +300 -0
- data/README.md +286 -0
- data/Rakefile +41 -138
- data/Rakefile.cross +71 -66
- data/certs/ged.pem +24 -0
- data/certs/kanis@comcard.de.pem +20 -0
- data/certs/larskanis-2022.pem +26 -0
- data/certs/larskanis-2023.pem +24 -0
- data/certs/larskanis-2024.pem +24 -0
- data/ext/errorcodes.def +84 -5
- data/ext/errorcodes.rb +1 -1
- data/ext/errorcodes.txt +23 -6
- data/ext/extconf.rb +109 -25
- data/ext/gvl_wrappers.c +4 -0
- data/ext/gvl_wrappers.h +23 -0
- data/ext/pg.c +213 -155
- data/ext/pg.h +89 -23
- data/ext/pg_binary_decoder.c +164 -16
- data/ext/pg_binary_encoder.c +238 -13
- data/ext/pg_coder.c +159 -35
- data/ext/pg_connection.c +1584 -967
- data/ext/pg_copy_coder.c +373 -43
- data/ext/pg_errors.c +1 -1
- data/ext/pg_record_coder.c +522 -0
- data/ext/pg_result.c +710 -217
- data/ext/pg_text_decoder.c +630 -43
- data/ext/pg_text_encoder.c +222 -72
- data/ext/pg_tuple.c +572 -0
- 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} +12 -12
- data/ext/{util.h → pg_util.h} +2 -2
- data/lib/pg/basic_type_map_based_on_result.rb +67 -0
- data/lib/pg/basic_type_map_for_queries.rb +202 -0
- data/lib/pg/basic_type_map_for_results.rb +104 -0
- data/lib/pg/basic_type_registry.rb +311 -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 +36 -13
- data/lib/pg/connection.rb +769 -70
- data/lib/pg/exceptions.rb +22 -2
- data/lib/pg/result.rb +14 -2
- data/lib/pg/text_decoder/date.rb +21 -0
- data/lib/pg/text_decoder/inet.rb +9 -0
- data/lib/pg/text_decoder/json.rb +17 -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 +13 -0
- data/lib/pg/text_encoder/inet.rb +31 -0
- data/lib/pg/text_encoder/json.rb +17 -0
- data/lib/pg/text_encoder/numeric.rb +9 -0
- data/lib/pg/text_encoder/timestamp.rb +24 -0
- data/lib/pg/tuple.rb +30 -0
- data/lib/pg/type_map_by_column.rb +3 -2
- data/lib/pg/version.rb +4 -0
- data/lib/pg.rb +106 -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 +36 -0
- data/rakelib/task_extension.rb +46 -0
- data/sample/array_insert.rb +20 -0
- data/sample/async_api.rb +102 -0
- data/sample/async_copyto.rb +39 -0
- data/sample/async_mixed.rb +56 -0
- data/sample/check_conn.rb +21 -0
- data/sample/copydata.rb +71 -0
- data/sample/copyfrom.rb +81 -0
- data/sample/copyto.rb +19 -0
- data/sample/cursor.rb +21 -0
- data/sample/disk_usage_report.rb +177 -0
- data/sample/issue-119.rb +94 -0
- data/sample/losample.rb +69 -0
- data/sample/minimal-testcase.rb +17 -0
- data/sample/notify_wait.rb +72 -0
- data/sample/pg_statistics.rb +285 -0
- data/sample/replication_monitor.rb +222 -0
- data/sample/test_binary_values.rb +33 -0
- data/sample/wal_shipper.rb +434 -0
- data/sample/warehouse_partitions.rb +311 -0
- data.tar.gz.sig +0 -0
- metadata +138 -223
- metadata.gz.sig +0 -0
- data/.gemtest +0 -0
- data/ChangeLog +0 -6595
- data/History.rdoc +0 -422
- data/README.ja.rdoc +0 -14
- data/README.rdoc +0 -167
- data/lib/pg/basic_type_mapping.rb +0 -426
- data/lib/pg/constants.rb +0 -11
- data/lib/pg/text_decoder.rb +0 -51
- data/lib/pg/text_encoder.rb +0 -35
- data/spec/data/expected_trace.out +0 -26
- data/spec/data/random_binary_data +0 -0
- data/spec/helpers.rb +0 -348
- data/spec/pg/basic_type_mapping_spec.rb +0 -305
- data/spec/pg/connection_spec.rb +0 -1719
- data/spec/pg/result_spec.rb +0 -456
- data/spec/pg/type_map_by_class_spec.rb +0 -138
- data/spec/pg/type_map_by_column_spec.rb +0 -222
- data/spec/pg/type_map_by_mri_type_spec.rb +0 -136
- data/spec/pg/type_map_by_oid_spec.rb +0 -149
- data/spec/pg/type_map_in_ruby_spec.rb +0 -164
- data/spec/pg/type_map_spec.rb +0 -22
- data/spec/pg/type_spec.rb +0 -777
- data/spec/pg_spec.rb +0 -50
data/ext/pg_connection.c
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
/*
|
2
2
|
* pg_connection.c - PG::Connection class extension
|
3
|
-
* $Id
|
3
|
+
* $Id$
|
4
4
|
*
|
5
5
|
*/
|
6
6
|
|
@@ -12,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
|
+
NORETURN( 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,99 +252,39 @@ 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
|
-
|
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));
|
267
|
+
rb_ivar_set(self, rb_intern("@iopts_for_reset"), Qnil);
|
201
268
|
|
202
269
|
return self;
|
203
270
|
}
|
204
271
|
|
205
|
-
|
206
|
-
/*
|
207
|
-
* Document-method: new
|
208
|
-
*
|
209
|
-
* call-seq:
|
210
|
-
* PG::Connection.new -> conn
|
211
|
-
* PG::Connection.new(connection_hash) -> conn
|
212
|
-
* PG::Connection.new(connection_string) -> conn
|
213
|
-
* PG::Connection.new(host, port, options, tty, dbname, user, password) -> conn
|
214
|
-
*
|
215
|
-
* Create a connection to the specified server.
|
216
|
-
*
|
217
|
-
* [+host+]
|
218
|
-
* server hostname
|
219
|
-
* [+hostaddr+]
|
220
|
-
* server address (avoids hostname lookup, overrides +host+)
|
221
|
-
* [+port+]
|
222
|
-
* server port number
|
223
|
-
* [+dbname+]
|
224
|
-
* connecting database name
|
225
|
-
* [+user+]
|
226
|
-
* login user name
|
227
|
-
* [+password+]
|
228
|
-
* login password
|
229
|
-
* [+connect_timeout+]
|
230
|
-
* maximum time to wait for connection to succeed
|
231
|
-
* [+options+]
|
232
|
-
* backend options
|
233
|
-
* [+tty+]
|
234
|
-
* (ignored in newer versions of PostgreSQL)
|
235
|
-
* [+sslmode+]
|
236
|
-
* (disable|allow|prefer|require)
|
237
|
-
* [+krbsrvname+]
|
238
|
-
* kerberos service name
|
239
|
-
* [+gsslib+]
|
240
|
-
* GSS library to use for GSSAPI authentication
|
241
|
-
* [+service+]
|
242
|
-
* service name to use for additional parameters
|
243
|
-
*
|
244
|
-
* Examples:
|
245
|
-
*
|
246
|
-
* # Connect using all defaults
|
247
|
-
* PG::Connection.new
|
248
|
-
*
|
249
|
-
* # As a Hash
|
250
|
-
* PG::Connection.new( :dbname => 'test', :port => 5432 )
|
251
|
-
*
|
252
|
-
* # As a String
|
253
|
-
* PG::Connection.new( "dbname=test port=5432" )
|
254
|
-
*
|
255
|
-
* # As an Array
|
256
|
-
* PG::Connection.new( nil, 5432, nil, nil, 'test', nil, nil )
|
257
|
-
*
|
258
|
-
* If the Ruby default internal encoding is set (i.e., Encoding.default_internal != nil), the
|
259
|
-
* connection will have its +client_encoding+ set accordingly.
|
260
|
-
*
|
261
|
-
* Raises a PG::Error if the connection fails.
|
262
|
-
*/
|
263
272
|
static VALUE
|
264
|
-
|
273
|
+
pgconn_s_sync_connect(int argc, VALUE *argv, VALUE klass)
|
265
274
|
{
|
266
275
|
t_pg_connection *this;
|
267
276
|
VALUE conninfo;
|
268
|
-
VALUE
|
277
|
+
VALUE self = pgconn_s_allocate( klass );
|
269
278
|
|
270
279
|
this = pg_get_connection( self );
|
271
280
|
conninfo = rb_funcall2( rb_cPGconn, rb_intern("parse_connect_args"), argc, argv );
|
272
281
|
this->pgconn = gvl_PQconnectdb(StringValueCStr(conninfo));
|
273
282
|
|
274
283
|
if(this->pgconn == NULL)
|
275
|
-
rb_raise(rb_ePGerror, "PQconnectdb() unable to allocate structure");
|
284
|
+
rb_raise(rb_ePGerror, "PQconnectdb() unable to allocate PGconn structure");
|
276
285
|
|
277
|
-
if (PQstatus(this->pgconn) == CONNECTION_BAD)
|
278
|
-
|
279
|
-
rb_iv_set(error, "@connection", self);
|
280
|
-
rb_exc_raise(error);
|
281
|
-
}
|
286
|
+
if (PQstatus(this->pgconn) == CONNECTION_BAD)
|
287
|
+
pg_raise_conn_error( rb_eConnectionBad, self, "%s", PQerrorMessage(this->pgconn));
|
282
288
|
|
283
289
|
pgconn_set_default_encoding( self );
|
284
290
|
|
@@ -294,14 +300,16 @@ pgconn_init(int argc, VALUE *argv, VALUE self)
|
|
294
300
|
* PG::Connection.connect_start(connection_string) -> conn
|
295
301
|
* PG::Connection.connect_start(host, port, options, tty, dbname, login, password) -> conn
|
296
302
|
*
|
297
|
-
* This is an asynchronous version of PG::Connection.
|
303
|
+
* This is an asynchronous version of PG::Connection.new.
|
298
304
|
*
|
299
305
|
* Use #connect_poll to poll the status of the connection.
|
300
306
|
*
|
301
307
|
* NOTE: this does *not* set the connection's +client_encoding+ for you if
|
302
|
-
* Encoding.default_internal is set. To set it after the connection is established,
|
308
|
+
* +Encoding.default_internal+ is set. To set it after the connection is established,
|
303
309
|
* call #internal_encoding=. You can also set it automatically by setting
|
304
|
-
* ENV['PGCLIENTENCODING']
|
310
|
+
* <code>ENV['PGCLIENTENCODING']</code>, or include the 'options' connection parameter.
|
311
|
+
*
|
312
|
+
* See also the 'sample' directory of this gem and the corresponding {libpq functions}[https://www.postgresql.org/docs/current/libpq-connect.html#LIBPQ-PQCONNECTSTARTPARAMS].
|
305
313
|
*
|
306
314
|
*/
|
307
315
|
static VALUE
|
@@ -309,7 +317,6 @@ pgconn_s_connect_start( int argc, VALUE *argv, VALUE klass )
|
|
309
317
|
{
|
310
318
|
VALUE rb_conn;
|
311
319
|
VALUE conninfo;
|
312
|
-
VALUE error;
|
313
320
|
t_pg_connection *this;
|
314
321
|
|
315
322
|
/*
|
@@ -322,13 +329,10 @@ pgconn_s_connect_start( int argc, VALUE *argv, VALUE klass )
|
|
322
329
|
this->pgconn = gvl_PQconnectStart( StringValueCStr(conninfo) );
|
323
330
|
|
324
331
|
if( this->pgconn == NULL )
|
325
|
-
rb_raise(rb_ePGerror, "PQconnectStart() unable to allocate structure");
|
332
|
+
rb_raise(rb_ePGerror, "PQconnectStart() unable to allocate PGconn structure");
|
326
333
|
|
327
|
-
if ( PQstatus(this->pgconn) == CONNECTION_BAD )
|
328
|
-
|
329
|
-
rb_iv_set(error, "@connection", rb_conn);
|
330
|
-
rb_exc_raise(error);
|
331
|
-
}
|
334
|
+
if ( PQstatus(this->pgconn) == CONNECTION_BAD )
|
335
|
+
pg_raise_conn_error( rb_eConnectionBad, rb_conn, "%s", PQerrorMessage(this->pgconn));
|
332
336
|
|
333
337
|
if ( rb_block_given_p() ) {
|
334
338
|
return rb_ensure( rb_yield, rb_conn, pgconn_finish, rb_conn );
|
@@ -336,34 +340,14 @@ pgconn_s_connect_start( int argc, VALUE *argv, VALUE klass )
|
|
336
340
|
return rb_conn;
|
337
341
|
}
|
338
342
|
|
339
|
-
/*
|
340
|
-
* call-seq:
|
341
|
-
* PG::Connection.ping(connection_hash) -> Integer
|
342
|
-
* PG::Connection.ping(connection_string) -> Integer
|
343
|
-
* PG::Connection.ping(host, port, options, tty, dbname, login, password) -> Integer
|
344
|
-
*
|
345
|
-
* Check server status.
|
346
|
-
*
|
347
|
-
* Returns one of:
|
348
|
-
* [+PQPING_OK+]
|
349
|
-
* server is accepting connections
|
350
|
-
* [+PQPING_REJECT+]
|
351
|
-
* server is alive but rejecting connections
|
352
|
-
* [+PQPING_NO_RESPONSE+]
|
353
|
-
* could not establish connection
|
354
|
-
* [+PQPING_NO_ATTEMPT+]
|
355
|
-
* connection not attempted (bad params)
|
356
|
-
*
|
357
|
-
* Available since PostgreSQL-9.1
|
358
|
-
*/
|
359
343
|
static VALUE
|
360
|
-
|
344
|
+
pgconn_s_sync_ping( int argc, VALUE *argv, VALUE klass )
|
361
345
|
{
|
362
346
|
PGPing ping;
|
363
347
|
VALUE conninfo;
|
364
348
|
|
365
349
|
conninfo = rb_funcall2( klass, rb_intern("parse_connect_args"), argc, argv );
|
366
|
-
ping =
|
350
|
+
ping = gvl_PQping( StringValueCStr(conninfo) );
|
367
351
|
|
368
352
|
return INT2FIX((int)ping);
|
369
353
|
}
|
@@ -404,31 +388,40 @@ pgconn_s_conndefaults(VALUE self)
|
|
404
388
|
return array;
|
405
389
|
}
|
406
390
|
|
407
|
-
|
408
|
-
#ifdef HAVE_PQENCRYPTPASSWORDCONN
|
409
391
|
/*
|
410
|
-
*
|
411
|
-
* conn.encrypt_password( password, username, algorithm=nil ) -> String
|
412
|
-
*
|
413
|
-
* This function is intended to be used by client applications that wish to send commands like <tt>ALTER USER joe PASSWORD 'pwd'</tt>.
|
414
|
-
* 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.
|
415
|
-
* Instead, use this function to convert the password to encrypted form before it is sent.
|
392
|
+
* Document-method: PG::Connection.conninfo_parse
|
416
393
|
*
|
417
|
-
*
|
418
|
-
*
|
419
|
-
* 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).
|
420
|
-
* Note that support for +scram-sha-256+ was introduced in PostgreSQL version 10, and will not work correctly with older server versions.
|
421
|
-
* If algorithm is omitted or +nil+, this function will query the server for the current value of the +password_encryption+ setting.
|
422
|
-
* That can block, and will fail if the current transaction is aborted, or if the connection is busy executing another query.
|
423
|
-
* 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.
|
424
|
-
*
|
425
|
-
* Return value is the encrypted password.
|
426
|
-
* The caller can assume the string doesn't contain any special characters that would require escaping.
|
394
|
+
* call-seq:
|
395
|
+
* PG::Connection.conninfo_parse(conninfo_string) -> Array
|
427
396
|
*
|
428
|
-
*
|
397
|
+
* Returns parsed connection options from the provided connection string as an array of hashes.
|
398
|
+
* Each hash has the same keys as PG::Connection.conndefaults() .
|
399
|
+
* The values from the +conninfo_string+ are stored in the +:val+ key.
|
429
400
|
*/
|
430
401
|
static VALUE
|
431
|
-
|
402
|
+
pgconn_s_conninfo_parse(VALUE self, VALUE conninfo)
|
403
|
+
{
|
404
|
+
VALUE array;
|
405
|
+
char *errmsg = NULL;
|
406
|
+
PQconninfoOption *options = PQconninfoParse(StringValueCStr(conninfo), &errmsg);
|
407
|
+
if(errmsg){
|
408
|
+
VALUE error = rb_str_new_cstr(errmsg);
|
409
|
+
PQfreemem(errmsg);
|
410
|
+
rb_raise(rb_ePGerror, "%"PRIsVALUE, error);
|
411
|
+
}
|
412
|
+
array = pgconn_make_conninfo_array( options );
|
413
|
+
|
414
|
+
PQconninfoFree(options);
|
415
|
+
|
416
|
+
UNUSED( self );
|
417
|
+
|
418
|
+
return array;
|
419
|
+
}
|
420
|
+
|
421
|
+
|
422
|
+
#ifdef HAVE_PQENCRYPTPASSWORDCONN
|
423
|
+
static VALUE
|
424
|
+
pgconn_sync_encrypt_password(int argc, VALUE *argv, VALUE self)
|
432
425
|
{
|
433
426
|
char *encrypted = NULL;
|
434
427
|
VALUE rval = Qnil;
|
@@ -444,12 +437,8 @@ pgconn_encrypt_password(int argc, VALUE *argv, VALUE self)
|
|
444
437
|
if ( encrypted ) {
|
445
438
|
rval = rb_str_new2( encrypted );
|
446
439
|
PQfreemem( encrypted );
|
447
|
-
|
448
|
-
OBJ_INFECT( rval, password );
|
449
|
-
OBJ_INFECT( rval, username );
|
450
|
-
OBJ_INFECT( rval, algorithm );
|
451
440
|
} else {
|
452
|
-
|
441
|
+
pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(conn));
|
453
442
|
}
|
454
443
|
|
455
444
|
return rval;
|
@@ -480,9 +469,6 @@ pgconn_s_encrypt_password(VALUE self, VALUE password, VALUE username)
|
|
480
469
|
rval = rb_str_new2( encrypted );
|
481
470
|
PQfreemem( encrypted );
|
482
471
|
|
483
|
-
OBJ_INFECT( rval, password );
|
484
|
-
OBJ_INFECT( rval, username );
|
485
|
-
|
486
472
|
return rval;
|
487
473
|
}
|
488
474
|
|
@@ -506,17 +492,18 @@ pgconn_s_encrypt_password(VALUE self, VALUE password, VALUE username)
|
|
506
492
|
* the asynchronous connection is ready
|
507
493
|
*
|
508
494
|
* Example:
|
509
|
-
*
|
510
|
-
*
|
495
|
+
* require "io/wait"
|
496
|
+
*
|
497
|
+
* conn = PG::Connection.connect_start(dbname: 'mydatabase')
|
511
498
|
* status = conn.connect_poll
|
512
499
|
* while(status != PG::PGRES_POLLING_OK) do
|
513
500
|
* # do some work while waiting for the connection to complete
|
514
501
|
* if(status == PG::PGRES_POLLING_READING)
|
515
|
-
*
|
502
|
+
* unless conn.socket_io.wait_readable(10.0)
|
516
503
|
* raise "Asynchronous connection timed out!"
|
517
504
|
* end
|
518
505
|
* elsif(status == PG::PGRES_POLLING_WRITING)
|
519
|
-
*
|
506
|
+
* unless conn.socket_io.wait_writable(10.0)
|
520
507
|
* raise "Asynchronous connection timed out!"
|
521
508
|
* end
|
522
509
|
* end
|
@@ -529,7 +516,10 @@ static VALUE
|
|
529
516
|
pgconn_connect_poll(VALUE self)
|
530
517
|
{
|
531
518
|
PostgresPollingStatusType status;
|
519
|
+
|
520
|
+
pgconn_close_socket_io(self);
|
532
521
|
status = gvl_PQconnectPoll(pg_get_pgconn(self));
|
522
|
+
|
533
523
|
return INT2FIX((int)status);
|
534
524
|
}
|
535
525
|
|
@@ -566,21 +556,35 @@ pgconn_finished_p( VALUE self )
|
|
566
556
|
}
|
567
557
|
|
568
558
|
|
569
|
-
/*
|
570
|
-
* call-seq:
|
571
|
-
* conn.reset()
|
572
|
-
*
|
573
|
-
* Resets the backend connection. This method closes the
|
574
|
-
* backend connection and tries to re-connect.
|
575
|
-
*/
|
576
559
|
static VALUE
|
577
|
-
|
560
|
+
pgconn_sync_reset( VALUE self )
|
578
561
|
{
|
579
562
|
pgconn_close_socket_io( self );
|
580
563
|
gvl_PQreset( pg_get_pgconn(self) );
|
581
564
|
return self;
|
582
565
|
}
|
583
566
|
|
567
|
+
static VALUE
|
568
|
+
pgconn_reset_start2( VALUE self, VALUE conninfo )
|
569
|
+
{
|
570
|
+
t_pg_connection *this = pg_get_connection( self );
|
571
|
+
|
572
|
+
/* Close old connection */
|
573
|
+
pgconn_close_socket_io( self );
|
574
|
+
PQfinish( this->pgconn );
|
575
|
+
|
576
|
+
/* Start new connection */
|
577
|
+
this->pgconn = gvl_PQconnectStart( StringValueCStr(conninfo) );
|
578
|
+
|
579
|
+
if( this->pgconn == NULL )
|
580
|
+
rb_raise(rb_ePGerror, "PQconnectStart() unable to allocate PGconn structure");
|
581
|
+
|
582
|
+
if ( PQstatus(this->pgconn) == CONNECTION_BAD )
|
583
|
+
pg_raise_conn_error( rb_eConnectionBad, self, "%s", PQerrorMessage(this->pgconn));
|
584
|
+
|
585
|
+
return Qnil;
|
586
|
+
}
|
587
|
+
|
584
588
|
/*
|
585
589
|
* call-seq:
|
586
590
|
* conn.reset_start() -> nil
|
@@ -596,7 +600,7 @@ pgconn_reset_start(VALUE self)
|
|
596
600
|
{
|
597
601
|
pgconn_close_socket_io( self );
|
598
602
|
if(gvl_PQresetStart(pg_get_pgconn(self)) == 0)
|
599
|
-
|
603
|
+
pg_raise_conn_error( rb_eUnableToSend, self, "reset has failed");
|
600
604
|
return Qnil;
|
601
605
|
}
|
602
606
|
|
@@ -612,7 +616,10 @@ static VALUE
|
|
612
616
|
pgconn_reset_poll(VALUE self)
|
613
617
|
{
|
614
618
|
PostgresPollingStatusType status;
|
619
|
+
|
620
|
+
pgconn_close_socket_io(self);
|
615
621
|
status = gvl_PQresetPoll(pg_get_pgconn(self));
|
622
|
+
|
616
623
|
return INT2FIX((int)status);
|
617
624
|
}
|
618
625
|
|
@@ -628,7 +635,7 @@ pgconn_db(VALUE self)
|
|
628
635
|
{
|
629
636
|
char *db = PQdb(pg_get_pgconn(self));
|
630
637
|
if (!db) return Qnil;
|
631
|
-
return
|
638
|
+
return rb_str_new2(db);
|
632
639
|
}
|
633
640
|
|
634
641
|
/*
|
@@ -642,7 +649,7 @@ pgconn_user(VALUE self)
|
|
642
649
|
{
|
643
650
|
char *user = PQuser(pg_get_pgconn(self));
|
644
651
|
if (!user) return Qnil;
|
645
|
-
return
|
652
|
+
return rb_str_new2(user);
|
646
653
|
}
|
647
654
|
|
648
655
|
/*
|
@@ -656,22 +663,53 @@ pgconn_pass(VALUE self)
|
|
656
663
|
{
|
657
664
|
char *user = PQpass(pg_get_pgconn(self));
|
658
665
|
if (!user) return Qnil;
|
659
|
-
return
|
666
|
+
return rb_str_new2(user);
|
660
667
|
}
|
661
668
|
|
662
669
|
/*
|
663
670
|
* call-seq:
|
664
671
|
* conn.host()
|
665
672
|
*
|
666
|
-
* Returns the
|
673
|
+
* Returns the server host name of the active connection.
|
674
|
+
* This can be a host name, an IP address, or a directory path if the connection is via Unix socket.
|
675
|
+
* (The path case can be distinguished because it will always be an absolute path, beginning with +/+ .)
|
676
|
+
*
|
677
|
+
* If the connection parameters specified both host and hostaddr, then +host+ will return the host information.
|
678
|
+
* If only hostaddr was specified, then that is returned.
|
679
|
+
* If multiple hosts were specified in the connection parameters, +host+ returns the host actually connected to.
|
680
|
+
*
|
681
|
+
* 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.
|
682
|
+
*
|
683
|
+
* 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.
|
684
|
+
* The status of the connection can be checked using the function Connection#status .
|
667
685
|
*/
|
668
686
|
static VALUE
|
669
687
|
pgconn_host(VALUE self)
|
670
688
|
{
|
671
689
|
char *host = PQhost(pg_get_pgconn(self));
|
672
690
|
if (!host) return Qnil;
|
673
|
-
return
|
691
|
+
return rb_str_new2(host);
|
692
|
+
}
|
693
|
+
|
694
|
+
/* PQhostaddr() appeared in PostgreSQL-12 together with PQresultMemorySize() */
|
695
|
+
#if defined(HAVE_PQRESULTMEMORYSIZE)
|
696
|
+
/*
|
697
|
+
* call-seq:
|
698
|
+
* conn.hostaddr()
|
699
|
+
*
|
700
|
+
* Returns the server IP address of the active connection.
|
701
|
+
* This can be the address that a host name resolved to, or an IP address provided through the hostaddr parameter.
|
702
|
+
* 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.
|
703
|
+
*
|
704
|
+
*/
|
705
|
+
static VALUE
|
706
|
+
pgconn_hostaddr(VALUE self)
|
707
|
+
{
|
708
|
+
char *host = PQhostaddr(pg_get_pgconn(self));
|
709
|
+
if (!host) return Qnil;
|
710
|
+
return rb_str_new2(host);
|
674
711
|
}
|
712
|
+
#endif
|
675
713
|
|
676
714
|
/*
|
677
715
|
* call-seq:
|
@@ -683,21 +721,22 @@ static VALUE
|
|
683
721
|
pgconn_port(VALUE self)
|
684
722
|
{
|
685
723
|
char* port = PQport(pg_get_pgconn(self));
|
686
|
-
|
724
|
+
if (!port || port[0] == '\0')
|
725
|
+
return INT2NUM(DEF_PGPORT);
|
726
|
+
else
|
727
|
+
return INT2NUM(atoi(port));
|
687
728
|
}
|
688
729
|
|
689
730
|
/*
|
690
731
|
* call-seq:
|
691
732
|
* conn.tty()
|
692
733
|
*
|
693
|
-
*
|
734
|
+
* Obsolete function.
|
694
735
|
*/
|
695
736
|
static VALUE
|
696
737
|
pgconn_tty(VALUE self)
|
697
738
|
{
|
698
|
-
|
699
|
-
if (!tty) return Qnil;
|
700
|
-
return rb_tainted_str_new2(tty);
|
739
|
+
return rb_str_new2("");
|
701
740
|
}
|
702
741
|
|
703
742
|
/*
|
@@ -711,11 +750,10 @@ pgconn_options(VALUE self)
|
|
711
750
|
{
|
712
751
|
char *options = PQoptions(pg_get_pgconn(self));
|
713
752
|
if (!options) return Qnil;
|
714
|
-
return
|
753
|
+
return rb_str_new2(options);
|
715
754
|
}
|
716
755
|
|
717
756
|
|
718
|
-
#ifdef HAVE_PQCONNINFO
|
719
757
|
/*
|
720
758
|
* call-seq:
|
721
759
|
* conn.conninfo -> hash
|
@@ -735,14 +773,24 @@ pgconn_conninfo( VALUE self )
|
|
735
773
|
|
736
774
|
return array;
|
737
775
|
}
|
738
|
-
#endif
|
739
776
|
|
740
777
|
|
741
778
|
/*
|
742
779
|
* call-seq:
|
743
780
|
* conn.status()
|
744
781
|
*
|
745
|
-
* Returns status of connection
|
782
|
+
* Returns the status of the connection, which is one:
|
783
|
+
* PG::Constants::CONNECTION_OK
|
784
|
+
* PG::Constants::CONNECTION_BAD
|
785
|
+
*
|
786
|
+
* ... and other constants of kind PG::Constants::CONNECTION_*
|
787
|
+
*
|
788
|
+
* This method returns the status of the last command from memory.
|
789
|
+
* It doesn't do any socket access hence is not suitable to test the connectivity.
|
790
|
+
* See check_socket for a way to verify the socket state.
|
791
|
+
*
|
792
|
+
* Example:
|
793
|
+
* PG.constants.grep(/CONNECTION_/).find{|c| PG.const_get(c) == conn.status} # => :CONNECTION_OK
|
746
794
|
*/
|
747
795
|
static VALUE
|
748
796
|
pgconn_status(VALUE self)
|
@@ -792,7 +840,7 @@ pgconn_parameter_status(VALUE self, VALUE param_name)
|
|
792
840
|
if(ret == NULL)
|
793
841
|
return Qnil;
|
794
842
|
else
|
795
|
-
return
|
843
|
+
return rb_str_new2(ret);
|
796
844
|
}
|
797
845
|
|
798
846
|
/*
|
@@ -830,14 +878,17 @@ pgconn_server_version(VALUE self)
|
|
830
878
|
* call-seq:
|
831
879
|
* conn.error_message -> String
|
832
880
|
*
|
833
|
-
* Returns the error message
|
881
|
+
* Returns the error message most recently generated by an operation on the connection.
|
882
|
+
*
|
883
|
+
* Nearly all libpq functions will set a message for conn.error_message if they fail.
|
884
|
+
* Note that by libpq convention, a nonempty error_message result can consist of multiple lines, and will include a trailing newline.
|
834
885
|
*/
|
835
886
|
static VALUE
|
836
887
|
pgconn_error_message(VALUE self)
|
837
888
|
{
|
838
889
|
char *error = PQerrorMessage(pg_get_pgconn(self));
|
839
890
|
if (!error) return Qnil;
|
840
|
-
return
|
891
|
+
return rb_str_new2(error);
|
841
892
|
}
|
842
893
|
|
843
894
|
/*
|
@@ -861,8 +912,11 @@ static VALUE
|
|
861
912
|
pgconn_socket(VALUE self)
|
862
913
|
{
|
863
914
|
int sd;
|
915
|
+
pg_deprecated(4, ("conn.socket is deprecated and should be replaced by conn.socket_io"));
|
916
|
+
|
864
917
|
if( (sd = PQsocket(pg_get_pgconn(self))) < 0)
|
865
|
-
|
918
|
+
pg_raise_conn_error( rb_eConnectionBad, self, "PQsocket() can't get socket descriptor");
|
919
|
+
|
866
920
|
return INT2NUM(sd);
|
867
921
|
}
|
868
922
|
|
@@ -870,41 +924,47 @@ pgconn_socket(VALUE self)
|
|
870
924
|
* call-seq:
|
871
925
|
* conn.socket_io() -> IO
|
872
926
|
*
|
873
|
-
* Fetch
|
874
|
-
* This object can be used for IO.select to wait for events while running
|
875
|
-
*
|
927
|
+
* Fetch an IO object created from the Connection's underlying socket.
|
928
|
+
* 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.
|
929
|
+
* <tt>IO#wait_*able</tt> is is <tt>Fiber.scheduler</tt> compatible in contrast to <tt>IO.select</tt>.
|
876
930
|
*
|
877
|
-
*
|
878
|
-
*
|
879
|
-
*
|
931
|
+
* The IO object can change while the connection is established, but is memorized afterwards.
|
932
|
+
* So be sure not to cache the IO object, but repeat calling <tt>conn.socket_io</tt> instead.
|
933
|
+
*
|
934
|
+
* Using this method also works on Windows in contrast to using #socket .
|
935
|
+
* 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.
|
880
936
|
*/
|
881
937
|
static VALUE
|
882
938
|
pgconn_socket_io(VALUE self)
|
883
939
|
{
|
884
940
|
int sd;
|
885
941
|
int ruby_sd;
|
886
|
-
ID id_autoclose = rb_intern("autoclose=");
|
887
942
|
t_pg_connection *this = pg_get_connection_safe( self );
|
943
|
+
VALUE cSocket;
|
888
944
|
VALUE socket_io = this->socket_io;
|
889
945
|
|
890
946
|
if ( !RTEST(socket_io) ) {
|
891
|
-
if( (sd = PQsocket(this->pgconn)) < 0)
|
892
|
-
|
947
|
+
if( (sd = PQsocket(this->pgconn)) < 0){
|
948
|
+
pg_raise_conn_error( rb_eConnectionBad, self, "PQsocket() can't get socket descriptor");
|
949
|
+
}
|
893
950
|
|
894
951
|
#ifdef _WIN32
|
895
952
|
ruby_sd = rb_w32_wrap_io_handle((HANDLE)(intptr_t)sd, O_RDWR|O_BINARY|O_NOINHERIT);
|
953
|
+
if( ruby_sd == -1 )
|
954
|
+
pg_raise_conn_error( rb_eConnectionBad, self, "Could not wrap win32 socket handle");
|
955
|
+
|
956
|
+
this->ruby_sd = ruby_sd;
|
896
957
|
#else
|
897
958
|
ruby_sd = sd;
|
898
959
|
#endif
|
899
960
|
|
900
|
-
|
961
|
+
cSocket = rb_const_get(rb_cObject, rb_intern("BasicSocket"));
|
962
|
+
socket_io = rb_funcall( cSocket, rb_intern("for_fd"), 1, INT2NUM(ruby_sd));
|
901
963
|
|
902
|
-
/* Disable autoclose feature
|
903
|
-
|
904
|
-
rb_funcall( socket_io, id_autoclose, 1, Qfalse );
|
905
|
-
}
|
964
|
+
/* Disable autoclose feature */
|
965
|
+
rb_funcall( socket_io, s_id_autoclose_set, 1, Qfalse );
|
906
966
|
|
907
|
-
this->socket_io
|
967
|
+
RB_OBJ_WRITE(self, &this->socket_io, socket_io);
|
908
968
|
}
|
909
969
|
|
910
970
|
return socket_io;
|
@@ -924,6 +984,51 @@ pgconn_backend_pid(VALUE self)
|
|
924
984
|
return INT2NUM(PQbackendPID(pg_get_pgconn(self)));
|
925
985
|
}
|
926
986
|
|
987
|
+
typedef struct
|
988
|
+
{
|
989
|
+
struct sockaddr_storage addr;
|
990
|
+
socklen_t salen;
|
991
|
+
} SockAddr;
|
992
|
+
|
993
|
+
/* Copy of struct pg_cancel from libpq-int.h
|
994
|
+
*
|
995
|
+
* See https://github.com/postgres/postgres/blame/master/src/interfaces/libpq/libpq-int.h#L577-L586
|
996
|
+
*/
|
997
|
+
struct pg_cancel
|
998
|
+
{
|
999
|
+
SockAddr raddr; /* Remote address */
|
1000
|
+
int be_pid; /* PID of backend --- needed for cancels */
|
1001
|
+
int be_key; /* key of backend --- needed for cancels */
|
1002
|
+
};
|
1003
|
+
|
1004
|
+
/*
|
1005
|
+
* call-seq:
|
1006
|
+
* conn.backend_key() -> Integer
|
1007
|
+
*
|
1008
|
+
* Returns the key of the backend server process for this connection.
|
1009
|
+
* This key can be used to cancel queries on the server.
|
1010
|
+
*/
|
1011
|
+
static VALUE
|
1012
|
+
pgconn_backend_key(VALUE self)
|
1013
|
+
{
|
1014
|
+
int be_key;
|
1015
|
+
struct pg_cancel *cancel;
|
1016
|
+
PGconn *conn = pg_get_pgconn(self);
|
1017
|
+
|
1018
|
+
cancel = (struct pg_cancel*)PQgetCancel(conn);
|
1019
|
+
if(cancel == NULL)
|
1020
|
+
pg_raise_conn_error( rb_ePGerror, self, "Invalid connection!");
|
1021
|
+
|
1022
|
+
if( cancel->be_pid != PQbackendPID(conn) )
|
1023
|
+
rb_raise(rb_ePGerror,"Unexpected binary struct layout - please file a bug report at ruby-pg!");
|
1024
|
+
|
1025
|
+
be_key = cancel->be_key;
|
1026
|
+
|
1027
|
+
PQfreeCancel(cancel);
|
1028
|
+
|
1029
|
+
return INT2NUM(be_key);
|
1030
|
+
}
|
1031
|
+
|
927
1032
|
/*
|
928
1033
|
* call-seq:
|
929
1034
|
* conn.connection_needs_password() -> Boolean
|
@@ -954,44 +1059,35 @@ pgconn_connection_used_password(VALUE self)
|
|
954
1059
|
/* :TODO: get_ssl */
|
955
1060
|
|
956
1061
|
|
957
|
-
static VALUE
|
1062
|
+
static VALUE pgconn_sync_exec_params( int, VALUE *, VALUE );
|
958
1063
|
|
959
1064
|
/*
|
960
1065
|
* call-seq:
|
961
|
-
* conn.
|
962
|
-
* conn.
|
963
|
-
*
|
964
|
-
* Sends SQL query request specified by _sql_ to PostgreSQL.
|
965
|
-
* Returns a PG::Result instance on success.
|
966
|
-
* On failure, it raises a PG::Error.
|
1066
|
+
* conn.sync_exec(sql) -> PG::Result
|
1067
|
+
* conn.sync_exec(sql) {|pg_result| block }
|
967
1068
|
*
|
968
|
-
*
|
969
|
-
*
|
970
|
-
* argument placeholders are used.
|
1069
|
+
* This function has the same behavior as #async_exec, but is implemented using the synchronous command processing API of libpq.
|
1070
|
+
* It's not recommended to use explicit sync or async variants but #exec instead, unless you have a good reason to do so.
|
971
1071
|
*
|
972
|
-
*
|
973
|
-
*
|
974
|
-
* In this instance, <code>conn.exec</code> returns the value of the block.
|
1072
|
+
* Both #sync_exec and #async_exec release the GVL while waiting for server response, so that concurrent threads will get executed.
|
1073
|
+
* However #async_exec has two advantages:
|
975
1074
|
*
|
976
|
-
* #
|
977
|
-
*
|
978
|
-
*
|
979
|
-
* the query is finished. This is most notably visible by a delayed reaction to Control+C.
|
980
|
-
* Both methods ensure that other threads can process while waiting for the server to
|
981
|
-
* complete the request.
|
1075
|
+
* 1. #async_exec can be aborted by signals (like Ctrl-C), while #exec blocks signal processing until the query is answered.
|
1076
|
+
* 2. Ruby VM gets notified about IO blocked operations and can pass them through <tt>Fiber.scheduler</tt>.
|
1077
|
+
* So only <tt>async_*</tt> methods are compatible to event based schedulers like the async gem.
|
982
1078
|
*/
|
983
1079
|
static VALUE
|
984
|
-
|
1080
|
+
pgconn_sync_exec(int argc, VALUE *argv, VALUE self)
|
985
1081
|
{
|
986
|
-
|
1082
|
+
t_pg_connection *this = pg_get_connection_safe( self );
|
987
1083
|
PGresult *result = NULL;
|
988
1084
|
VALUE rb_pgresult;
|
989
1085
|
|
990
|
-
/* If called with no parameters, use PQexec */
|
991
|
-
if ( argc == 1 ) {
|
1086
|
+
/* If called with no or nil parameters, use PQexec for compatibility */
|
1087
|
+
if ( argc == 1 || (argc >= 2 && argc <= 4 && NIL_P(argv[1]) )) {
|
992
1088
|
VALUE query_str = argv[0];
|
993
1089
|
|
994
|
-
result = gvl_PQexec(
|
1090
|
+
result = gvl_PQexec(this->pgconn, pg_cstr_enc(query_str, this->enc_idx));
|
995
1091
|
rb_pgresult = pg_new_result(result, self);
|
996
1092
|
pg_result_check(rb_pgresult);
|
997
1093
|
if (rb_block_given_p()) {
|
@@ -999,11 +1095,10 @@ pgconn_exec(int argc, VALUE *argv, VALUE self)
|
|
999
1095
|
}
|
1000
1096
|
return rb_pgresult;
|
1001
1097
|
}
|
1098
|
+
pg_deprecated(0, ("forwarding exec to exec_params is deprecated"));
|
1002
1099
|
|
1003
1100
|
/* Otherwise, just call #exec_params instead for backward-compatibility */
|
1004
|
-
|
1005
|
-
return pgconn_exec_params( argc, argv, self );
|
1006
|
-
}
|
1101
|
+
return pgconn_sync_exec_params( argc, argv, self );
|
1007
1102
|
|
1008
1103
|
}
|
1009
1104
|
|
@@ -1035,7 +1130,7 @@ struct query_params_data {
|
|
1035
1130
|
* Filled by alloc_query_params()
|
1036
1131
|
*/
|
1037
1132
|
|
1038
|
-
/* Wraps the pointer of allocated memory, if function parameters
|
1133
|
+
/* Wraps the pointer of allocated memory, if function parameters don't
|
1039
1134
|
* fit in the memory_pool below.
|
1040
1135
|
*/
|
1041
1136
|
VALUE heap_pool;
|
@@ -1053,7 +1148,7 @@ struct query_params_data {
|
|
1053
1148
|
Oid *types;
|
1054
1149
|
|
1055
1150
|
/* This array takes the string values for the timeframe of the query,
|
1056
|
-
* if param value
|
1151
|
+
* if param value conversion is required
|
1057
1152
|
*/
|
1058
1153
|
VALUE gc_array;
|
1059
1154
|
|
@@ -1067,8 +1162,9 @@ struct query_params_data {
|
|
1067
1162
|
};
|
1068
1163
|
|
1069
1164
|
static void
|
1070
|
-
free_typecast_heap_chain(
|
1165
|
+
free_typecast_heap_chain(void *_chain_entry)
|
1071
1166
|
{
|
1167
|
+
struct linked_typecast_data *chain_entry = (struct linked_typecast_data *)_chain_entry;
|
1072
1168
|
while(chain_entry){
|
1073
1169
|
struct linked_typecast_data *next = chain_entry->next;
|
1074
1170
|
xfree(chain_entry);
|
@@ -1076,6 +1172,18 @@ free_typecast_heap_chain(struct linked_typecast_data *chain_entry)
|
|
1076
1172
|
}
|
1077
1173
|
}
|
1078
1174
|
|
1175
|
+
static const rb_data_type_t pg_typecast_buffer_type = {
|
1176
|
+
"PG::Connection typecast buffer chain",
|
1177
|
+
{
|
1178
|
+
(RUBY_DATA_FUNC) NULL,
|
1179
|
+
free_typecast_heap_chain,
|
1180
|
+
(size_t (*)(const void *))NULL,
|
1181
|
+
},
|
1182
|
+
0,
|
1183
|
+
0,
|
1184
|
+
RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
|
1185
|
+
};
|
1186
|
+
|
1079
1187
|
static char *
|
1080
1188
|
alloc_typecast_buf( VALUE *typecast_heap_chain, int len )
|
1081
1189
|
{
|
@@ -1086,17 +1194,28 @@ alloc_typecast_buf( VALUE *typecast_heap_chain, int len )
|
|
1086
1194
|
/* Did we already wrap a memory chain per T_DATA object? */
|
1087
1195
|
if( NIL_P( *typecast_heap_chain ) ){
|
1088
1196
|
/* Leave free'ing of the buffer chain to the GC, when paramsData has left the stack */
|
1089
|
-
*typecast_heap_chain =
|
1197
|
+
*typecast_heap_chain = TypedData_Wrap_Struct( rb_cObject, &pg_typecast_buffer_type, allocated );
|
1090
1198
|
allocated->next = NULL;
|
1091
1199
|
} else {
|
1092
1200
|
/* Append to the chain */
|
1093
|
-
allocated->next =
|
1094
|
-
|
1201
|
+
allocated->next = RTYPEDDATA_DATA( *typecast_heap_chain );
|
1202
|
+
RTYPEDDATA_DATA( *typecast_heap_chain ) = allocated;
|
1095
1203
|
}
|
1096
1204
|
|
1097
1205
|
return &allocated->data[0];
|
1098
1206
|
}
|
1099
1207
|
|
1208
|
+
static const rb_data_type_t pg_query_heap_pool_type = {
|
1209
|
+
"PG::Connection query heap pool",
|
1210
|
+
{
|
1211
|
+
(RUBY_DATA_FUNC) NULL,
|
1212
|
+
RUBY_TYPED_DEFAULT_FREE,
|
1213
|
+
(size_t (*)(const void *))NULL,
|
1214
|
+
},
|
1215
|
+
0,
|
1216
|
+
0,
|
1217
|
+
RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
|
1218
|
+
};
|
1100
1219
|
|
1101
1220
|
static int
|
1102
1221
|
alloc_query_params(struct query_params_data *paramsData)
|
@@ -1111,7 +1230,7 @@ alloc_query_params(struct query_params_data *paramsData)
|
|
1111
1230
|
|
1112
1231
|
Check_Type(paramsData->params, T_ARRAY);
|
1113
1232
|
|
1114
|
-
p_typemap =
|
1233
|
+
p_typemap = RTYPEDDATA_DATA( paramsData->typemap );
|
1115
1234
|
p_typemap->funcs.fit_to_query( paramsData->typemap, paramsData->params );
|
1116
1235
|
|
1117
1236
|
paramsData->heap_pool = Qnil;
|
@@ -1130,7 +1249,7 @@ alloc_query_params(struct query_params_data *paramsData)
|
|
1130
1249
|
/* Allocate one combined memory pool for all possible function parameters */
|
1131
1250
|
memory_pool = (char*)xmalloc( required_pool_size );
|
1132
1251
|
/* Leave free'ing of the buffer to the GC, when paramsData has left the stack */
|
1133
|
-
paramsData->heap_pool =
|
1252
|
+
paramsData->heap_pool = TypedData_Wrap_Struct( rb_cObject, &pg_query_heap_pool_type, memory_pool );
|
1134
1253
|
required_pool_size = 0;
|
1135
1254
|
}else{
|
1136
1255
|
/* Use stack memory for function parameters */
|
@@ -1243,85 +1362,52 @@ pgconn_query_assign_typemap( VALUE self, struct query_params_data *paramsData )
|
|
1243
1362
|
/* Use default typemap for queries. It's type is checked when assigned. */
|
1244
1363
|
paramsData->typemap = pg_get_connection(self)->type_map_for_queries;
|
1245
1364
|
}else{
|
1365
|
+
t_typemap *tm;
|
1366
|
+
UNUSED(tm);
|
1367
|
+
|
1246
1368
|
/* Check type of method param */
|
1247
|
-
|
1248
|
-
rb_raise( rb_eTypeError, "wrong argument type %s (expected kind of PG::TypeMap)",
|
1249
|
-
rb_obj_classname( paramsData->typemap ) );
|
1250
|
-
}
|
1251
|
-
Check_Type( paramsData->typemap, T_DATA );
|
1369
|
+
TypedData_Get_Struct(paramsData->typemap, t_typemap, &pg_typemap_type, tm);
|
1252
1370
|
}
|
1253
1371
|
}
|
1254
1372
|
|
1255
1373
|
/*
|
1256
1374
|
* call-seq:
|
1257
|
-
* conn.
|
1258
|
-
* conn.
|
1259
|
-
*
|
1260
|
-
* Sends SQL query request specified by +sql+ to PostgreSQL using placeholders
|
1261
|
-
* for parameters.
|
1262
|
-
*
|
1263
|
-
* Returns a PG::Result instance on success. On failure, it raises a PG::Error.
|
1264
|
-
*
|
1265
|
-
* +params+ is an array of the bind parameters for the SQL query.
|
1266
|
-
* Each element of the +params+ array may be either:
|
1267
|
-
* a hash of the form:
|
1268
|
-
* {:value => String (value of bind parameter)
|
1269
|
-
* :type => Integer (oid of type of bind parameter)
|
1270
|
-
* :format => Integer (0 for text, 1 for binary)
|
1271
|
-
* }
|
1272
|
-
* or, it may be a String. If it is a string, that is equivalent to the hash:
|
1273
|
-
* { :value => <string value>, :type => 0, :format => 0 }
|
1274
|
-
*
|
1275
|
-
* PostgreSQL bind parameters are represented as $1, $1, $2, etc.,
|
1276
|
-
* inside the SQL query. The 0th element of the +params+ array is bound
|
1277
|
-
* to $1, the 1st element is bound to $2, etc. +nil+ is treated as +NULL+.
|
1278
|
-
*
|
1279
|
-
* If the types are not specified, they will be inferred by PostgreSQL.
|
1280
|
-
* Instead of specifying type oids, it's recommended to simply add
|
1281
|
-
* explicit casts in the query to ensure that the right type is used.
|
1282
|
-
*
|
1283
|
-
* For example: "SELECT $1::int"
|
1284
|
-
*
|
1285
|
-
* The optional +result_format+ should be 0 for text results, 1
|
1286
|
-
* for binary.
|
1287
|
-
*
|
1288
|
-
* type_map can be a PG::TypeMap derivation (such as PG::BasicTypeMapForQueries).
|
1289
|
-
* This will type cast the params from various Ruby types before transmission
|
1290
|
-
* based on the encoders defined by the type map. When a type encoder is used
|
1291
|
-
* the format and oid of a given bind parameter are retrieved from the encoder
|
1292
|
-
* instead out of the hash form described above.
|
1375
|
+
* conn.sync_exec_params(sql, params[, result_format[, type_map]] ) -> PG::Result
|
1376
|
+
* conn.sync_exec_params(sql, params[, result_format[, type_map]] ) {|pg_result| block }
|
1293
1377
|
*
|
1294
|
-
*
|
1295
|
-
*
|
1296
|
-
*
|
1378
|
+
* This function has the same behavior as #async_exec_params, but is implemented using the synchronous command processing API of libpq.
|
1379
|
+
* See #async_exec for the differences between the two API variants.
|
1380
|
+
* It's not recommended to use explicit sync or async variants but #exec_params instead, unless you have a good reason to do so.
|
1297
1381
|
*/
|
1298
1382
|
static VALUE
|
1299
|
-
|
1383
|
+
pgconn_sync_exec_params( int argc, VALUE *argv, VALUE self )
|
1300
1384
|
{
|
1301
|
-
|
1385
|
+
t_pg_connection *this = pg_get_connection_safe( self );
|
1302
1386
|
PGresult *result = NULL;
|
1303
1387
|
VALUE rb_pgresult;
|
1304
1388
|
VALUE command, in_res_fmt;
|
1305
1389
|
int nParams;
|
1306
1390
|
int resultFormat;
|
1307
|
-
struct query_params_data paramsData = {
|
1391
|
+
struct query_params_data paramsData = { this->enc_idx };
|
1308
1392
|
|
1393
|
+
/* For compatibility we accept 1 to 4 parameters */
|
1309
1394
|
rb_scan_args(argc, argv, "13", &command, ¶msData.params, &in_res_fmt, ¶msData.typemap);
|
1310
1395
|
paramsData.with_types = 1;
|
1311
1396
|
|
1312
1397
|
/*
|
1313
|
-
*
|
1314
|
-
*
|
1398
|
+
* For backward compatibility no or +nil+ for the second parameter
|
1399
|
+
* is passed to #exec
|
1315
1400
|
*/
|
1316
1401
|
if ( NIL_P(paramsData.params) ) {
|
1317
|
-
|
1402
|
+
pg_deprecated(1, ("forwarding exec_params to exec is deprecated"));
|
1403
|
+
return pgconn_sync_exec( 1, argv, self );
|
1318
1404
|
}
|
1319
1405
|
pgconn_query_assign_typemap( self, ¶msData );
|
1320
1406
|
|
1321
1407
|
resultFormat = NIL_P(in_res_fmt) ? 0 : NUM2INT(in_res_fmt);
|
1322
1408
|
nParams = alloc_query_params( ¶msData );
|
1323
1409
|
|
1324
|
-
result = gvl_PQexecParams(
|
1410
|
+
result = gvl_PQexecParams(this->pgconn, pg_cstr_enc(command, paramsData.enc_idx), nParams, paramsData.types,
|
1325
1411
|
(const char * const *)paramsData.values, paramsData.lengths, paramsData.formats, resultFormat);
|
1326
1412
|
|
1327
1413
|
free_query_params( ¶msData );
|
@@ -1338,28 +1424,16 @@ pgconn_exec_params( int argc, VALUE *argv, VALUE self )
|
|
1338
1424
|
|
1339
1425
|
/*
|
1340
1426
|
* 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"
|
1427
|
+
* conn.sync_prepare(stmt_name, sql [, param_types ] ) -> PG::Result
|
1355
1428
|
*
|
1356
|
-
*
|
1357
|
-
*
|
1429
|
+
* This function has the same behavior as #async_prepare, but is implemented using the synchronous command processing API of libpq.
|
1430
|
+
* See #async_exec for the differences between the two API variants.
|
1431
|
+
* It's not recommended to use explicit sync or async variants but #prepare instead, unless you have a good reason to do so.
|
1358
1432
|
*/
|
1359
1433
|
static VALUE
|
1360
|
-
|
1434
|
+
pgconn_sync_prepare(int argc, VALUE *argv, VALUE self)
|
1361
1435
|
{
|
1362
|
-
|
1436
|
+
t_pg_connection *this = pg_get_connection_safe( self );
|
1363
1437
|
PGresult *result = NULL;
|
1364
1438
|
VALUE rb_pgresult;
|
1365
1439
|
VALUE name, command, in_paramtypes;
|
@@ -1369,7 +1443,7 @@ pgconn_prepare(int argc, VALUE *argv, VALUE self)
|
|
1369
1443
|
Oid *paramTypes = NULL;
|
1370
1444
|
const char *name_cstr;
|
1371
1445
|
const char *command_cstr;
|
1372
|
-
int enc_idx =
|
1446
|
+
int enc_idx = this->enc_idx;
|
1373
1447
|
|
1374
1448
|
rb_scan_args(argc, argv, "21", &name, &command, &in_paramtypes);
|
1375
1449
|
name_cstr = pg_cstr_enc(name, enc_idx);
|
@@ -1387,7 +1461,7 @@ pgconn_prepare(int argc, VALUE *argv, VALUE self)
|
|
1387
1461
|
paramTypes[i] = NUM2UINT(param);
|
1388
1462
|
}
|
1389
1463
|
}
|
1390
|
-
result = gvl_PQprepare(
|
1464
|
+
result = gvl_PQprepare(this->pgconn, name_cstr, command_cstr, nParams, paramTypes);
|
1391
1465
|
|
1392
1466
|
xfree(paramTypes);
|
1393
1467
|
|
@@ -1398,49 +1472,23 @@ pgconn_prepare(int argc, VALUE *argv, VALUE self)
|
|
1398
1472
|
|
1399
1473
|
/*
|
1400
1474
|
* 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.
|
1475
|
+
* conn.sync_exec_prepared(statement_name [, params, result_format[, type_map]] ) -> PG::Result
|
1476
|
+
* conn.sync_exec_prepared(statement_name [, params, result_format[, type_map]] ) {|pg_result| block }
|
1429
1477
|
*
|
1430
|
-
*
|
1431
|
-
*
|
1432
|
-
*
|
1478
|
+
* This function has the same behavior as #async_exec_prepared, but is implemented using the synchronous command processing API of libpq.
|
1479
|
+
* See #async_exec for the differences between the two API variants.
|
1480
|
+
* 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
1481
|
*/
|
1434
1482
|
static VALUE
|
1435
|
-
|
1483
|
+
pgconn_sync_exec_prepared(int argc, VALUE *argv, VALUE self)
|
1436
1484
|
{
|
1437
|
-
|
1485
|
+
t_pg_connection *this = pg_get_connection_safe( self );
|
1438
1486
|
PGresult *result = NULL;
|
1439
1487
|
VALUE rb_pgresult;
|
1440
1488
|
VALUE name, in_res_fmt;
|
1441
1489
|
int nParams;
|
1442
1490
|
int resultFormat;
|
1443
|
-
struct query_params_data paramsData = {
|
1491
|
+
struct query_params_data paramsData = { this->enc_idx };
|
1444
1492
|
|
1445
1493
|
rb_scan_args(argc, argv, "13", &name, ¶msData.params, &in_res_fmt, ¶msData.typemap);
|
1446
1494
|
paramsData.with_types = 0;
|
@@ -1453,7 +1501,7 @@ pgconn_exec_prepared(int argc, VALUE *argv, VALUE self)
|
|
1453
1501
|
resultFormat = NIL_P(in_res_fmt) ? 0 : NUM2INT(in_res_fmt);
|
1454
1502
|
nParams = alloc_query_params( ¶msData );
|
1455
1503
|
|
1456
|
-
result = gvl_PQexecPrepared(
|
1504
|
+
result = gvl_PQexecPrepared(this->pgconn, pg_cstr_enc(name, paramsData.enc_idx), nParams,
|
1457
1505
|
(const char * const *)paramsData.values, paramsData.lengths, paramsData.formats,
|
1458
1506
|
resultFormat);
|
1459
1507
|
|
@@ -1470,25 +1518,26 @@ pgconn_exec_prepared(int argc, VALUE *argv, VALUE self)
|
|
1470
1518
|
|
1471
1519
|
/*
|
1472
1520
|
* call-seq:
|
1473
|
-
* conn.
|
1521
|
+
* conn.sync_describe_prepared( statement_name ) -> PG::Result
|
1474
1522
|
*
|
1475
|
-
*
|
1476
|
-
*
|
1523
|
+
* This function has the same behavior as #async_describe_prepared, but is implemented using the synchronous command processing API of libpq.
|
1524
|
+
* See #async_exec for the differences between the two API variants.
|
1525
|
+
* 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
1526
|
*/
|
1478
1527
|
static VALUE
|
1479
|
-
|
1528
|
+
pgconn_sync_describe_prepared(VALUE self, VALUE stmt_name)
|
1480
1529
|
{
|
1481
1530
|
PGresult *result;
|
1482
1531
|
VALUE rb_pgresult;
|
1483
|
-
|
1532
|
+
t_pg_connection *this = pg_get_connection_safe( self );
|
1484
1533
|
const char *stmt;
|
1485
1534
|
if(NIL_P(stmt_name)) {
|
1486
1535
|
stmt = NULL;
|
1487
1536
|
}
|
1488
1537
|
else {
|
1489
|
-
stmt = pg_cstr_enc(stmt_name,
|
1538
|
+
stmt = pg_cstr_enc(stmt_name, this->enc_idx);
|
1490
1539
|
}
|
1491
|
-
result = gvl_PQdescribePrepared(
|
1540
|
+
result = gvl_PQdescribePrepared(this->pgconn, stmt);
|
1492
1541
|
rb_pgresult = pg_new_result(result, self);
|
1493
1542
|
pg_result_check(rb_pgresult);
|
1494
1543
|
return rb_pgresult;
|
@@ -1497,25 +1546,26 @@ pgconn_describe_prepared(VALUE self, VALUE stmt_name)
|
|
1497
1546
|
|
1498
1547
|
/*
|
1499
1548
|
* call-seq:
|
1500
|
-
* conn.
|
1549
|
+
* conn.sync_describe_portal( portal_name ) -> PG::Result
|
1501
1550
|
*
|
1502
|
-
*
|
1551
|
+
* This function has the same behavior as #async_describe_portal, but is implemented using the synchronous command processing API of libpq.
|
1552
|
+
* See #async_exec for the differences between the two API variants.
|
1553
|
+
* 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
1554
|
*/
|
1504
1555
|
static VALUE
|
1505
|
-
|
1506
|
-
VALUE self, stmt_name;
|
1556
|
+
pgconn_sync_describe_portal(VALUE self, VALUE stmt_name)
|
1507
1557
|
{
|
1508
1558
|
PGresult *result;
|
1509
1559
|
VALUE rb_pgresult;
|
1510
|
-
|
1560
|
+
t_pg_connection *this = pg_get_connection_safe( self );
|
1511
1561
|
const char *stmt;
|
1512
1562
|
if(NIL_P(stmt_name)) {
|
1513
1563
|
stmt = NULL;
|
1514
1564
|
}
|
1515
1565
|
else {
|
1516
|
-
stmt = pg_cstr_enc(stmt_name,
|
1566
|
+
stmt = pg_cstr_enc(stmt_name, this->enc_idx);
|
1517
1567
|
}
|
1518
|
-
result = gvl_PQdescribePortal(
|
1568
|
+
result = gvl_PQdescribePortal(this->pgconn, stmt);
|
1519
1569
|
rb_pgresult = pg_new_result(result, self);
|
1520
1570
|
pg_result_check(rb_pgresult);
|
1521
1571
|
return rb_pgresult;
|
@@ -1537,6 +1587,9 @@ pgconn_describe_portal(self, stmt_name)
|
|
1537
1587
|
* * +PGRES_NONFATAL_ERROR+
|
1538
1588
|
* * +PGRES_FATAL_ERROR+
|
1539
1589
|
* * +PGRES_COPY_BOTH+
|
1590
|
+
* * +PGRES_SINGLE_TUPLE+
|
1591
|
+
* * +PGRES_PIPELINE_SYNC+
|
1592
|
+
* * +PGRES_PIPELINE_ABORTED+
|
1540
1593
|
*/
|
1541
1594
|
static VALUE
|
1542
1595
|
pgconn_make_empty_pgresult(VALUE self, VALUE status)
|
@@ -1562,13 +1615,15 @@ pgconn_make_empty_pgresult(VALUE self, VALUE status)
|
|
1562
1615
|
* Consider using exec_params, which avoids the need for passing values
|
1563
1616
|
* inside of SQL commands.
|
1564
1617
|
*
|
1565
|
-
*
|
1618
|
+
* Character encoding of escaped string will be equal to client encoding of connection.
|
1566
1619
|
*
|
1567
1620
|
* NOTE: This class version of this method can only be used safely in client
|
1568
1621
|
* programs that use a single PostgreSQL connection at a time (in this case it can
|
1569
1622
|
* find out what it needs to know "behind the scenes"). It might give the wrong
|
1570
1623
|
* results if used in programs that use multiple database connections; use the
|
1571
1624
|
* same method on the connection object in such cases.
|
1625
|
+
*
|
1626
|
+
* See also convenience functions #escape_literal and #escape_identifier which also add proper quotes around the string.
|
1572
1627
|
*/
|
1573
1628
|
static VALUE
|
1574
1629
|
pgconn_s_escape(VALUE self, VALUE string)
|
@@ -1579,8 +1634,8 @@ pgconn_s_escape(VALUE self, VALUE string)
|
|
1579
1634
|
int enc_idx;
|
1580
1635
|
int singleton = !rb_obj_is_kind_of(self, rb_cPGconn);
|
1581
1636
|
|
1582
|
-
|
1583
|
-
enc_idx =
|
1637
|
+
StringValueCStr(string);
|
1638
|
+
enc_idx = singleton ? ENCODING_GET(string) : pg_get_connection(self)->enc_idx;
|
1584
1639
|
if( ENCODING_GET(string) != enc_idx ){
|
1585
1640
|
string = rb_str_export_to_enc(string, rb_enc_from_index(enc_idx));
|
1586
1641
|
}
|
@@ -1590,14 +1645,13 @@ pgconn_s_escape(VALUE self, VALUE string)
|
|
1590
1645
|
if( !singleton ) {
|
1591
1646
|
size = PQescapeStringConn(pg_get_pgconn(self), RSTRING_PTR(result),
|
1592
1647
|
RSTRING_PTR(string), RSTRING_LEN(string), &error);
|
1593
|
-
if(error)
|
1594
|
-
|
1595
|
-
|
1648
|
+
if(error)
|
1649
|
+
pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(pg_get_pgconn(self)));
|
1650
|
+
|
1596
1651
|
} else {
|
1597
1652
|
size = PQescapeString(RSTRING_PTR(result), RSTRING_PTR(string), RSTRING_LEN(string));
|
1598
1653
|
}
|
1599
1654
|
rb_str_set_len(result, size);
|
1600
|
-
OBJ_INFECT(result, string);
|
1601
1655
|
|
1602
1656
|
return result;
|
1603
1657
|
}
|
@@ -1643,7 +1697,6 @@ pgconn_s_escape_bytea(VALUE self, VALUE str)
|
|
1643
1697
|
}
|
1644
1698
|
|
1645
1699
|
ret = rb_str_new((char*)to, to_len - 1);
|
1646
|
-
OBJ_INFECT(ret, str);
|
1647
1700
|
PQfreemem(to);
|
1648
1701
|
return ret;
|
1649
1702
|
}
|
@@ -1673,7 +1726,6 @@ pgconn_s_unescape_bytea(VALUE self, VALUE str)
|
|
1673
1726
|
to = PQunescapeBytea(from, &to_len);
|
1674
1727
|
|
1675
1728
|
ret = rb_str_new((char*)to, to_len);
|
1676
|
-
OBJ_INFECT(ret, str);
|
1677
1729
|
PQfreemem(to);
|
1678
1730
|
return ret;
|
1679
1731
|
}
|
@@ -1684,33 +1736,27 @@ pgconn_s_unescape_bytea(VALUE self, VALUE str)
|
|
1684
1736
|
*
|
1685
1737
|
* Escape an arbitrary String +str+ as a literal.
|
1686
1738
|
*
|
1687
|
-
*
|
1739
|
+
* See also PG::TextEncoder::QuotedLiteral for a type cast integrated version of this function.
|
1688
1740
|
*/
|
1689
1741
|
static VALUE
|
1690
1742
|
pgconn_escape_literal(VALUE self, VALUE string)
|
1691
1743
|
{
|
1692
|
-
|
1744
|
+
t_pg_connection *this = pg_get_connection_safe( self );
|
1693
1745
|
char *escaped = NULL;
|
1694
|
-
VALUE error;
|
1695
1746
|
VALUE result = Qnil;
|
1696
|
-
int enc_idx =
|
1747
|
+
int enc_idx = this->enc_idx;
|
1697
1748
|
|
1698
|
-
|
1749
|
+
StringValueCStr(string);
|
1699
1750
|
if( ENCODING_GET(string) != enc_idx ){
|
1700
1751
|
string = rb_str_export_to_enc(string, rb_enc_from_index(enc_idx));
|
1701
1752
|
}
|
1702
1753
|
|
1703
|
-
escaped = PQescapeLiteral(
|
1754
|
+
escaped = PQescapeLiteral(this->pgconn, RSTRING_PTR(string), RSTRING_LEN(string));
|
1704
1755
|
if (escaped == NULL)
|
1705
|
-
|
1706
|
-
|
1707
|
-
rb_iv_set(error, "@connection", self);
|
1708
|
-
rb_exc_raise(error);
|
1709
|
-
return Qnil;
|
1710
|
-
}
|
1756
|
+
pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(this->pgconn));
|
1757
|
+
|
1711
1758
|
result = rb_str_new2(escaped);
|
1712
1759
|
PQfreemem(escaped);
|
1713
|
-
OBJ_INFECT(result, string);
|
1714
1760
|
PG_ENCODING_SET_NOCHECK(result, enc_idx);
|
1715
1761
|
|
1716
1762
|
return result;
|
@@ -1725,34 +1771,26 @@ pgconn_escape_literal(VALUE self, VALUE string)
|
|
1725
1771
|
* This method does the same as #quote_ident with a String argument,
|
1726
1772
|
* but it doesn't support an Array argument and it makes use of libpq
|
1727
1773
|
* to process the string.
|
1728
|
-
*
|
1729
|
-
* Available since PostgreSQL-9.0
|
1730
1774
|
*/
|
1731
1775
|
static VALUE
|
1732
1776
|
pgconn_escape_identifier(VALUE self, VALUE string)
|
1733
1777
|
{
|
1734
|
-
|
1778
|
+
t_pg_connection *this = pg_get_connection_safe( self );
|
1735
1779
|
char *escaped = NULL;
|
1736
|
-
VALUE error;
|
1737
1780
|
VALUE result = Qnil;
|
1738
|
-
int enc_idx =
|
1781
|
+
int enc_idx = this->enc_idx;
|
1739
1782
|
|
1740
|
-
|
1783
|
+
StringValueCStr(string);
|
1741
1784
|
if( ENCODING_GET(string) != enc_idx ){
|
1742
1785
|
string = rb_str_export_to_enc(string, rb_enc_from_index(enc_idx));
|
1743
1786
|
}
|
1744
1787
|
|
1745
|
-
escaped = PQescapeIdentifier(
|
1788
|
+
escaped = PQescapeIdentifier(this->pgconn, RSTRING_PTR(string), RSTRING_LEN(string));
|
1746
1789
|
if (escaped == NULL)
|
1747
|
-
|
1748
|
-
|
1749
|
-
rb_iv_set(error, "@connection", self);
|
1750
|
-
rb_exc_raise(error);
|
1751
|
-
return Qnil;
|
1752
|
-
}
|
1790
|
+
pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(this->pgconn));
|
1791
|
+
|
1753
1792
|
result = rb_str_new2(escaped);
|
1754
1793
|
PQfreemem(escaped);
|
1755
|
-
OBJ_INFECT(result, string);
|
1756
1794
|
PG_ENCODING_SET_NOCHECK(result, enc_idx);
|
1757
1795
|
|
1758
1796
|
return result;
|
@@ -1793,34 +1831,65 @@ pgconn_escape_identifier(VALUE self, VALUE string)
|
|
1793
1831
|
* # do something with the received row
|
1794
1832
|
* end
|
1795
1833
|
* end
|
1796
|
-
*
|
1797
|
-
* Available since PostgreSQL-9.2
|
1798
1834
|
*/
|
1799
1835
|
static VALUE
|
1800
1836
|
pgconn_set_single_row_mode(VALUE self)
|
1801
1837
|
{
|
1802
1838
|
PGconn *conn = pg_get_pgconn(self);
|
1803
|
-
VALUE error;
|
1804
1839
|
|
1840
|
+
rb_check_frozen(self);
|
1805
1841
|
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
|
-
}
|
1842
|
+
pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(conn));
|
1811
1843
|
|
1812
1844
|
return self;
|
1813
1845
|
}
|
1814
1846
|
|
1847
|
+
static VALUE pgconn_send_query_params(int argc, VALUE *argv, VALUE self);
|
1848
|
+
|
1849
|
+
/*
|
1850
|
+
* call-seq:
|
1851
|
+
* conn.send_query(sql) -> nil
|
1852
|
+
*
|
1853
|
+
* Sends SQL query request specified by _sql_ to PostgreSQL for
|
1854
|
+
* asynchronous processing, and immediately returns.
|
1855
|
+
* On failure, it raises a PG::Error.
|
1856
|
+
*
|
1857
|
+
* For backward compatibility, if you pass more than one parameter to this method,
|
1858
|
+
* it will call #send_query_params for you. New code should explicitly use #send_query_params if
|
1859
|
+
* argument placeholders are used.
|
1860
|
+
*
|
1861
|
+
*/
|
1862
|
+
static VALUE
|
1863
|
+
pgconn_send_query(int argc, VALUE *argv, VALUE self)
|
1864
|
+
{
|
1865
|
+
t_pg_connection *this = pg_get_connection_safe( self );
|
1866
|
+
|
1867
|
+
/* If called with no or nil parameters, use PQexec for compatibility */
|
1868
|
+
if ( argc == 1 || (argc >= 2 && argc <= 4 && NIL_P(argv[1]) )) {
|
1869
|
+
if(gvl_PQsendQuery(this->pgconn, pg_cstr_enc(argv[0], this->enc_idx)) == 0)
|
1870
|
+
pg_raise_conn_error( rb_eUnableToSend, self, "%s", PQerrorMessage(this->pgconn));
|
1871
|
+
|
1872
|
+
pgconn_wait_for_flush( self );
|
1873
|
+
return Qnil;
|
1874
|
+
}
|
1875
|
+
|
1876
|
+
pg_deprecated(2, ("forwarding async_exec to async_exec_params and send_query to send_query_params is deprecated"));
|
1877
|
+
|
1878
|
+
/* If called with parameters, and optionally result_format,
|
1879
|
+
* use PQsendQueryParams
|
1880
|
+
*/
|
1881
|
+
return pgconn_send_query_params( argc, argv, self);
|
1882
|
+
}
|
1883
|
+
|
1815
1884
|
/*
|
1816
1885
|
* call-seq:
|
1817
|
-
* conn.
|
1886
|
+
* conn.send_query_params(sql, params [, result_format [, type_map ]] ) -> nil
|
1818
1887
|
*
|
1819
1888
|
* Sends SQL query request specified by _sql_ to PostgreSQL for
|
1820
1889
|
* asynchronous processing, and immediately returns.
|
1821
1890
|
* On failure, it raises a PG::Error.
|
1822
1891
|
*
|
1823
|
-
* +params+ is an
|
1892
|
+
* +params+ is an array of the bind parameters for the SQL query.
|
1824
1893
|
* Each element of the +params+ array may be either:
|
1825
1894
|
* a hash of the form:
|
1826
1895
|
* {:value => String (value of bind parameter)
|
@@ -1830,7 +1899,7 @@ pgconn_set_single_row_mode(VALUE self)
|
|
1830
1899
|
* or, it may be a String. If it is a string, that is equivalent to the hash:
|
1831
1900
|
* { :value => <string value>, :type => 0, :format => 0 }
|
1832
1901
|
*
|
1833
|
-
* PostgreSQL bind parameters are represented as $1, $
|
1902
|
+
* PostgreSQL bind parameters are represented as $1, $2, $3, etc.,
|
1834
1903
|
* inside the SQL query. The 0th element of the +params+ array is bound
|
1835
1904
|
* to $1, the 1st element is bound to $2, etc. +nil+ is treated as +NULL+.
|
1836
1905
|
*
|
@@ -1843,7 +1912,7 @@ pgconn_set_single_row_mode(VALUE self)
|
|
1843
1912
|
* The optional +result_format+ should be 0 for text results, 1
|
1844
1913
|
* for binary.
|
1845
1914
|
*
|
1846
|
-
* type_map can be a PG::TypeMap derivation (such as PG::BasicTypeMapForQueries).
|
1915
|
+
* +type_map+ can be a PG::TypeMap derivation (such as PG::BasicTypeMapForQueries).
|
1847
1916
|
* This will type cast the params from various Ruby types before transmission
|
1848
1917
|
* based on the encoders defined by the type map. When a type encoder is used
|
1849
1918
|
* the format and oid of a given bind parameter are retrieved from the encoder
|
@@ -1851,47 +1920,31 @@ pgconn_set_single_row_mode(VALUE self)
|
|
1851
1920
|
*
|
1852
1921
|
*/
|
1853
1922
|
static VALUE
|
1854
|
-
|
1923
|
+
pgconn_send_query_params(int argc, VALUE *argv, VALUE self)
|
1855
1924
|
{
|
1856
|
-
|
1925
|
+
t_pg_connection *this = pg_get_connection_safe( self );
|
1857
1926
|
int result;
|
1858
1927
|
VALUE command, in_res_fmt;
|
1859
|
-
VALUE error;
|
1860
1928
|
int nParams;
|
1861
1929
|
int resultFormat;
|
1862
|
-
struct query_params_data paramsData = {
|
1930
|
+
struct query_params_data paramsData = { this->enc_idx };
|
1863
1931
|
|
1864
|
-
rb_scan_args(argc, argv, "
|
1932
|
+
rb_scan_args(argc, argv, "22", &command, ¶msData.params, &in_res_fmt, ¶msData.typemap);
|
1865
1933
|
paramsData.with_types = 1;
|
1866
1934
|
|
1867
|
-
/* If called with no parameters, use PQsendQuery */
|
1868
|
-
if(NIL_P(paramsData.params)) {
|
1869
|
-
if(gvl_PQsendQuery(conn, pg_cstr_enc(command, paramsData.enc_idx)) == 0) {
|
1870
|
-
error = rb_exc_new2(rb_eUnableToSend, PQerrorMessage(conn));
|
1871
|
-
rb_iv_set(error, "@connection", self);
|
1872
|
-
rb_exc_raise(error);
|
1873
|
-
}
|
1874
|
-
return Qnil;
|
1875
|
-
}
|
1876
|
-
|
1877
|
-
/* If called with parameters, and optionally result_format,
|
1878
|
-
* use PQsendQueryParams
|
1879
|
-
*/
|
1880
|
-
|
1881
1935
|
pgconn_query_assign_typemap( self, ¶msData );
|
1882
1936
|
resultFormat = NIL_P(in_res_fmt) ? 0 : NUM2INT(in_res_fmt);
|
1883
1937
|
nParams = alloc_query_params( ¶msData );
|
1884
1938
|
|
1885
|
-
result = gvl_PQsendQueryParams(
|
1939
|
+
result = gvl_PQsendQueryParams(this->pgconn, pg_cstr_enc(command, paramsData.enc_idx), nParams, paramsData.types,
|
1886
1940
|
(const char * const *)paramsData.values, paramsData.lengths, paramsData.formats, resultFormat);
|
1887
1941
|
|
1888
1942
|
free_query_params( ¶msData );
|
1889
1943
|
|
1890
|
-
if(result == 0)
|
1891
|
-
|
1892
|
-
|
1893
|
-
|
1894
|
-
}
|
1944
|
+
if(result == 0)
|
1945
|
+
pg_raise_conn_error( rb_eUnableToSend, self, "%s", PQerrorMessage(this->pgconn));
|
1946
|
+
|
1947
|
+
pgconn_wait_for_flush( self );
|
1895
1948
|
return Qnil;
|
1896
1949
|
}
|
1897
1950
|
|
@@ -1912,23 +1965,22 @@ pgconn_send_query(int argc, VALUE *argv, VALUE self)
|
|
1912
1965
|
*
|
1913
1966
|
* For example: "SELECT $1::int"
|
1914
1967
|
*
|
1915
|
-
* PostgreSQL bind parameters are represented as $1, $
|
1968
|
+
* PostgreSQL bind parameters are represented as $1, $2, $3, etc.,
|
1916
1969
|
* inside the SQL query.
|
1917
1970
|
*/
|
1918
1971
|
static VALUE
|
1919
1972
|
pgconn_send_prepare(int argc, VALUE *argv, VALUE self)
|
1920
1973
|
{
|
1921
|
-
|
1974
|
+
t_pg_connection *this = pg_get_connection_safe( self );
|
1922
1975
|
int result;
|
1923
1976
|
VALUE name, command, in_paramtypes;
|
1924
1977
|
VALUE param;
|
1925
|
-
VALUE error;
|
1926
1978
|
int i = 0;
|
1927
1979
|
int nParams = 0;
|
1928
1980
|
Oid *paramTypes = NULL;
|
1929
1981
|
const char *name_cstr;
|
1930
1982
|
const char *command_cstr;
|
1931
|
-
int enc_idx =
|
1983
|
+
int enc_idx = this->enc_idx;
|
1932
1984
|
|
1933
1985
|
rb_scan_args(argc, argv, "21", &name, &command, &in_paramtypes);
|
1934
1986
|
name_cstr = pg_cstr_enc(name, enc_idx);
|
@@ -1946,15 +1998,14 @@ pgconn_send_prepare(int argc, VALUE *argv, VALUE self)
|
|
1946
1998
|
paramTypes[i] = NUM2UINT(param);
|
1947
1999
|
}
|
1948
2000
|
}
|
1949
|
-
result = gvl_PQsendPrepare(
|
2001
|
+
result = gvl_PQsendPrepare(this->pgconn, name_cstr, command_cstr, nParams, paramTypes);
|
1950
2002
|
|
1951
2003
|
xfree(paramTypes);
|
1952
2004
|
|
1953
2005
|
if(result == 0) {
|
1954
|
-
|
1955
|
-
rb_iv_set(error, "@connection", self);
|
1956
|
-
rb_exc_raise(error);
|
2006
|
+
pg_raise_conn_error( rb_eUnableToSend, self, "%s", PQerrorMessage(this->pgconn));
|
1957
2007
|
}
|
2008
|
+
pgconn_wait_for_flush( self );
|
1958
2009
|
return Qnil;
|
1959
2010
|
}
|
1960
2011
|
|
@@ -1976,14 +2027,14 @@ pgconn_send_prepare(int argc, VALUE *argv, VALUE self)
|
|
1976
2027
|
* or, it may be a String. If it is a string, that is equivalent to the hash:
|
1977
2028
|
* { :value => <string value>, :format => 0 }
|
1978
2029
|
*
|
1979
|
-
* PostgreSQL bind parameters are represented as $1, $
|
2030
|
+
* PostgreSQL bind parameters are represented as $1, $2, $3, etc.,
|
1980
2031
|
* inside the SQL query. The 0th element of the +params+ array is bound
|
1981
2032
|
* to $1, the 1st element is bound to $2, etc. +nil+ is treated as +NULL+.
|
1982
2033
|
*
|
1983
2034
|
* The optional +result_format+ should be 0 for text results, 1
|
1984
2035
|
* for binary.
|
1985
2036
|
*
|
1986
|
-
* type_map can be a PG::TypeMap derivation (such as PG::BasicTypeMapForQueries).
|
2037
|
+
* +type_map+ can be a PG::TypeMap derivation (such as PG::BasicTypeMapForQueries).
|
1987
2038
|
* This will type cast the params from various Ruby types before transmission
|
1988
2039
|
* based on the encoders defined by the type map. When a type encoder is used
|
1989
2040
|
* the format and oid of a given bind parameter are retrieved from the encoder
|
@@ -1993,37 +2044,34 @@ pgconn_send_prepare(int argc, VALUE *argv, VALUE self)
|
|
1993
2044
|
static VALUE
|
1994
2045
|
pgconn_send_query_prepared(int argc, VALUE *argv, VALUE self)
|
1995
2046
|
{
|
1996
|
-
|
2047
|
+
t_pg_connection *this = pg_get_connection_safe( self );
|
1997
2048
|
int result;
|
1998
2049
|
VALUE name, in_res_fmt;
|
1999
|
-
VALUE error;
|
2000
2050
|
int nParams;
|
2001
2051
|
int resultFormat;
|
2002
|
-
struct query_params_data paramsData = {
|
2052
|
+
struct query_params_data paramsData = { this->enc_idx };
|
2003
2053
|
|
2004
2054
|
rb_scan_args(argc, argv, "13", &name, ¶msData.params, &in_res_fmt, ¶msData.typemap);
|
2005
2055
|
paramsData.with_types = 0;
|
2006
2056
|
|
2007
2057
|
if(NIL_P(paramsData.params)) {
|
2008
2058
|
paramsData.params = rb_ary_new2(0);
|
2009
|
-
resultFormat = 0;
|
2010
2059
|
}
|
2011
2060
|
pgconn_query_assign_typemap( self, ¶msData );
|
2012
2061
|
|
2013
2062
|
resultFormat = NIL_P(in_res_fmt) ? 0 : NUM2INT(in_res_fmt);
|
2014
2063
|
nParams = alloc_query_params( ¶msData );
|
2015
2064
|
|
2016
|
-
result = gvl_PQsendQueryPrepared(
|
2065
|
+
result = gvl_PQsendQueryPrepared(this->pgconn, pg_cstr_enc(name, paramsData.enc_idx), nParams,
|
2017
2066
|
(const char * const *)paramsData.values, paramsData.lengths, paramsData.formats,
|
2018
2067
|
resultFormat);
|
2019
2068
|
|
2020
2069
|
free_query_params( ¶msData );
|
2021
2070
|
|
2022
|
-
if(result == 0)
|
2023
|
-
|
2024
|
-
|
2025
|
-
|
2026
|
-
}
|
2071
|
+
if(result == 0)
|
2072
|
+
pg_raise_conn_error( rb_eUnableToSend, self, "%s", PQerrorMessage(this->pgconn));
|
2073
|
+
|
2074
|
+
pgconn_wait_for_flush( self );
|
2027
2075
|
return Qnil;
|
2028
2076
|
}
|
2029
2077
|
|
@@ -2037,14 +2085,12 @@ pgconn_send_query_prepared(int argc, VALUE *argv, VALUE self)
|
|
2037
2085
|
static VALUE
|
2038
2086
|
pgconn_send_describe_prepared(VALUE self, VALUE stmt_name)
|
2039
2087
|
{
|
2040
|
-
|
2041
|
-
PGconn *conn = pg_get_pgconn(self);
|
2088
|
+
t_pg_connection *this = pg_get_connection_safe( self );
|
2042
2089
|
/* returns 0 on failure */
|
2043
|
-
if(gvl_PQsendDescribePrepared(
|
2044
|
-
|
2045
|
-
|
2046
|
-
|
2047
|
-
}
|
2090
|
+
if(gvl_PQsendDescribePrepared(this->pgconn, pg_cstr_enc(stmt_name, this->enc_idx)) == 0)
|
2091
|
+
pg_raise_conn_error( rb_eUnableToSend, self, "%s", PQerrorMessage(this->pgconn));
|
2092
|
+
|
2093
|
+
pgconn_wait_for_flush( self );
|
2048
2094
|
return Qnil;
|
2049
2095
|
}
|
2050
2096
|
|
@@ -2059,36 +2105,18 @@ pgconn_send_describe_prepared(VALUE self, VALUE stmt_name)
|
|
2059
2105
|
static VALUE
|
2060
2106
|
pgconn_send_describe_portal(VALUE self, VALUE portal)
|
2061
2107
|
{
|
2062
|
-
|
2063
|
-
PGconn *conn = pg_get_pgconn(self);
|
2108
|
+
t_pg_connection *this = pg_get_connection_safe( self );
|
2064
2109
|
/* returns 0 on failure */
|
2065
|
-
if(gvl_PQsendDescribePortal(
|
2066
|
-
|
2067
|
-
|
2068
|
-
|
2069
|
-
}
|
2110
|
+
if(gvl_PQsendDescribePortal(this->pgconn, pg_cstr_enc(portal, this->enc_idx)) == 0)
|
2111
|
+
pg_raise_conn_error( rb_eUnableToSend, self, "%s", PQerrorMessage(this->pgconn));
|
2112
|
+
|
2113
|
+
pgconn_wait_for_flush( self );
|
2070
2114
|
return Qnil;
|
2071
2115
|
}
|
2072
2116
|
|
2073
2117
|
|
2074
|
-
/*
|
2075
|
-
* call-seq:
|
2076
|
-
* conn.get_result() -> PG::Result
|
2077
|
-
* conn.get_result() {|pg_result| block }
|
2078
|
-
*
|
2079
|
-
* Blocks waiting for the next result from a call to
|
2080
|
-
* #send_query (or another asynchronous command), and returns
|
2081
|
-
* it. Returns +nil+ if no more results are available.
|
2082
|
-
*
|
2083
|
-
* Note: call this function repeatedly until it returns +nil+, or else
|
2084
|
-
* you will not be able to issue further commands.
|
2085
|
-
*
|
2086
|
-
* If the optional code block is given, it will be passed <i>result</i> as an argument,
|
2087
|
-
* and the PG::Result object will automatically be cleared when the block terminates.
|
2088
|
-
* In this instance, <code>conn.exec</code> returns the value of the block.
|
2089
|
-
*/
|
2090
2118
|
static VALUE
|
2091
|
-
|
2119
|
+
pgconn_sync_get_result(VALUE self)
|
2092
2120
|
{
|
2093
2121
|
PGconn *conn = pg_get_pgconn(self);
|
2094
2122
|
PGresult *result;
|
@@ -2114,17 +2142,15 @@ pgconn_get_result(VALUE self)
|
|
2114
2142
|
* or *notifies* to see if the state has changed.
|
2115
2143
|
*/
|
2116
2144
|
static VALUE
|
2117
|
-
pgconn_consume_input(self)
|
2118
|
-
VALUE self;
|
2145
|
+
pgconn_consume_input(VALUE self)
|
2119
2146
|
{
|
2120
|
-
VALUE error;
|
2121
2147
|
PGconn *conn = pg_get_pgconn(self);
|
2122
2148
|
/* returns 0 on error */
|
2123
2149
|
if(PQconsumeInput(conn) == 0) {
|
2124
|
-
|
2125
|
-
|
2126
|
-
rb_exc_raise(error);
|
2150
|
+
pgconn_close_socket_io(self);
|
2151
|
+
pg_raise_conn_error( rb_eConnectionBad, self, "%s", PQerrorMessage(conn));
|
2127
2152
|
}
|
2153
|
+
|
2128
2154
|
return Qnil;
|
2129
2155
|
}
|
2130
2156
|
|
@@ -2133,38 +2159,20 @@ pgconn_consume_input(self)
|
|
2133
2159
|
* conn.is_busy() -> Boolean
|
2134
2160
|
*
|
2135
2161
|
* Returns +true+ if a command is busy, that is, if
|
2136
|
-
*
|
2162
|
+
* #get_result would block. Otherwise returns +false+.
|
2137
2163
|
*/
|
2138
2164
|
static VALUE
|
2139
|
-
pgconn_is_busy(self)
|
2140
|
-
VALUE self;
|
2165
|
+
pgconn_is_busy(VALUE self)
|
2141
2166
|
{
|
2142
2167
|
return gvl_PQisBusy(pg_get_pgconn(self)) ? Qtrue : Qfalse;
|
2143
2168
|
}
|
2144
2169
|
|
2145
|
-
/*
|
2146
|
-
* call-seq:
|
2147
|
-
* conn.setnonblocking(Boolean) -> nil
|
2148
|
-
*
|
2149
|
-
* Sets the nonblocking status of the connection.
|
2150
|
-
* In the blocking state, calls to #send_query
|
2151
|
-
* will block until the message is sent to the server,
|
2152
|
-
* but will not wait for the query results.
|
2153
|
-
* In the nonblocking state, calls to #send_query
|
2154
|
-
* will return an error if the socket is not ready for
|
2155
|
-
* writing.
|
2156
|
-
* Note: This function does not affect #exec, because
|
2157
|
-
* that function doesn't return until the server has
|
2158
|
-
* processed the query and returned the results.
|
2159
|
-
* Returns +nil+.
|
2160
|
-
*/
|
2161
2170
|
static VALUE
|
2162
|
-
|
2163
|
-
VALUE self, state;
|
2171
|
+
pgconn_sync_setnonblocking(VALUE self, VALUE state)
|
2164
2172
|
{
|
2165
2173
|
int arg;
|
2166
|
-
VALUE error;
|
2167
2174
|
PGconn *conn = pg_get_pgconn(self);
|
2175
|
+
rb_check_frozen(self);
|
2168
2176
|
if(state == Qtrue)
|
2169
2177
|
arg = 1;
|
2170
2178
|
else if (state == Qfalse)
|
@@ -2172,67 +2180,32 @@ pgconn_setnonblocking(self, state)
|
|
2172
2180
|
else
|
2173
2181
|
rb_raise(rb_eArgError, "Boolean value expected");
|
2174
2182
|
|
2175
|
-
if(PQsetnonblocking(conn, arg) == -1)
|
2176
|
-
|
2177
|
-
|
2178
|
-
rb_exc_raise(error);
|
2179
|
-
}
|
2183
|
+
if(PQsetnonblocking(conn, arg) == -1)
|
2184
|
+
pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(conn));
|
2185
|
+
|
2180
2186
|
return Qnil;
|
2181
2187
|
}
|
2182
2188
|
|
2183
2189
|
|
2184
|
-
/*
|
2185
|
-
* call-seq:
|
2186
|
-
* conn.isnonblocking() -> Boolean
|
2187
|
-
*
|
2188
|
-
* Returns +true+ if a command is busy, that is, if
|
2189
|
-
* PQgetResult would block. Otherwise returns +false+.
|
2190
|
-
*/
|
2191
2190
|
static VALUE
|
2192
|
-
|
2193
|
-
VALUE self;
|
2191
|
+
pgconn_sync_isnonblocking(VALUE self)
|
2194
2192
|
{
|
2195
2193
|
return PQisnonblocking(pg_get_pgconn(self)) ? Qtrue : Qfalse;
|
2196
2194
|
}
|
2197
2195
|
|
2198
|
-
/*
|
2199
|
-
* call-seq:
|
2200
|
-
* conn.flush() -> Boolean
|
2201
|
-
*
|
2202
|
-
* Attempts to flush any queued output data to the server.
|
2203
|
-
* Returns +true+ if data is successfully flushed, +false+
|
2204
|
-
* if not (can only return +false+ if connection is
|
2205
|
-
* nonblocking.
|
2206
|
-
* Raises PG::Error if some other failure occurred.
|
2207
|
-
*/
|
2208
2196
|
static VALUE
|
2209
|
-
|
2210
|
-
VALUE self;
|
2197
|
+
pgconn_sync_flush(VALUE self)
|
2211
2198
|
{
|
2212
2199
|
PGconn *conn = pg_get_pgconn(self);
|
2213
|
-
int ret;
|
2214
|
-
|
2215
|
-
|
2216
|
-
|
2217
|
-
error = rb_exc_new2(rb_ePGerror, PQerrorMessage(conn));
|
2218
|
-
rb_iv_set(error, "@connection", self);
|
2219
|
-
rb_exc_raise(error);
|
2220
|
-
}
|
2200
|
+
int ret = PQflush(conn);
|
2201
|
+
if(ret == -1)
|
2202
|
+
pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(conn));
|
2203
|
+
|
2221
2204
|
return (ret) ? Qfalse : Qtrue;
|
2222
2205
|
}
|
2223
2206
|
|
2224
|
-
/*
|
2225
|
-
* call-seq:
|
2226
|
-
* conn.cancel() -> String
|
2227
|
-
*
|
2228
|
-
* Requests cancellation of the command currently being
|
2229
|
-
* processed. (Only implemented in PostgreSQL >= 8.0)
|
2230
|
-
*
|
2231
|
-
* Returns +nil+ on success, or a string containing the
|
2232
|
-
* error message if a failure occurs.
|
2233
|
-
*/
|
2234
2207
|
static VALUE
|
2235
|
-
|
2208
|
+
pgconn_sync_cancel(VALUE self)
|
2236
2209
|
{
|
2237
2210
|
char errbuf[256];
|
2238
2211
|
PGcancel *cancel;
|
@@ -2241,9 +2214,9 @@ pgconn_cancel(VALUE self)
|
|
2241
2214
|
|
2242
2215
|
cancel = PQgetCancel(pg_get_pgconn(self));
|
2243
2216
|
if(cancel == NULL)
|
2244
|
-
|
2217
|
+
pg_raise_conn_error( rb_ePGerror, self, "Invalid connection!");
|
2245
2218
|
|
2246
|
-
ret = gvl_PQcancel(cancel, errbuf,
|
2219
|
+
ret = gvl_PQcancel(cancel, errbuf, sizeof(errbuf));
|
2247
2220
|
if(ret == 1)
|
2248
2221
|
retval = Qnil;
|
2249
2222
|
else
|
@@ -2264,7 +2237,7 @@ pgconn_cancel(VALUE self)
|
|
2264
2237
|
static VALUE
|
2265
2238
|
pgconn_notifies(VALUE self)
|
2266
2239
|
{
|
2267
|
-
|
2240
|
+
t_pg_connection *this = pg_get_connection_safe( self );
|
2268
2241
|
PGnotify *notification;
|
2269
2242
|
VALUE hash;
|
2270
2243
|
VALUE sym_relname, sym_be_pid, sym_extra;
|
@@ -2274,17 +2247,17 @@ pgconn_notifies(VALUE self)
|
|
2274
2247
|
sym_be_pid = ID2SYM(rb_intern("be_pid"));
|
2275
2248
|
sym_extra = ID2SYM(rb_intern("extra"));
|
2276
2249
|
|
2277
|
-
notification = gvl_PQnotifies(
|
2250
|
+
notification = gvl_PQnotifies(this->pgconn);
|
2278
2251
|
if (notification == NULL) {
|
2279
2252
|
return Qnil;
|
2280
2253
|
}
|
2281
2254
|
|
2282
2255
|
hash = rb_hash_new();
|
2283
|
-
relname =
|
2256
|
+
relname = rb_str_new2(notification->relname);
|
2284
2257
|
be_pid = INT2NUM(notification->be_pid);
|
2285
|
-
extra =
|
2286
|
-
PG_ENCODING_SET_NOCHECK( relname,
|
2287
|
-
PG_ENCODING_SET_NOCHECK( extra,
|
2258
|
+
extra = rb_str_new2(notification->extra);
|
2259
|
+
PG_ENCODING_SET_NOCHECK( relname, this->enc_idx );
|
2260
|
+
PG_ENCODING_SET_NOCHECK( extra, this->enc_idx );
|
2288
2261
|
|
2289
2262
|
rb_hash_aset(hash, sym_relname, relname);
|
2290
2263
|
rb_hash_aset(hash, sym_be_pid, be_pid);
|
@@ -2294,59 +2267,72 @@ pgconn_notifies(VALUE self)
|
|
2294
2267
|
return hash;
|
2295
2268
|
}
|
2296
2269
|
|
2297
|
-
|
2298
|
-
|
2299
|
-
|
2300
|
-
|
2301
|
-
|
2270
|
+
#ifndef HAVE_RB_IO_DESCRIPTOR
|
2271
|
+
static int
|
2272
|
+
rb_io_descriptor(VALUE io)
|
2273
|
+
{
|
2274
|
+
Check_Type(io, T_FILE);
|
2275
|
+
rb_io_t *fptr = RFILE(io)->fptr;
|
2276
|
+
rb_io_check_closed(fptr);
|
2277
|
+
return fptr->fd;
|
2278
|
+
}
|
2279
|
+
#endif
|
2280
|
+
|
2281
|
+
#if defined(_WIN32)
|
2282
|
+
|
2283
|
+
/* We use a specialized implementation of rb_io_wait() on Windows.
|
2284
|
+
* This is because rb_io_wait() and rb_wait_for_single_fd() are very slow on Windows.
|
2302
2285
|
*/
|
2303
2286
|
|
2287
|
+
#if defined(HAVE_RUBY_FIBER_SCHEDULER_H)
|
2288
|
+
#include <ruby/fiber/scheduler.h>
|
2289
|
+
#endif
|
2290
|
+
|
2291
|
+
typedef enum {
|
2292
|
+
PG_RUBY_IO_READABLE = RB_WAITFD_IN,
|
2293
|
+
PG_RUBY_IO_WRITABLE = RB_WAITFD_OUT,
|
2294
|
+
PG_RUBY_IO_PRIORITY = RB_WAITFD_PRI,
|
2295
|
+
} pg_rb_io_event_t;
|
2296
|
+
|
2304
2297
|
int rb_w32_wait_events( HANDLE *events, int num, DWORD timeout );
|
2305
2298
|
|
2306
|
-
|
2307
|
-
|
2308
|
-
|
2299
|
+
static VALUE
|
2300
|
+
pg_rb_thread_io_wait(VALUE io, VALUE events, VALUE timeout) {
|
2301
|
+
struct timeval ptimeout;
|
2309
2302
|
|
2310
|
-
static void *
|
2311
|
-
wait_socket_readable( PGconn *conn, struct timeval *ptimeout, void *(*is_readable)(PGconn *) )
|
2312
|
-
{
|
2313
|
-
int sd = PQsocket( conn );
|
2314
|
-
void *retval;
|
2315
2303
|
struct timeval aborttime={0,0}, currtime, waittime;
|
2316
2304
|
DWORD timeout_milisec = INFINITE;
|
2317
|
-
|
2318
|
-
WSAEVENT hEvent;
|
2319
|
-
|
2320
|
-
if ( sd < 0 )
|
2321
|
-
rb_raise(rb_eConnectionBad, "PQsocket() can't get socket descriptor");
|
2305
|
+
HANDLE hEvent = WSACreateEvent();
|
2322
2306
|
|
2323
|
-
|
2307
|
+
long rb_events = NUM2UINT(events);
|
2308
|
+
long w32_events = 0;
|
2309
|
+
DWORD wait_ret;
|
2324
2310
|
|
2325
|
-
|
2326
|
-
|
2327
|
-
|
2328
|
-
rb_raise( rb_eConnectionBad, "PQconsumeInput() %s", PQerrorMessage(conn) );
|
2329
|
-
}
|
2311
|
+
if( !NIL_P(timeout) ){
|
2312
|
+
ptimeout.tv_sec = (time_t)(NUM2DBL(timeout));
|
2313
|
+
ptimeout.tv_usec = (time_t)((NUM2DBL(timeout) - (double)ptimeout.tv_sec) * 1e6);
|
2330
2314
|
|
2331
|
-
if ( ptimeout ) {
|
2332
2315
|
gettimeofday(&currtime, NULL);
|
2333
|
-
timeradd(&currtime, ptimeout, &aborttime);
|
2316
|
+
timeradd(&currtime, &ptimeout, &aborttime);
|
2334
2317
|
}
|
2335
2318
|
|
2336
|
-
|
2337
|
-
|
2319
|
+
if(rb_events & PG_RUBY_IO_READABLE) w32_events |= FD_READ | FD_ACCEPT | FD_CLOSE;
|
2320
|
+
if(rb_events & PG_RUBY_IO_WRITABLE) w32_events |= FD_WRITE | FD_CONNECT;
|
2321
|
+
if(rb_events & PG_RUBY_IO_PRIORITY) w32_events |= FD_OOB;
|
2322
|
+
|
2323
|
+
for(;;) {
|
2324
|
+
if ( WSAEventSelect(_get_osfhandle(rb_io_descriptor(io)), hEvent, w32_events) == SOCKET_ERROR ) {
|
2338
2325
|
WSACloseEvent( hEvent );
|
2339
2326
|
rb_raise( rb_eConnectionBad, "WSAEventSelect socket error: %d", WSAGetLastError() );
|
2340
2327
|
}
|
2341
2328
|
|
2342
|
-
if (
|
2329
|
+
if ( !NIL_P(timeout) ) {
|
2343
2330
|
gettimeofday(&currtime, NULL);
|
2344
2331
|
timersub(&aborttime, &currtime, &waittime);
|
2345
2332
|
timeout_milisec = (DWORD)( waittime.tv_sec * 1e3 + waittime.tv_usec / 1e3 );
|
2346
2333
|
}
|
2347
2334
|
|
2348
|
-
|
2349
|
-
if( !ptimeout || (waittime.tv_sec >= 0 && waittime.tv_usec >= 0) ){
|
2335
|
+
if( NIL_P(timeout) || (waittime.tv_sec >= 0 && waittime.tv_usec >= 0) ){
|
2350
2336
|
/* Wait for the socket to become readable before checking again */
|
2351
2337
|
wait_ret = rb_w32_wait_events( &hEvent, 1, timeout_milisec );
|
2352
2338
|
} else {
|
@@ -2355,9 +2341,11 @@ wait_socket_readable( PGconn *conn, struct timeval *ptimeout, void *(*is_readabl
|
|
2355
2341
|
|
2356
2342
|
if ( wait_ret == WAIT_TIMEOUT ) {
|
2357
2343
|
WSACloseEvent( hEvent );
|
2358
|
-
return
|
2344
|
+
return UINT2NUM(0);
|
2359
2345
|
} else if ( wait_ret == WAIT_OBJECT_0 ) {
|
2346
|
+
WSACloseEvent( hEvent );
|
2360
2347
|
/* The event we were waiting for. */
|
2348
|
+
return UINT2NUM(rb_events);
|
2361
2349
|
} else if ( wait_ret == WAIT_OBJECT_0 + 1) {
|
2362
2350
|
/* This indicates interruption from timer thread, GC, exception
|
2363
2351
|
* from other threads etc... */
|
@@ -2369,39 +2357,64 @@ wait_socket_readable( PGconn *conn, struct timeval *ptimeout, void *(*is_readabl
|
|
2369
2357
|
WSACloseEvent( hEvent );
|
2370
2358
|
rb_raise( rb_eConnectionBad, "Wait on socket abandoned (WaitForMultipleObjects)" );
|
2371
2359
|
}
|
2372
|
-
|
2373
|
-
/* Check for connection errors (PQisBusy is true on connection errors) */
|
2374
|
-
if ( PQconsumeInput(conn) == 0 ) {
|
2375
|
-
WSACloseEvent( hEvent );
|
2376
|
-
rb_raise( rb_eConnectionBad, "PQconsumeInput() %s", PQerrorMessage(conn) );
|
2377
|
-
}
|
2378
2360
|
}
|
2361
|
+
}
|
2379
2362
|
|
2380
|
-
|
2381
|
-
|
2363
|
+
static VALUE
|
2364
|
+
pg_rb_io_wait(VALUE io, VALUE events, VALUE timeout) {
|
2365
|
+
#if defined(HAVE_RUBY_FIBER_SCHEDULER_H)
|
2366
|
+
/* We don't support Fiber.scheduler on Windows ruby-3.0 because there is no fast way to check whether a scheduler is active.
|
2367
|
+
* Fortunately ruby-3.1 offers a C-API for it.
|
2368
|
+
*/
|
2369
|
+
VALUE scheduler = rb_fiber_scheduler_current();
|
2370
|
+
|
2371
|
+
if (!NIL_P(scheduler)) {
|
2372
|
+
return rb_io_wait(io, events, timeout);
|
2373
|
+
}
|
2374
|
+
#endif
|
2375
|
+
return pg_rb_thread_io_wait(io, events, timeout);
|
2382
2376
|
}
|
2383
2377
|
|
2378
|
+
#elif defined(HAVE_RB_IO_WAIT)
|
2379
|
+
|
2380
|
+
/* Use our own function and constants names, to avoid conflicts with truffleruby-head on its road to ruby-3.0 compatibility. */
|
2381
|
+
#define pg_rb_io_wait rb_io_wait
|
2382
|
+
#define PG_RUBY_IO_READABLE RUBY_IO_READABLE
|
2383
|
+
#define PG_RUBY_IO_WRITABLE RUBY_IO_WRITABLE
|
2384
|
+
#define PG_RUBY_IO_PRIORITY RUBY_IO_PRIORITY
|
2385
|
+
|
2384
2386
|
#else
|
2387
|
+
/* For compat with ruby < 3.0 */
|
2388
|
+
|
2389
|
+
typedef enum {
|
2390
|
+
PG_RUBY_IO_READABLE = RB_WAITFD_IN,
|
2391
|
+
PG_RUBY_IO_WRITABLE = RB_WAITFD_OUT,
|
2392
|
+
PG_RUBY_IO_PRIORITY = RB_WAITFD_PRI,
|
2393
|
+
} pg_rb_io_event_t;
|
2394
|
+
|
2395
|
+
static VALUE
|
2396
|
+
pg_rb_io_wait(VALUE io, VALUE events, VALUE timeout) {
|
2397
|
+
struct timeval waittime;
|
2398
|
+
int res;
|
2399
|
+
|
2400
|
+
if( !NIL_P(timeout) ){
|
2401
|
+
waittime.tv_sec = (time_t)(NUM2DBL(timeout));
|
2402
|
+
waittime.tv_usec = (time_t)((NUM2DBL(timeout) - (double)waittime.tv_sec) * 1e6);
|
2403
|
+
}
|
2404
|
+
res = rb_wait_for_single_fd(rb_io_descriptor(io), NUM2UINT(events), NIL_P(timeout) ? NULL : &waittime);
|
2385
2405
|
|
2386
|
-
|
2406
|
+
return UINT2NUM(res);
|
2407
|
+
}
|
2408
|
+
#endif
|
2387
2409
|
|
2388
2410
|
static void *
|
2389
|
-
wait_socket_readable(
|
2411
|
+
wait_socket_readable( VALUE self, struct timeval *ptimeout, void *(*is_readable)(PGconn *))
|
2390
2412
|
{
|
2391
|
-
|
2392
|
-
int ret;
|
2413
|
+
VALUE ret;
|
2393
2414
|
void *retval;
|
2394
|
-
rb_fdset_t sd_rset;
|
2395
2415
|
struct timeval aborttime={0,0}, currtime, waittime;
|
2396
|
-
|
2397
|
-
|
2398
|
-
rb_raise(rb_eConnectionBad, "PQsocket() can't get socket descriptor");
|
2399
|
-
|
2400
|
-
/* Check for connection errors (PQisBusy is true on connection errors) */
|
2401
|
-
if ( PQconsumeInput(conn) == 0 )
|
2402
|
-
rb_raise( rb_eConnectionBad, "PQconsumeInput() %s", PQerrorMessage(conn) );
|
2403
|
-
|
2404
|
-
rb_fd_init( &sd_rset );
|
2416
|
+
VALUE wait_timeout = Qnil;
|
2417
|
+
PGconn *conn = pg_get_pgconn(self);
|
2405
2418
|
|
2406
2419
|
if ( ptimeout ) {
|
2407
2420
|
gettimeofday(&currtime, NULL);
|
@@ -2409,46 +2422,84 @@ wait_socket_readable( PGconn *conn, struct timeval *ptimeout, void *(*is_readabl
|
|
2409
2422
|
}
|
2410
2423
|
|
2411
2424
|
while ( !(retval=is_readable(conn)) ) {
|
2412
|
-
rb_fd_zero( &sd_rset );
|
2413
|
-
rb_fd_set( sd, &sd_rset );
|
2414
|
-
|
2415
2425
|
if ( ptimeout ) {
|
2416
2426
|
gettimeofday(&currtime, NULL);
|
2417
2427
|
timersub(&aborttime, &currtime, &waittime);
|
2428
|
+
wait_timeout = DBL2NUM((double)(waittime.tv_sec) + (double)(waittime.tv_usec) / 1000000.0);
|
2418
2429
|
}
|
2419
2430
|
|
2420
2431
|
/* Is the given timeout valid? */
|
2421
2432
|
if( !ptimeout || (waittime.tv_sec >= 0 && waittime.tv_usec >= 0) ){
|
2433
|
+
VALUE socket_io;
|
2434
|
+
|
2435
|
+
/* before we wait for data, make sure everything has been sent */
|
2436
|
+
pgconn_async_flush(self);
|
2437
|
+
if ((retval=is_readable(conn)))
|
2438
|
+
return retval;
|
2439
|
+
|
2440
|
+
socket_io = pgconn_socket_io(self);
|
2422
2441
|
/* Wait for the socket to become readable before checking again */
|
2423
|
-
ret =
|
2442
|
+
ret = pg_rb_io_wait(socket_io, RB_INT2NUM(PG_RUBY_IO_READABLE), wait_timeout);
|
2424
2443
|
} else {
|
2425
|
-
ret =
|
2426
|
-
}
|
2427
|
-
|
2428
|
-
if ( ret < 0 ){
|
2429
|
-
rb_fd_term( &sd_rset );
|
2430
|
-
rb_sys_fail( "rb_thread_select()" );
|
2444
|
+
ret = Qfalse;
|
2431
2445
|
}
|
2432
2446
|
|
2433
2447
|
/* Return false if the select() timed out */
|
2434
|
-
if ( ret ==
|
2435
|
-
rb_fd_term( &sd_rset );
|
2448
|
+
if ( ret == Qfalse ){
|
2436
2449
|
return NULL;
|
2437
2450
|
}
|
2438
2451
|
|
2439
2452
|
/* Check for connection errors (PQisBusy is true on connection errors) */
|
2440
2453
|
if ( PQconsumeInput(conn) == 0 ){
|
2441
|
-
|
2442
|
-
|
2454
|
+
pgconn_close_socket_io(self);
|
2455
|
+
pg_raise_conn_error(rb_eConnectionBad, self, "PQconsumeInput() %s", PQerrorMessage(conn));
|
2443
2456
|
}
|
2444
2457
|
}
|
2445
2458
|
|
2446
|
-
rb_fd_term( &sd_rset );
|
2447
2459
|
return retval;
|
2448
2460
|
}
|
2449
2461
|
|
2462
|
+
/*
|
2463
|
+
* call-seq:
|
2464
|
+
* conn.flush() -> Boolean
|
2465
|
+
*
|
2466
|
+
* Attempts to flush any queued output data to the server.
|
2467
|
+
* Returns +true+ if data is successfully flushed, +false+
|
2468
|
+
* if not. It can only return +false+ if connection is
|
2469
|
+
* in nonblocking mode.
|
2470
|
+
* Raises PG::Error if some other failure occurred.
|
2471
|
+
*/
|
2472
|
+
static VALUE
|
2473
|
+
pgconn_async_flush(VALUE self)
|
2474
|
+
{
|
2475
|
+
while( pgconn_sync_flush(self) == Qfalse ){
|
2476
|
+
/* wait for the socket to become read- or write-ready */
|
2477
|
+
int events;
|
2478
|
+
VALUE socket_io = pgconn_socket_io(self);
|
2479
|
+
events = RB_NUM2INT(pg_rb_io_wait(socket_io, RB_INT2NUM(PG_RUBY_IO_READABLE | PG_RUBY_IO_WRITABLE), Qnil));
|
2480
|
+
|
2481
|
+
if (events & PG_RUBY_IO_READABLE){
|
2482
|
+
pgconn_consume_input(self);
|
2483
|
+
}
|
2484
|
+
}
|
2485
|
+
return Qtrue;
|
2486
|
+
}
|
2487
|
+
|
2488
|
+
static VALUE
|
2489
|
+
pgconn_wait_for_flush( VALUE self ){
|
2490
|
+
if( !pg_get_connection_safe(self)->flush_data )
|
2491
|
+
return Qnil;
|
2492
|
+
|
2493
|
+
return pgconn_async_flush(self);
|
2494
|
+
}
|
2450
2495
|
|
2451
|
-
|
2496
|
+
static VALUE
|
2497
|
+
pgconn_flush_data_set( VALUE self, VALUE enabled ){
|
2498
|
+
t_pg_connection *conn = pg_get_connection(self);
|
2499
|
+
rb_check_frozen(self);
|
2500
|
+
conn->flush_data = RTEST(enabled);
|
2501
|
+
return enabled;
|
2502
|
+
}
|
2452
2503
|
|
2453
2504
|
static void *
|
2454
2505
|
notify_readable(PGconn *conn)
|
@@ -2458,27 +2509,20 @@ notify_readable(PGconn *conn)
|
|
2458
2509
|
|
2459
2510
|
/*
|
2460
2511
|
* call-seq:
|
2461
|
-
* conn.wait_for_notify( [ timeout ] ) -> String
|
2462
|
-
* conn.wait_for_notify( [ timeout ] ) { |event, pid| block }
|
2463
|
-
* conn.wait_for_notify( [ timeout ] ) { |event, pid, payload| block } # PostgreSQL 9.0
|
2512
|
+
* conn.wait_for_notify( [ timeout ] ) { |event, pid, payload| block } -> String
|
2464
2513
|
*
|
2465
2514
|
* Blocks while waiting for notification(s), or until the optional
|
2466
2515
|
* _timeout_ is reached, whichever comes first. _timeout_ is
|
2467
2516
|
* measured in seconds and can be fractional.
|
2468
2517
|
*
|
2469
|
-
* Returns +nil+ if _timeout_ is reached, the name of the NOTIFY
|
2470
|
-
*
|
2471
|
-
*
|
2472
|
-
*
|
2473
|
-
* Under PostgreSQL 9.0 and later, if the notification is sent with
|
2474
|
-
* the optional +payload+ string, it will be given to the block as the
|
2475
|
-
* third argument.
|
2476
|
-
*
|
2518
|
+
* Returns +nil+ if _timeout_ is reached, the name of the NOTIFY event otherwise.
|
2519
|
+
* If used in block form, passes the name of the NOTIFY +event+, the generating
|
2520
|
+
* +pid+ and the optional +payload+ string into the block.
|
2477
2521
|
*/
|
2478
2522
|
static VALUE
|
2479
2523
|
pgconn_wait_for_notify(int argc, VALUE *argv, VALUE self)
|
2480
2524
|
{
|
2481
|
-
|
2525
|
+
t_pg_connection *this = pg_get_connection_safe( self );
|
2482
2526
|
PGnotify *pnotification;
|
2483
2527
|
struct timeval timeout;
|
2484
2528
|
struct timeval *ptimeout = NULL;
|
@@ -2494,17 +2538,17 @@ pgconn_wait_for_notify(int argc, VALUE *argv, VALUE self)
|
|
2494
2538
|
ptimeout = &timeout;
|
2495
2539
|
}
|
2496
2540
|
|
2497
|
-
pnotification = (PGnotify*) wait_socket_readable(
|
2541
|
+
pnotification = (PGnotify*) wait_socket_readable( self, ptimeout, notify_readable);
|
2498
2542
|
|
2499
2543
|
/* Return nil if the select timed out */
|
2500
2544
|
if ( !pnotification ) return Qnil;
|
2501
2545
|
|
2502
|
-
relname =
|
2503
|
-
PG_ENCODING_SET_NOCHECK( relname,
|
2546
|
+
relname = rb_str_new2( pnotification->relname );
|
2547
|
+
PG_ENCODING_SET_NOCHECK( relname, this->enc_idx );
|
2504
2548
|
be_pid = INT2NUM( pnotification->be_pid );
|
2505
2549
|
if ( *pnotification->extra ) {
|
2506
|
-
extra =
|
2507
|
-
PG_ENCODING_SET_NOCHECK( extra,
|
2550
|
+
extra = rb_str_new2( pnotification->extra );
|
2551
|
+
PG_ENCODING_SET_NOCHECK( extra, this->enc_idx );
|
2508
2552
|
}
|
2509
2553
|
PQfreemem( pnotification );
|
2510
2554
|
|
@@ -2515,28 +2559,8 @@ pgconn_wait_for_notify(int argc, VALUE *argv, VALUE self)
|
|
2515
2559
|
}
|
2516
2560
|
|
2517
2561
|
|
2518
|
-
/*
|
2519
|
-
* call-seq:
|
2520
|
-
* conn.put_copy_data( buffer [, encoder] ) -> Boolean
|
2521
|
-
*
|
2522
|
-
* Transmits _buffer_ as copy data to the server.
|
2523
|
-
* Returns true if the data was sent, false if it was
|
2524
|
-
* not sent (false is only possible if the connection
|
2525
|
-
* is in nonblocking mode, and this command would block).
|
2526
|
-
*
|
2527
|
-
* _encoder_ can be a PG::Coder derivation (typically PG::TextEncoder::CopyRow).
|
2528
|
-
* This encodes the data fields given as _buffer_ from an Array of Strings to
|
2529
|
-
* PostgreSQL's COPY text format inclusive proper escaping. Optionally
|
2530
|
-
* the encoder can type cast the fields from various Ruby types in one step,
|
2531
|
-
* if PG::TextEncoder::CopyRow#type_map is set accordingly.
|
2532
|
-
*
|
2533
|
-
* Raises an exception if an error occurs.
|
2534
|
-
*
|
2535
|
-
* See also #copy_data.
|
2536
|
-
*
|
2537
|
-
*/
|
2538
2562
|
static VALUE
|
2539
|
-
|
2563
|
+
pgconn_sync_put_copy_data(int argc, VALUE *argv, VALUE self)
|
2540
2564
|
{
|
2541
2565
|
int ret;
|
2542
2566
|
int len;
|
@@ -2553,18 +2577,16 @@ pgconn_put_copy_data(int argc, VALUE *argv, VALUE self)
|
|
2553
2577
|
if( NIL_P(this->encoder_for_put_copy_data) ){
|
2554
2578
|
buffer = value;
|
2555
2579
|
} else {
|
2556
|
-
p_coder =
|
2580
|
+
p_coder = RTYPEDDATA_DATA( this->encoder_for_put_copy_data );
|
2557
2581
|
}
|
2558
|
-
} else if( rb_obj_is_kind_of(encoder, rb_cPG_Coder) ) {
|
2559
|
-
Data_Get_Struct( encoder, t_pg_coder, p_coder );
|
2560
2582
|
} else {
|
2561
|
-
|
2562
|
-
|
2583
|
+
/* Check argument type and use argument encoder */
|
2584
|
+
TypedData_Get_Struct(encoder, t_pg_coder, &pg_coder_type, p_coder);
|
2563
2585
|
}
|
2564
2586
|
|
2565
2587
|
if( p_coder ){
|
2566
2588
|
t_pg_coder_enc_func enc_func;
|
2567
|
-
int enc_idx =
|
2589
|
+
int enc_idx = this->enc_idx;
|
2568
2590
|
|
2569
2591
|
enc_func = pg_coder_enc_func( p_coder );
|
2570
2592
|
len = enc_func( p_coder, value, NULL, &intermediate, enc_idx);
|
@@ -2582,76 +2604,39 @@ pgconn_put_copy_data(int argc, VALUE *argv, VALUE self)
|
|
2582
2604
|
Check_Type(buffer, T_STRING);
|
2583
2605
|
|
2584
2606
|
ret = gvl_PQputCopyData(this->pgconn, RSTRING_PTR(buffer), RSTRING_LENINT(buffer));
|
2585
|
-
if(ret == -1)
|
2586
|
-
|
2587
|
-
|
2588
|
-
rb_exc_raise(error);
|
2589
|
-
}
|
2607
|
+
if(ret == -1)
|
2608
|
+
pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(this->pgconn));
|
2609
|
+
|
2590
2610
|
RB_GC_GUARD(intermediate);
|
2591
2611
|
RB_GC_GUARD(buffer);
|
2592
2612
|
|
2593
2613
|
return (ret) ? Qtrue : Qfalse;
|
2594
2614
|
}
|
2595
2615
|
|
2596
|
-
/*
|
2597
|
-
* call-seq:
|
2598
|
-
* conn.put_copy_end( [ error_message ] ) -> Boolean
|
2599
|
-
*
|
2600
|
-
* Sends end-of-data indication to the server.
|
2601
|
-
*
|
2602
|
-
* _error_message_ is an optional parameter, and if set,
|
2603
|
-
* forces the COPY command to fail with the string
|
2604
|
-
* _error_message_.
|
2605
|
-
*
|
2606
|
-
* Returns true if the end-of-data was sent, false if it was
|
2607
|
-
* not sent (false is only possible if the connection
|
2608
|
-
* is in nonblocking mode, and this command would block).
|
2609
|
-
*/
|
2610
2616
|
static VALUE
|
2611
|
-
|
2617
|
+
pgconn_sync_put_copy_end(int argc, VALUE *argv, VALUE self)
|
2612
2618
|
{
|
2613
2619
|
VALUE str;
|
2614
|
-
VALUE error;
|
2615
2620
|
int ret;
|
2616
2621
|
const char *error_message = NULL;
|
2617
|
-
|
2622
|
+
t_pg_connection *this = pg_get_connection_safe( self );
|
2618
2623
|
|
2619
2624
|
if (rb_scan_args(argc, argv, "01", &str) == 0)
|
2620
2625
|
error_message = NULL;
|
2621
2626
|
else
|
2622
|
-
error_message = pg_cstr_enc(str,
|
2627
|
+
error_message = pg_cstr_enc(str, this->enc_idx);
|
2628
|
+
|
2629
|
+
ret = gvl_PQputCopyEnd(this->pgconn, error_message);
|
2630
|
+
if(ret == -1)
|
2631
|
+
pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(this->pgconn));
|
2623
2632
|
|
2624
|
-
ret = gvl_PQputCopyEnd(conn, error_message);
|
2625
|
-
if(ret == -1) {
|
2626
|
-
error = rb_exc_new2(rb_ePGerror, PQerrorMessage(conn));
|
2627
|
-
rb_iv_set(error, "@connection", self);
|
2628
|
-
rb_exc_raise(error);
|
2629
|
-
}
|
2630
2633
|
return (ret) ? Qtrue : Qfalse;
|
2631
2634
|
}
|
2632
2635
|
|
2633
|
-
/*
|
2634
|
-
* call-seq:
|
2635
|
-
* conn.get_copy_data( [ async = false [, decoder = nil ]] ) -> String
|
2636
|
-
*
|
2637
|
-
* Return a string containing one row of data, +nil+
|
2638
|
-
* if the copy is done, or +false+ if the call would
|
2639
|
-
* block (only possible if _async_ is true).
|
2640
|
-
*
|
2641
|
-
* _decoder_ can be a PG::Coder derivation (typically PG::TextDecoder::CopyRow).
|
2642
|
-
* This decodes the received data fields from PostgreSQL's COPY text format to an
|
2643
|
-
* Array of Strings. Optionally
|
2644
|
-
* the decoder can type cast the fields to various Ruby types in one step,
|
2645
|
-
* if PG::TextDecoder::CopyRow#type_map is set accordingly.
|
2646
|
-
*
|
2647
|
-
* See also #copy_data.
|
2648
|
-
*
|
2649
|
-
*/
|
2650
2636
|
static VALUE
|
2651
|
-
|
2637
|
+
pgconn_sync_get_copy_data(int argc, VALUE *argv, VALUE self )
|
2652
2638
|
{
|
2653
2639
|
VALUE async_in;
|
2654
|
-
VALUE error;
|
2655
2640
|
VALUE result;
|
2656
2641
|
int ret;
|
2657
2642
|
char *buffer;
|
@@ -2663,20 +2648,16 @@ pgconn_get_copy_data(int argc, VALUE *argv, VALUE self )
|
|
2663
2648
|
|
2664
2649
|
if( NIL_P(decoder) ){
|
2665
2650
|
if( !NIL_P(this->decoder_for_get_copy_data) ){
|
2666
|
-
p_coder =
|
2651
|
+
p_coder = RTYPEDDATA_DATA( this->decoder_for_get_copy_data );
|
2667
2652
|
}
|
2668
|
-
} else if( rb_obj_is_kind_of(decoder, rb_cPG_Coder) ) {
|
2669
|
-
Data_Get_Struct( decoder, t_pg_coder, p_coder );
|
2670
2653
|
} else {
|
2671
|
-
|
2672
|
-
|
2654
|
+
/* Check argument type and use argument decoder */
|
2655
|
+
TypedData_Get_Struct(decoder, t_pg_coder, &pg_coder_type, p_coder);
|
2673
2656
|
}
|
2674
2657
|
|
2675
2658
|
ret = gvl_PQgetCopyData(this->pgconn, &buffer, RTEST(async_in));
|
2676
|
-
if(ret == -2)
|
2677
|
-
|
2678
|
-
rb_iv_set(error, "@connection", self);
|
2679
|
-
rb_exc_raise(error);
|
2659
|
+
if(ret == -2){ /* error */
|
2660
|
+
pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(this->pgconn));
|
2680
2661
|
}
|
2681
2662
|
if(ret == -1) { /* No data left */
|
2682
2663
|
return Qnil;
|
@@ -2687,9 +2668,9 @@ pgconn_get_copy_data(int argc, VALUE *argv, VALUE self )
|
|
2687
2668
|
|
2688
2669
|
if( p_coder ){
|
2689
2670
|
t_pg_coder_dec_func dec_func = pg_coder_dec_func( p_coder, p_coder->format );
|
2690
|
-
result = dec_func( p_coder, buffer, ret, 0, 0,
|
2671
|
+
result = dec_func( p_coder, buffer, ret, 0, 0, this->enc_idx );
|
2691
2672
|
} else {
|
2692
|
-
result =
|
2673
|
+
result = rb_str_new(buffer, ret);
|
2693
2674
|
}
|
2694
2675
|
|
2695
2676
|
PQfreemem(buffer);
|
@@ -2702,9 +2683,16 @@ pgconn_get_copy_data(int argc, VALUE *argv, VALUE self )
|
|
2702
2683
|
*
|
2703
2684
|
* Sets connection's verbosity to _verbosity_ and returns
|
2704
2685
|
* the previous setting. Available settings are:
|
2686
|
+
*
|
2705
2687
|
* * PQERRORS_TERSE
|
2706
2688
|
* * PQERRORS_DEFAULT
|
2707
2689
|
* * PQERRORS_VERBOSE
|
2690
|
+
* * PQERRORS_SQLSTATE
|
2691
|
+
*
|
2692
|
+
* Changing the verbosity does not affect the messages available from already-existing PG::Result objects, only subsequently-created ones.
|
2693
|
+
* (But see PG::Result#verbose_error_message if you want to print a previous error with a different verbosity.)
|
2694
|
+
*
|
2695
|
+
* See also corresponding {libpq function}[https://www.postgresql.org/docs/current/libpq-control.html#LIBPQ-PQSETERRORVERBOSITY].
|
2708
2696
|
*/
|
2709
2697
|
static VALUE
|
2710
2698
|
pgconn_set_error_verbosity(VALUE self, VALUE in_verbosity)
|
@@ -2714,6 +2702,37 @@ pgconn_set_error_verbosity(VALUE self, VALUE in_verbosity)
|
|
2714
2702
|
return INT2FIX(PQsetErrorVerbosity(conn, verbosity));
|
2715
2703
|
}
|
2716
2704
|
|
2705
|
+
#ifdef HAVE_PQRESULTVERBOSEERRORMESSAGE
|
2706
|
+
/*
|
2707
|
+
* call-seq:
|
2708
|
+
* conn.set_error_context_visibility( context_visibility ) -> Integer
|
2709
|
+
*
|
2710
|
+
* Sets connection's context display mode to _context_visibility_ and returns
|
2711
|
+
* the previous setting. Available settings are:
|
2712
|
+
* * PQSHOW_CONTEXT_NEVER
|
2713
|
+
* * PQSHOW_CONTEXT_ERRORS
|
2714
|
+
* * PQSHOW_CONTEXT_ALWAYS
|
2715
|
+
*
|
2716
|
+
* This mode controls whether the CONTEXT field is included in messages (unless the verbosity setting is TERSE, in which case CONTEXT is never shown).
|
2717
|
+
* The NEVER mode never includes CONTEXT, while ALWAYS always includes it if available.
|
2718
|
+
* In ERRORS mode (the default), CONTEXT fields are included only for error messages, not for notices and warnings.
|
2719
|
+
*
|
2720
|
+
* Changing this mode does not affect the messages available from already-existing PG::Result objects, only subsequently-created ones.
|
2721
|
+
* (But see PG::Result#verbose_error_message if you want to print a previous error with a different display mode.)
|
2722
|
+
*
|
2723
|
+
* See also corresponding {libpq function}[https://www.postgresql.org/docs/current/libpq-control.html#LIBPQ-PQSETERRORCONTEXTVISIBILITY].
|
2724
|
+
*
|
2725
|
+
* Available since PostgreSQL-9.6
|
2726
|
+
*/
|
2727
|
+
static VALUE
|
2728
|
+
pgconn_set_error_context_visibility(VALUE self, VALUE in_context_visibility)
|
2729
|
+
{
|
2730
|
+
PGconn *conn = pg_get_pgconn(self);
|
2731
|
+
PGContextVisibility context_visibility = NUM2INT(in_context_visibility);
|
2732
|
+
return INT2FIX(PQsetErrorContextVisibility(conn, context_visibility));
|
2733
|
+
}
|
2734
|
+
#endif
|
2735
|
+
|
2717
2736
|
/*
|
2718
2737
|
* call-seq:
|
2719
2738
|
* conn.trace( stream ) -> nil
|
@@ -2732,7 +2751,8 @@ pgconn_trace(VALUE self, VALUE stream)
|
|
2732
2751
|
VALUE new_file;
|
2733
2752
|
t_pg_connection *this = pg_get_connection_safe( self );
|
2734
2753
|
|
2735
|
-
|
2754
|
+
rb_check_frozen(self);
|
2755
|
+
if(!rb_respond_to(stream,rb_intern("fileno")))
|
2736
2756
|
rb_raise(rb_eArgError, "stream does not respond to method: fileno");
|
2737
2757
|
|
2738
2758
|
fileno = rb_funcall(stream, rb_intern("fileno"), 0);
|
@@ -2753,7 +2773,7 @@ pgconn_trace(VALUE self, VALUE stream)
|
|
2753
2773
|
rb_raise(rb_eArgError, "stream is not writable");
|
2754
2774
|
|
2755
2775
|
new_file = rb_funcall(rb_cIO, rb_intern("new"), 1, INT2NUM(new_fd));
|
2756
|
-
this->trace_stream
|
2776
|
+
RB_OBJ_WRITE(self, &this->trace_stream, new_file);
|
2757
2777
|
|
2758
2778
|
PQtrace(this->pgconn, new_fp);
|
2759
2779
|
return Qnil;
|
@@ -2772,7 +2792,7 @@ pgconn_untrace(VALUE self)
|
|
2772
2792
|
|
2773
2793
|
PQuntrace(this->pgconn);
|
2774
2794
|
rb_funcall(this->trace_stream, rb_intern("close"), 0);
|
2775
|
-
this->trace_stream
|
2795
|
+
RB_OBJ_WRITE(self, &this->trace_stream, Qnil);
|
2776
2796
|
return Qnil;
|
2777
2797
|
}
|
2778
2798
|
|
@@ -2831,13 +2851,14 @@ pgconn_set_notice_receiver(VALUE self)
|
|
2831
2851
|
VALUE proc, old_proc;
|
2832
2852
|
t_pg_connection *this = pg_get_connection_safe( self );
|
2833
2853
|
|
2854
|
+
rb_check_frozen(self);
|
2834
2855
|
/* If default_notice_receiver is unset, assume that the current
|
2835
2856
|
* notice receiver is the default, and save it to a global variable.
|
2836
2857
|
* This should not be a problem because the default receiver is
|
2837
2858
|
* always the same, so won't vary among connections.
|
2838
2859
|
*/
|
2839
|
-
if(default_notice_receiver == NULL)
|
2840
|
-
default_notice_receiver = PQsetNoticeReceiver(this->pgconn, NULL, NULL);
|
2860
|
+
if(this->default_notice_receiver == NULL)
|
2861
|
+
this->default_notice_receiver = PQsetNoticeReceiver(this->pgconn, NULL, NULL);
|
2841
2862
|
|
2842
2863
|
old_proc = this->notice_receiver;
|
2843
2864
|
if( rb_block_given_p() ) {
|
@@ -2846,10 +2867,10 @@ pgconn_set_notice_receiver(VALUE self)
|
|
2846
2867
|
} else {
|
2847
2868
|
/* if no block is given, set back to default */
|
2848
2869
|
proc = Qnil;
|
2849
|
-
PQsetNoticeReceiver(this->pgconn, default_notice_receiver, NULL);
|
2870
|
+
PQsetNoticeReceiver(this->pgconn, this->default_notice_receiver, NULL);
|
2850
2871
|
}
|
2851
2872
|
|
2852
|
-
this->notice_receiver
|
2873
|
+
RB_OBJ_WRITE(self, &this->notice_receiver, proc);
|
2853
2874
|
return old_proc;
|
2854
2875
|
}
|
2855
2876
|
|
@@ -2864,10 +2885,10 @@ notice_processor_proxy(void *arg, const char *message)
|
|
2864
2885
|
VALUE self = (VALUE)arg;
|
2865
2886
|
t_pg_connection *this = pg_get_connection( self );
|
2866
2887
|
|
2867
|
-
if (this->
|
2868
|
-
VALUE message_str =
|
2869
|
-
PG_ENCODING_SET_NOCHECK( message_str,
|
2870
|
-
rb_funcall(this->
|
2888
|
+
if (this->notice_processor != Qnil) {
|
2889
|
+
VALUE message_str = rb_str_new2(message);
|
2890
|
+
PG_ENCODING_SET_NOCHECK( message_str, this->enc_idx );
|
2891
|
+
rb_funcall(this->notice_processor, rb_intern("call"), 1, message_str);
|
2871
2892
|
}
|
2872
2893
|
return;
|
2873
2894
|
}
|
@@ -2876,7 +2897,7 @@ notice_processor_proxy(void *arg, const char *message)
|
|
2876
2897
|
* call-seq:
|
2877
2898
|
* conn.set_notice_processor {|message| ... } -> Proc
|
2878
2899
|
*
|
2879
|
-
* See #set_notice_receiver for the
|
2900
|
+
* See #set_notice_receiver for the description of what this and the
|
2880
2901
|
* notice_processor methods do.
|
2881
2902
|
*
|
2882
2903
|
* This function takes a new block to act as the notice processor and returns
|
@@ -2891,25 +2912,26 @@ pgconn_set_notice_processor(VALUE self)
|
|
2891
2912
|
VALUE proc, old_proc;
|
2892
2913
|
t_pg_connection *this = pg_get_connection_safe( self );
|
2893
2914
|
|
2915
|
+
rb_check_frozen(self);
|
2894
2916
|
/* If default_notice_processor is unset, assume that the current
|
2895
2917
|
* notice processor is the default, and save it to a global variable.
|
2896
2918
|
* This should not be a problem because the default processor is
|
2897
2919
|
* always the same, so won't vary among connections.
|
2898
2920
|
*/
|
2899
|
-
if(default_notice_processor == NULL)
|
2900
|
-
default_notice_processor = PQsetNoticeProcessor(this->pgconn, NULL, NULL);
|
2921
|
+
if(this->default_notice_processor == NULL)
|
2922
|
+
this->default_notice_processor = PQsetNoticeProcessor(this->pgconn, NULL, NULL);
|
2901
2923
|
|
2902
|
-
old_proc = this->
|
2924
|
+
old_proc = this->notice_processor;
|
2903
2925
|
if( rb_block_given_p() ) {
|
2904
2926
|
proc = rb_block_proc();
|
2905
2927
|
PQsetNoticeProcessor(this->pgconn, gvl_notice_processor_proxy, (void *)self);
|
2906
2928
|
} else {
|
2907
2929
|
/* if no block is given, set back to default */
|
2908
2930
|
proc = Qnil;
|
2909
|
-
PQsetNoticeProcessor(this->pgconn, default_notice_processor, NULL);
|
2931
|
+
PQsetNoticeProcessor(this->pgconn, this->default_notice_processor, NULL);
|
2910
2932
|
}
|
2911
2933
|
|
2912
|
-
this->
|
2934
|
+
RB_OBJ_WRITE(self, &this->notice_processor, proc);
|
2913
2935
|
return old_proc;
|
2914
2936
|
}
|
2915
2937
|
|
@@ -2924,74 +2946,34 @@ static VALUE
|
|
2924
2946
|
pgconn_get_client_encoding(VALUE self)
|
2925
2947
|
{
|
2926
2948
|
char *encoding = (char *)pg_encoding_to_char(PQclientEncoding(pg_get_pgconn(self)));
|
2927
|
-
return
|
2949
|
+
return rb_str_new2(encoding);
|
2928
2950
|
}
|
2929
2951
|
|
2930
2952
|
|
2931
2953
|
/*
|
2932
2954
|
* call-seq:
|
2933
|
-
* conn.
|
2955
|
+
* conn.sync_set_client_encoding( encoding )
|
2934
2956
|
*
|
2935
|
-
*
|
2957
|
+
* This function has the same behavior as #async_set_client_encoding, but is implemented using the synchronous command processing API of libpq.
|
2958
|
+
* See #async_exec for the differences between the two API variants.
|
2959
|
+
* 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.
|
2936
2960
|
*/
|
2937
2961
|
static VALUE
|
2938
|
-
|
2962
|
+
pgconn_sync_set_client_encoding(VALUE self, VALUE str)
|
2939
2963
|
{
|
2940
2964
|
PGconn *conn = pg_get_pgconn( self );
|
2941
2965
|
|
2966
|
+
rb_check_frozen(self);
|
2942
2967
|
Check_Type(str, T_STRING);
|
2943
2968
|
|
2944
|
-
if ( (gvl_PQsetClientEncoding(conn, StringValueCStr(str))) == -1 )
|
2945
|
-
|
2946
|
-
|
2969
|
+
if ( (gvl_PQsetClientEncoding(conn, StringValueCStr(str))) == -1 )
|
2970
|
+
pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(conn));
|
2971
|
+
|
2947
2972
|
pgconn_set_internal_encoding_index( self );
|
2948
2973
|
|
2949
2974
|
return Qnil;
|
2950
2975
|
}
|
2951
2976
|
|
2952
|
-
/*
|
2953
|
-
* call-seq:
|
2954
|
-
* conn.transaction { |conn| ... } -> result of the block
|
2955
|
-
*
|
2956
|
-
* Executes a +BEGIN+ at the start of the block,
|
2957
|
-
* and a +COMMIT+ at the end of the block, or
|
2958
|
-
* +ROLLBACK+ if any exception occurs.
|
2959
|
-
*/
|
2960
|
-
static VALUE
|
2961
|
-
pgconn_transaction(VALUE self)
|
2962
|
-
{
|
2963
|
-
PGconn *conn = pg_get_pgconn(self);
|
2964
|
-
PGresult *result;
|
2965
|
-
VALUE rb_pgresult;
|
2966
|
-
VALUE block_result = Qnil;
|
2967
|
-
int status;
|
2968
|
-
|
2969
|
-
if (rb_block_given_p()) {
|
2970
|
-
result = gvl_PQexec(conn, "BEGIN");
|
2971
|
-
rb_pgresult = pg_new_result(result, self);
|
2972
|
-
pg_result_check(rb_pgresult);
|
2973
|
-
block_result = rb_protect(rb_yield, self, &status);
|
2974
|
-
if(status == 0) {
|
2975
|
-
result = gvl_PQexec(conn, "COMMIT");
|
2976
|
-
rb_pgresult = pg_new_result(result, self);
|
2977
|
-
pg_result_check(rb_pgresult);
|
2978
|
-
}
|
2979
|
-
else {
|
2980
|
-
/* exception occurred, ROLLBACK and re-raise */
|
2981
|
-
result = gvl_PQexec(conn, "ROLLBACK");
|
2982
|
-
rb_pgresult = pg_new_result(result, self);
|
2983
|
-
pg_result_check(rb_pgresult);
|
2984
|
-
rb_jump_tag(status);
|
2985
|
-
}
|
2986
|
-
|
2987
|
-
}
|
2988
|
-
else {
|
2989
|
-
/* no block supplied? */
|
2990
|
-
rb_raise(rb_eArgError, "Must supply block for PG::Connection#transaction");
|
2991
|
-
}
|
2992
|
-
return block_result;
|
2993
|
-
}
|
2994
|
-
|
2995
2977
|
|
2996
2978
|
/*
|
2997
2979
|
* call-seq:
|
@@ -3036,14 +3018,12 @@ pgconn_s_quote_ident(VALUE self, VALUE str_or_array)
|
|
3036
3018
|
int enc_idx;
|
3037
3019
|
|
3038
3020
|
if( rb_obj_is_kind_of(self, rb_cPGconn) ){
|
3039
|
-
enc_idx =
|
3021
|
+
enc_idx = pg_get_connection(self)->enc_idx;
|
3040
3022
|
}else{
|
3041
3023
|
enc_idx = RB_TYPE_P(str_or_array, T_STRING) ? ENCODING_GET( str_or_array ) : rb_ascii8bit_encindex();
|
3042
3024
|
}
|
3043
3025
|
pg_text_enc_identifier(NULL, str_or_array, NULL, &ret, enc_idx);
|
3044
3026
|
|
3045
|
-
OBJ_INFECT(ret, str_or_array);
|
3046
|
-
|
3047
3027
|
return ret;
|
3048
3028
|
}
|
3049
3029
|
|
@@ -3068,14 +3048,8 @@ get_result_readable(PGconn *conn)
|
|
3068
3048
|
* If +true+ is returned, +conn.is_busy+ will return +false+
|
3069
3049
|
* and +conn.get_result+ will not block.
|
3070
3050
|
*/
|
3071
|
-
|
3051
|
+
VALUE
|
3072
3052
|
pgconn_block( int argc, VALUE *argv, VALUE self ) {
|
3073
|
-
PGconn *conn = pg_get_pgconn( self );
|
3074
|
-
|
3075
|
-
/* If WIN32 and Ruby 1.9 do not use rb_thread_select() which sometimes hangs
|
3076
|
-
* and does not wait (nor sleep) any time even if timeout is given.
|
3077
|
-
* Instead use the Winsock events and rb_w32_wait_events(). */
|
3078
|
-
|
3079
3053
|
struct timeval timeout;
|
3080
3054
|
struct timeval *ptimeout = NULL;
|
3081
3055
|
VALUE timeout_in;
|
@@ -3089,7 +3063,7 @@ pgconn_block( int argc, VALUE *argv, VALUE self ) {
|
|
3089
3063
|
ptimeout = &timeout;
|
3090
3064
|
}
|
3091
3065
|
|
3092
|
-
ret = wait_socket_readable(
|
3066
|
+
ret = wait_socket_readable( self, ptimeout, get_result_readable);
|
3093
3067
|
|
3094
3068
|
if( !ret )
|
3095
3069
|
return Qfalse;
|
@@ -3098,6 +3072,42 @@ pgconn_block( int argc, VALUE *argv, VALUE self ) {
|
|
3098
3072
|
}
|
3099
3073
|
|
3100
3074
|
|
3075
|
+
/*
|
3076
|
+
* call-seq:
|
3077
|
+
* conn.sync_get_last_result( ) -> PG::Result
|
3078
|
+
*
|
3079
|
+
* This function has the same behavior as #async_get_last_result, but is implemented using the synchronous command processing API of libpq.
|
3080
|
+
* See #async_exec for the differences between the two API variants.
|
3081
|
+
* 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.
|
3082
|
+
*/
|
3083
|
+
static VALUE
|
3084
|
+
pgconn_sync_get_last_result(VALUE self)
|
3085
|
+
{
|
3086
|
+
PGconn *conn = pg_get_pgconn(self);
|
3087
|
+
VALUE rb_pgresult = Qnil;
|
3088
|
+
PGresult *cur, *prev;
|
3089
|
+
|
3090
|
+
|
3091
|
+
cur = prev = NULL;
|
3092
|
+
while ((cur = gvl_PQgetResult(conn)) != NULL) {
|
3093
|
+
int status;
|
3094
|
+
|
3095
|
+
if (prev) PQclear(prev);
|
3096
|
+
prev = cur;
|
3097
|
+
|
3098
|
+
status = PQresultStatus(cur);
|
3099
|
+
if (status == PGRES_COPY_OUT || status == PGRES_COPY_IN || status == PGRES_COPY_BOTH)
|
3100
|
+
break;
|
3101
|
+
}
|
3102
|
+
|
3103
|
+
if (prev) {
|
3104
|
+
rb_pgresult = pg_new_result( prev, self );
|
3105
|
+
pg_result_check(rb_pgresult);
|
3106
|
+
}
|
3107
|
+
|
3108
|
+
return rb_pgresult;
|
3109
|
+
}
|
3110
|
+
|
3101
3111
|
/*
|
3102
3112
|
* call-seq:
|
3103
3113
|
* conn.get_last_result( ) -> PG::Result
|
@@ -3108,27 +3118,38 @@ pgconn_block( int argc, VALUE *argv, VALUE self ) {
|
|
3108
3118
|
* returns the last non-NULL result, or +nil+ if no
|
3109
3119
|
* results are available.
|
3110
3120
|
*
|
3121
|
+
* If the last result contains a bad result_status, an
|
3122
|
+
* appropriate exception is raised.
|
3123
|
+
*
|
3111
3124
|
* This function is similar to #get_result
|
3112
3125
|
* except that it is designed to get one and only
|
3113
|
-
* one result.
|
3126
|
+
* one result and that it checks the result state.
|
3114
3127
|
*/
|
3115
3128
|
static VALUE
|
3116
|
-
|
3129
|
+
pgconn_async_get_last_result(VALUE self)
|
3117
3130
|
{
|
3118
3131
|
PGconn *conn = pg_get_pgconn(self);
|
3119
3132
|
VALUE rb_pgresult = Qnil;
|
3120
3133
|
PGresult *cur, *prev;
|
3121
3134
|
|
3122
|
-
|
3123
3135
|
cur = prev = NULL;
|
3124
|
-
|
3136
|
+
for(;;) {
|
3125
3137
|
int status;
|
3126
3138
|
|
3139
|
+
/* Wait for input before reading each result.
|
3140
|
+
* That way we support the ruby-3.x IO scheduler and don't block other ruby threads.
|
3141
|
+
*/
|
3142
|
+
wait_socket_readable(self, NULL, get_result_readable);
|
3143
|
+
|
3144
|
+
cur = gvl_PQgetResult(conn);
|
3145
|
+
if (cur == NULL)
|
3146
|
+
break;
|
3147
|
+
|
3127
3148
|
if (prev) PQclear(prev);
|
3128
3149
|
prev = cur;
|
3129
3150
|
|
3130
3151
|
status = PQresultStatus(cur);
|
3131
|
-
if (status == PGRES_COPY_OUT || status == PGRES_COPY_IN)
|
3152
|
+
if (status == PGRES_COPY_OUT || status == PGRES_COPY_IN || status == PGRES_COPY_BOTH)
|
3132
3153
|
break;
|
3133
3154
|
}
|
3134
3155
|
|
@@ -3142,25 +3163,343 @@ pgconn_get_last_result(VALUE self)
|
|
3142
3163
|
|
3143
3164
|
/*
|
3144
3165
|
* call-seq:
|
3145
|
-
* conn.
|
3146
|
-
*
|
3166
|
+
* conn.discard_results()
|
3167
|
+
*
|
3168
|
+
* Silently discard any prior query result that application didn't eat.
|
3169
|
+
* This is internally used prior to Connection#exec and sibling methods.
|
3170
|
+
* It doesn't raise an exception on connection errors, but returns +false+ instead.
|
3171
|
+
*
|
3172
|
+
* Returns:
|
3173
|
+
* * +nil+ when the connection is already idle
|
3174
|
+
* * +true+ when some results have been discarded
|
3175
|
+
* * +false+ when a failure occurred and the connection was closed
|
3176
|
+
*
|
3177
|
+
*/
|
3178
|
+
static VALUE
|
3179
|
+
pgconn_discard_results(VALUE self)
|
3180
|
+
{
|
3181
|
+
PGconn *conn = pg_get_pgconn(self);
|
3182
|
+
VALUE socket_io;
|
3183
|
+
|
3184
|
+
switch( PQtransactionStatus(conn) ) {
|
3185
|
+
case PQTRANS_IDLE:
|
3186
|
+
case PQTRANS_INTRANS:
|
3187
|
+
case PQTRANS_INERROR:
|
3188
|
+
return Qnil;
|
3189
|
+
default:;
|
3190
|
+
}
|
3191
|
+
|
3192
|
+
socket_io = pgconn_socket_io(self);
|
3193
|
+
|
3194
|
+
for(;;) {
|
3195
|
+
PGresult *cur;
|
3196
|
+
int status;
|
3197
|
+
|
3198
|
+
/* pgconn_block() raises an exception in case of errors.
|
3199
|
+
* To avoid this call pg_rb_io_wait() and PQconsumeInput() without rb_raise().
|
3200
|
+
*/
|
3201
|
+
while( gvl_PQisBusy(conn) ){
|
3202
|
+
int events;
|
3203
|
+
|
3204
|
+
switch( PQflush(conn) ) {
|
3205
|
+
case 1:
|
3206
|
+
events = RB_NUM2INT(pg_rb_io_wait(socket_io, RB_INT2NUM(PG_RUBY_IO_READABLE | PG_RUBY_IO_WRITABLE), Qnil));
|
3207
|
+
if (events & PG_RUBY_IO_READABLE){
|
3208
|
+
if ( PQconsumeInput(conn) == 0 ) goto error;
|
3209
|
+
}
|
3210
|
+
break;
|
3211
|
+
case 0:
|
3212
|
+
pg_rb_io_wait(socket_io, RB_INT2NUM(PG_RUBY_IO_READABLE), Qnil);
|
3213
|
+
if ( PQconsumeInput(conn) == 0 ) goto error;
|
3214
|
+
break;
|
3215
|
+
default:
|
3216
|
+
goto error;
|
3217
|
+
}
|
3218
|
+
}
|
3219
|
+
|
3220
|
+
cur = gvl_PQgetResult(conn);
|
3221
|
+
if( cur == NULL) break;
|
3222
|
+
|
3223
|
+
status = PQresultStatus(cur);
|
3224
|
+
PQclear(cur);
|
3225
|
+
if (status == PGRES_COPY_IN){
|
3226
|
+
while( gvl_PQputCopyEnd(conn, "COPY terminated by new query or discard_results") == 0 ){
|
3227
|
+
pgconn_async_flush(self);
|
3228
|
+
}
|
3229
|
+
}
|
3230
|
+
if (status == PGRES_COPY_OUT){
|
3231
|
+
for(;;) {
|
3232
|
+
char *buffer = NULL;
|
3233
|
+
int st = gvl_PQgetCopyData(conn, &buffer, 1);
|
3234
|
+
if( st == 0 ) {
|
3235
|
+
/* would block -> wait for readable data */
|
3236
|
+
pg_rb_io_wait(socket_io, RB_INT2NUM(PG_RUBY_IO_READABLE), Qnil);
|
3237
|
+
if ( PQconsumeInput(conn) == 0 ) goto error;
|
3238
|
+
} else if( st > 0 ) {
|
3239
|
+
/* some data retrieved -> discard it */
|
3240
|
+
PQfreemem(buffer);
|
3241
|
+
} else {
|
3242
|
+
/* no more data */
|
3243
|
+
break;
|
3244
|
+
}
|
3245
|
+
}
|
3246
|
+
}
|
3247
|
+
}
|
3248
|
+
|
3249
|
+
return Qtrue;
|
3250
|
+
|
3251
|
+
error:
|
3252
|
+
pgconn_close_socket_io(self);
|
3253
|
+
return Qfalse;
|
3254
|
+
}
|
3255
|
+
|
3256
|
+
/*
|
3257
|
+
* call-seq:
|
3258
|
+
* conn.exec(sql) -> PG::Result
|
3259
|
+
* conn.exec(sql) {|pg_result| block }
|
3260
|
+
*
|
3261
|
+
* Sends SQL query request specified by _sql_ to PostgreSQL.
|
3262
|
+
* On success, it returns a PG::Result instance with all result rows and columns.
|
3263
|
+
* On failure, it raises a PG::Error.
|
3264
|
+
*
|
3265
|
+
* For backward compatibility, if you pass more than one parameter to this method,
|
3266
|
+
* it will call #exec_params for you. New code should explicitly use #exec_params if
|
3267
|
+
* argument placeholders are used.
|
3268
|
+
*
|
3269
|
+
* If the optional code block is given, it will be passed <i>result</i> as an argument,
|
3270
|
+
* and the PG::Result object will automatically be cleared when the block terminates.
|
3271
|
+
* In this instance, <code>conn.exec</code> returns the value of the block.
|
3272
|
+
*
|
3273
|
+
* #exec is an alias for #async_exec which is almost identical to #sync_exec .
|
3274
|
+
* #sync_exec is implemented on the simpler synchronous command processing API of libpq, whereas
|
3275
|
+
* #async_exec is implemented on the asynchronous API and on ruby's IO mechanisms.
|
3276
|
+
* Only #async_exec is compatible to <tt>Fiber.scheduler</tt> based asynchronous IO processing introduced in ruby-3.0.
|
3277
|
+
* Both methods ensure that other threads can process while waiting for the server to
|
3278
|
+
* complete the request, but #sync_exec blocks all signals to be processed until the query is finished.
|
3279
|
+
* This is most notably visible by a delayed reaction to Control+C.
|
3280
|
+
* It's not recommended to use explicit sync or async variants but #exec instead, unless you have a good reason to do so.
|
3147
3281
|
*
|
3148
|
-
*
|
3149
|
-
* but is implemented using the asynchronous command
|
3150
|
-
* processing API of libpq.
|
3282
|
+
* See also corresponding {libpq function}[https://www.postgresql.org/docs/current/libpq-exec.html#LIBPQ-PQEXEC].
|
3151
3283
|
*/
|
3152
3284
|
static VALUE
|
3153
3285
|
pgconn_async_exec(int argc, VALUE *argv, VALUE self)
|
3154
3286
|
{
|
3155
3287
|
VALUE rb_pgresult = Qnil;
|
3156
3288
|
|
3157
|
-
|
3158
|
-
pgconn_block( 0, NULL, self ); /* wait for input (without blocking) before reading the last result */
|
3159
|
-
pgconn_get_last_result( self );
|
3160
|
-
|
3289
|
+
pgconn_discard_results( self );
|
3161
3290
|
pgconn_send_query( argc, argv, self );
|
3162
|
-
|
3163
|
-
|
3291
|
+
rb_pgresult = pgconn_async_get_last_result( self );
|
3292
|
+
|
3293
|
+
if ( rb_block_given_p() ) {
|
3294
|
+
return rb_ensure( rb_yield, rb_pgresult, pg_result_clear, rb_pgresult );
|
3295
|
+
}
|
3296
|
+
return rb_pgresult;
|
3297
|
+
}
|
3298
|
+
|
3299
|
+
|
3300
|
+
/*
|
3301
|
+
* call-seq:
|
3302
|
+
* conn.exec_params(sql, params [, result_format [, type_map ]] ) -> nil
|
3303
|
+
* conn.exec_params(sql, params [, result_format [, type_map ]] ) {|pg_result| block }
|
3304
|
+
*
|
3305
|
+
* Sends SQL query request specified by +sql+ to PostgreSQL using placeholders
|
3306
|
+
* for parameters.
|
3307
|
+
*
|
3308
|
+
* Returns a PG::Result instance on success. On failure, it raises a PG::Error.
|
3309
|
+
*
|
3310
|
+
* +params+ is an array of the bind parameters for the SQL query.
|
3311
|
+
* Each element of the +params+ array may be either:
|
3312
|
+
* a hash of the form:
|
3313
|
+
* {:value => String (value of bind parameter)
|
3314
|
+
* :type => Integer (oid of type of bind parameter)
|
3315
|
+
* :format => Integer (0 for text, 1 for binary)
|
3316
|
+
* }
|
3317
|
+
* or, it may be a String. If it is a string, that is equivalent to the hash:
|
3318
|
+
* { :value => <string value>, :type => 0, :format => 0 }
|
3319
|
+
*
|
3320
|
+
* PostgreSQL bind parameters are represented as $1, $2, $3, etc.,
|
3321
|
+
* inside the SQL query. The 0th element of the +params+ array is bound
|
3322
|
+
* to $1, the 1st element is bound to $2, etc. +nil+ is treated as +NULL+.
|
3323
|
+
*
|
3324
|
+
* If the types are not specified, they will be inferred by PostgreSQL.
|
3325
|
+
* Instead of specifying type oids, it's recommended to simply add
|
3326
|
+
* explicit casts in the query to ensure that the right type is used.
|
3327
|
+
*
|
3328
|
+
* For example: "SELECT $1::int"
|
3329
|
+
*
|
3330
|
+
* The optional +result_format+ should be 0 for text results, 1
|
3331
|
+
* for binary.
|
3332
|
+
*
|
3333
|
+
* +type_map+ can be a PG::TypeMap derivation (such as PG::BasicTypeMapForQueries).
|
3334
|
+
* This will type cast the params from various Ruby types before transmission
|
3335
|
+
* based on the encoders defined by the type map. When a type encoder is used
|
3336
|
+
* the format and oid of a given bind parameter are retrieved from the encoder
|
3337
|
+
* instead out of the hash form described above.
|
3338
|
+
*
|
3339
|
+
* If the optional code block is given, it will be passed <i>result</i> as an argument,
|
3340
|
+
* and the PG::Result object will automatically be cleared when the block terminates.
|
3341
|
+
* In this instance, <code>conn.exec</code> returns the value of the block.
|
3342
|
+
*
|
3343
|
+
* 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.
|
3344
|
+
* Unlike #exec, #exec_params allows at most one SQL command in the given string.
|
3345
|
+
* (There can be semicolons in it, but not more than one nonempty command.)
|
3346
|
+
* This is a limitation of the underlying protocol, but has some usefulness as an extra defense against SQL-injection attacks.
|
3347
|
+
*
|
3348
|
+
* See also corresponding {libpq function}[https://www.postgresql.org/docs/current/libpq-exec.html#LIBPQ-PQEXECPARAMS].
|
3349
|
+
*/
|
3350
|
+
static VALUE
|
3351
|
+
pgconn_async_exec_params(int argc, VALUE *argv, VALUE self)
|
3352
|
+
{
|
3353
|
+
VALUE rb_pgresult = Qnil;
|
3354
|
+
|
3355
|
+
pgconn_discard_results( self );
|
3356
|
+
/* If called with no or nil parameters, use PQsendQuery for compatibility */
|
3357
|
+
if ( argc == 1 || (argc >= 2 && argc <= 4 && NIL_P(argv[1]) )) {
|
3358
|
+
pg_deprecated(3, ("forwarding async_exec_params to async_exec is deprecated"));
|
3359
|
+
pgconn_send_query( argc, argv, self );
|
3360
|
+
} else {
|
3361
|
+
pgconn_send_query_params( argc, argv, self );
|
3362
|
+
}
|
3363
|
+
rb_pgresult = pgconn_async_get_last_result( self );
|
3364
|
+
|
3365
|
+
if ( rb_block_given_p() ) {
|
3366
|
+
return rb_ensure( rb_yield, rb_pgresult, pg_result_clear, rb_pgresult );
|
3367
|
+
}
|
3368
|
+
return rb_pgresult;
|
3369
|
+
}
|
3370
|
+
|
3371
|
+
|
3372
|
+
/*
|
3373
|
+
* call-seq:
|
3374
|
+
* conn.prepare(stmt_name, sql [, param_types ] ) -> PG::Result
|
3375
|
+
*
|
3376
|
+
* Prepares statement _sql_ with name _name_ to be executed later.
|
3377
|
+
* Returns a PG::Result instance on success.
|
3378
|
+
* On failure, it raises a PG::Error.
|
3379
|
+
*
|
3380
|
+
* +param_types+ is an optional parameter to specify the Oids of the
|
3381
|
+
* types of the parameters.
|
3382
|
+
*
|
3383
|
+
* If the types are not specified, they will be inferred by PostgreSQL.
|
3384
|
+
* Instead of specifying type oids, it's recommended to simply add
|
3385
|
+
* explicit casts in the query to ensure that the right type is used.
|
3386
|
+
*
|
3387
|
+
* For example: "SELECT $1::int"
|
3388
|
+
*
|
3389
|
+
* PostgreSQL bind parameters are represented as $1, $2, $3, etc.,
|
3390
|
+
* inside the SQL query.
|
3391
|
+
*
|
3392
|
+
* See also corresponding {libpq function}[https://www.postgresql.org/docs/current/libpq-exec.html#LIBPQ-PQPREPARE].
|
3393
|
+
*/
|
3394
|
+
static VALUE
|
3395
|
+
pgconn_async_prepare(int argc, VALUE *argv, VALUE self)
|
3396
|
+
{
|
3397
|
+
VALUE rb_pgresult = Qnil;
|
3398
|
+
|
3399
|
+
pgconn_discard_results( self );
|
3400
|
+
pgconn_send_prepare( argc, argv, self );
|
3401
|
+
rb_pgresult = pgconn_async_get_last_result( self );
|
3402
|
+
|
3403
|
+
if ( rb_block_given_p() ) {
|
3404
|
+
return rb_ensure( rb_yield, rb_pgresult, pg_result_clear, rb_pgresult );
|
3405
|
+
}
|
3406
|
+
return rb_pgresult;
|
3407
|
+
}
|
3408
|
+
|
3409
|
+
|
3410
|
+
/*
|
3411
|
+
* call-seq:
|
3412
|
+
* conn.exec_prepared(statement_name [, params, result_format[, type_map]] ) -> PG::Result
|
3413
|
+
* conn.exec_prepared(statement_name [, params, result_format[, type_map]] ) {|pg_result| block }
|
3414
|
+
*
|
3415
|
+
* Execute prepared named statement specified by _statement_name_.
|
3416
|
+
* Returns a PG::Result instance on success.
|
3417
|
+
* On failure, it raises a PG::Error.
|
3418
|
+
*
|
3419
|
+
* +params+ is an array of the optional bind parameters for the
|
3420
|
+
* SQL query. Each element of the +params+ array may be either:
|
3421
|
+
* a hash of the form:
|
3422
|
+
* {:value => String (value of bind parameter)
|
3423
|
+
* :format => Integer (0 for text, 1 for binary)
|
3424
|
+
* }
|
3425
|
+
* or, it may be a String. If it is a string, that is equivalent to the hash:
|
3426
|
+
* { :value => <string value>, :format => 0 }
|
3427
|
+
*
|
3428
|
+
* PostgreSQL bind parameters are represented as $1, $2, $3, etc.,
|
3429
|
+
* inside the SQL query. The 0th element of the +params+ array is bound
|
3430
|
+
* to $1, the 1st element is bound to $2, etc. +nil+ is treated as +NULL+.
|
3431
|
+
*
|
3432
|
+
* The optional +result_format+ should be 0 for text results, 1
|
3433
|
+
* for binary.
|
3434
|
+
*
|
3435
|
+
* +type_map+ can be a PG::TypeMap derivation (such as PG::BasicTypeMapForQueries).
|
3436
|
+
* This will type cast the params from various Ruby types before transmission
|
3437
|
+
* based on the encoders defined by the type map. When a type encoder is used
|
3438
|
+
* the format and oid of a given bind parameter are retrieved from the encoder
|
3439
|
+
* instead out of the hash form described above.
|
3440
|
+
*
|
3441
|
+
* If the optional code block is given, it will be passed <i>result</i> as an argument,
|
3442
|
+
* and the PG::Result object will automatically be cleared when the block terminates.
|
3443
|
+
* In this instance, <code>conn.exec_prepared</code> returns the value of the block.
|
3444
|
+
*
|
3445
|
+
* See also corresponding {libpq function}[https://www.postgresql.org/docs/current/libpq-exec.html#LIBPQ-PQEXECPREPARED].
|
3446
|
+
*/
|
3447
|
+
static VALUE
|
3448
|
+
pgconn_async_exec_prepared(int argc, VALUE *argv, VALUE self)
|
3449
|
+
{
|
3450
|
+
VALUE rb_pgresult = Qnil;
|
3451
|
+
|
3452
|
+
pgconn_discard_results( self );
|
3453
|
+
pgconn_send_query_prepared( argc, argv, self );
|
3454
|
+
rb_pgresult = pgconn_async_get_last_result( self );
|
3455
|
+
|
3456
|
+
if ( rb_block_given_p() ) {
|
3457
|
+
return rb_ensure( rb_yield, rb_pgresult, pg_result_clear, rb_pgresult );
|
3458
|
+
}
|
3459
|
+
return rb_pgresult;
|
3460
|
+
}
|
3461
|
+
|
3462
|
+
|
3463
|
+
/*
|
3464
|
+
* call-seq:
|
3465
|
+
* conn.describe_portal( portal_name ) -> PG::Result
|
3466
|
+
*
|
3467
|
+
* Retrieve information about the portal _portal_name_.
|
3468
|
+
*
|
3469
|
+
* See also corresponding {libpq function}[https://www.postgresql.org/docs/current/libpq-exec.html#LIBPQ-PQDESCRIBEPORTAL].
|
3470
|
+
*/
|
3471
|
+
static VALUE
|
3472
|
+
pgconn_async_describe_portal(VALUE self, VALUE portal)
|
3473
|
+
{
|
3474
|
+
VALUE rb_pgresult = Qnil;
|
3475
|
+
|
3476
|
+
pgconn_discard_results( self );
|
3477
|
+
pgconn_send_describe_portal( self, portal );
|
3478
|
+
rb_pgresult = pgconn_async_get_last_result( self );
|
3479
|
+
|
3480
|
+
if ( rb_block_given_p() ) {
|
3481
|
+
return rb_ensure( rb_yield, rb_pgresult, pg_result_clear, rb_pgresult );
|
3482
|
+
}
|
3483
|
+
return rb_pgresult;
|
3484
|
+
}
|
3485
|
+
|
3486
|
+
|
3487
|
+
/*
|
3488
|
+
* call-seq:
|
3489
|
+
* conn.describe_prepared( statement_name ) -> PG::Result
|
3490
|
+
*
|
3491
|
+
* Retrieve information about the prepared statement _statement_name_.
|
3492
|
+
*
|
3493
|
+
* See also corresponding {libpq function}[https://www.postgresql.org/docs/current/libpq-exec.html#LIBPQ-PQDESCRIBEPREPARED].
|
3494
|
+
*/
|
3495
|
+
static VALUE
|
3496
|
+
pgconn_async_describe_prepared(VALUE self, VALUE stmt_name)
|
3497
|
+
{
|
3498
|
+
VALUE rb_pgresult = Qnil;
|
3499
|
+
|
3500
|
+
pgconn_discard_results( self );
|
3501
|
+
pgconn_send_describe_prepared( self, stmt_name );
|
3502
|
+
rb_pgresult = pgconn_async_get_last_result( self );
|
3164
3503
|
|
3165
3504
|
if ( rb_block_given_p() ) {
|
3166
3505
|
return rb_ensure( rb_yield, rb_pgresult, pg_result_clear, rb_pgresult );
|
@@ -3174,7 +3513,7 @@ pgconn_async_exec(int argc, VALUE *argv, VALUE self)
|
|
3174
3513
|
* call-seq:
|
3175
3514
|
* conn.ssl_in_use? -> Boolean
|
3176
3515
|
*
|
3177
|
-
* Returns +true+ if the connection uses SSL, +false+ if not.
|
3516
|
+
* Returns +true+ if the connection uses SSL/TLS, +false+ if not.
|
3178
3517
|
*
|
3179
3518
|
* Available since PostgreSQL-9.5
|
3180
3519
|
*/
|
@@ -3208,7 +3547,7 @@ pgconn_ssl_in_use(VALUE self)
|
|
3208
3547
|
* 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".
|
3209
3548
|
*
|
3210
3549
|
*
|
3211
|
-
* See also #ssl_attribute_names and
|
3550
|
+
* See also #ssl_attribute_names and the {corresponding libpq function}[https://www.postgresql.org/docs/current/libpq-status.html#LIBPQ-PQSSLATTRIBUTE].
|
3212
3551
|
*
|
3213
3552
|
* Available since PostgreSQL-9.5
|
3214
3553
|
*/
|
@@ -3248,10 +3587,134 @@ pgconn_ssl_attribute_names(VALUE self)
|
|
3248
3587
|
#endif
|
3249
3588
|
|
3250
3589
|
|
3590
|
+
#ifdef HAVE_PQENTERPIPELINEMODE
|
3591
|
+
/*
|
3592
|
+
* call-seq:
|
3593
|
+
* conn.pipeline_status -> Integer
|
3594
|
+
*
|
3595
|
+
* Returns the current pipeline mode status of the libpq connection.
|
3596
|
+
*
|
3597
|
+
* PQpipelineStatus can return one of the following values:
|
3598
|
+
*
|
3599
|
+
* * PQ_PIPELINE_ON - The libpq connection is in pipeline mode.
|
3600
|
+
* * PQ_PIPELINE_OFF - The libpq connection is not in pipeline mode.
|
3601
|
+
* * PQ_PIPELINE_ABORTED - The libpq connection is in pipeline mode and an error occurred while processing the current pipeline.
|
3602
|
+
* The aborted flag is cleared when PQgetResult returns a result of type PGRES_PIPELINE_SYNC.
|
3603
|
+
*
|
3604
|
+
* Available since PostgreSQL-14
|
3605
|
+
*/
|
3606
|
+
static VALUE
|
3607
|
+
pgconn_pipeline_status(VALUE self)
|
3608
|
+
{
|
3609
|
+
int res = PQpipelineStatus(pg_get_pgconn(self));
|
3610
|
+
return INT2FIX(res);
|
3611
|
+
}
|
3612
|
+
|
3613
|
+
|
3614
|
+
/*
|
3615
|
+
* call-seq:
|
3616
|
+
* conn.enter_pipeline_mode -> nil
|
3617
|
+
*
|
3618
|
+
* Causes a connection to enter pipeline mode if it is currently idle or already in pipeline mode.
|
3619
|
+
*
|
3620
|
+
* 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.
|
3621
|
+
* This function does not actually send anything to the server, it just changes the libpq connection state.
|
3622
|
+
*
|
3623
|
+
* Available since PostgreSQL-14
|
3624
|
+
*/
|
3625
|
+
static VALUE
|
3626
|
+
pgconn_enter_pipeline_mode(VALUE self)
|
3627
|
+
{
|
3628
|
+
PGconn *conn = pg_get_pgconn(self);
|
3629
|
+
int res = PQenterPipelineMode(conn);
|
3630
|
+
if( res != 1 )
|
3631
|
+
pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(conn));
|
3632
|
+
|
3633
|
+
return Qnil;
|
3634
|
+
}
|
3635
|
+
|
3636
|
+
/*
|
3637
|
+
* call-seq:
|
3638
|
+
* conn.exit_pipeline_mode -> nil
|
3639
|
+
*
|
3640
|
+
* Causes a connection to exit pipeline mode if it is currently in pipeline mode with an empty queue and no pending results.
|
3641
|
+
*
|
3642
|
+
* Takes no action if not in pipeline mode.
|
3643
|
+
* 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.
|
3644
|
+
*
|
3645
|
+
* Available since PostgreSQL-14
|
3646
|
+
*/
|
3647
|
+
static VALUE
|
3648
|
+
pgconn_exit_pipeline_mode(VALUE self)
|
3649
|
+
{
|
3650
|
+
PGconn *conn = pg_get_pgconn(self);
|
3651
|
+
int res = PQexitPipelineMode(conn);
|
3652
|
+
if( res != 1 )
|
3653
|
+
pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(conn));
|
3654
|
+
|
3655
|
+
return Qnil;
|
3656
|
+
}
|
3657
|
+
|
3658
|
+
|
3659
|
+
/*
|
3660
|
+
* call-seq:
|
3661
|
+
* conn.pipeline_sync -> nil
|
3662
|
+
*
|
3663
|
+
* Marks a synchronization point in a pipeline by sending a sync message and flushing the send buffer.
|
3664
|
+
* This serves as the delimiter of an implicit transaction and an error recovery point; see Section 34.5.1.3 of the PostgreSQL documentation.
|
3665
|
+
*
|
3666
|
+
* Raises PG::Error if the connection is not in pipeline mode or sending a sync message failed.
|
3667
|
+
*
|
3668
|
+
* Available since PostgreSQL-14
|
3669
|
+
*/
|
3670
|
+
static VALUE
|
3671
|
+
pgconn_pipeline_sync(VALUE self)
|
3672
|
+
{
|
3673
|
+
PGconn *conn = pg_get_pgconn(self);
|
3674
|
+
int res = PQpipelineSync(conn);
|
3675
|
+
if( res != 1 )
|
3676
|
+
pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(conn));
|
3677
|
+
|
3678
|
+
return Qnil;
|
3679
|
+
}
|
3680
|
+
|
3681
|
+
/*
|
3682
|
+
* call-seq:
|
3683
|
+
* conn.pipeline_sync -> nil
|
3684
|
+
*
|
3685
|
+
* Sends a request for the server to flush its output buffer.
|
3686
|
+
*
|
3687
|
+
* 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.
|
3688
|
+
* This function is useful to cause the server to flush its output buffer in pipeline mode without establishing a synchronization point.
|
3689
|
+
* Note that the request is not itself flushed to the server automatically; use Connection#flush if necessary.
|
3690
|
+
*
|
3691
|
+
* Available since PostgreSQL-14
|
3692
|
+
*/
|
3693
|
+
static VALUE
|
3694
|
+
pgconn_send_flush_request(VALUE self)
|
3695
|
+
{
|
3696
|
+
PGconn *conn = pg_get_pgconn(self);
|
3697
|
+
int res = PQsendFlushRequest(conn);
|
3698
|
+
if( res != 1 )
|
3699
|
+
pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(conn));
|
3700
|
+
|
3701
|
+
return Qnil;
|
3702
|
+
}
|
3703
|
+
|
3704
|
+
#endif
|
3705
|
+
|
3251
3706
|
/**************************************************************************
|
3252
3707
|
* LARGE OBJECT SUPPORT
|
3253
3708
|
**************************************************************************/
|
3254
3709
|
|
3710
|
+
#define BLOCKING_BEGIN(conn) do { \
|
3711
|
+
int old_nonblocking = PQisnonblocking(conn); \
|
3712
|
+
PQsetnonblocking(conn, 0);
|
3713
|
+
|
3714
|
+
#define BLOCKING_END(th) \
|
3715
|
+
PQsetnonblocking(conn, old_nonblocking); \
|
3716
|
+
} while(0);
|
3717
|
+
|
3255
3718
|
/*
|
3256
3719
|
* call-seq:
|
3257
3720
|
* conn.lo_creat( [mode] ) -> Integer
|
@@ -3272,9 +3735,12 @@ pgconn_locreat(int argc, VALUE *argv, VALUE self)
|
|
3272
3735
|
else
|
3273
3736
|
mode = NUM2INT(nmode);
|
3274
3737
|
|
3275
|
-
|
3738
|
+
BLOCKING_BEGIN(conn)
|
3739
|
+
lo_oid = lo_creat(conn, mode);
|
3740
|
+
BLOCKING_END(conn)
|
3741
|
+
|
3276
3742
|
if (lo_oid == 0)
|
3277
|
-
|
3743
|
+
pg_raise_conn_error( rb_ePGerror, self, "lo_creat failed");
|
3278
3744
|
|
3279
3745
|
return UINT2NUM(lo_oid);
|
3280
3746
|
}
|
@@ -3295,7 +3761,7 @@ pgconn_locreate(VALUE self, VALUE in_lo_oid)
|
|
3295
3761
|
|
3296
3762
|
ret = lo_create(conn, lo_oid);
|
3297
3763
|
if (ret == InvalidOid)
|
3298
|
-
|
3764
|
+
pg_raise_conn_error( rb_ePGerror, self, "lo_create failed");
|
3299
3765
|
|
3300
3766
|
return UINT2NUM(ret);
|
3301
3767
|
}
|
@@ -3317,9 +3783,12 @@ pgconn_loimport(VALUE self, VALUE filename)
|
|
3317
3783
|
|
3318
3784
|
Check_Type(filename, T_STRING);
|
3319
3785
|
|
3320
|
-
|
3786
|
+
BLOCKING_BEGIN(conn)
|
3787
|
+
lo_oid = lo_import(conn, StringValueCStr(filename));
|
3788
|
+
BLOCKING_END(conn)
|
3789
|
+
|
3321
3790
|
if (lo_oid == 0) {
|
3322
|
-
|
3791
|
+
pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(conn));
|
3323
3792
|
}
|
3324
3793
|
return UINT2NUM(lo_oid);
|
3325
3794
|
}
|
@@ -3335,12 +3804,17 @@ pgconn_loexport(VALUE self, VALUE lo_oid, VALUE filename)
|
|
3335
3804
|
{
|
3336
3805
|
PGconn *conn = pg_get_pgconn(self);
|
3337
3806
|
Oid oid;
|
3807
|
+
int ret;
|
3338
3808
|
Check_Type(filename, T_STRING);
|
3339
3809
|
|
3340
3810
|
oid = NUM2UINT(lo_oid);
|
3341
3811
|
|
3342
|
-
|
3343
|
-
|
3812
|
+
BLOCKING_BEGIN(conn)
|
3813
|
+
ret = lo_export(conn, oid, StringValueCStr(filename));
|
3814
|
+
BLOCKING_END(conn)
|
3815
|
+
|
3816
|
+
if (ret < 0) {
|
3817
|
+
pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(conn));
|
3344
3818
|
}
|
3345
3819
|
return Qnil;
|
3346
3820
|
}
|
@@ -3370,8 +3844,12 @@ pgconn_loopen(int argc, VALUE *argv, VALUE self)
|
|
3370
3844
|
else
|
3371
3845
|
mode = NUM2INT(nmode);
|
3372
3846
|
|
3373
|
-
|
3374
|
-
|
3847
|
+
BLOCKING_BEGIN(conn)
|
3848
|
+
fd = lo_open(conn, lo_oid, mode);
|
3849
|
+
BLOCKING_END(conn)
|
3850
|
+
|
3851
|
+
if(fd < 0) {
|
3852
|
+
pg_raise_conn_error( rb_ePGerror, self, "can't open large object: %s", PQerrorMessage(conn));
|
3375
3853
|
}
|
3376
3854
|
return INT2FIX(fd);
|
3377
3855
|
}
|
@@ -3393,11 +3871,15 @@ pgconn_lowrite(VALUE self, VALUE in_lo_desc, VALUE buffer)
|
|
3393
3871
|
Check_Type(buffer, T_STRING);
|
3394
3872
|
|
3395
3873
|
if( RSTRING_LEN(buffer) < 0) {
|
3396
|
-
|
3874
|
+
pg_raise_conn_error( rb_ePGerror, self, "write buffer zero string");
|
3397
3875
|
}
|
3398
|
-
|
3399
|
-
|
3400
|
-
|
3876
|
+
BLOCKING_BEGIN(conn)
|
3877
|
+
n = lo_write(conn, fd, StringValuePtr(buffer),
|
3878
|
+
RSTRING_LEN(buffer));
|
3879
|
+
BLOCKING_END(conn)
|
3880
|
+
|
3881
|
+
if(n < 0) {
|
3882
|
+
pg_raise_conn_error( rb_ePGerror, self, "lo_write failed: %s", PQerrorMessage(conn));
|
3401
3883
|
}
|
3402
3884
|
|
3403
3885
|
return INT2FIX(n);
|
@@ -3420,23 +3902,24 @@ pgconn_loread(VALUE self, VALUE in_lo_desc, VALUE in_len)
|
|
3420
3902
|
VALUE str;
|
3421
3903
|
char *buffer;
|
3422
3904
|
|
3423
|
-
|
3424
|
-
|
3425
|
-
rb_raise(rb_eNoMemError, "ALLOC failed!");
|
3905
|
+
if (len < 0)
|
3906
|
+
pg_raise_conn_error( rb_ePGerror, self, "negative length %d given", len);
|
3426
3907
|
|
3427
|
-
|
3428
|
-
|
3429
|
-
|
3908
|
+
buffer = ALLOC_N(char, len);
|
3909
|
+
|
3910
|
+
BLOCKING_BEGIN(conn)
|
3911
|
+
ret = lo_read(conn, lo_desc, buffer, len);
|
3912
|
+
BLOCKING_END(conn)
|
3430
3913
|
|
3431
|
-
if(
|
3432
|
-
|
3914
|
+
if(ret < 0)
|
3915
|
+
pg_raise_conn_error( rb_ePGerror, self, "lo_read failed");
|
3433
3916
|
|
3434
3917
|
if(ret == 0) {
|
3435
3918
|
xfree(buffer);
|
3436
3919
|
return Qnil;
|
3437
3920
|
}
|
3438
3921
|
|
3439
|
-
str =
|
3922
|
+
str = rb_str_new(buffer, ret);
|
3440
3923
|
xfree(buffer);
|
3441
3924
|
|
3442
3925
|
return str;
|
@@ -3458,8 +3941,12 @@ pgconn_lolseek(VALUE self, VALUE in_lo_desc, VALUE offset, VALUE whence)
|
|
3458
3941
|
int lo_desc = NUM2INT(in_lo_desc);
|
3459
3942
|
int ret;
|
3460
3943
|
|
3461
|
-
|
3462
|
-
|
3944
|
+
BLOCKING_BEGIN(conn)
|
3945
|
+
ret = lo_lseek(conn, lo_desc, NUM2INT(offset), NUM2INT(whence));
|
3946
|
+
BLOCKING_END(conn)
|
3947
|
+
|
3948
|
+
if(ret < 0) {
|
3949
|
+
pg_raise_conn_error( rb_ePGerror, self, "lo_lseek failed");
|
3463
3950
|
}
|
3464
3951
|
|
3465
3952
|
return INT2FIX(ret);
|
@@ -3478,8 +3965,12 @@ pgconn_lotell(VALUE self, VALUE in_lo_desc)
|
|
3478
3965
|
PGconn *conn = pg_get_pgconn(self);
|
3479
3966
|
int lo_desc = NUM2INT(in_lo_desc);
|
3480
3967
|
|
3481
|
-
|
3482
|
-
|
3968
|
+
BLOCKING_BEGIN(conn)
|
3969
|
+
position = lo_tell(conn, lo_desc);
|
3970
|
+
BLOCKING_END(conn)
|
3971
|
+
|
3972
|
+
if(position < 0)
|
3973
|
+
pg_raise_conn_error( rb_ePGerror, self, "lo_tell failed");
|
3483
3974
|
|
3484
3975
|
return INT2FIX(position);
|
3485
3976
|
}
|
@@ -3496,9 +3987,14 @@ pgconn_lotruncate(VALUE self, VALUE in_lo_desc, VALUE in_len)
|
|
3496
3987
|
PGconn *conn = pg_get_pgconn(self);
|
3497
3988
|
int lo_desc = NUM2INT(in_lo_desc);
|
3498
3989
|
size_t len = NUM2INT(in_len);
|
3990
|
+
int ret;
|
3499
3991
|
|
3500
|
-
|
3501
|
-
|
3992
|
+
BLOCKING_BEGIN(conn)
|
3993
|
+
ret = lo_truncate(conn,lo_desc,len);
|
3994
|
+
BLOCKING_END(conn)
|
3995
|
+
|
3996
|
+
if(ret < 0)
|
3997
|
+
pg_raise_conn_error( rb_ePGerror, self, "lo_truncate failed");
|
3502
3998
|
|
3503
3999
|
return Qnil;
|
3504
4000
|
}
|
@@ -3514,9 +4010,14 @@ pgconn_loclose(VALUE self, VALUE in_lo_desc)
|
|
3514
4010
|
{
|
3515
4011
|
PGconn *conn = pg_get_pgconn(self);
|
3516
4012
|
int lo_desc = NUM2INT(in_lo_desc);
|
4013
|
+
int ret;
|
3517
4014
|
|
3518
|
-
|
3519
|
-
|
4015
|
+
BLOCKING_BEGIN(conn)
|
4016
|
+
ret = lo_close(conn,lo_desc);
|
4017
|
+
BLOCKING_END(conn)
|
4018
|
+
|
4019
|
+
if(ret < 0)
|
4020
|
+
pg_raise_conn_error( rb_ePGerror, self, "lo_close failed");
|
3520
4021
|
|
3521
4022
|
return Qnil;
|
3522
4023
|
}
|
@@ -3532,20 +4033,28 @@ pgconn_lounlink(VALUE self, VALUE in_oid)
|
|
3532
4033
|
{
|
3533
4034
|
PGconn *conn = pg_get_pgconn(self);
|
3534
4035
|
Oid oid = NUM2UINT(in_oid);
|
4036
|
+
int ret;
|
4037
|
+
|
4038
|
+
BLOCKING_BEGIN(conn)
|
4039
|
+
ret = lo_unlink(conn,oid);
|
4040
|
+
BLOCKING_END(conn)
|
3535
4041
|
|
3536
|
-
if(
|
3537
|
-
|
4042
|
+
if(ret < 0)
|
4043
|
+
pg_raise_conn_error( rb_ePGerror, self, "lo_unlink failed");
|
3538
4044
|
|
3539
4045
|
return Qnil;
|
3540
4046
|
}
|
3541
4047
|
|
3542
4048
|
|
3543
|
-
void
|
4049
|
+
static void
|
3544
4050
|
pgconn_set_internal_encoding_index( VALUE self )
|
3545
4051
|
{
|
3546
|
-
|
3547
|
-
|
3548
|
-
|
4052
|
+
int enc_idx;
|
4053
|
+
t_pg_connection *this = pg_get_connection_safe( self );
|
4054
|
+
rb_encoding *enc = pg_conn_enc_get( this->pgconn );
|
4055
|
+
enc_idx = rb_enc_to_index(enc);
|
4056
|
+
if( enc_idx >= (1<<(PG_ENC_IDX_BITS-1)) ) rb_raise(rb_eArgError, "unsupported encoding index %d", enc_idx);
|
4057
|
+
this->enc_idx = enc_idx;
|
3549
4058
|
}
|
3550
4059
|
|
3551
4060
|
/*
|
@@ -3588,13 +4097,13 @@ static VALUE pgconn_external_encoding(VALUE self);
|
|
3588
4097
|
static VALUE
|
3589
4098
|
pgconn_internal_encoding_set(VALUE self, VALUE enc)
|
3590
4099
|
{
|
3591
|
-
|
4100
|
+
rb_check_frozen(self);
|
3592
4101
|
if (NIL_P(enc)) {
|
3593
|
-
|
4102
|
+
pgconn_sync_set_client_encoding( self, rb_usascii_str_new_cstr("SQL_ASCII") );
|
3594
4103
|
return enc;
|
3595
4104
|
}
|
3596
4105
|
else if ( TYPE(enc) == T_STRING && strcasecmp("JOHAB", StringValueCStr(enc)) == 0 ) {
|
3597
|
-
|
4106
|
+
pgconn_sync_set_client_encoding(self, rb_usascii_str_new_cstr("JOHAB"));
|
3598
4107
|
return enc;
|
3599
4108
|
}
|
3600
4109
|
else {
|
@@ -3609,11 +4118,6 @@ pgconn_internal_encoding_set(VALUE self, VALUE enc)
|
|
3609
4118
|
pgconn_set_internal_encoding_index( self );
|
3610
4119
|
return enc;
|
3611
4120
|
}
|
3612
|
-
|
3613
|
-
enc_inspect = rb_inspect(enc);
|
3614
|
-
rb_raise( rb_ePGerror, "unknown encoding: %s", StringValueCStr(enc_inspect) );
|
3615
|
-
|
3616
|
-
return Qnil;
|
3617
4121
|
}
|
3618
4122
|
|
3619
4123
|
|
@@ -3632,42 +4136,56 @@ pgconn_external_encoding(VALUE self)
|
|
3632
4136
|
rb_encoding *enc = NULL;
|
3633
4137
|
const char *pg_encname = NULL;
|
3634
4138
|
|
3635
|
-
/* Use cached value if found */
|
3636
|
-
if ( RTEST(this->external_encoding) ) return this->external_encoding;
|
3637
|
-
|
3638
4139
|
pg_encname = PQparameterStatus( this->pgconn, "server_encoding" );
|
3639
4140
|
enc = pg_get_pg_encname_as_rb_encoding( pg_encname );
|
3640
|
-
|
3641
|
-
|
3642
|
-
return this->external_encoding;
|
4141
|
+
return rb_enc_from_encoding( enc );
|
3643
4142
|
}
|
3644
4143
|
|
4144
|
+
/*
|
4145
|
+
* call-seq:
|
4146
|
+
* conn.set_client_encoding( encoding )
|
4147
|
+
*
|
4148
|
+
* Sets the client encoding to the _encoding_ String.
|
4149
|
+
*/
|
4150
|
+
static VALUE
|
4151
|
+
pgconn_async_set_client_encoding(VALUE self, VALUE encname)
|
4152
|
+
{
|
4153
|
+
VALUE query_format, query;
|
4154
|
+
|
4155
|
+
rb_check_frozen(self);
|
4156
|
+
Check_Type(encname, T_STRING);
|
4157
|
+
query_format = rb_str_new_cstr("set client_encoding to '%s'");
|
4158
|
+
query = rb_funcall(query_format, rb_intern("%"), 1, encname);
|
4159
|
+
|
4160
|
+
pgconn_async_exec(1, &query, self);
|
4161
|
+
pgconn_set_internal_encoding_index( self );
|
4162
|
+
|
4163
|
+
return Qnil;
|
4164
|
+
}
|
3645
4165
|
|
3646
4166
|
static VALUE
|
3647
4167
|
pgconn_set_client_encoding_async1( VALUE args )
|
3648
4168
|
{
|
3649
4169
|
VALUE self = ((VALUE*)args)[0];
|
3650
4170
|
VALUE encname = ((VALUE*)args)[1];
|
3651
|
-
|
3652
|
-
VALUE query = rb_funcall(query_format, rb_intern("%"), 1, encname);
|
3653
|
-
|
3654
|
-
pgconn_async_exec(1, &query, self);
|
4171
|
+
pgconn_async_set_client_encoding(self, encname);
|
3655
4172
|
return 0;
|
3656
4173
|
}
|
3657
4174
|
|
3658
4175
|
|
3659
4176
|
static VALUE
|
3660
|
-
pgconn_set_client_encoding_async2( VALUE arg )
|
4177
|
+
pgconn_set_client_encoding_async2( VALUE arg, VALUE ex )
|
3661
4178
|
{
|
3662
4179
|
UNUSED(arg);
|
4180
|
+
UNUSED(ex);
|
3663
4181
|
return 1;
|
3664
4182
|
}
|
3665
4183
|
|
3666
4184
|
|
3667
4185
|
static VALUE
|
3668
|
-
pgconn_set_client_encoding_async( VALUE self,
|
4186
|
+
pgconn_set_client_encoding_async( VALUE self, VALUE encname )
|
3669
4187
|
{
|
3670
|
-
VALUE args[] = { self,
|
4188
|
+
VALUE args[] = { self, encname };
|
3671
4189
|
return rb_rescue(pgconn_set_client_encoding_async1, (VALUE)&args, pgconn_set_client_encoding_async2, Qnil);
|
3672
4190
|
}
|
3673
4191
|
|
@@ -3684,16 +4202,23 @@ static VALUE
|
|
3684
4202
|
pgconn_set_default_encoding( VALUE self )
|
3685
4203
|
{
|
3686
4204
|
PGconn *conn = pg_get_pgconn( self );
|
3687
|
-
rb_encoding *
|
3688
|
-
|
3689
|
-
|
3690
|
-
if ((
|
3691
|
-
|
3692
|
-
|
3693
|
-
|
3694
|
-
|
4205
|
+
rb_encoding *rb_enc;
|
4206
|
+
|
4207
|
+
rb_check_frozen(self);
|
4208
|
+
if (( rb_enc = rb_default_internal_encoding() )) {
|
4209
|
+
rb_encoding * conn_encoding = pg_conn_enc_get( conn );
|
4210
|
+
|
4211
|
+
/* Don't set the server encoding, if it's unnecessary.
|
4212
|
+
* This is important for connection proxies, who disallow configuration settings.
|
4213
|
+
*/
|
4214
|
+
if ( conn_encoding != rb_enc ) {
|
4215
|
+
const char *encname = pg_get_rb_encoding_as_pg_encoding( rb_enc );
|
4216
|
+
if ( pgconn_set_client_encoding_async(self, rb_str_new_cstr(encname)) != 0 )
|
4217
|
+
rb_warning( "Failed to set the default_internal encoding to %s: '%s'",
|
4218
|
+
encname, PQerrorMessage(conn) );
|
4219
|
+
}
|
3695
4220
|
pgconn_set_internal_encoding_index( self );
|
3696
|
-
return rb_enc_from_encoding(
|
4221
|
+
return rb_enc_from_encoding( rb_enc );
|
3697
4222
|
} else {
|
3698
4223
|
pgconn_set_internal_encoding_index( self );
|
3699
4224
|
return Qnil;
|
@@ -3714,13 +4239,14 @@ static VALUE
|
|
3714
4239
|
pgconn_type_map_for_queries_set(VALUE self, VALUE typemap)
|
3715
4240
|
{
|
3716
4241
|
t_pg_connection *this = pg_get_connection( self );
|
4242
|
+
t_typemap *tm;
|
4243
|
+
UNUSED(tm);
|
3717
4244
|
|
3718
|
-
|
3719
|
-
|
3720
|
-
|
3721
|
-
|
3722
|
-
|
3723
|
-
this->type_map_for_queries = typemap;
|
4245
|
+
rb_check_frozen(self);
|
4246
|
+
/* Check type of method param */
|
4247
|
+
TypedData_Get_Struct(typemap, t_typemap, &pg_typemap_type, tm);
|
4248
|
+
|
4249
|
+
RB_OBJ_WRITE(self, &this->type_map_for_queries, typemap);
|
3724
4250
|
|
3725
4251
|
return typemap;
|
3726
4252
|
}
|
@@ -3754,13 +4280,12 @@ static VALUE
|
|
3754
4280
|
pgconn_type_map_for_results_set(VALUE self, VALUE typemap)
|
3755
4281
|
{
|
3756
4282
|
t_pg_connection *this = pg_get_connection( self );
|
4283
|
+
t_typemap *tm;
|
4284
|
+
UNUSED(tm);
|
3757
4285
|
|
3758
|
-
|
3759
|
-
|
3760
|
-
|
3761
|
-
}
|
3762
|
-
Check_Type(typemap, T_DATA);
|
3763
|
-
this->type_map_for_results = typemap;
|
4286
|
+
rb_check_frozen(self);
|
4287
|
+
TypedData_Get_Struct(typemap, t_typemap, &pg_typemap_type, tm);
|
4288
|
+
RB_OBJ_WRITE(self, &this->type_map_for_results, typemap);
|
3764
4289
|
|
3765
4290
|
return typemap;
|
3766
4291
|
}
|
@@ -3794,20 +4319,20 @@ pgconn_type_map_for_results_get(VALUE self)
|
|
3794
4319
|
*
|
3795
4320
|
*/
|
3796
4321
|
static VALUE
|
3797
|
-
pgconn_encoder_for_put_copy_data_set(VALUE self, VALUE
|
4322
|
+
pgconn_encoder_for_put_copy_data_set(VALUE self, VALUE encoder)
|
3798
4323
|
{
|
3799
4324
|
t_pg_connection *this = pg_get_connection( self );
|
3800
4325
|
|
3801
|
-
|
3802
|
-
|
3803
|
-
|
3804
|
-
|
3805
|
-
|
3806
|
-
|
4326
|
+
rb_check_frozen(self);
|
4327
|
+
if( encoder != Qnil ){
|
4328
|
+
t_pg_coder *co;
|
4329
|
+
UNUSED(co);
|
4330
|
+
/* Check argument type */
|
4331
|
+
TypedData_Get_Struct(encoder, t_pg_coder, &pg_coder_type, co);
|
3807
4332
|
}
|
3808
|
-
this->encoder_for_put_copy_data
|
4333
|
+
RB_OBJ_WRITE(self, &this->encoder_for_put_copy_data, encoder);
|
3809
4334
|
|
3810
|
-
return
|
4335
|
+
return encoder;
|
3811
4336
|
}
|
3812
4337
|
|
3813
4338
|
/*
|
@@ -3843,20 +4368,20 @@ pgconn_encoder_for_put_copy_data_get(VALUE self)
|
|
3843
4368
|
*
|
3844
4369
|
*/
|
3845
4370
|
static VALUE
|
3846
|
-
pgconn_decoder_for_get_copy_data_set(VALUE self, VALUE
|
4371
|
+
pgconn_decoder_for_get_copy_data_set(VALUE self, VALUE decoder)
|
3847
4372
|
{
|
3848
4373
|
t_pg_connection *this = pg_get_connection( self );
|
3849
4374
|
|
3850
|
-
|
3851
|
-
|
3852
|
-
|
3853
|
-
|
3854
|
-
|
3855
|
-
|
4375
|
+
rb_check_frozen(self);
|
4376
|
+
if( decoder != Qnil ){
|
4377
|
+
t_pg_coder *co;
|
4378
|
+
UNUSED(co);
|
4379
|
+
/* Check argument type */
|
4380
|
+
TypedData_Get_Struct(decoder, t_pg_coder, &pg_coder_type, co);
|
3856
4381
|
}
|
3857
|
-
this->decoder_for_get_copy_data
|
4382
|
+
RB_OBJ_WRITE(self, &this->decoder_for_get_copy_data, decoder);
|
3858
4383
|
|
3859
|
-
return
|
4384
|
+
return decoder;
|
3860
4385
|
}
|
3861
4386
|
|
3862
4387
|
/*
|
@@ -3879,28 +4404,83 @@ pgconn_decoder_for_get_copy_data_get(VALUE self)
|
|
3879
4404
|
return this->decoder_for_get_copy_data;
|
3880
4405
|
}
|
3881
4406
|
|
4407
|
+
/*
|
4408
|
+
* call-seq:
|
4409
|
+
* conn.field_name_type = Symbol
|
4410
|
+
*
|
4411
|
+
* Set default type of field names of results retrieved by this connection.
|
4412
|
+
* It can be set to one of:
|
4413
|
+
* * +:string+ to use String based field names
|
4414
|
+
* * +:symbol+ to use Symbol based field names
|
4415
|
+
*
|
4416
|
+
* The default is +:string+ .
|
4417
|
+
*
|
4418
|
+
* Settings the type of field names affects only future results.
|
4419
|
+
*
|
4420
|
+
* See further description at PG::Result#field_name_type=
|
4421
|
+
*
|
4422
|
+
*/
|
4423
|
+
static VALUE
|
4424
|
+
pgconn_field_name_type_set(VALUE self, VALUE sym)
|
4425
|
+
{
|
4426
|
+
t_pg_connection *this = pg_get_connection( self );
|
4427
|
+
|
4428
|
+
rb_check_frozen(self);
|
4429
|
+
this->flags &= ~PG_RESULT_FIELD_NAMES_MASK;
|
4430
|
+
if( sym == sym_symbol ) this->flags |= PG_RESULT_FIELD_NAMES_SYMBOL;
|
4431
|
+
else if ( sym == sym_static_symbol ) this->flags |= PG_RESULT_FIELD_NAMES_STATIC_SYMBOL;
|
4432
|
+
else if ( sym == sym_string );
|
4433
|
+
else rb_raise(rb_eArgError, "invalid argument %+"PRIsVALUE, sym);
|
4434
|
+
|
4435
|
+
return sym;
|
4436
|
+
}
|
4437
|
+
|
4438
|
+
/*
|
4439
|
+
* call-seq:
|
4440
|
+
* conn.field_name_type -> Symbol
|
4441
|
+
*
|
4442
|
+
* Get type of field names.
|
4443
|
+
*
|
4444
|
+
* See description at #field_name_type=
|
4445
|
+
*/
|
4446
|
+
static VALUE
|
4447
|
+
pgconn_field_name_type_get(VALUE self)
|
4448
|
+
{
|
4449
|
+
t_pg_connection *this = pg_get_connection( self );
|
4450
|
+
|
4451
|
+
if( this->flags & PG_RESULT_FIELD_NAMES_SYMBOL ){
|
4452
|
+
return sym_symbol;
|
4453
|
+
} else if( this->flags & PG_RESULT_FIELD_NAMES_STATIC_SYMBOL ){
|
4454
|
+
return sym_static_symbol;
|
4455
|
+
} else {
|
4456
|
+
return sym_string;
|
4457
|
+
}
|
4458
|
+
}
|
4459
|
+
|
3882
4460
|
|
3883
4461
|
/*
|
3884
4462
|
* Document-class: PG::Connection
|
3885
4463
|
*/
|
3886
4464
|
void
|
3887
|
-
init_pg_connection()
|
4465
|
+
init_pg_connection(void)
|
3888
4466
|
{
|
3889
4467
|
s_id_encode = rb_intern("encode");
|
4468
|
+
s_id_autoclose_set = rb_intern("autoclose=");
|
3890
4469
|
sym_type = ID2SYM(rb_intern("type"));
|
3891
4470
|
sym_format = ID2SYM(rb_intern("format"));
|
3892
4471
|
sym_value = ID2SYM(rb_intern("value"));
|
4472
|
+
sym_string = ID2SYM(rb_intern("string"));
|
4473
|
+
sym_symbol = ID2SYM(rb_intern("symbol"));
|
4474
|
+
sym_static_symbol = ID2SYM(rb_intern("static_symbol"));
|
3893
4475
|
|
3894
4476
|
rb_cPGconn = rb_define_class_under( rb_mPG, "Connection", rb_cObject );
|
4477
|
+
/* Help rdoc to known the Constants module */
|
4478
|
+
/* rb_mPGconstants = rb_define_module_under( rb_mPG, "Constants" ); */
|
3895
4479
|
rb_include_module(rb_cPGconn, rb_mPGconstants);
|
3896
4480
|
|
3897
4481
|
/****** PG::Connection CLASS METHODS ******/
|
3898
4482
|
rb_define_alloc_func( rb_cPGconn, pgconn_s_allocate );
|
3899
4483
|
|
3900
|
-
SINGLETON_ALIAS(rb_cPGconn, "connect", "new");
|
3901
|
-
SINGLETON_ALIAS(rb_cPGconn, "open", "new");
|
3902
|
-
SINGLETON_ALIAS(rb_cPGconn, "setdb", "new");
|
3903
|
-
SINGLETON_ALIAS(rb_cPGconn, "setdblogin", "new");
|
3904
4484
|
rb_define_singleton_method(rb_cPGconn, "escape_string", pgconn_s_escape, 1);
|
3905
4485
|
SINGLETON_ALIAS(rb_cPGconn, "escape", "escape_string");
|
3906
4486
|
rb_define_singleton_method(rb_cPGconn, "escape_bytea", pgconn_s_escape_bytea, 1);
|
@@ -3909,15 +4489,17 @@ init_pg_connection()
|
|
3909
4489
|
rb_define_singleton_method(rb_cPGconn, "quote_ident", pgconn_s_quote_ident, 1);
|
3910
4490
|
rb_define_singleton_method(rb_cPGconn, "connect_start", pgconn_s_connect_start, -1);
|
3911
4491
|
rb_define_singleton_method(rb_cPGconn, "conndefaults", pgconn_s_conndefaults, 0);
|
3912
|
-
rb_define_singleton_method(rb_cPGconn, "
|
4492
|
+
rb_define_singleton_method(rb_cPGconn, "conninfo_parse", pgconn_s_conninfo_parse, 1);
|
4493
|
+
rb_define_singleton_method(rb_cPGconn, "sync_ping", pgconn_s_sync_ping, -1);
|
4494
|
+
rb_define_singleton_method(rb_cPGconn, "sync_connect", pgconn_s_sync_connect, -1);
|
3913
4495
|
|
3914
4496
|
/****** PG::Connection INSTANCE METHODS: Connection Control ******/
|
3915
|
-
rb_define_method(rb_cPGconn, "initialize", pgconn_init, -1);
|
3916
4497
|
rb_define_method(rb_cPGconn, "connect_poll", pgconn_connect_poll, 0);
|
3917
4498
|
rb_define_method(rb_cPGconn, "finish", pgconn_finish, 0);
|
3918
4499
|
rb_define_method(rb_cPGconn, "finished?", pgconn_finished_p, 0);
|
3919
|
-
rb_define_method(rb_cPGconn, "
|
4500
|
+
rb_define_method(rb_cPGconn, "sync_reset", pgconn_sync_reset, 0);
|
3920
4501
|
rb_define_method(rb_cPGconn, "reset_start", pgconn_reset_start, 0);
|
4502
|
+
rb_define_private_method(rb_cPGconn, "reset_start2", pgconn_reset_start2, 1);
|
3921
4503
|
rb_define_method(rb_cPGconn, "reset_poll", pgconn_reset_poll, 0);
|
3922
4504
|
rb_define_alias(rb_cPGconn, "close", "finish");
|
3923
4505
|
|
@@ -3926,11 +4508,12 @@ init_pg_connection()
|
|
3926
4508
|
rb_define_method(rb_cPGconn, "user", pgconn_user, 0);
|
3927
4509
|
rb_define_method(rb_cPGconn, "pass", pgconn_pass, 0);
|
3928
4510
|
rb_define_method(rb_cPGconn, "host", pgconn_host, 0);
|
4511
|
+
#if defined(HAVE_PQRESULTMEMORYSIZE)
|
4512
|
+
rb_define_method(rb_cPGconn, "hostaddr", pgconn_hostaddr, 0);
|
4513
|
+
#endif
|
3929
4514
|
rb_define_method(rb_cPGconn, "port", pgconn_port, 0);
|
3930
4515
|
rb_define_method(rb_cPGconn, "tty", pgconn_tty, 0);
|
3931
|
-
#ifdef HAVE_PQCONNINFO
|
3932
4516
|
rb_define_method(rb_cPGconn, "conninfo", pgconn_conninfo, 0);
|
3933
|
-
#endif
|
3934
4517
|
rb_define_method(rb_cPGconn, "options", pgconn_options, 0);
|
3935
4518
|
rb_define_method(rb_cPGconn, "status", pgconn_status, 0);
|
3936
4519
|
rb_define_method(rb_cPGconn, "transaction_status", pgconn_transaction_status, 0);
|
@@ -3941,18 +4524,34 @@ init_pg_connection()
|
|
3941
4524
|
rb_define_method(rb_cPGconn, "socket", pgconn_socket, 0);
|
3942
4525
|
rb_define_method(rb_cPGconn, "socket_io", pgconn_socket_io, 0);
|
3943
4526
|
rb_define_method(rb_cPGconn, "backend_pid", pgconn_backend_pid, 0);
|
4527
|
+
rb_define_method(rb_cPGconn, "backend_key", pgconn_backend_key, 0);
|
3944
4528
|
rb_define_method(rb_cPGconn, "connection_needs_password", pgconn_connection_needs_password, 0);
|
3945
4529
|
rb_define_method(rb_cPGconn, "connection_used_password", pgconn_connection_used_password, 0);
|
3946
4530
|
/* rb_define_method(rb_cPGconn, "getssl", pgconn_getssl, 0); */
|
3947
4531
|
|
3948
4532
|
/****** PG::Connection INSTANCE METHODS: Command Execution ******/
|
3949
|
-
rb_define_method(rb_cPGconn, "
|
3950
|
-
|
3951
|
-
rb_define_method(rb_cPGconn, "
|
3952
|
-
rb_define_method(rb_cPGconn, "
|
3953
|
-
rb_define_method(rb_cPGconn, "
|
3954
|
-
rb_define_method(rb_cPGconn, "
|
3955
|
-
|
4533
|
+
rb_define_method(rb_cPGconn, "sync_exec", pgconn_sync_exec, -1);
|
4534
|
+
rb_define_method(rb_cPGconn, "sync_exec_params", pgconn_sync_exec_params, -1);
|
4535
|
+
rb_define_method(rb_cPGconn, "sync_prepare", pgconn_sync_prepare, -1);
|
4536
|
+
rb_define_method(rb_cPGconn, "sync_exec_prepared", pgconn_sync_exec_prepared, -1);
|
4537
|
+
rb_define_method(rb_cPGconn, "sync_describe_prepared", pgconn_sync_describe_prepared, 1);
|
4538
|
+
rb_define_method(rb_cPGconn, "sync_describe_portal", pgconn_sync_describe_portal, 1);
|
4539
|
+
|
4540
|
+
rb_define_method(rb_cPGconn, "exec", pgconn_async_exec, -1);
|
4541
|
+
rb_define_method(rb_cPGconn, "exec_params", pgconn_async_exec_params, -1);
|
4542
|
+
rb_define_method(rb_cPGconn, "prepare", pgconn_async_prepare, -1);
|
4543
|
+
rb_define_method(rb_cPGconn, "exec_prepared", pgconn_async_exec_prepared, -1);
|
4544
|
+
rb_define_method(rb_cPGconn, "describe_prepared", pgconn_async_describe_prepared, 1);
|
4545
|
+
rb_define_method(rb_cPGconn, "describe_portal", pgconn_async_describe_portal, 1);
|
4546
|
+
|
4547
|
+
rb_define_alias(rb_cPGconn, "async_exec", "exec");
|
4548
|
+
rb_define_alias(rb_cPGconn, "async_query", "async_exec");
|
4549
|
+
rb_define_alias(rb_cPGconn, "async_exec_params", "exec_params");
|
4550
|
+
rb_define_alias(rb_cPGconn, "async_prepare", "prepare");
|
4551
|
+
rb_define_alias(rb_cPGconn, "async_exec_prepared", "exec_prepared");
|
4552
|
+
rb_define_alias(rb_cPGconn, "async_describe_prepared", "describe_prepared");
|
4553
|
+
rb_define_alias(rb_cPGconn, "async_describe_portal", "describe_portal");
|
4554
|
+
|
3956
4555
|
rb_define_method(rb_cPGconn, "make_empty_pgresult", pgconn_make_empty_pgresult, 1);
|
3957
4556
|
rb_define_method(rb_cPGconn, "escape_string", pgconn_s_escape, 1);
|
3958
4557
|
rb_define_alias(rb_cPGconn, "escape", "escape_string");
|
@@ -3964,31 +4563,37 @@ init_pg_connection()
|
|
3964
4563
|
|
3965
4564
|
/****** PG::Connection INSTANCE METHODS: Asynchronous Command Processing ******/
|
3966
4565
|
rb_define_method(rb_cPGconn, "send_query", pgconn_send_query, -1);
|
4566
|
+
rb_define_method(rb_cPGconn, "send_query_params", pgconn_send_query_params, -1);
|
3967
4567
|
rb_define_method(rb_cPGconn, "send_prepare", pgconn_send_prepare, -1);
|
3968
4568
|
rb_define_method(rb_cPGconn, "send_query_prepared", pgconn_send_query_prepared, -1);
|
3969
4569
|
rb_define_method(rb_cPGconn, "send_describe_prepared", pgconn_send_describe_prepared, 1);
|
3970
4570
|
rb_define_method(rb_cPGconn, "send_describe_portal", pgconn_send_describe_portal, 1);
|
3971
|
-
rb_define_method(rb_cPGconn, "
|
4571
|
+
rb_define_method(rb_cPGconn, "sync_get_result", pgconn_sync_get_result, 0);
|
3972
4572
|
rb_define_method(rb_cPGconn, "consume_input", pgconn_consume_input, 0);
|
3973
4573
|
rb_define_method(rb_cPGconn, "is_busy", pgconn_is_busy, 0);
|
3974
|
-
rb_define_method(rb_cPGconn, "
|
3975
|
-
rb_define_method(rb_cPGconn, "
|
3976
|
-
|
3977
|
-
rb_define_method(rb_cPGconn, "flush",
|
4574
|
+
rb_define_method(rb_cPGconn, "sync_setnonblocking", pgconn_sync_setnonblocking, 1);
|
4575
|
+
rb_define_method(rb_cPGconn, "sync_isnonblocking", pgconn_sync_isnonblocking, 0);
|
4576
|
+
rb_define_method(rb_cPGconn, "sync_flush", pgconn_sync_flush, 0);
|
4577
|
+
rb_define_method(rb_cPGconn, "flush", pgconn_async_flush, 0);
|
4578
|
+
rb_define_alias(rb_cPGconn, "async_flush", "flush");
|
4579
|
+
rb_define_method(rb_cPGconn, "discard_results", pgconn_discard_results, 0);
|
3978
4580
|
|
3979
4581
|
/****** PG::Connection INSTANCE METHODS: Cancelling Queries in Progress ******/
|
3980
|
-
rb_define_method(rb_cPGconn, "
|
4582
|
+
rb_define_method(rb_cPGconn, "sync_cancel", pgconn_sync_cancel, 0);
|
3981
4583
|
|
3982
4584
|
/****** PG::Connection INSTANCE METHODS: NOTIFY ******/
|
3983
4585
|
rb_define_method(rb_cPGconn, "notifies", pgconn_notifies, 0);
|
3984
4586
|
|
3985
4587
|
/****** PG::Connection INSTANCE METHODS: COPY ******/
|
3986
|
-
rb_define_method(rb_cPGconn, "
|
3987
|
-
rb_define_method(rb_cPGconn, "
|
3988
|
-
rb_define_method(rb_cPGconn, "
|
4588
|
+
rb_define_method(rb_cPGconn, "sync_put_copy_data", pgconn_sync_put_copy_data, -1);
|
4589
|
+
rb_define_method(rb_cPGconn, "sync_put_copy_end", pgconn_sync_put_copy_end, -1);
|
4590
|
+
rb_define_method(rb_cPGconn, "sync_get_copy_data", pgconn_sync_get_copy_data, -1);
|
3989
4591
|
|
3990
4592
|
/****** PG::Connection INSTANCE METHODS: Control Functions ******/
|
3991
4593
|
rb_define_method(rb_cPGconn, "set_error_verbosity", pgconn_set_error_verbosity, 1);
|
4594
|
+
#ifdef HAVE_PQRESULTVERBOSEERRORMESSAGE
|
4595
|
+
rb_define_method(rb_cPGconn, "set_error_context_visibility", pgconn_set_error_context_visibility, 1 );
|
4596
|
+
#endif
|
3992
4597
|
rb_define_method(rb_cPGconn, "trace", pgconn_trace, 1);
|
3993
4598
|
rb_define_method(rb_cPGconn, "untrace", pgconn_untrace, 0);
|
3994
4599
|
|
@@ -3998,18 +4603,20 @@ init_pg_connection()
|
|
3998
4603
|
|
3999
4604
|
/****** PG::Connection INSTANCE METHODS: Other ******/
|
4000
4605
|
rb_define_method(rb_cPGconn, "get_client_encoding", pgconn_get_client_encoding, 0);
|
4001
|
-
rb_define_method(rb_cPGconn, "
|
4606
|
+
rb_define_method(rb_cPGconn, "sync_set_client_encoding", pgconn_sync_set_client_encoding, 1);
|
4607
|
+
rb_define_method(rb_cPGconn, "set_client_encoding", pgconn_async_set_client_encoding, 1);
|
4608
|
+
rb_define_alias(rb_cPGconn, "async_set_client_encoding", "set_client_encoding");
|
4002
4609
|
rb_define_alias(rb_cPGconn, "client_encoding=", "set_client_encoding");
|
4003
|
-
rb_define_method(rb_cPGconn, "transaction", pgconn_transaction, 0);
|
4004
4610
|
rb_define_method(rb_cPGconn, "block", pgconn_block, -1);
|
4611
|
+
rb_define_private_method(rb_cPGconn, "flush_data=", pgconn_flush_data_set, 1);
|
4005
4612
|
rb_define_method(rb_cPGconn, "wait_for_notify", pgconn_wait_for_notify, -1);
|
4006
4613
|
rb_define_alias(rb_cPGconn, "notifies_wait", "wait_for_notify");
|
4007
4614
|
rb_define_method(rb_cPGconn, "quote_ident", pgconn_s_quote_ident, 1);
|
4008
|
-
rb_define_method(rb_cPGconn, "
|
4009
|
-
|
4010
|
-
|
4615
|
+
rb_define_method(rb_cPGconn, "sync_get_last_result", pgconn_sync_get_last_result, 0);
|
4616
|
+
rb_define_method(rb_cPGconn, "get_last_result", pgconn_async_get_last_result, 0);
|
4617
|
+
rb_define_alias(rb_cPGconn, "async_get_last_result", "get_last_result");
|
4011
4618
|
#ifdef HAVE_PQENCRYPTPASSWORDCONN
|
4012
|
-
rb_define_method(rb_cPGconn, "
|
4619
|
+
rb_define_method(rb_cPGconn, "sync_encrypt_password", pgconn_sync_encrypt_password, -1);
|
4013
4620
|
#endif
|
4014
4621
|
|
4015
4622
|
#ifdef HAVE_PQSSLATTRIBUTE
|
@@ -4018,6 +4625,14 @@ init_pg_connection()
|
|
4018
4625
|
rb_define_method(rb_cPGconn, "ssl_attribute_names", pgconn_ssl_attribute_names, 0);
|
4019
4626
|
#endif
|
4020
4627
|
|
4628
|
+
#ifdef HAVE_PQENTERPIPELINEMODE
|
4629
|
+
rb_define_method(rb_cPGconn, "pipeline_status", pgconn_pipeline_status, 0);
|
4630
|
+
rb_define_method(rb_cPGconn, "enter_pipeline_mode", pgconn_enter_pipeline_mode, 0);
|
4631
|
+
rb_define_method(rb_cPGconn, "exit_pipeline_mode", pgconn_exit_pipeline_mode, 0);
|
4632
|
+
rb_define_method(rb_cPGconn, "pipeline_sync", pgconn_pipeline_sync, 0);
|
4633
|
+
rb_define_method(rb_cPGconn, "send_flush_request", pgconn_send_flush_request, 0);
|
4634
|
+
#endif
|
4635
|
+
|
4021
4636
|
/****** PG::Connection INSTANCE METHODS: Large Object Support ******/
|
4022
4637
|
rb_define_method(rb_cPGconn, "lo_creat", pgconn_locreat, -1);
|
4023
4638
|
rb_define_alias(rb_cPGconn, "locreat", "lo_creat");
|
@@ -4059,5 +4674,7 @@ init_pg_connection()
|
|
4059
4674
|
rb_define_method(rb_cPGconn, "encoder_for_put_copy_data", pgconn_encoder_for_put_copy_data_get, 0);
|
4060
4675
|
rb_define_method(rb_cPGconn, "decoder_for_get_copy_data=", pgconn_decoder_for_get_copy_data_set, 1);
|
4061
4676
|
rb_define_method(rb_cPGconn, "decoder_for_get_copy_data", pgconn_decoder_for_get_copy_data_get, 0);
|
4062
|
-
}
|
4063
4677
|
|
4678
|
+
rb_define_method(rb_cPGconn, "field_name_type=", pgconn_field_name_type_set, 1 );
|
4679
|
+
rb_define_method(rb_cPGconn, "field_name_type", pgconn_field_name_type_get, 0 );
|
4680
|
+
}
|