pg 1.2.3 → 1.4.4
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/.appveyor.yml +36 -0
- data/.gems +6 -0
- data/.github/workflows/binary-gems.yml +86 -0
- data/.github/workflows/source-gem.yml +131 -0
- data/.gitignore +13 -0
- data/.hgsigs +34 -0
- data/.hgtags +41 -0
- data/.irbrc +23 -0
- data/.pryrc +23 -0
- data/.tm_properties +21 -0
- data/.travis.yml +49 -0
- data/Gemfile +14 -0
- data/History.rdoc +209 -7
- data/Manifest.txt +0 -1
- data/README.rdoc +31 -11
- data/Rakefile +27 -138
- data/Rakefile.cross +8 -5
- data/certs/ged.pem +24 -0
- data/certs/larskanis-2022.pem +26 -0
- data/ext/errorcodes.def +8 -0
- data/ext/errorcodes.rb +0 -0
- data/ext/errorcodes.txt +3 -1
- data/ext/extconf.rb +100 -25
- data/ext/gvl_wrappers.c +4 -0
- data/ext/gvl_wrappers.h +23 -0
- data/ext/pg.c +59 -29
- data/ext/pg.h +20 -1
- data/ext/pg_binary_decoder.c +1 -1
- data/ext/pg_binary_encoder.c +1 -1
- data/ext/pg_coder.c +83 -29
- data/ext/pg_connection.c +856 -656
- data/ext/pg_copy_coder.c +46 -17
- data/ext/pg_errors.c +1 -1
- data/ext/pg_record_coder.c +46 -16
- data/ext/pg_result.c +88 -49
- data/ext/pg_text_decoder.c +2 -2
- data/ext/pg_text_encoder.c +7 -7
- data/ext/pg_tuple.c +50 -30
- data/ext/pg_type_map.c +42 -9
- data/ext/pg_type_map_all_strings.c +16 -2
- data/ext/pg_type_map_by_class.c +50 -25
- data/ext/pg_type_map_by_column.c +68 -30
- data/ext/pg_type_map_by_mri_type.c +48 -19
- data/ext/pg_type_map_by_oid.c +53 -24
- data/ext/pg_type_map_in_ruby.c +51 -20
- data/ext/pg_util.c +2 -2
- data/lib/pg/basic_type_map_based_on_result.rb +47 -0
- data/lib/pg/basic_type_map_for_queries.rb +193 -0
- data/lib/pg/basic_type_map_for_results.rb +81 -0
- data/lib/pg/basic_type_registry.rb +301 -0
- data/lib/pg/coder.rb +1 -1
- data/lib/pg/connection.rb +655 -69
- data/lib/pg/exceptions.rb +7 -1
- data/lib/pg/version.rb +4 -0
- data/lib/pg.rb +47 -32
- data/misc/openssl-pg-segfault.rb +31 -0
- data/misc/postgres/History.txt +9 -0
- data/misc/postgres/Manifest.txt +5 -0
- data/misc/postgres/README.txt +21 -0
- data/misc/postgres/Rakefile +21 -0
- data/misc/postgres/lib/postgres.rb +16 -0
- data/misc/ruby-pg/History.txt +9 -0
- data/misc/ruby-pg/Manifest.txt +5 -0
- data/misc/ruby-pg/README.txt +21 -0
- data/misc/ruby-pg/Rakefile +21 -0
- data/misc/ruby-pg/lib/ruby/pg.rb +16 -0
- data/pg.gemspec +32 -0
- data/rakelib/task_extension.rb +46 -0
- data/sample/array_insert.rb +20 -0
- data/sample/async_api.rb +102 -0
- data/sample/async_copyto.rb +39 -0
- data/sample/async_mixed.rb +56 -0
- data/sample/check_conn.rb +21 -0
- data/sample/copydata.rb +71 -0
- data/sample/copyfrom.rb +81 -0
- data/sample/copyto.rb +19 -0
- data/sample/cursor.rb +21 -0
- data/sample/disk_usage_report.rb +177 -0
- data/sample/issue-119.rb +94 -0
- data/sample/losample.rb +69 -0
- data/sample/minimal-testcase.rb +17 -0
- data/sample/notify_wait.rb +72 -0
- data/sample/pg_statistics.rb +285 -0
- data/sample/replication_monitor.rb +222 -0
- data/sample/test_binary_values.rb +33 -0
- data/sample/wal_shipper.rb +434 -0
- data/sample/warehouse_partitions.rb +311 -0
- data.tar.gz.sig +0 -0
- metadata +81 -224
- metadata.gz.sig +0 -0
- data/ChangeLog +0 -0
- data/lib/pg/basic_type_mapping.rb +0 -522
- data/spec/data/expected_trace.out +0 -26
- data/spec/data/random_binary_data +0 -0
- data/spec/helpers.rb +0 -380
- data/spec/pg/basic_type_mapping_spec.rb +0 -630
- data/spec/pg/connection_spec.rb +0 -1949
- data/spec/pg/connection_sync_spec.rb +0 -41
- data/spec/pg/result_spec.rb +0 -681
- data/spec/pg/tuple_spec.rb +0 -333
- data/spec/pg/type_map_by_class_spec.rb +0 -138
- data/spec/pg/type_map_by_column_spec.rb +0 -226
- 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 -1123
- data/spec/pg_spec.rb +0 -50
data/ext/pg_connection.c
CHANGED
|
@@ -12,6 +12,7 @@
|
|
|
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 VALUE sym_symbol, sym_string, sym_static_symbol;
|
|
17
18
|
|
|
@@ -20,12 +21,35 @@ static PQnoticeProcessor default_notice_processor = NULL;
|
|
|
20
21
|
|
|
21
22
|
static VALUE pgconn_finish( VALUE );
|
|
22
23
|
static VALUE pgconn_set_default_encoding( VALUE self );
|
|
24
|
+
static VALUE pgconn_wait_for_flush( VALUE self );
|
|
23
25
|
static void pgconn_set_internal_encoding_index( VALUE );
|
|
26
|
+
static const rb_data_type_t pg_connection_type;
|
|
27
|
+
static VALUE pgconn_async_flush(VALUE self);
|
|
24
28
|
|
|
25
29
|
/*
|
|
26
30
|
* Global functions
|
|
27
31
|
*/
|
|
28
32
|
|
|
33
|
+
/*
|
|
34
|
+
* Convenience function to raise connection errors
|
|
35
|
+
*/
|
|
36
|
+
#ifdef __GNUC__
|
|
37
|
+
__attribute__((format(printf, 3, 4)))
|
|
38
|
+
#endif
|
|
39
|
+
static void
|
|
40
|
+
pg_raise_conn_error( VALUE klass, VALUE self, const char *format, ...)
|
|
41
|
+
{
|
|
42
|
+
VALUE msg, error;
|
|
43
|
+
va_list ap;
|
|
44
|
+
|
|
45
|
+
va_start(ap, format);
|
|
46
|
+
msg = rb_vsprintf(format, ap);
|
|
47
|
+
va_end(ap);
|
|
48
|
+
error = rb_exc_new_str(klass, msg);
|
|
49
|
+
rb_iv_set(error, "@connection", self);
|
|
50
|
+
rb_exc_raise(error);
|
|
51
|
+
}
|
|
52
|
+
|
|
29
53
|
/*
|
|
30
54
|
* Fetch the PG::Connection object data pointer.
|
|
31
55
|
*/
|
|
@@ -33,7 +57,7 @@ t_pg_connection *
|
|
|
33
57
|
pg_get_connection( VALUE self )
|
|
34
58
|
{
|
|
35
59
|
t_pg_connection *this;
|
|
36
|
-
|
|
60
|
+
TypedData_Get_Struct( self, t_pg_connection, &pg_connection_type, this);
|
|
37
61
|
|
|
38
62
|
return this;
|
|
39
63
|
}
|
|
@@ -46,10 +70,10 @@ static t_pg_connection *
|
|
|
46
70
|
pg_get_connection_safe( VALUE self )
|
|
47
71
|
{
|
|
48
72
|
t_pg_connection *this;
|
|
49
|
-
|
|
73
|
+
TypedData_Get_Struct( self, t_pg_connection, &pg_connection_type, this);
|
|
50
74
|
|
|
51
75
|
if ( !this->pgconn )
|
|
52
|
-
|
|
76
|
+
pg_raise_conn_error( rb_eConnectionBad, self, "connection is closed");
|
|
53
77
|
|
|
54
78
|
return this;
|
|
55
79
|
}
|
|
@@ -65,10 +89,11 @@ PGconn *
|
|
|
65
89
|
pg_get_pgconn( VALUE self )
|
|
66
90
|
{
|
|
67
91
|
t_pg_connection *this;
|
|
68
|
-
|
|
92
|
+
TypedData_Get_Struct( self, t_pg_connection, &pg_connection_type, this);
|
|
69
93
|
|
|
70
|
-
if ( !this->pgconn )
|
|
71
|
-
|
|
94
|
+
if ( !this->pgconn ){
|
|
95
|
+
pg_raise_conn_error( rb_eConnectionBad, self, "connection is closed");
|
|
96
|
+
}
|
|
72
97
|
|
|
73
98
|
return this->pgconn;
|
|
74
99
|
}
|
|
@@ -86,9 +111,8 @@ pgconn_close_socket_io( VALUE self )
|
|
|
86
111
|
|
|
87
112
|
if ( RTEST(socket_io) ) {
|
|
88
113
|
#if defined(_WIN32)
|
|
89
|
-
if( rb_w32_unwrap_io_handle(this->ruby_sd) )
|
|
90
|
-
|
|
91
|
-
}
|
|
114
|
+
if( rb_w32_unwrap_io_handle(this->ruby_sd) )
|
|
115
|
+
pg_raise_conn_error( rb_eConnectionBad, self, "Could not unwrap win32 socket handle");
|
|
92
116
|
#endif
|
|
93
117
|
rb_funcall( socket_io, rb_intern("close"), 0 );
|
|
94
118
|
}
|
|
@@ -145,16 +169,31 @@ static const char *pg_cstr_enc(VALUE str, int enc_idx){
|
|
|
145
169
|
* GC Mark function
|
|
146
170
|
*/
|
|
147
171
|
static void
|
|
148
|
-
pgconn_gc_mark(
|
|
172
|
+
pgconn_gc_mark( void *_this )
|
|
173
|
+
{
|
|
174
|
+
t_pg_connection *this = (t_pg_connection *)_this;
|
|
175
|
+
rb_gc_mark_movable( this->socket_io );
|
|
176
|
+
rb_gc_mark_movable( this->notice_receiver );
|
|
177
|
+
rb_gc_mark_movable( this->notice_processor );
|
|
178
|
+
rb_gc_mark_movable( this->type_map_for_queries );
|
|
179
|
+
rb_gc_mark_movable( this->type_map_for_results );
|
|
180
|
+
rb_gc_mark_movable( this->trace_stream );
|
|
181
|
+
rb_gc_mark_movable( this->encoder_for_put_copy_data );
|
|
182
|
+
rb_gc_mark_movable( this->decoder_for_get_copy_data );
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
static void
|
|
186
|
+
pgconn_gc_compact( void *_this )
|
|
149
187
|
{
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
188
|
+
t_pg_connection *this = (t_pg_connection *)_this;
|
|
189
|
+
pg_gc_location( this->socket_io );
|
|
190
|
+
pg_gc_location( this->notice_receiver );
|
|
191
|
+
pg_gc_location( this->notice_processor );
|
|
192
|
+
pg_gc_location( this->type_map_for_queries );
|
|
193
|
+
pg_gc_location( this->type_map_for_results );
|
|
194
|
+
pg_gc_location( this->trace_stream );
|
|
195
|
+
pg_gc_location( this->encoder_for_put_copy_data );
|
|
196
|
+
pg_gc_location( this->decoder_for_get_copy_data );
|
|
158
197
|
}
|
|
159
198
|
|
|
160
199
|
|
|
@@ -162,11 +201,15 @@ pgconn_gc_mark( t_pg_connection *this )
|
|
|
162
201
|
* GC Free function
|
|
163
202
|
*/
|
|
164
203
|
static void
|
|
165
|
-
pgconn_gc_free(
|
|
204
|
+
pgconn_gc_free( void *_this )
|
|
166
205
|
{
|
|
206
|
+
t_pg_connection *this = (t_pg_connection *)_this;
|
|
167
207
|
#if defined(_WIN32)
|
|
168
|
-
if ( RTEST(this->socket_io) )
|
|
169
|
-
rb_w32_unwrap_io_handle(
|
|
208
|
+
if ( RTEST(this->socket_io) ) {
|
|
209
|
+
if( rb_w32_unwrap_io_handle(this->ruby_sd) ){
|
|
210
|
+
rb_warn("pg: Could not unwrap win32 socket handle by garbage collector");
|
|
211
|
+
}
|
|
212
|
+
}
|
|
170
213
|
#endif
|
|
171
214
|
if (this->pgconn != NULL)
|
|
172
215
|
PQfinish( this->pgconn );
|
|
@@ -174,6 +217,29 @@ pgconn_gc_free( t_pg_connection *this )
|
|
|
174
217
|
xfree(this);
|
|
175
218
|
}
|
|
176
219
|
|
|
220
|
+
/*
|
|
221
|
+
* Object Size function
|
|
222
|
+
*/
|
|
223
|
+
static size_t
|
|
224
|
+
pgconn_memsize( const void *_this )
|
|
225
|
+
{
|
|
226
|
+
const t_pg_connection *this = (const t_pg_connection *)_this;
|
|
227
|
+
return sizeof(*this);
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
static const rb_data_type_t pg_connection_type = {
|
|
231
|
+
"PG::Connection",
|
|
232
|
+
{
|
|
233
|
+
pgconn_gc_mark,
|
|
234
|
+
pgconn_gc_free,
|
|
235
|
+
pgconn_memsize,
|
|
236
|
+
pg_compact_callback(pgconn_gc_compact),
|
|
237
|
+
},
|
|
238
|
+
0,
|
|
239
|
+
0,
|
|
240
|
+
0,
|
|
241
|
+
};
|
|
242
|
+
|
|
177
243
|
|
|
178
244
|
/**************************************************************************
|
|
179
245
|
* Class Methods
|
|
@@ -189,7 +255,7 @@ static VALUE
|
|
|
189
255
|
pgconn_s_allocate( VALUE klass )
|
|
190
256
|
{
|
|
191
257
|
t_pg_connection *this;
|
|
192
|
-
VALUE self =
|
|
258
|
+
VALUE self = TypedData_Make_Struct( klass, t_pg_connection, &pg_connection_type, this );
|
|
193
259
|
|
|
194
260
|
this->pgconn = NULL;
|
|
195
261
|
this->socket_io = Qnil;
|
|
@@ -200,82 +266,27 @@ pgconn_s_allocate( VALUE klass )
|
|
|
200
266
|
this->encoder_for_put_copy_data = Qnil;
|
|
201
267
|
this->decoder_for_get_copy_data = Qnil;
|
|
202
268
|
this->trace_stream = Qnil;
|
|
269
|
+
rb_ivar_set(self, rb_intern("@calls_to_put_copy_data"), INT2FIX(0));
|
|
203
270
|
|
|
204
271
|
return self;
|
|
205
272
|
}
|
|
206
273
|
|
|
207
|
-
|
|
208
|
-
/*
|
|
209
|
-
* Document-method: new
|
|
210
|
-
*
|
|
211
|
-
* call-seq:
|
|
212
|
-
* PG::Connection.new -> conn
|
|
213
|
-
* PG::Connection.new(connection_hash) -> conn
|
|
214
|
-
* PG::Connection.new(connection_string) -> conn
|
|
215
|
-
* PG::Connection.new(host, port, options, tty, dbname, user, password) -> conn
|
|
216
|
-
*
|
|
217
|
-
* Create a connection to the specified server.
|
|
218
|
-
*
|
|
219
|
-
* +connection_hash+ must be a ruby Hash with connection parameters.
|
|
220
|
-
* See the {list of valid parameters}[https://www.postgresql.org/docs/current/libpq-connect.html#LIBPQ-PARAMKEYWORDS] in the PostgreSQL documentation.
|
|
221
|
-
*
|
|
222
|
-
* There are two accepted formats for +connection_string+: plain <code>keyword = value</code> strings and URIs.
|
|
223
|
-
* See the documentation of {connection strings}[https://www.postgresql.org/docs/current/libpq-connect.html#LIBPQ-CONNSTRING].
|
|
224
|
-
*
|
|
225
|
-
* The positional parameter form has the same functionality except that the missing parameters will always take on default values. The parameters are:
|
|
226
|
-
* [+host+]
|
|
227
|
-
* server hostname
|
|
228
|
-
* [+port+]
|
|
229
|
-
* server port number
|
|
230
|
-
* [+options+]
|
|
231
|
-
* backend options
|
|
232
|
-
* [+tty+]
|
|
233
|
-
* (ignored in newer versions of PostgreSQL)
|
|
234
|
-
* [+dbname+]
|
|
235
|
-
* connecting database name
|
|
236
|
-
* [+user+]
|
|
237
|
-
* login user name
|
|
238
|
-
* [+password+]
|
|
239
|
-
* login password
|
|
240
|
-
*
|
|
241
|
-
* Examples:
|
|
242
|
-
*
|
|
243
|
-
* # Connect using all defaults
|
|
244
|
-
* PG::Connection.new
|
|
245
|
-
*
|
|
246
|
-
* # As a Hash
|
|
247
|
-
* PG::Connection.new( :dbname => 'test', :port => 5432 )
|
|
248
|
-
*
|
|
249
|
-
* # As a String
|
|
250
|
-
* PG::Connection.new( "dbname=test port=5432" )
|
|
251
|
-
*
|
|
252
|
-
* # As an Array
|
|
253
|
-
* PG::Connection.new( nil, 5432, nil, nil, 'test', nil, nil )
|
|
254
|
-
*
|
|
255
|
-
* If the Ruby default internal encoding is set (i.e., <code>Encoding.default_internal != nil</code>), the
|
|
256
|
-
* connection will have its +client_encoding+ set accordingly.
|
|
257
|
-
*
|
|
258
|
-
* Raises a PG::Error if the connection fails.
|
|
259
|
-
*/
|
|
260
274
|
static VALUE
|
|
261
|
-
|
|
275
|
+
pgconn_s_sync_connect(int argc, VALUE *argv, VALUE klass)
|
|
262
276
|
{
|
|
263
277
|
t_pg_connection *this;
|
|
264
278
|
VALUE conninfo;
|
|
265
|
-
VALUE
|
|
279
|
+
VALUE self = pgconn_s_allocate( klass );
|
|
266
280
|
|
|
267
281
|
this = pg_get_connection( self );
|
|
268
282
|
conninfo = rb_funcall2( rb_cPGconn, rb_intern("parse_connect_args"), argc, argv );
|
|
269
283
|
this->pgconn = gvl_PQconnectdb(StringValueCStr(conninfo));
|
|
270
284
|
|
|
271
285
|
if(this->pgconn == NULL)
|
|
272
|
-
rb_raise(rb_ePGerror, "PQconnectdb() unable to allocate structure");
|
|
286
|
+
rb_raise(rb_ePGerror, "PQconnectdb() unable to allocate PGconn structure");
|
|
273
287
|
|
|
274
|
-
if (PQstatus(this->pgconn) == CONNECTION_BAD)
|
|
275
|
-
|
|
276
|
-
rb_iv_set(error, "@connection", self);
|
|
277
|
-
rb_exc_raise(error);
|
|
278
|
-
}
|
|
288
|
+
if (PQstatus(this->pgconn) == CONNECTION_BAD)
|
|
289
|
+
pg_raise_conn_error( rb_eConnectionBad, self, "%s", PQerrorMessage(this->pgconn));
|
|
279
290
|
|
|
280
291
|
pgconn_set_default_encoding( self );
|
|
281
292
|
|
|
@@ -308,7 +319,6 @@ pgconn_s_connect_start( int argc, VALUE *argv, VALUE klass )
|
|
|
308
319
|
{
|
|
309
320
|
VALUE rb_conn;
|
|
310
321
|
VALUE conninfo;
|
|
311
|
-
VALUE error;
|
|
312
322
|
t_pg_connection *this;
|
|
313
323
|
|
|
314
324
|
/*
|
|
@@ -321,13 +331,10 @@ pgconn_s_connect_start( int argc, VALUE *argv, VALUE klass )
|
|
|
321
331
|
this->pgconn = gvl_PQconnectStart( StringValueCStr(conninfo) );
|
|
322
332
|
|
|
323
333
|
if( this->pgconn == NULL )
|
|
324
|
-
rb_raise(rb_ePGerror, "PQconnectStart() unable to allocate structure");
|
|
334
|
+
rb_raise(rb_ePGerror, "PQconnectStart() unable to allocate PGconn structure");
|
|
325
335
|
|
|
326
|
-
if ( PQstatus(this->pgconn) == CONNECTION_BAD )
|
|
327
|
-
|
|
328
|
-
rb_iv_set(error, "@connection", rb_conn);
|
|
329
|
-
rb_exc_raise(error);
|
|
330
|
-
}
|
|
336
|
+
if ( PQstatus(this->pgconn) == CONNECTION_BAD )
|
|
337
|
+
pg_raise_conn_error( rb_eConnectionBad, rb_conn, "%s", PQerrorMessage(this->pgconn));
|
|
331
338
|
|
|
332
339
|
if ( rb_block_given_p() ) {
|
|
333
340
|
return rb_ensure( rb_yield, rb_conn, pgconn_finish, rb_conn );
|
|
@@ -335,34 +342,14 @@ pgconn_s_connect_start( int argc, VALUE *argv, VALUE klass )
|
|
|
335
342
|
return rb_conn;
|
|
336
343
|
}
|
|
337
344
|
|
|
338
|
-
/*
|
|
339
|
-
* call-seq:
|
|
340
|
-
* PG::Connection.ping(connection_hash) -> Integer
|
|
341
|
-
* PG::Connection.ping(connection_string) -> Integer
|
|
342
|
-
* PG::Connection.ping(host, port, options, tty, dbname, login, password) -> Integer
|
|
343
|
-
*
|
|
344
|
-
* Check server status.
|
|
345
|
-
*
|
|
346
|
-
* See PG::Connection.new for a description of the parameters.
|
|
347
|
-
*
|
|
348
|
-
* Returns one of:
|
|
349
|
-
* [+PQPING_OK+]
|
|
350
|
-
* server is accepting connections
|
|
351
|
-
* [+PQPING_REJECT+]
|
|
352
|
-
* server is alive but rejecting connections
|
|
353
|
-
* [+PQPING_NO_RESPONSE+]
|
|
354
|
-
* could not establish connection
|
|
355
|
-
* [+PQPING_NO_ATTEMPT+]
|
|
356
|
-
* connection not attempted (bad params)
|
|
357
|
-
*/
|
|
358
345
|
static VALUE
|
|
359
|
-
|
|
346
|
+
pgconn_s_sync_ping( int argc, VALUE *argv, VALUE klass )
|
|
360
347
|
{
|
|
361
348
|
PGPing ping;
|
|
362
349
|
VALUE conninfo;
|
|
363
350
|
|
|
364
351
|
conninfo = rb_funcall2( klass, rb_intern("parse_connect_args"), argc, argv );
|
|
365
|
-
ping =
|
|
352
|
+
ping = gvl_PQping( StringValueCStr(conninfo) );
|
|
366
353
|
|
|
367
354
|
return INT2FIX((int)ping);
|
|
368
355
|
}
|
|
@@ -403,32 +390,40 @@ pgconn_s_conndefaults(VALUE self)
|
|
|
403
390
|
return array;
|
|
404
391
|
}
|
|
405
392
|
|
|
406
|
-
|
|
407
|
-
#ifdef HAVE_PQENCRYPTPASSWORDCONN
|
|
408
393
|
/*
|
|
409
|
-
*
|
|
410
|
-
* conn.encrypt_password( password, username, algorithm=nil ) -> String
|
|
411
|
-
*
|
|
412
|
-
* This function is intended to be used by client applications that wish to send commands like <tt>ALTER USER joe PASSWORD 'pwd'</tt>.
|
|
413
|
-
* 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.
|
|
414
|
-
* Instead, use this function to convert the password to encrypted form before it is sent.
|
|
415
|
-
*
|
|
416
|
-
* The +password+ and +username+ arguments are the cleartext password, and the SQL name of the user it is for.
|
|
417
|
-
* +algorithm+ specifies the encryption algorithm to use to encrypt the password.
|
|
418
|
-
* 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).
|
|
419
|
-
* Note that support for +scram-sha-256+ was introduced in PostgreSQL version 10, and will not work correctly with older server versions.
|
|
420
|
-
* If algorithm is omitted or +nil+, this function will query the server for the current value of the +password_encryption+ setting.
|
|
421
|
-
* That can block, and will fail if the current transaction is aborted, or if the connection is busy executing another query.
|
|
422
|
-
* 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.
|
|
394
|
+
* Document-method: PG::Connection.conninfo_parse
|
|
423
395
|
*
|
|
424
|
-
*
|
|
425
|
-
*
|
|
396
|
+
* call-seq:
|
|
397
|
+
* PG::Connection.conninfo_parse(conninfo_string) -> Array
|
|
426
398
|
*
|
|
427
|
-
*
|
|
428
|
-
*
|
|
399
|
+
* Returns parsed connection options from the provided connection string as an array of hashes.
|
|
400
|
+
* Each hash has the same keys as PG::Connection.conndefaults() .
|
|
401
|
+
* The values from the +conninfo_string+ are stored in the +:val+ key.
|
|
429
402
|
*/
|
|
430
403
|
static VALUE
|
|
431
|
-
|
|
404
|
+
pgconn_s_conninfo_parse(VALUE self, VALUE conninfo)
|
|
405
|
+
{
|
|
406
|
+
VALUE array;
|
|
407
|
+
char *errmsg = NULL;
|
|
408
|
+
PQconninfoOption *options = PQconninfoParse(StringValueCStr(conninfo), &errmsg);
|
|
409
|
+
if(errmsg){
|
|
410
|
+
VALUE error = rb_str_new_cstr(errmsg);
|
|
411
|
+
PQfreemem(errmsg);
|
|
412
|
+
rb_raise(rb_ePGerror, "%"PRIsVALUE, error);
|
|
413
|
+
}
|
|
414
|
+
array = pgconn_make_conninfo_array( options );
|
|
415
|
+
|
|
416
|
+
PQconninfoFree(options);
|
|
417
|
+
|
|
418
|
+
UNUSED( self );
|
|
419
|
+
|
|
420
|
+
return array;
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
|
|
424
|
+
#ifdef HAVE_PQENCRYPTPASSWORDCONN
|
|
425
|
+
static VALUE
|
|
426
|
+
pgconn_sync_encrypt_password(int argc, VALUE *argv, VALUE self)
|
|
432
427
|
{
|
|
433
428
|
char *encrypted = NULL;
|
|
434
429
|
VALUE rval = Qnil;
|
|
@@ -445,7 +440,7 @@ pgconn_encrypt_password(int argc, VALUE *argv, VALUE self)
|
|
|
445
440
|
rval = rb_str_new2( encrypted );
|
|
446
441
|
PQfreemem( encrypted );
|
|
447
442
|
} else {
|
|
448
|
-
|
|
443
|
+
pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(conn));
|
|
449
444
|
}
|
|
450
445
|
|
|
451
446
|
return rval;
|
|
@@ -499,17 +494,18 @@ pgconn_s_encrypt_password(VALUE self, VALUE password, VALUE username)
|
|
|
499
494
|
* the asynchronous connection is ready
|
|
500
495
|
*
|
|
501
496
|
* Example:
|
|
502
|
-
*
|
|
503
|
-
*
|
|
497
|
+
* require "io/wait"
|
|
498
|
+
*
|
|
499
|
+
* conn = PG::Connection.connect_start(dbname: 'mydatabase')
|
|
504
500
|
* status = conn.connect_poll
|
|
505
501
|
* while(status != PG::PGRES_POLLING_OK) do
|
|
506
502
|
* # do some work while waiting for the connection to complete
|
|
507
503
|
* if(status == PG::PGRES_POLLING_READING)
|
|
508
|
-
*
|
|
504
|
+
* unless conn.socket_io.wait_readable(10.0)
|
|
509
505
|
* raise "Asynchronous connection timed out!"
|
|
510
506
|
* end
|
|
511
507
|
* elsif(status == PG::PGRES_POLLING_WRITING)
|
|
512
|
-
*
|
|
508
|
+
* unless conn.socket_io.wait_writable(10.0)
|
|
513
509
|
* raise "Asynchronous connection timed out!"
|
|
514
510
|
* end
|
|
515
511
|
* end
|
|
@@ -523,6 +519,9 @@ pgconn_connect_poll(VALUE self)
|
|
|
523
519
|
{
|
|
524
520
|
PostgresPollingStatusType status;
|
|
525
521
|
status = gvl_PQconnectPoll(pg_get_pgconn(self));
|
|
522
|
+
|
|
523
|
+
pgconn_close_socket_io(self);
|
|
524
|
+
|
|
526
525
|
return INT2FIX((int)status);
|
|
527
526
|
}
|
|
528
527
|
|
|
@@ -559,15 +558,8 @@ pgconn_finished_p( VALUE self )
|
|
|
559
558
|
}
|
|
560
559
|
|
|
561
560
|
|
|
562
|
-
/*
|
|
563
|
-
* call-seq:
|
|
564
|
-
* conn.reset()
|
|
565
|
-
*
|
|
566
|
-
* Resets the backend connection. This method closes the
|
|
567
|
-
* backend connection and tries to re-connect.
|
|
568
|
-
*/
|
|
569
561
|
static VALUE
|
|
570
|
-
|
|
562
|
+
pgconn_sync_reset( VALUE self )
|
|
571
563
|
{
|
|
572
564
|
pgconn_close_socket_io( self );
|
|
573
565
|
gvl_PQreset( pg_get_pgconn(self) );
|
|
@@ -589,7 +581,7 @@ pgconn_reset_start(VALUE self)
|
|
|
589
581
|
{
|
|
590
582
|
pgconn_close_socket_io( self );
|
|
591
583
|
if(gvl_PQresetStart(pg_get_pgconn(self)) == 0)
|
|
592
|
-
|
|
584
|
+
pg_raise_conn_error( rb_eUnableToSend, self, "reset has failed");
|
|
593
585
|
return Qnil;
|
|
594
586
|
}
|
|
595
587
|
|
|
@@ -606,6 +598,9 @@ pgconn_reset_poll(VALUE self)
|
|
|
606
598
|
{
|
|
607
599
|
PostgresPollingStatusType status;
|
|
608
600
|
status = gvl_PQresetPoll(pg_get_pgconn(self));
|
|
601
|
+
|
|
602
|
+
pgconn_close_socket_io(self);
|
|
603
|
+
|
|
609
604
|
return INT2FIX((int)status);
|
|
610
605
|
}
|
|
611
606
|
|
|
@@ -656,7 +651,18 @@ pgconn_pass(VALUE self)
|
|
|
656
651
|
* call-seq:
|
|
657
652
|
* conn.host()
|
|
658
653
|
*
|
|
659
|
-
* Returns the
|
|
654
|
+
* Returns the server host name of the active connection.
|
|
655
|
+
* This can be a host name, an IP address, or a directory path if the connection is via Unix socket.
|
|
656
|
+
* (The path case can be distinguished because it will always be an absolute path, beginning with +/+ .)
|
|
657
|
+
*
|
|
658
|
+
* If the connection parameters specified both host and hostaddr, then +host+ will return the host information.
|
|
659
|
+
* If only hostaddr was specified, then that is returned.
|
|
660
|
+
* If multiple hosts were specified in the connection parameters, +host+ returns the host actually connected to.
|
|
661
|
+
*
|
|
662
|
+
* If there is an error producing the host information (perhaps if the connection has not been fully established or there was an error), it returns an empty string.
|
|
663
|
+
*
|
|
664
|
+
* If multiple hosts were specified in the connection parameters, it is not possible to rely on the result of +host+ until the connection is established.
|
|
665
|
+
* The status of the connection can be checked using the function Connection#status .
|
|
660
666
|
*/
|
|
661
667
|
static VALUE
|
|
662
668
|
pgconn_host(VALUE self)
|
|
@@ -666,6 +672,26 @@ pgconn_host(VALUE self)
|
|
|
666
672
|
return rb_str_new2(host);
|
|
667
673
|
}
|
|
668
674
|
|
|
675
|
+
/* PQhostaddr() appeared in PostgreSQL-12 together with PQresultMemorySize() */
|
|
676
|
+
#if defined(HAVE_PQRESULTMEMORYSIZE)
|
|
677
|
+
/*
|
|
678
|
+
* call-seq:
|
|
679
|
+
* conn.hostaddr()
|
|
680
|
+
*
|
|
681
|
+
* Returns the server IP address of the active connection.
|
|
682
|
+
* This can be the address that a host name resolved to, or an IP address provided through the hostaddr parameter.
|
|
683
|
+
* If there is an error producing the host information (perhaps if the connection has not been fully established or there was an error), it returns an empty string.
|
|
684
|
+
*
|
|
685
|
+
*/
|
|
686
|
+
static VALUE
|
|
687
|
+
pgconn_hostaddr(VALUE self)
|
|
688
|
+
{
|
|
689
|
+
char *host = PQhostaddr(pg_get_pgconn(self));
|
|
690
|
+
if (!host) return Qnil;
|
|
691
|
+
return rb_str_new2(host);
|
|
692
|
+
}
|
|
693
|
+
#endif
|
|
694
|
+
|
|
669
695
|
/*
|
|
670
696
|
* call-seq:
|
|
671
697
|
* conn.port()
|
|
@@ -676,21 +702,19 @@ static VALUE
|
|
|
676
702
|
pgconn_port(VALUE self)
|
|
677
703
|
{
|
|
678
704
|
char* port = PQport(pg_get_pgconn(self));
|
|
679
|
-
return INT2NUM(
|
|
705
|
+
return INT2NUM(atoi(port));
|
|
680
706
|
}
|
|
681
707
|
|
|
682
708
|
/*
|
|
683
709
|
* call-seq:
|
|
684
710
|
* conn.tty()
|
|
685
711
|
*
|
|
686
|
-
*
|
|
712
|
+
* Obsolete function.
|
|
687
713
|
*/
|
|
688
714
|
static VALUE
|
|
689
715
|
pgconn_tty(VALUE self)
|
|
690
716
|
{
|
|
691
|
-
|
|
692
|
-
if (!tty) return Qnil;
|
|
693
|
-
return rb_str_new2(tty);
|
|
717
|
+
return rb_str_new2("");
|
|
694
718
|
}
|
|
695
719
|
|
|
696
720
|
/*
|
|
@@ -708,7 +732,6 @@ pgconn_options(VALUE self)
|
|
|
708
732
|
}
|
|
709
733
|
|
|
710
734
|
|
|
711
|
-
#ifdef HAVE_PQCONNINFO
|
|
712
735
|
/*
|
|
713
736
|
* call-seq:
|
|
714
737
|
* conn.conninfo -> hash
|
|
@@ -728,14 +751,20 @@ pgconn_conninfo( VALUE self )
|
|
|
728
751
|
|
|
729
752
|
return array;
|
|
730
753
|
}
|
|
731
|
-
#endif
|
|
732
754
|
|
|
733
755
|
|
|
734
756
|
/*
|
|
735
757
|
* call-seq:
|
|
736
758
|
* conn.status()
|
|
737
759
|
*
|
|
738
|
-
* Returns status of connection
|
|
760
|
+
* Returns the status of the connection, which is one:
|
|
761
|
+
* PG::Constants::CONNECTION_OK
|
|
762
|
+
* PG::Constants::CONNECTION_BAD
|
|
763
|
+
*
|
|
764
|
+
* ... and other constants of kind PG::Constants::CONNECTION_*
|
|
765
|
+
*
|
|
766
|
+
* Example:
|
|
767
|
+
* PG.constants.grep(/CONNECTION_/).find{|c| PG.const_get(c) == conn.status} # => :CONNECTION_OK
|
|
739
768
|
*/
|
|
740
769
|
static VALUE
|
|
741
770
|
pgconn_status(VALUE self)
|
|
@@ -823,7 +852,10 @@ pgconn_server_version(VALUE self)
|
|
|
823
852
|
* call-seq:
|
|
824
853
|
* conn.error_message -> String
|
|
825
854
|
*
|
|
826
|
-
* Returns the error message
|
|
855
|
+
* Returns the error message most recently generated by an operation on the connection.
|
|
856
|
+
*
|
|
857
|
+
* Nearly all libpq functions will set a message for conn.error_message if they fail.
|
|
858
|
+
* Note that by libpq convention, a nonempty error_message result can consist of multiple lines, and will include a trailing newline.
|
|
827
859
|
*/
|
|
828
860
|
static VALUE
|
|
829
861
|
pgconn_error_message(VALUE self)
|
|
@@ -857,7 +889,8 @@ pgconn_socket(VALUE self)
|
|
|
857
889
|
pg_deprecated(4, ("conn.socket is deprecated and should be replaced by conn.socket_io"));
|
|
858
890
|
|
|
859
891
|
if( (sd = PQsocket(pg_get_pgconn(self))) < 0)
|
|
860
|
-
|
|
892
|
+
pg_raise_conn_error( rb_eConnectionBad, self, "PQsocket() can't get socket descriptor");
|
|
893
|
+
|
|
861
894
|
return INT2NUM(sd);
|
|
862
895
|
}
|
|
863
896
|
|
|
@@ -865,38 +898,45 @@ pgconn_socket(VALUE self)
|
|
|
865
898
|
* call-seq:
|
|
866
899
|
* conn.socket_io() -> IO
|
|
867
900
|
*
|
|
868
|
-
* Fetch
|
|
869
|
-
* This object can be used for IO.select to wait for events while running
|
|
870
|
-
*
|
|
901
|
+
* Fetch an IO object created from the Connection's underlying socket.
|
|
902
|
+
* This object can be used per <tt>socket_io.wait_readable</tt>, <tt>socket_io.wait_writable</tt> or for <tt>IO.select</tt> to wait for events while running asynchronous API calls.
|
|
903
|
+
* <tt>IO#wait_*able</tt> is is <tt>Fiber.scheduler</tt> compatible in contrast to <tt>IO.select</tt>.
|
|
871
904
|
*
|
|
872
|
-
*
|
|
873
|
-
*
|
|
874
|
-
*
|
|
905
|
+
* The IO object can change while the connection is established, but is memorized afterwards.
|
|
906
|
+
* So be sure not to cache the IO object, but repeat calling <tt>conn.socket_io</tt> instead.
|
|
907
|
+
*
|
|
908
|
+
* Using this method also works on Windows in contrast to using #socket .
|
|
909
|
+
* It also avoids the problem of the underlying connection being closed by Ruby when an IO created using <tt>IO.for_fd(conn.socket)</tt> goes out of scope.
|
|
875
910
|
*/
|
|
876
911
|
static VALUE
|
|
877
912
|
pgconn_socket_io(VALUE self)
|
|
878
913
|
{
|
|
879
914
|
int sd;
|
|
880
915
|
int ruby_sd;
|
|
881
|
-
ID id_autoclose = rb_intern("autoclose=");
|
|
882
916
|
t_pg_connection *this = pg_get_connection_safe( self );
|
|
917
|
+
VALUE cSocket;
|
|
883
918
|
VALUE socket_io = this->socket_io;
|
|
884
919
|
|
|
885
920
|
if ( !RTEST(socket_io) ) {
|
|
886
|
-
if( (sd = PQsocket(this->pgconn)) < 0)
|
|
887
|
-
|
|
921
|
+
if( (sd = PQsocket(this->pgconn)) < 0){
|
|
922
|
+
pg_raise_conn_error( rb_eConnectionBad, self, "PQsocket() can't get socket descriptor");
|
|
923
|
+
}
|
|
888
924
|
|
|
889
925
|
#ifdef _WIN32
|
|
890
926
|
ruby_sd = rb_w32_wrap_io_handle((HANDLE)(intptr_t)sd, O_RDWR|O_BINARY|O_NOINHERIT);
|
|
927
|
+
if( ruby_sd == -1 )
|
|
928
|
+
pg_raise_conn_error( rb_eConnectionBad, self, "Could not wrap win32 socket handle");
|
|
929
|
+
|
|
891
930
|
this->ruby_sd = ruby_sd;
|
|
892
931
|
#else
|
|
893
932
|
ruby_sd = sd;
|
|
894
933
|
#endif
|
|
895
934
|
|
|
896
|
-
|
|
935
|
+
cSocket = rb_const_get(rb_cObject, rb_intern("BasicSocket"));
|
|
936
|
+
socket_io = rb_funcall( cSocket, rb_intern("for_fd"), 1, INT2NUM(ruby_sd));
|
|
897
937
|
|
|
898
938
|
/* Disable autoclose feature */
|
|
899
|
-
rb_funcall( socket_io,
|
|
939
|
+
rb_funcall( socket_io, s_id_autoclose_set, 1, Qfalse );
|
|
900
940
|
|
|
901
941
|
this->socket_io = socket_io;
|
|
902
942
|
}
|
|
@@ -918,6 +958,51 @@ pgconn_backend_pid(VALUE self)
|
|
|
918
958
|
return INT2NUM(PQbackendPID(pg_get_pgconn(self)));
|
|
919
959
|
}
|
|
920
960
|
|
|
961
|
+
typedef struct
|
|
962
|
+
{
|
|
963
|
+
struct sockaddr_storage addr;
|
|
964
|
+
socklen_t salen;
|
|
965
|
+
} SockAddr;
|
|
966
|
+
|
|
967
|
+
/* Copy of struct pg_cancel from libpq-int.h
|
|
968
|
+
*
|
|
969
|
+
* See https://github.com/postgres/postgres/blame/master/src/interfaces/libpq/libpq-int.h#L577-L586
|
|
970
|
+
*/
|
|
971
|
+
struct pg_cancel
|
|
972
|
+
{
|
|
973
|
+
SockAddr raddr; /* Remote address */
|
|
974
|
+
int be_pid; /* PID of backend --- needed for cancels */
|
|
975
|
+
int be_key; /* key of backend --- needed for cancels */
|
|
976
|
+
};
|
|
977
|
+
|
|
978
|
+
/*
|
|
979
|
+
* call-seq:
|
|
980
|
+
* conn.backend_key() -> Integer
|
|
981
|
+
*
|
|
982
|
+
* Returns the key of the backend server process for this connection.
|
|
983
|
+
* This key can be used to cancel queries on the server.
|
|
984
|
+
*/
|
|
985
|
+
static VALUE
|
|
986
|
+
pgconn_backend_key(VALUE self)
|
|
987
|
+
{
|
|
988
|
+
int be_key;
|
|
989
|
+
struct pg_cancel *cancel;
|
|
990
|
+
PGconn *conn = pg_get_pgconn(self);
|
|
991
|
+
|
|
992
|
+
cancel = (struct pg_cancel*)PQgetCancel(conn);
|
|
993
|
+
if(cancel == NULL)
|
|
994
|
+
pg_raise_conn_error( rb_ePGerror, self, "Invalid connection!");
|
|
995
|
+
|
|
996
|
+
if( cancel->be_pid != PQbackendPID(conn) )
|
|
997
|
+
rb_raise(rb_ePGerror,"Unexpected binary struct layout - please file a bug report at ruby-pg!");
|
|
998
|
+
|
|
999
|
+
be_key = cancel->be_key;
|
|
1000
|
+
|
|
1001
|
+
PQfreeCancel(cancel);
|
|
1002
|
+
|
|
1003
|
+
return INT2NUM(be_key);
|
|
1004
|
+
}
|
|
1005
|
+
|
|
921
1006
|
/*
|
|
922
1007
|
* call-seq:
|
|
923
1008
|
* conn.connection_needs_password() -> Boolean
|
|
@@ -948,7 +1033,7 @@ pgconn_connection_used_password(VALUE self)
|
|
|
948
1033
|
/* :TODO: get_ssl */
|
|
949
1034
|
|
|
950
1035
|
|
|
951
|
-
static VALUE
|
|
1036
|
+
static VALUE pgconn_sync_exec_params( int, VALUE *, VALUE );
|
|
952
1037
|
|
|
953
1038
|
/*
|
|
954
1039
|
* call-seq:
|
|
@@ -962,11 +1047,11 @@ static VALUE pgconn_exec_params( int, VALUE *, VALUE );
|
|
|
962
1047
|
* However #async_exec has two advantages:
|
|
963
1048
|
*
|
|
964
1049
|
* 1. #async_exec can be aborted by signals (like Ctrl-C), while #exec blocks signal processing until the query is answered.
|
|
965
|
-
* 2. Ruby VM gets notified about IO blocked operations.
|
|
966
|
-
*
|
|
1050
|
+
* 2. Ruby VM gets notified about IO blocked operations and can pass them through <tt>Fiber.scheduler</tt>.
|
|
1051
|
+
* So only <tt>async_*</tt> methods are compatible to event based schedulers like the async gem.
|
|
967
1052
|
*/
|
|
968
1053
|
static VALUE
|
|
969
|
-
|
|
1054
|
+
pgconn_sync_exec(int argc, VALUE *argv, VALUE self)
|
|
970
1055
|
{
|
|
971
1056
|
t_pg_connection *this = pg_get_connection_safe( self );
|
|
972
1057
|
PGresult *result = NULL;
|
|
@@ -987,7 +1072,7 @@ pgconn_exec(int argc, VALUE *argv, VALUE self)
|
|
|
987
1072
|
pg_deprecated(0, ("forwarding exec to exec_params is deprecated"));
|
|
988
1073
|
|
|
989
1074
|
/* Otherwise, just call #exec_params instead for backward-compatibility */
|
|
990
|
-
return
|
|
1075
|
+
return pgconn_sync_exec_params( argc, argv, self );
|
|
991
1076
|
|
|
992
1077
|
}
|
|
993
1078
|
|
|
@@ -1019,7 +1104,7 @@ struct query_params_data {
|
|
|
1019
1104
|
* Filled by alloc_query_params()
|
|
1020
1105
|
*/
|
|
1021
1106
|
|
|
1022
|
-
/* Wraps the pointer of allocated memory, if function parameters
|
|
1107
|
+
/* Wraps the pointer of allocated memory, if function parameters don't
|
|
1023
1108
|
* fit in the memory_pool below.
|
|
1024
1109
|
*/
|
|
1025
1110
|
VALUE heap_pool;
|
|
@@ -1037,7 +1122,7 @@ struct query_params_data {
|
|
|
1037
1122
|
Oid *types;
|
|
1038
1123
|
|
|
1039
1124
|
/* This array takes the string values for the timeframe of the query,
|
|
1040
|
-
* if param value
|
|
1125
|
+
* if param value conversion is required
|
|
1041
1126
|
*/
|
|
1042
1127
|
VALUE gc_array;
|
|
1043
1128
|
|
|
@@ -1051,8 +1136,9 @@ struct query_params_data {
|
|
|
1051
1136
|
};
|
|
1052
1137
|
|
|
1053
1138
|
static void
|
|
1054
|
-
free_typecast_heap_chain(
|
|
1139
|
+
free_typecast_heap_chain(void *_chain_entry)
|
|
1055
1140
|
{
|
|
1141
|
+
struct linked_typecast_data *chain_entry = (struct linked_typecast_data *)_chain_entry;
|
|
1056
1142
|
while(chain_entry){
|
|
1057
1143
|
struct linked_typecast_data *next = chain_entry->next;
|
|
1058
1144
|
xfree(chain_entry);
|
|
@@ -1060,6 +1146,18 @@ free_typecast_heap_chain(struct linked_typecast_data *chain_entry)
|
|
|
1060
1146
|
}
|
|
1061
1147
|
}
|
|
1062
1148
|
|
|
1149
|
+
static const rb_data_type_t pg_typecast_buffer_type = {
|
|
1150
|
+
"PG::Connection typecast buffer chain",
|
|
1151
|
+
{
|
|
1152
|
+
(RUBY_DATA_FUNC) NULL,
|
|
1153
|
+
free_typecast_heap_chain,
|
|
1154
|
+
(size_t (*)(const void *))NULL,
|
|
1155
|
+
},
|
|
1156
|
+
0,
|
|
1157
|
+
0,
|
|
1158
|
+
RUBY_TYPED_FREE_IMMEDIATELY,
|
|
1159
|
+
};
|
|
1160
|
+
|
|
1063
1161
|
static char *
|
|
1064
1162
|
alloc_typecast_buf( VALUE *typecast_heap_chain, int len )
|
|
1065
1163
|
{
|
|
@@ -1070,17 +1168,28 @@ alloc_typecast_buf( VALUE *typecast_heap_chain, int len )
|
|
|
1070
1168
|
/* Did we already wrap a memory chain per T_DATA object? */
|
|
1071
1169
|
if( NIL_P( *typecast_heap_chain ) ){
|
|
1072
1170
|
/* Leave free'ing of the buffer chain to the GC, when paramsData has left the stack */
|
|
1073
|
-
*typecast_heap_chain =
|
|
1171
|
+
*typecast_heap_chain = TypedData_Wrap_Struct( rb_cObject, &pg_typecast_buffer_type, allocated );
|
|
1074
1172
|
allocated->next = NULL;
|
|
1075
1173
|
} else {
|
|
1076
1174
|
/* Append to the chain */
|
|
1077
|
-
allocated->next =
|
|
1078
|
-
|
|
1175
|
+
allocated->next = RTYPEDDATA_DATA( *typecast_heap_chain );
|
|
1176
|
+
RTYPEDDATA_DATA( *typecast_heap_chain ) = allocated;
|
|
1079
1177
|
}
|
|
1080
1178
|
|
|
1081
1179
|
return &allocated->data[0];
|
|
1082
1180
|
}
|
|
1083
1181
|
|
|
1182
|
+
static const rb_data_type_t pg_query_heap_pool_type = {
|
|
1183
|
+
"PG::Connection query heap pool",
|
|
1184
|
+
{
|
|
1185
|
+
(RUBY_DATA_FUNC) NULL,
|
|
1186
|
+
RUBY_TYPED_DEFAULT_FREE,
|
|
1187
|
+
(size_t (*)(const void *))NULL,
|
|
1188
|
+
},
|
|
1189
|
+
0,
|
|
1190
|
+
0,
|
|
1191
|
+
RUBY_TYPED_FREE_IMMEDIATELY,
|
|
1192
|
+
};
|
|
1084
1193
|
|
|
1085
1194
|
static int
|
|
1086
1195
|
alloc_query_params(struct query_params_data *paramsData)
|
|
@@ -1095,7 +1204,7 @@ alloc_query_params(struct query_params_data *paramsData)
|
|
|
1095
1204
|
|
|
1096
1205
|
Check_Type(paramsData->params, T_ARRAY);
|
|
1097
1206
|
|
|
1098
|
-
p_typemap =
|
|
1207
|
+
p_typemap = RTYPEDDATA_DATA( paramsData->typemap );
|
|
1099
1208
|
p_typemap->funcs.fit_to_query( paramsData->typemap, paramsData->params );
|
|
1100
1209
|
|
|
1101
1210
|
paramsData->heap_pool = Qnil;
|
|
@@ -1114,7 +1223,7 @@ alloc_query_params(struct query_params_data *paramsData)
|
|
|
1114
1223
|
/* Allocate one combined memory pool for all possible function parameters */
|
|
1115
1224
|
memory_pool = (char*)xmalloc( required_pool_size );
|
|
1116
1225
|
/* Leave free'ing of the buffer to the GC, when paramsData has left the stack */
|
|
1117
|
-
paramsData->heap_pool =
|
|
1226
|
+
paramsData->heap_pool = TypedData_Wrap_Struct( rb_cObject, &pg_query_heap_pool_type, memory_pool );
|
|
1118
1227
|
required_pool_size = 0;
|
|
1119
1228
|
}else{
|
|
1120
1229
|
/* Use stack memory for function parameters */
|
|
@@ -1227,12 +1336,11 @@ pgconn_query_assign_typemap( VALUE self, struct query_params_data *paramsData )
|
|
|
1227
1336
|
/* Use default typemap for queries. It's type is checked when assigned. */
|
|
1228
1337
|
paramsData->typemap = pg_get_connection(self)->type_map_for_queries;
|
|
1229
1338
|
}else{
|
|
1339
|
+
t_typemap *tm;
|
|
1340
|
+
UNUSED(tm);
|
|
1341
|
+
|
|
1230
1342
|
/* Check type of method param */
|
|
1231
|
-
|
|
1232
|
-
rb_raise( rb_eTypeError, "wrong argument type %s (expected kind of PG::TypeMap)",
|
|
1233
|
-
rb_obj_classname( paramsData->typemap ) );
|
|
1234
|
-
}
|
|
1235
|
-
Check_Type( paramsData->typemap, T_DATA );
|
|
1343
|
+
TypedData_Get_Struct(paramsData->typemap, t_typemap, &pg_typemap_type, tm);
|
|
1236
1344
|
}
|
|
1237
1345
|
}
|
|
1238
1346
|
|
|
@@ -1246,7 +1354,7 @@ pgconn_query_assign_typemap( VALUE self, struct query_params_data *paramsData )
|
|
|
1246
1354
|
* It's not recommended to use explicit sync or async variants but #exec_params instead, unless you have a good reason to do so.
|
|
1247
1355
|
*/
|
|
1248
1356
|
static VALUE
|
|
1249
|
-
|
|
1357
|
+
pgconn_sync_exec_params( int argc, VALUE *argv, VALUE self )
|
|
1250
1358
|
{
|
|
1251
1359
|
t_pg_connection *this = pg_get_connection_safe( self );
|
|
1252
1360
|
PGresult *result = NULL;
|
|
@@ -1266,7 +1374,7 @@ pgconn_exec_params( int argc, VALUE *argv, VALUE self )
|
|
|
1266
1374
|
*/
|
|
1267
1375
|
if ( NIL_P(paramsData.params) ) {
|
|
1268
1376
|
pg_deprecated(1, ("forwarding exec_params to exec is deprecated"));
|
|
1269
|
-
return
|
|
1377
|
+
return pgconn_sync_exec( 1, argv, self );
|
|
1270
1378
|
}
|
|
1271
1379
|
pgconn_query_assign_typemap( self, ¶msData );
|
|
1272
1380
|
|
|
@@ -1297,7 +1405,7 @@ pgconn_exec_params( int argc, VALUE *argv, VALUE self )
|
|
|
1297
1405
|
* It's not recommended to use explicit sync or async variants but #prepare instead, unless you have a good reason to do so.
|
|
1298
1406
|
*/
|
|
1299
1407
|
static VALUE
|
|
1300
|
-
|
|
1408
|
+
pgconn_sync_prepare(int argc, VALUE *argv, VALUE self)
|
|
1301
1409
|
{
|
|
1302
1410
|
t_pg_connection *this = pg_get_connection_safe( self );
|
|
1303
1411
|
PGresult *result = NULL;
|
|
@@ -1346,7 +1454,7 @@ pgconn_prepare(int argc, VALUE *argv, VALUE self)
|
|
|
1346
1454
|
* It's not recommended to use explicit sync or async variants but #exec_prepared instead, unless you have a good reason to do so.
|
|
1347
1455
|
*/
|
|
1348
1456
|
static VALUE
|
|
1349
|
-
|
|
1457
|
+
pgconn_sync_exec_prepared(int argc, VALUE *argv, VALUE self)
|
|
1350
1458
|
{
|
|
1351
1459
|
t_pg_connection *this = pg_get_connection_safe( self );
|
|
1352
1460
|
PGresult *result = NULL;
|
|
@@ -1391,7 +1499,7 @@ pgconn_exec_prepared(int argc, VALUE *argv, VALUE self)
|
|
|
1391
1499
|
* It's not recommended to use explicit sync or async variants but #describe_prepared instead, unless you have a good reason to do so.
|
|
1392
1500
|
*/
|
|
1393
1501
|
static VALUE
|
|
1394
|
-
|
|
1502
|
+
pgconn_sync_describe_prepared(VALUE self, VALUE stmt_name)
|
|
1395
1503
|
{
|
|
1396
1504
|
PGresult *result;
|
|
1397
1505
|
VALUE rb_pgresult;
|
|
@@ -1419,8 +1527,7 @@ pgconn_describe_prepared(VALUE self, VALUE stmt_name)
|
|
|
1419
1527
|
* It's not recommended to use explicit sync or async variants but #describe_portal instead, unless you have a good reason to do so.
|
|
1420
1528
|
*/
|
|
1421
1529
|
static VALUE
|
|
1422
|
-
|
|
1423
|
-
VALUE self, stmt_name;
|
|
1530
|
+
pgconn_sync_describe_portal(VALUE self, VALUE stmt_name)
|
|
1424
1531
|
{
|
|
1425
1532
|
PGresult *result;
|
|
1426
1533
|
VALUE rb_pgresult;
|
|
@@ -1454,6 +1561,9 @@ pgconn_describe_portal(self, stmt_name)
|
|
|
1454
1561
|
* * +PGRES_NONFATAL_ERROR+
|
|
1455
1562
|
* * +PGRES_FATAL_ERROR+
|
|
1456
1563
|
* * +PGRES_COPY_BOTH+
|
|
1564
|
+
* * +PGRES_SINGLE_TUPLE+
|
|
1565
|
+
* * +PGRES_PIPELINE_SYNC+
|
|
1566
|
+
* * +PGRES_PIPELINE_ABORTED+
|
|
1457
1567
|
*/
|
|
1458
1568
|
static VALUE
|
|
1459
1569
|
pgconn_make_empty_pgresult(VALUE self, VALUE status)
|
|
@@ -1509,9 +1619,9 @@ pgconn_s_escape(VALUE self, VALUE string)
|
|
|
1509
1619
|
if( !singleton ) {
|
|
1510
1620
|
size = PQescapeStringConn(pg_get_pgconn(self), RSTRING_PTR(result),
|
|
1511
1621
|
RSTRING_PTR(string), RSTRING_LEN(string), &error);
|
|
1512
|
-
if(error)
|
|
1513
|
-
|
|
1514
|
-
|
|
1622
|
+
if(error)
|
|
1623
|
+
pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(pg_get_pgconn(self)));
|
|
1624
|
+
|
|
1515
1625
|
} else {
|
|
1516
1626
|
size = PQescapeString(RSTRING_PTR(result), RSTRING_PTR(string), RSTRING_LEN(string));
|
|
1517
1627
|
}
|
|
@@ -1607,7 +1717,6 @@ pgconn_escape_literal(VALUE self, VALUE string)
|
|
|
1607
1717
|
{
|
|
1608
1718
|
t_pg_connection *this = pg_get_connection_safe( self );
|
|
1609
1719
|
char *escaped = NULL;
|
|
1610
|
-
VALUE error;
|
|
1611
1720
|
VALUE result = Qnil;
|
|
1612
1721
|
int enc_idx = this->enc_idx;
|
|
1613
1722
|
|
|
@@ -1618,12 +1727,8 @@ pgconn_escape_literal(VALUE self, VALUE string)
|
|
|
1618
1727
|
|
|
1619
1728
|
escaped = PQescapeLiteral(this->pgconn, RSTRING_PTR(string), RSTRING_LEN(string));
|
|
1620
1729
|
if (escaped == NULL)
|
|
1621
|
-
|
|
1622
|
-
|
|
1623
|
-
rb_iv_set(error, "@connection", self);
|
|
1624
|
-
rb_exc_raise(error);
|
|
1625
|
-
return Qnil;
|
|
1626
|
-
}
|
|
1730
|
+
pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(this->pgconn));
|
|
1731
|
+
|
|
1627
1732
|
result = rb_str_new2(escaped);
|
|
1628
1733
|
PQfreemem(escaped);
|
|
1629
1734
|
PG_ENCODING_SET_NOCHECK(result, enc_idx);
|
|
@@ -1646,7 +1751,6 @@ pgconn_escape_identifier(VALUE self, VALUE string)
|
|
|
1646
1751
|
{
|
|
1647
1752
|
t_pg_connection *this = pg_get_connection_safe( self );
|
|
1648
1753
|
char *escaped = NULL;
|
|
1649
|
-
VALUE error;
|
|
1650
1754
|
VALUE result = Qnil;
|
|
1651
1755
|
int enc_idx = this->enc_idx;
|
|
1652
1756
|
|
|
@@ -1657,12 +1761,8 @@ pgconn_escape_identifier(VALUE self, VALUE string)
|
|
|
1657
1761
|
|
|
1658
1762
|
escaped = PQescapeIdentifier(this->pgconn, RSTRING_PTR(string), RSTRING_LEN(string));
|
|
1659
1763
|
if (escaped == NULL)
|
|
1660
|
-
|
|
1661
|
-
|
|
1662
|
-
rb_iv_set(error, "@connection", self);
|
|
1663
|
-
rb_exc_raise(error);
|
|
1664
|
-
return Qnil;
|
|
1665
|
-
}
|
|
1764
|
+
pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(this->pgconn));
|
|
1765
|
+
|
|
1666
1766
|
result = rb_str_new2(escaped);
|
|
1667
1767
|
PQfreemem(escaped);
|
|
1668
1768
|
PG_ENCODING_SET_NOCHECK(result, enc_idx);
|
|
@@ -1710,14 +1810,9 @@ static VALUE
|
|
|
1710
1810
|
pgconn_set_single_row_mode(VALUE self)
|
|
1711
1811
|
{
|
|
1712
1812
|
PGconn *conn = pg_get_pgconn(self);
|
|
1713
|
-
VALUE error;
|
|
1714
1813
|
|
|
1715
1814
|
if( PQsetSingleRowMode(conn) == 0 )
|
|
1716
|
-
|
|
1717
|
-
error = rb_exc_new2(rb_ePGerror, PQerrorMessage(conn));
|
|
1718
|
-
rb_iv_set(error, "@connection", self);
|
|
1719
|
-
rb_exc_raise(error);
|
|
1720
|
-
}
|
|
1815
|
+
pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(conn));
|
|
1721
1816
|
|
|
1722
1817
|
return self;
|
|
1723
1818
|
}
|
|
@@ -1741,15 +1836,13 @@ static VALUE
|
|
|
1741
1836
|
pgconn_send_query(int argc, VALUE *argv, VALUE self)
|
|
1742
1837
|
{
|
|
1743
1838
|
t_pg_connection *this = pg_get_connection_safe( self );
|
|
1744
|
-
VALUE error;
|
|
1745
1839
|
|
|
1746
1840
|
/* If called with no or nil parameters, use PQexec for compatibility */
|
|
1747
1841
|
if ( argc == 1 || (argc >= 2 && argc <= 4 && NIL_P(argv[1]) )) {
|
|
1748
|
-
if(gvl_PQsendQuery(this->pgconn, pg_cstr_enc(argv[0], this->enc_idx)) == 0)
|
|
1749
|
-
|
|
1750
|
-
|
|
1751
|
-
|
|
1752
|
-
}
|
|
1842
|
+
if(gvl_PQsendQuery(this->pgconn, pg_cstr_enc(argv[0], this->enc_idx)) == 0)
|
|
1843
|
+
pg_raise_conn_error( rb_eUnableToSend, self, "%s", PQerrorMessage(this->pgconn));
|
|
1844
|
+
|
|
1845
|
+
pgconn_wait_for_flush( self );
|
|
1753
1846
|
return Qnil;
|
|
1754
1847
|
}
|
|
1755
1848
|
|
|
@@ -1779,7 +1872,7 @@ pgconn_send_query(int argc, VALUE *argv, VALUE self)
|
|
|
1779
1872
|
* or, it may be a String. If it is a string, that is equivalent to the hash:
|
|
1780
1873
|
* { :value => <string value>, :type => 0, :format => 0 }
|
|
1781
1874
|
*
|
|
1782
|
-
* PostgreSQL bind parameters are represented as $1, $
|
|
1875
|
+
* PostgreSQL bind parameters are represented as $1, $2, $3, etc.,
|
|
1783
1876
|
* inside the SQL query. The 0th element of the +params+ array is bound
|
|
1784
1877
|
* to $1, the 1st element is bound to $2, etc. +nil+ is treated as +NULL+.
|
|
1785
1878
|
*
|
|
@@ -1805,7 +1898,6 @@ pgconn_send_query_params(int argc, VALUE *argv, VALUE self)
|
|
|
1805
1898
|
t_pg_connection *this = pg_get_connection_safe( self );
|
|
1806
1899
|
int result;
|
|
1807
1900
|
VALUE command, in_res_fmt;
|
|
1808
|
-
VALUE error;
|
|
1809
1901
|
int nParams;
|
|
1810
1902
|
int resultFormat;
|
|
1811
1903
|
struct query_params_data paramsData = { this->enc_idx };
|
|
@@ -1822,11 +1914,10 @@ pgconn_send_query_params(int argc, VALUE *argv, VALUE self)
|
|
|
1822
1914
|
|
|
1823
1915
|
free_query_params( ¶msData );
|
|
1824
1916
|
|
|
1825
|
-
if(result == 0)
|
|
1826
|
-
|
|
1827
|
-
|
|
1828
|
-
|
|
1829
|
-
}
|
|
1917
|
+
if(result == 0)
|
|
1918
|
+
pg_raise_conn_error( rb_eUnableToSend, self, "%s", PQerrorMessage(this->pgconn));
|
|
1919
|
+
|
|
1920
|
+
pgconn_wait_for_flush( self );
|
|
1830
1921
|
return Qnil;
|
|
1831
1922
|
}
|
|
1832
1923
|
|
|
@@ -1847,7 +1938,7 @@ pgconn_send_query_params(int argc, VALUE *argv, VALUE self)
|
|
|
1847
1938
|
*
|
|
1848
1939
|
* For example: "SELECT $1::int"
|
|
1849
1940
|
*
|
|
1850
|
-
* PostgreSQL bind parameters are represented as $1, $
|
|
1941
|
+
* PostgreSQL bind parameters are represented as $1, $2, $3, etc.,
|
|
1851
1942
|
* inside the SQL query.
|
|
1852
1943
|
*/
|
|
1853
1944
|
static VALUE
|
|
@@ -1857,7 +1948,6 @@ pgconn_send_prepare(int argc, VALUE *argv, VALUE self)
|
|
|
1857
1948
|
int result;
|
|
1858
1949
|
VALUE name, command, in_paramtypes;
|
|
1859
1950
|
VALUE param;
|
|
1860
|
-
VALUE error;
|
|
1861
1951
|
int i = 0;
|
|
1862
1952
|
int nParams = 0;
|
|
1863
1953
|
Oid *paramTypes = NULL;
|
|
@@ -1886,10 +1976,9 @@ pgconn_send_prepare(int argc, VALUE *argv, VALUE self)
|
|
|
1886
1976
|
xfree(paramTypes);
|
|
1887
1977
|
|
|
1888
1978
|
if(result == 0) {
|
|
1889
|
-
|
|
1890
|
-
rb_iv_set(error, "@connection", self);
|
|
1891
|
-
rb_exc_raise(error);
|
|
1979
|
+
pg_raise_conn_error( rb_eUnableToSend, self, "%s", PQerrorMessage(this->pgconn));
|
|
1892
1980
|
}
|
|
1981
|
+
pgconn_wait_for_flush( self );
|
|
1893
1982
|
return Qnil;
|
|
1894
1983
|
}
|
|
1895
1984
|
|
|
@@ -1911,7 +2000,7 @@ pgconn_send_prepare(int argc, VALUE *argv, VALUE self)
|
|
|
1911
2000
|
* or, it may be a String. If it is a string, that is equivalent to the hash:
|
|
1912
2001
|
* { :value => <string value>, :format => 0 }
|
|
1913
2002
|
*
|
|
1914
|
-
* PostgreSQL bind parameters are represented as $1, $
|
|
2003
|
+
* PostgreSQL bind parameters are represented as $1, $2, $3, etc.,
|
|
1915
2004
|
* inside the SQL query. The 0th element of the +params+ array is bound
|
|
1916
2005
|
* to $1, the 1st element is bound to $2, etc. +nil+ is treated as +NULL+.
|
|
1917
2006
|
*
|
|
@@ -1931,7 +2020,6 @@ pgconn_send_query_prepared(int argc, VALUE *argv, VALUE self)
|
|
|
1931
2020
|
t_pg_connection *this = pg_get_connection_safe( self );
|
|
1932
2021
|
int result;
|
|
1933
2022
|
VALUE name, in_res_fmt;
|
|
1934
|
-
VALUE error;
|
|
1935
2023
|
int nParams;
|
|
1936
2024
|
int resultFormat;
|
|
1937
2025
|
struct query_params_data paramsData = { this->enc_idx };
|
|
@@ -1941,7 +2029,6 @@ pgconn_send_query_prepared(int argc, VALUE *argv, VALUE self)
|
|
|
1941
2029
|
|
|
1942
2030
|
if(NIL_P(paramsData.params)) {
|
|
1943
2031
|
paramsData.params = rb_ary_new2(0);
|
|
1944
|
-
resultFormat = 0;
|
|
1945
2032
|
}
|
|
1946
2033
|
pgconn_query_assign_typemap( self, ¶msData );
|
|
1947
2034
|
|
|
@@ -1954,11 +2041,10 @@ pgconn_send_query_prepared(int argc, VALUE *argv, VALUE self)
|
|
|
1954
2041
|
|
|
1955
2042
|
free_query_params( ¶msData );
|
|
1956
2043
|
|
|
1957
|
-
if(result == 0)
|
|
1958
|
-
|
|
1959
|
-
|
|
1960
|
-
|
|
1961
|
-
}
|
|
2044
|
+
if(result == 0)
|
|
2045
|
+
pg_raise_conn_error( rb_eUnableToSend, self, "%s", PQerrorMessage(this->pgconn));
|
|
2046
|
+
|
|
2047
|
+
pgconn_wait_for_flush( self );
|
|
1962
2048
|
return Qnil;
|
|
1963
2049
|
}
|
|
1964
2050
|
|
|
@@ -1972,14 +2058,12 @@ pgconn_send_query_prepared(int argc, VALUE *argv, VALUE self)
|
|
|
1972
2058
|
static VALUE
|
|
1973
2059
|
pgconn_send_describe_prepared(VALUE self, VALUE stmt_name)
|
|
1974
2060
|
{
|
|
1975
|
-
VALUE error;
|
|
1976
2061
|
t_pg_connection *this = pg_get_connection_safe( self );
|
|
1977
2062
|
/* returns 0 on failure */
|
|
1978
|
-
if(gvl_PQsendDescribePrepared(this->pgconn, pg_cstr_enc(stmt_name, this->enc_idx)) == 0)
|
|
1979
|
-
|
|
1980
|
-
|
|
1981
|
-
|
|
1982
|
-
}
|
|
2063
|
+
if(gvl_PQsendDescribePrepared(this->pgconn, pg_cstr_enc(stmt_name, this->enc_idx)) == 0)
|
|
2064
|
+
pg_raise_conn_error( rb_eUnableToSend, self, "%s", PQerrorMessage(this->pgconn));
|
|
2065
|
+
|
|
2066
|
+
pgconn_wait_for_flush( self );
|
|
1983
2067
|
return Qnil;
|
|
1984
2068
|
}
|
|
1985
2069
|
|
|
@@ -1994,36 +2078,18 @@ pgconn_send_describe_prepared(VALUE self, VALUE stmt_name)
|
|
|
1994
2078
|
static VALUE
|
|
1995
2079
|
pgconn_send_describe_portal(VALUE self, VALUE portal)
|
|
1996
2080
|
{
|
|
1997
|
-
VALUE error;
|
|
1998
2081
|
t_pg_connection *this = pg_get_connection_safe( self );
|
|
1999
2082
|
/* returns 0 on failure */
|
|
2000
|
-
if(gvl_PQsendDescribePortal(this->pgconn, pg_cstr_enc(portal, this->enc_idx)) == 0)
|
|
2001
|
-
|
|
2002
|
-
|
|
2003
|
-
|
|
2004
|
-
}
|
|
2083
|
+
if(gvl_PQsendDescribePortal(this->pgconn, pg_cstr_enc(portal, this->enc_idx)) == 0)
|
|
2084
|
+
pg_raise_conn_error( rb_eUnableToSend, self, "%s", PQerrorMessage(this->pgconn));
|
|
2085
|
+
|
|
2086
|
+
pgconn_wait_for_flush( self );
|
|
2005
2087
|
return Qnil;
|
|
2006
2088
|
}
|
|
2007
2089
|
|
|
2008
2090
|
|
|
2009
|
-
/*
|
|
2010
|
-
* call-seq:
|
|
2011
|
-
* conn.get_result() -> PG::Result
|
|
2012
|
-
* conn.get_result() {|pg_result| block }
|
|
2013
|
-
*
|
|
2014
|
-
* Blocks waiting for the next result from a call to
|
|
2015
|
-
* #send_query (or another asynchronous command), and returns
|
|
2016
|
-
* it. Returns +nil+ if no more results are available.
|
|
2017
|
-
*
|
|
2018
|
-
* Note: call this function repeatedly until it returns +nil+, or else
|
|
2019
|
-
* you will not be able to issue further commands.
|
|
2020
|
-
*
|
|
2021
|
-
* If the optional code block is given, it will be passed <i>result</i> as an argument,
|
|
2022
|
-
* and the PG::Result object will automatically be cleared when the block terminates.
|
|
2023
|
-
* In this instance, <code>conn.exec</code> returns the value of the block.
|
|
2024
|
-
*/
|
|
2025
2091
|
static VALUE
|
|
2026
|
-
|
|
2092
|
+
pgconn_sync_get_result(VALUE self)
|
|
2027
2093
|
{
|
|
2028
2094
|
PGconn *conn = pg_get_pgconn(self);
|
|
2029
2095
|
PGresult *result;
|
|
@@ -2049,17 +2115,15 @@ pgconn_get_result(VALUE self)
|
|
|
2049
2115
|
* or *notifies* to see if the state has changed.
|
|
2050
2116
|
*/
|
|
2051
2117
|
static VALUE
|
|
2052
|
-
pgconn_consume_input(self)
|
|
2053
|
-
VALUE self;
|
|
2118
|
+
pgconn_consume_input(VALUE self)
|
|
2054
2119
|
{
|
|
2055
|
-
VALUE error;
|
|
2056
2120
|
PGconn *conn = pg_get_pgconn(self);
|
|
2057
2121
|
/* returns 0 on error */
|
|
2058
2122
|
if(PQconsumeInput(conn) == 0) {
|
|
2059
|
-
|
|
2060
|
-
|
|
2061
|
-
rb_exc_raise(error);
|
|
2123
|
+
pgconn_close_socket_io(self);
|
|
2124
|
+
pg_raise_conn_error( rb_eConnectionBad, self, "%s", PQerrorMessage(conn));
|
|
2062
2125
|
}
|
|
2126
|
+
|
|
2063
2127
|
return Qnil;
|
|
2064
2128
|
}
|
|
2065
2129
|
|
|
@@ -2068,37 +2132,18 @@ pgconn_consume_input(self)
|
|
|
2068
2132
|
* conn.is_busy() -> Boolean
|
|
2069
2133
|
*
|
|
2070
2134
|
* Returns +true+ if a command is busy, that is, if
|
|
2071
|
-
*
|
|
2135
|
+
* #get_result would block. Otherwise returns +false+.
|
|
2072
2136
|
*/
|
|
2073
2137
|
static VALUE
|
|
2074
|
-
pgconn_is_busy(self)
|
|
2075
|
-
VALUE self;
|
|
2138
|
+
pgconn_is_busy(VALUE self)
|
|
2076
2139
|
{
|
|
2077
2140
|
return gvl_PQisBusy(pg_get_pgconn(self)) ? Qtrue : Qfalse;
|
|
2078
2141
|
}
|
|
2079
2142
|
|
|
2080
|
-
/*
|
|
2081
|
-
* call-seq:
|
|
2082
|
-
* conn.setnonblocking(Boolean) -> nil
|
|
2083
|
-
*
|
|
2084
|
-
* Sets the nonblocking status of the connection.
|
|
2085
|
-
* In the blocking state, calls to #send_query
|
|
2086
|
-
* will block until the message is sent to the server,
|
|
2087
|
-
* but will not wait for the query results.
|
|
2088
|
-
* In the nonblocking state, calls to #send_query
|
|
2089
|
-
* will return an error if the socket is not ready for
|
|
2090
|
-
* writing.
|
|
2091
|
-
* Note: This function does not affect #exec, because
|
|
2092
|
-
* that function doesn't return until the server has
|
|
2093
|
-
* processed the query and returned the results.
|
|
2094
|
-
* Returns +nil+.
|
|
2095
|
-
*/
|
|
2096
2143
|
static VALUE
|
|
2097
|
-
|
|
2098
|
-
VALUE self, state;
|
|
2144
|
+
pgconn_sync_setnonblocking(VALUE self, VALUE state)
|
|
2099
2145
|
{
|
|
2100
2146
|
int arg;
|
|
2101
|
-
VALUE error;
|
|
2102
2147
|
PGconn *conn = pg_get_pgconn(self);
|
|
2103
2148
|
if(state == Qtrue)
|
|
2104
2149
|
arg = 1;
|
|
@@ -2107,67 +2152,32 @@ pgconn_setnonblocking(self, state)
|
|
|
2107
2152
|
else
|
|
2108
2153
|
rb_raise(rb_eArgError, "Boolean value expected");
|
|
2109
2154
|
|
|
2110
|
-
if(PQsetnonblocking(conn, arg) == -1)
|
|
2111
|
-
|
|
2112
|
-
|
|
2113
|
-
rb_exc_raise(error);
|
|
2114
|
-
}
|
|
2155
|
+
if(PQsetnonblocking(conn, arg) == -1)
|
|
2156
|
+
pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(conn));
|
|
2157
|
+
|
|
2115
2158
|
return Qnil;
|
|
2116
2159
|
}
|
|
2117
2160
|
|
|
2118
2161
|
|
|
2119
|
-
/*
|
|
2120
|
-
* call-seq:
|
|
2121
|
-
* conn.isnonblocking() -> Boolean
|
|
2122
|
-
*
|
|
2123
|
-
* Returns +true+ if a command is busy, that is, if
|
|
2124
|
-
* PQgetResult would block. Otherwise returns +false+.
|
|
2125
|
-
*/
|
|
2126
2162
|
static VALUE
|
|
2127
|
-
|
|
2128
|
-
VALUE self;
|
|
2163
|
+
pgconn_sync_isnonblocking(VALUE self)
|
|
2129
2164
|
{
|
|
2130
2165
|
return PQisnonblocking(pg_get_pgconn(self)) ? Qtrue : Qfalse;
|
|
2131
2166
|
}
|
|
2132
2167
|
|
|
2133
|
-
/*
|
|
2134
|
-
* call-seq:
|
|
2135
|
-
* conn.flush() -> Boolean
|
|
2136
|
-
*
|
|
2137
|
-
* Attempts to flush any queued output data to the server.
|
|
2138
|
-
* Returns +true+ if data is successfully flushed, +false+
|
|
2139
|
-
* if not (can only return +false+ if connection is
|
|
2140
|
-
* nonblocking.
|
|
2141
|
-
* Raises PG::Error if some other failure occurred.
|
|
2142
|
-
*/
|
|
2143
2168
|
static VALUE
|
|
2144
|
-
|
|
2145
|
-
VALUE self;
|
|
2169
|
+
pgconn_sync_flush(VALUE self)
|
|
2146
2170
|
{
|
|
2147
2171
|
PGconn *conn = pg_get_pgconn(self);
|
|
2148
|
-
int ret;
|
|
2149
|
-
|
|
2150
|
-
|
|
2151
|
-
|
|
2152
|
-
error = rb_exc_new2(rb_ePGerror, PQerrorMessage(conn));
|
|
2153
|
-
rb_iv_set(error, "@connection", self);
|
|
2154
|
-
rb_exc_raise(error);
|
|
2155
|
-
}
|
|
2172
|
+
int ret = PQflush(conn);
|
|
2173
|
+
if(ret == -1)
|
|
2174
|
+
pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(conn));
|
|
2175
|
+
|
|
2156
2176
|
return (ret) ? Qfalse : Qtrue;
|
|
2157
2177
|
}
|
|
2158
2178
|
|
|
2159
|
-
/*
|
|
2160
|
-
* call-seq:
|
|
2161
|
-
* conn.cancel() -> String
|
|
2162
|
-
*
|
|
2163
|
-
* Requests cancellation of the command currently being
|
|
2164
|
-
* processed. (Only implemented in PostgreSQL >= 8.0)
|
|
2165
|
-
*
|
|
2166
|
-
* Returns +nil+ on success, or a string containing the
|
|
2167
|
-
* error message if a failure occurs.
|
|
2168
|
-
*/
|
|
2169
2179
|
static VALUE
|
|
2170
|
-
|
|
2180
|
+
pgconn_sync_cancel(VALUE self)
|
|
2171
2181
|
{
|
|
2172
2182
|
char errbuf[256];
|
|
2173
2183
|
PGcancel *cancel;
|
|
@@ -2176,9 +2186,9 @@ pgconn_cancel(VALUE self)
|
|
|
2176
2186
|
|
|
2177
2187
|
cancel = PQgetCancel(pg_get_pgconn(self));
|
|
2178
2188
|
if(cancel == NULL)
|
|
2179
|
-
|
|
2189
|
+
pg_raise_conn_error( rb_ePGerror, self, "Invalid connection!");
|
|
2180
2190
|
|
|
2181
|
-
ret = gvl_PQcancel(cancel, errbuf,
|
|
2191
|
+
ret = gvl_PQcancel(cancel, errbuf, sizeof(errbuf));
|
|
2182
2192
|
if(ret == 1)
|
|
2183
2193
|
retval = Qnil;
|
|
2184
2194
|
else
|
|
@@ -2229,55 +2239,63 @@ pgconn_notifies(VALUE self)
|
|
|
2229
2239
|
return hash;
|
|
2230
2240
|
}
|
|
2231
2241
|
|
|
2232
|
-
|
|
2233
|
-
|
|
2234
|
-
/*
|
|
2235
|
-
*
|
|
2236
|
-
* instead of rb_wait_for_single_fd().
|
|
2242
|
+
#if defined(_WIN32)
|
|
2243
|
+
|
|
2244
|
+
/* We use a specialized implementation of rb_io_wait() on Windows.
|
|
2245
|
+
* This is because rb_io_wait() and rb_wait_for_single_fd() are very slow on Windows.
|
|
2237
2246
|
*/
|
|
2238
2247
|
|
|
2248
|
+
#if defined(HAVE_RUBY_FIBER_SCHEDULER_H)
|
|
2249
|
+
#include <ruby/fiber/scheduler.h>
|
|
2250
|
+
#endif
|
|
2251
|
+
|
|
2252
|
+
typedef enum {
|
|
2253
|
+
PG_RUBY_IO_READABLE = RB_WAITFD_IN,
|
|
2254
|
+
PG_RUBY_IO_WRITABLE = RB_WAITFD_OUT,
|
|
2255
|
+
PG_RUBY_IO_PRIORITY = RB_WAITFD_PRI,
|
|
2256
|
+
} pg_rb_io_event_t;
|
|
2257
|
+
|
|
2239
2258
|
int rb_w32_wait_events( HANDLE *events, int num, DWORD timeout );
|
|
2240
2259
|
|
|
2241
|
-
static
|
|
2242
|
-
|
|
2243
|
-
|
|
2244
|
-
|
|
2245
|
-
|
|
2260
|
+
static VALUE
|
|
2261
|
+
pg_rb_thread_io_wait(VALUE io, VALUE events, VALUE timeout) {
|
|
2262
|
+
rb_io_t *fptr;
|
|
2263
|
+
struct timeval ptimeout;
|
|
2264
|
+
|
|
2246
2265
|
struct timeval aborttime={0,0}, currtime, waittime;
|
|
2247
2266
|
DWORD timeout_milisec = INFINITE;
|
|
2248
|
-
|
|
2249
|
-
WSAEVENT hEvent;
|
|
2250
|
-
|
|
2251
|
-
if ( sd < 0 )
|
|
2252
|
-
rb_raise(rb_eConnectionBad, "PQsocket() can't get socket descriptor");
|
|
2267
|
+
HANDLE hEvent = WSACreateEvent();
|
|
2253
2268
|
|
|
2254
|
-
|
|
2269
|
+
long rb_events = NUM2UINT(events);
|
|
2270
|
+
long w32_events = 0;
|
|
2271
|
+
DWORD wait_ret;
|
|
2255
2272
|
|
|
2256
|
-
|
|
2257
|
-
if(
|
|
2258
|
-
|
|
2259
|
-
|
|
2260
|
-
}
|
|
2273
|
+
GetOpenFile((io), fptr);
|
|
2274
|
+
if( !NIL_P(timeout) ){
|
|
2275
|
+
ptimeout.tv_sec = (time_t)(NUM2DBL(timeout));
|
|
2276
|
+
ptimeout.tv_usec = (time_t)((NUM2DBL(timeout) - (double)ptimeout.tv_sec) * 1e6);
|
|
2261
2277
|
|
|
2262
|
-
if ( ptimeout ) {
|
|
2263
2278
|
gettimeofday(&currtime, NULL);
|
|
2264
|
-
timeradd(&currtime, ptimeout, &aborttime);
|
|
2279
|
+
timeradd(&currtime, &ptimeout, &aborttime);
|
|
2265
2280
|
}
|
|
2266
2281
|
|
|
2267
|
-
|
|
2268
|
-
|
|
2282
|
+
if(rb_events & PG_RUBY_IO_READABLE) w32_events |= FD_READ | FD_ACCEPT | FD_CLOSE;
|
|
2283
|
+
if(rb_events & PG_RUBY_IO_WRITABLE) w32_events |= FD_WRITE | FD_CONNECT;
|
|
2284
|
+
if(rb_events & PG_RUBY_IO_PRIORITY) w32_events |= FD_OOB;
|
|
2285
|
+
|
|
2286
|
+
for(;;) {
|
|
2287
|
+
if ( WSAEventSelect(_get_osfhandle(fptr->fd), hEvent, w32_events) == SOCKET_ERROR ) {
|
|
2269
2288
|
WSACloseEvent( hEvent );
|
|
2270
2289
|
rb_raise( rb_eConnectionBad, "WSAEventSelect socket error: %d", WSAGetLastError() );
|
|
2271
2290
|
}
|
|
2272
2291
|
|
|
2273
|
-
if (
|
|
2292
|
+
if ( !NIL_P(timeout) ) {
|
|
2274
2293
|
gettimeofday(&currtime, NULL);
|
|
2275
2294
|
timersub(&aborttime, &currtime, &waittime);
|
|
2276
2295
|
timeout_milisec = (DWORD)( waittime.tv_sec * 1e3 + waittime.tv_usec / 1e3 );
|
|
2277
2296
|
}
|
|
2278
2297
|
|
|
2279
|
-
|
|
2280
|
-
if( !ptimeout || (waittime.tv_sec >= 0 && waittime.tv_usec >= 0) ){
|
|
2298
|
+
if( NIL_P(timeout) || (waittime.tv_sec >= 0 && waittime.tv_usec >= 0) ){
|
|
2281
2299
|
/* Wait for the socket to become readable before checking again */
|
|
2282
2300
|
wait_ret = rb_w32_wait_events( &hEvent, 1, timeout_milisec );
|
|
2283
2301
|
} else {
|
|
@@ -2286,9 +2304,11 @@ wait_socket_readable( PGconn *conn, struct timeval *ptimeout, void *(*is_readabl
|
|
|
2286
2304
|
|
|
2287
2305
|
if ( wait_ret == WAIT_TIMEOUT ) {
|
|
2288
2306
|
WSACloseEvent( hEvent );
|
|
2289
|
-
return
|
|
2307
|
+
return UINT2NUM(0);
|
|
2290
2308
|
} else if ( wait_ret == WAIT_OBJECT_0 ) {
|
|
2309
|
+
WSACloseEvent( hEvent );
|
|
2291
2310
|
/* The event we were waiting for. */
|
|
2311
|
+
return UINT2NUM(rb_events);
|
|
2292
2312
|
} else if ( wait_ret == WAIT_OBJECT_0 + 1) {
|
|
2293
2313
|
/* This indicates interruption from timer thread, GC, exception
|
|
2294
2314
|
* from other threads etc... */
|
|
@@ -2300,36 +2320,66 @@ wait_socket_readable( PGconn *conn, struct timeval *ptimeout, void *(*is_readabl
|
|
|
2300
2320
|
WSACloseEvent( hEvent );
|
|
2301
2321
|
rb_raise( rb_eConnectionBad, "Wait on socket abandoned (WaitForMultipleObjects)" );
|
|
2302
2322
|
}
|
|
2303
|
-
|
|
2304
|
-
/* Check for connection errors (PQisBusy is true on connection errors) */
|
|
2305
|
-
if ( PQconsumeInput(conn) == 0 ) {
|
|
2306
|
-
WSACloseEvent( hEvent );
|
|
2307
|
-
rb_raise( rb_eConnectionBad, "PQconsumeInput() %s", PQerrorMessage(conn) );
|
|
2308
|
-
}
|
|
2309
2323
|
}
|
|
2324
|
+
}
|
|
2310
2325
|
|
|
2311
|
-
|
|
2312
|
-
|
|
2326
|
+
static VALUE
|
|
2327
|
+
pg_rb_io_wait(VALUE io, VALUE events, VALUE timeout) {
|
|
2328
|
+
#if defined(HAVE_RUBY_FIBER_SCHEDULER_H)
|
|
2329
|
+
/* We don't support Fiber.scheduler on Windows ruby-3.0 because there is no fast way to check whether a scheduler is active.
|
|
2330
|
+
* Fortunatelly ruby-3.1 offers a C-API for it.
|
|
2331
|
+
*/
|
|
2332
|
+
VALUE scheduler = rb_fiber_scheduler_current();
|
|
2333
|
+
|
|
2334
|
+
if (!NIL_P(scheduler)) {
|
|
2335
|
+
return rb_io_wait(io, events, timeout);
|
|
2336
|
+
}
|
|
2337
|
+
#endif
|
|
2338
|
+
return pg_rb_thread_io_wait(io, events, timeout);
|
|
2313
2339
|
}
|
|
2314
2340
|
|
|
2341
|
+
#elif defined(HAVE_RB_IO_WAIT)
|
|
2342
|
+
|
|
2343
|
+
/* Use our own function and constants names, to avoid conflicts with truffleruby-head on its road to ruby-3.0 compatibility. */
|
|
2344
|
+
#define pg_rb_io_wait rb_io_wait
|
|
2345
|
+
#define PG_RUBY_IO_READABLE RUBY_IO_READABLE
|
|
2346
|
+
#define PG_RUBY_IO_WRITABLE RUBY_IO_WRITABLE
|
|
2347
|
+
#define PG_RUBY_IO_PRIORITY RUBY_IO_PRIORITY
|
|
2348
|
+
|
|
2315
2349
|
#else
|
|
2350
|
+
/* For compat with ruby < 3.0 */
|
|
2351
|
+
|
|
2352
|
+
typedef enum {
|
|
2353
|
+
PG_RUBY_IO_READABLE = RB_WAITFD_IN,
|
|
2354
|
+
PG_RUBY_IO_WRITABLE = RB_WAITFD_OUT,
|
|
2355
|
+
PG_RUBY_IO_PRIORITY = RB_WAITFD_PRI,
|
|
2356
|
+
} pg_rb_io_event_t;
|
|
2316
2357
|
|
|
2317
|
-
|
|
2358
|
+
static VALUE
|
|
2359
|
+
pg_rb_io_wait(VALUE io, VALUE events, VALUE timeout) {
|
|
2360
|
+
rb_io_t *fptr;
|
|
2361
|
+
struct timeval waittime;
|
|
2362
|
+
int res;
|
|
2363
|
+
|
|
2364
|
+
GetOpenFile((io), fptr);
|
|
2365
|
+
if( !NIL_P(timeout) ){
|
|
2366
|
+
waittime.tv_sec = (time_t)(NUM2DBL(timeout));
|
|
2367
|
+
waittime.tv_usec = (time_t)((NUM2DBL(timeout) - (double)waittime.tv_sec) * 1e6);
|
|
2368
|
+
}
|
|
2369
|
+
res = rb_wait_for_single_fd(fptr->fd, NUM2UINT(events), NIL_P(timeout) ? NULL : &waittime);
|
|
2370
|
+
|
|
2371
|
+
return UINT2NUM(res);
|
|
2372
|
+
}
|
|
2373
|
+
#endif
|
|
2318
2374
|
|
|
2319
2375
|
static void *
|
|
2320
|
-
wait_socket_readable(
|
|
2376
|
+
wait_socket_readable( VALUE self, struct timeval *ptimeout, void *(*is_readable)(PGconn *))
|
|
2321
2377
|
{
|
|
2322
|
-
|
|
2323
|
-
int ret;
|
|
2378
|
+
VALUE ret;
|
|
2324
2379
|
void *retval;
|
|
2325
2380
|
struct timeval aborttime={0,0}, currtime, waittime;
|
|
2326
|
-
|
|
2327
|
-
|
|
2328
|
-
rb_raise(rb_eConnectionBad, "PQsocket() can't get socket descriptor");
|
|
2329
|
-
|
|
2330
|
-
/* Check for connection errors (PQisBusy is true on connection errors) */
|
|
2331
|
-
if ( PQconsumeInput(conn) == 0 )
|
|
2332
|
-
rb_raise( rb_eConnectionBad, "PQconsumeInput() %s", PQerrorMessage(conn) );
|
|
2381
|
+
VALUE wait_timeout = Qnil;
|
|
2382
|
+
PGconn *conn = pg_get_pgconn(self);
|
|
2333
2383
|
|
|
2334
2384
|
if ( ptimeout ) {
|
|
2335
2385
|
gettimeofday(&currtime, NULL);
|
|
@@ -2340,36 +2390,79 @@ wait_socket_readable( PGconn *conn, struct timeval *ptimeout, void *(*is_readabl
|
|
|
2340
2390
|
if ( ptimeout ) {
|
|
2341
2391
|
gettimeofday(&currtime, NULL);
|
|
2342
2392
|
timersub(&aborttime, &currtime, &waittime);
|
|
2393
|
+
wait_timeout = DBL2NUM((double)(waittime.tv_sec) + (double)(waittime.tv_usec) / 1000000.0);
|
|
2343
2394
|
}
|
|
2344
2395
|
|
|
2345
2396
|
/* Is the given timeout valid? */
|
|
2346
2397
|
if( !ptimeout || (waittime.tv_sec >= 0 && waittime.tv_usec >= 0) ){
|
|
2398
|
+
VALUE socket_io;
|
|
2399
|
+
|
|
2400
|
+
/* before we wait for data, make sure everything has been sent */
|
|
2401
|
+
pgconn_async_flush(self);
|
|
2402
|
+
if ((retval=is_readable(conn)))
|
|
2403
|
+
return retval;
|
|
2404
|
+
|
|
2405
|
+
socket_io = pgconn_socket_io(self);
|
|
2347
2406
|
/* Wait for the socket to become readable before checking again */
|
|
2348
|
-
ret =
|
|
2407
|
+
ret = pg_rb_io_wait(socket_io, RB_INT2NUM(PG_RUBY_IO_READABLE), wait_timeout);
|
|
2349
2408
|
} else {
|
|
2350
|
-
ret =
|
|
2351
|
-
}
|
|
2352
|
-
|
|
2353
|
-
if ( ret < 0 ){
|
|
2354
|
-
rb_sys_fail( "rb_wait_for_single_fd()" );
|
|
2409
|
+
ret = Qfalse;
|
|
2355
2410
|
}
|
|
2356
2411
|
|
|
2357
2412
|
/* Return false if the select() timed out */
|
|
2358
|
-
if ( ret ==
|
|
2413
|
+
if ( ret == Qfalse ){
|
|
2359
2414
|
return NULL;
|
|
2360
2415
|
}
|
|
2361
2416
|
|
|
2362
2417
|
/* Check for connection errors (PQisBusy is true on connection errors) */
|
|
2363
2418
|
if ( PQconsumeInput(conn) == 0 ){
|
|
2364
|
-
|
|
2419
|
+
pgconn_close_socket_io(self);
|
|
2420
|
+
pg_raise_conn_error(rb_eConnectionBad, self, "PQconsumeInput() %s", PQerrorMessage(conn));
|
|
2365
2421
|
}
|
|
2366
2422
|
}
|
|
2367
2423
|
|
|
2368
2424
|
return retval;
|
|
2369
2425
|
}
|
|
2370
2426
|
|
|
2427
|
+
/*
|
|
2428
|
+
* call-seq:
|
|
2429
|
+
* conn.flush() -> Boolean
|
|
2430
|
+
*
|
|
2431
|
+
* Attempts to flush any queued output data to the server.
|
|
2432
|
+
* Returns +true+ if data is successfully flushed, +false+
|
|
2433
|
+
* if not. It can only return +false+ if connection is
|
|
2434
|
+
* in nonblocking mode.
|
|
2435
|
+
* Raises PG::Error if some other failure occurred.
|
|
2436
|
+
*/
|
|
2437
|
+
static VALUE
|
|
2438
|
+
pgconn_async_flush(VALUE self)
|
|
2439
|
+
{
|
|
2440
|
+
while( pgconn_sync_flush(self) == Qfalse ){
|
|
2441
|
+
/* wait for the socket to become read- or write-ready */
|
|
2442
|
+
int events;
|
|
2443
|
+
VALUE socket_io = pgconn_socket_io(self);
|
|
2444
|
+
events = RB_NUM2INT(pg_rb_io_wait(socket_io, RB_INT2NUM(PG_RUBY_IO_READABLE | PG_RUBY_IO_WRITABLE), Qnil));
|
|
2445
|
+
|
|
2446
|
+
if (events & PG_RUBY_IO_READABLE)
|
|
2447
|
+
pgconn_consume_input(self);
|
|
2448
|
+
}
|
|
2449
|
+
return Qtrue;
|
|
2450
|
+
}
|
|
2451
|
+
|
|
2452
|
+
static VALUE
|
|
2453
|
+
pgconn_wait_for_flush( VALUE self ){
|
|
2454
|
+
if( !pg_get_connection_safe(self)->flush_data )
|
|
2455
|
+
return Qnil;
|
|
2371
2456
|
|
|
2372
|
-
|
|
2457
|
+
return pgconn_async_flush(self);
|
|
2458
|
+
}
|
|
2459
|
+
|
|
2460
|
+
static VALUE
|
|
2461
|
+
pgconn_flush_data_set( VALUE self, VALUE enabled ){
|
|
2462
|
+
t_pg_connection *conn = pg_get_connection(self);
|
|
2463
|
+
conn->flush_data = RTEST(enabled);
|
|
2464
|
+
return enabled;
|
|
2465
|
+
}
|
|
2373
2466
|
|
|
2374
2467
|
static void *
|
|
2375
2468
|
notify_readable(PGconn *conn)
|
|
@@ -2408,7 +2501,7 @@ pgconn_wait_for_notify(int argc, VALUE *argv, VALUE self)
|
|
|
2408
2501
|
ptimeout = &timeout;
|
|
2409
2502
|
}
|
|
2410
2503
|
|
|
2411
|
-
pnotification = (PGnotify*) wait_socket_readable(
|
|
2504
|
+
pnotification = (PGnotify*) wait_socket_readable( self, ptimeout, notify_readable);
|
|
2412
2505
|
|
|
2413
2506
|
/* Return nil if the select timed out */
|
|
2414
2507
|
if ( !pnotification ) return Qnil;
|
|
@@ -2429,28 +2522,8 @@ pgconn_wait_for_notify(int argc, VALUE *argv, VALUE self)
|
|
|
2429
2522
|
}
|
|
2430
2523
|
|
|
2431
2524
|
|
|
2432
|
-
/*
|
|
2433
|
-
* call-seq:
|
|
2434
|
-
* conn.put_copy_data( buffer [, encoder] ) -> Boolean
|
|
2435
|
-
*
|
|
2436
|
-
* Transmits _buffer_ as copy data to the server.
|
|
2437
|
-
* Returns true if the data was sent, false if it was
|
|
2438
|
-
* not sent (false is only possible if the connection
|
|
2439
|
-
* is in nonblocking mode, and this command would block).
|
|
2440
|
-
*
|
|
2441
|
-
* _encoder_ can be a PG::Coder derivation (typically PG::TextEncoder::CopyRow).
|
|
2442
|
-
* This encodes the data fields given as _buffer_ from an Array of Strings to
|
|
2443
|
-
* PostgreSQL's COPY text format inclusive proper escaping. Optionally
|
|
2444
|
-
* the encoder can type cast the fields from various Ruby types in one step,
|
|
2445
|
-
* if PG::TextEncoder::CopyRow#type_map is set accordingly.
|
|
2446
|
-
*
|
|
2447
|
-
* Raises an exception if an error occurs.
|
|
2448
|
-
*
|
|
2449
|
-
* See also #copy_data.
|
|
2450
|
-
*
|
|
2451
|
-
*/
|
|
2452
2525
|
static VALUE
|
|
2453
|
-
|
|
2526
|
+
pgconn_sync_put_copy_data(int argc, VALUE *argv, VALUE self)
|
|
2454
2527
|
{
|
|
2455
2528
|
int ret;
|
|
2456
2529
|
int len;
|
|
@@ -2467,13 +2540,11 @@ pgconn_put_copy_data(int argc, VALUE *argv, VALUE self)
|
|
|
2467
2540
|
if( NIL_P(this->encoder_for_put_copy_data) ){
|
|
2468
2541
|
buffer = value;
|
|
2469
2542
|
} else {
|
|
2470
|
-
p_coder =
|
|
2543
|
+
p_coder = RTYPEDDATA_DATA( this->encoder_for_put_copy_data );
|
|
2471
2544
|
}
|
|
2472
|
-
} else if( rb_obj_is_kind_of(encoder, rb_cPG_Coder) ) {
|
|
2473
|
-
Data_Get_Struct( encoder, t_pg_coder, p_coder );
|
|
2474
2545
|
} else {
|
|
2475
|
-
|
|
2476
|
-
|
|
2546
|
+
/* Check argument type and use argument encoder */
|
|
2547
|
+
TypedData_Get_Struct(encoder, t_pg_coder, &pg_coder_type, p_coder);
|
|
2477
2548
|
}
|
|
2478
2549
|
|
|
2479
2550
|
if( p_coder ){
|
|
@@ -2496,36 +2567,19 @@ pgconn_put_copy_data(int argc, VALUE *argv, VALUE self)
|
|
|
2496
2567
|
Check_Type(buffer, T_STRING);
|
|
2497
2568
|
|
|
2498
2569
|
ret = gvl_PQputCopyData(this->pgconn, RSTRING_PTR(buffer), RSTRING_LENINT(buffer));
|
|
2499
|
-
if(ret == -1)
|
|
2500
|
-
|
|
2501
|
-
|
|
2502
|
-
rb_exc_raise(error);
|
|
2503
|
-
}
|
|
2570
|
+
if(ret == -1)
|
|
2571
|
+
pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(this->pgconn));
|
|
2572
|
+
|
|
2504
2573
|
RB_GC_GUARD(intermediate);
|
|
2505
2574
|
RB_GC_GUARD(buffer);
|
|
2506
2575
|
|
|
2507
2576
|
return (ret) ? Qtrue : Qfalse;
|
|
2508
2577
|
}
|
|
2509
2578
|
|
|
2510
|
-
/*
|
|
2511
|
-
* call-seq:
|
|
2512
|
-
* conn.put_copy_end( [ error_message ] ) -> Boolean
|
|
2513
|
-
*
|
|
2514
|
-
* Sends end-of-data indication to the server.
|
|
2515
|
-
*
|
|
2516
|
-
* _error_message_ is an optional parameter, and if set,
|
|
2517
|
-
* forces the COPY command to fail with the string
|
|
2518
|
-
* _error_message_.
|
|
2519
|
-
*
|
|
2520
|
-
* Returns true if the end-of-data was sent, false if it was
|
|
2521
|
-
* not sent (false is only possible if the connection
|
|
2522
|
-
* is in nonblocking mode, and this command would block).
|
|
2523
|
-
*/
|
|
2524
2579
|
static VALUE
|
|
2525
|
-
|
|
2580
|
+
pgconn_sync_put_copy_end(int argc, VALUE *argv, VALUE self)
|
|
2526
2581
|
{
|
|
2527
2582
|
VALUE str;
|
|
2528
|
-
VALUE error;
|
|
2529
2583
|
int ret;
|
|
2530
2584
|
const char *error_message = NULL;
|
|
2531
2585
|
t_pg_connection *this = pg_get_connection_safe( self );
|
|
@@ -2536,38 +2590,16 @@ pgconn_put_copy_end(int argc, VALUE *argv, VALUE self)
|
|
|
2536
2590
|
error_message = pg_cstr_enc(str, this->enc_idx);
|
|
2537
2591
|
|
|
2538
2592
|
ret = gvl_PQputCopyEnd(this->pgconn, error_message);
|
|
2539
|
-
if(ret == -1)
|
|
2540
|
-
|
|
2541
|
-
|
|
2542
|
-
rb_exc_raise(error);
|
|
2543
|
-
}
|
|
2593
|
+
if(ret == -1)
|
|
2594
|
+
pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(this->pgconn));
|
|
2595
|
+
|
|
2544
2596
|
return (ret) ? Qtrue : Qfalse;
|
|
2545
2597
|
}
|
|
2546
2598
|
|
|
2547
|
-
/*
|
|
2548
|
-
* call-seq:
|
|
2549
|
-
* conn.get_copy_data( [ async = false [, decoder = nil ]] ) -> Object
|
|
2550
|
-
*
|
|
2551
|
-
* Return one row of data, +nil+
|
|
2552
|
-
* if the copy is done, or +false+ if the call would
|
|
2553
|
-
* block (only possible if _async_ is true).
|
|
2554
|
-
*
|
|
2555
|
-
* If _decoder_ is not set or +nil+, data is returned as binary string.
|
|
2556
|
-
*
|
|
2557
|
-
* If _decoder_ is set to a PG::Coder derivation, the return type depends on this decoder.
|
|
2558
|
-
* PG::TextDecoder::CopyRow decodes the received data fields from one row of PostgreSQL's
|
|
2559
|
-
* COPY text format to an Array of Strings.
|
|
2560
|
-
* Optionally the decoder can type cast the single fields to various Ruby types in one step,
|
|
2561
|
-
* if PG::TextDecoder::CopyRow#type_map is set accordingly.
|
|
2562
|
-
*
|
|
2563
|
-
* See also #copy_data.
|
|
2564
|
-
*
|
|
2565
|
-
*/
|
|
2566
2599
|
static VALUE
|
|
2567
|
-
|
|
2600
|
+
pgconn_sync_get_copy_data(int argc, VALUE *argv, VALUE self )
|
|
2568
2601
|
{
|
|
2569
2602
|
VALUE async_in;
|
|
2570
|
-
VALUE error;
|
|
2571
2603
|
VALUE result;
|
|
2572
2604
|
int ret;
|
|
2573
2605
|
char *buffer;
|
|
@@ -2579,20 +2611,16 @@ pgconn_get_copy_data(int argc, VALUE *argv, VALUE self )
|
|
|
2579
2611
|
|
|
2580
2612
|
if( NIL_P(decoder) ){
|
|
2581
2613
|
if( !NIL_P(this->decoder_for_get_copy_data) ){
|
|
2582
|
-
p_coder =
|
|
2614
|
+
p_coder = RTYPEDDATA_DATA( this->decoder_for_get_copy_data );
|
|
2583
2615
|
}
|
|
2584
|
-
} else if( rb_obj_is_kind_of(decoder, rb_cPG_Coder) ) {
|
|
2585
|
-
Data_Get_Struct( decoder, t_pg_coder, p_coder );
|
|
2586
2616
|
} else {
|
|
2587
|
-
|
|
2588
|
-
|
|
2617
|
+
/* Check argument type and use argument decoder */
|
|
2618
|
+
TypedData_Get_Struct(decoder, t_pg_coder, &pg_coder_type, p_coder);
|
|
2589
2619
|
}
|
|
2590
2620
|
|
|
2591
2621
|
ret = gvl_PQgetCopyData(this->pgconn, &buffer, RTEST(async_in));
|
|
2592
|
-
if(ret == -2)
|
|
2593
|
-
|
|
2594
|
-
rb_iv_set(error, "@connection", self);
|
|
2595
|
-
rb_exc_raise(error);
|
|
2622
|
+
if(ret == -2){ /* error */
|
|
2623
|
+
pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(this->pgconn));
|
|
2596
2624
|
}
|
|
2597
2625
|
if(ret == -1) { /* No data left */
|
|
2598
2626
|
return Qnil;
|
|
@@ -2830,7 +2858,7 @@ notice_processor_proxy(void *arg, const char *message)
|
|
|
2830
2858
|
* call-seq:
|
|
2831
2859
|
* conn.set_notice_processor {|message| ... } -> Proc
|
|
2832
2860
|
*
|
|
2833
|
-
* See #set_notice_receiver for the
|
|
2861
|
+
* See #set_notice_receiver for the description of what this and the
|
|
2834
2862
|
* notice_processor methods do.
|
|
2835
2863
|
*
|
|
2836
2864
|
* This function takes a new block to act as the notice processor and returns
|
|
@@ -2884,68 +2912,27 @@ pgconn_get_client_encoding(VALUE self)
|
|
|
2884
2912
|
|
|
2885
2913
|
/*
|
|
2886
2914
|
* call-seq:
|
|
2887
|
-
* conn.
|
|
2915
|
+
* conn.sync_set_client_encoding( encoding )
|
|
2888
2916
|
*
|
|
2889
|
-
*
|
|
2917
|
+
* This function has the same behavior as #async_set_client_encoding, but is implemented using the synchronous command processing API of libpq.
|
|
2918
|
+
* See #async_exec for the differences between the two API variants.
|
|
2919
|
+
* It's not recommended to use explicit sync or async variants but #set_client_encoding instead, unless you have a good reason to do so.
|
|
2890
2920
|
*/
|
|
2891
2921
|
static VALUE
|
|
2892
|
-
|
|
2922
|
+
pgconn_sync_set_client_encoding(VALUE self, VALUE str)
|
|
2893
2923
|
{
|
|
2894
2924
|
PGconn *conn = pg_get_pgconn( self );
|
|
2895
2925
|
|
|
2896
2926
|
Check_Type(str, T_STRING);
|
|
2897
2927
|
|
|
2898
|
-
if ( (gvl_PQsetClientEncoding(conn, StringValueCStr(str))) == -1 )
|
|
2899
|
-
|
|
2900
|
-
|
|
2928
|
+
if ( (gvl_PQsetClientEncoding(conn, StringValueCStr(str))) == -1 )
|
|
2929
|
+
pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(conn));
|
|
2930
|
+
|
|
2901
2931
|
pgconn_set_internal_encoding_index( self );
|
|
2902
2932
|
|
|
2903
2933
|
return Qnil;
|
|
2904
2934
|
}
|
|
2905
2935
|
|
|
2906
|
-
/*
|
|
2907
|
-
* call-seq:
|
|
2908
|
-
* conn.transaction { |conn| ... } -> result of the block
|
|
2909
|
-
*
|
|
2910
|
-
* Executes a +BEGIN+ at the start of the block,
|
|
2911
|
-
* and a +COMMIT+ at the end of the block, or
|
|
2912
|
-
* +ROLLBACK+ if any exception occurs.
|
|
2913
|
-
*/
|
|
2914
|
-
static VALUE
|
|
2915
|
-
pgconn_transaction(VALUE self)
|
|
2916
|
-
{
|
|
2917
|
-
PGconn *conn = pg_get_pgconn(self);
|
|
2918
|
-
PGresult *result;
|
|
2919
|
-
VALUE rb_pgresult;
|
|
2920
|
-
VALUE block_result = Qnil;
|
|
2921
|
-
int status;
|
|
2922
|
-
|
|
2923
|
-
if (rb_block_given_p()) {
|
|
2924
|
-
result = gvl_PQexec(conn, "BEGIN");
|
|
2925
|
-
rb_pgresult = pg_new_result(result, self);
|
|
2926
|
-
pg_result_check(rb_pgresult);
|
|
2927
|
-
block_result = rb_protect(rb_yield, self, &status);
|
|
2928
|
-
if(status == 0) {
|
|
2929
|
-
result = gvl_PQexec(conn, "COMMIT");
|
|
2930
|
-
rb_pgresult = pg_new_result(result, self);
|
|
2931
|
-
pg_result_check(rb_pgresult);
|
|
2932
|
-
}
|
|
2933
|
-
else {
|
|
2934
|
-
/* exception occurred, ROLLBACK and re-raise */
|
|
2935
|
-
result = gvl_PQexec(conn, "ROLLBACK");
|
|
2936
|
-
rb_pgresult = pg_new_result(result, self);
|
|
2937
|
-
pg_result_check(rb_pgresult);
|
|
2938
|
-
rb_jump_tag(status);
|
|
2939
|
-
}
|
|
2940
|
-
|
|
2941
|
-
}
|
|
2942
|
-
else {
|
|
2943
|
-
/* no block supplied? */
|
|
2944
|
-
rb_raise(rb_eArgError, "Must supply block for PG::Connection#transaction");
|
|
2945
|
-
}
|
|
2946
|
-
return block_result;
|
|
2947
|
-
}
|
|
2948
|
-
|
|
2949
2936
|
|
|
2950
2937
|
/*
|
|
2951
2938
|
* call-seq:
|
|
@@ -3020,10 +3007,8 @@ get_result_readable(PGconn *conn)
|
|
|
3020
3007
|
* If +true+ is returned, +conn.is_busy+ will return +false+
|
|
3021
3008
|
* and +conn.get_result+ will not block.
|
|
3022
3009
|
*/
|
|
3023
|
-
|
|
3010
|
+
VALUE
|
|
3024
3011
|
pgconn_block( int argc, VALUE *argv, VALUE self ) {
|
|
3025
|
-
PGconn *conn = pg_get_pgconn( self );
|
|
3026
|
-
|
|
3027
3012
|
struct timeval timeout;
|
|
3028
3013
|
struct timeval *ptimeout = NULL;
|
|
3029
3014
|
VALUE timeout_in;
|
|
@@ -3037,7 +3022,7 @@ pgconn_block( int argc, VALUE *argv, VALUE self ) {
|
|
|
3037
3022
|
ptimeout = &timeout;
|
|
3038
3023
|
}
|
|
3039
3024
|
|
|
3040
|
-
ret = wait_socket_readable(
|
|
3025
|
+
ret = wait_socket_readable( self, ptimeout, get_result_readable);
|
|
3041
3026
|
|
|
3042
3027
|
if( !ret )
|
|
3043
3028
|
return Qfalse;
|
|
@@ -3046,6 +3031,42 @@ pgconn_block( int argc, VALUE *argv, VALUE self ) {
|
|
|
3046
3031
|
}
|
|
3047
3032
|
|
|
3048
3033
|
|
|
3034
|
+
/*
|
|
3035
|
+
* call-seq:
|
|
3036
|
+
* conn.sync_get_last_result( ) -> PG::Result
|
|
3037
|
+
*
|
|
3038
|
+
* This function has the same behavior as #async_get_last_result, but is implemented using the synchronous command processing API of libpq.
|
|
3039
|
+
* See #async_exec for the differences between the two API variants.
|
|
3040
|
+
* It's not recommended to use explicit sync or async variants but #get_last_result instead, unless you have a good reason to do so.
|
|
3041
|
+
*/
|
|
3042
|
+
static VALUE
|
|
3043
|
+
pgconn_sync_get_last_result(VALUE self)
|
|
3044
|
+
{
|
|
3045
|
+
PGconn *conn = pg_get_pgconn(self);
|
|
3046
|
+
VALUE rb_pgresult = Qnil;
|
|
3047
|
+
PGresult *cur, *prev;
|
|
3048
|
+
|
|
3049
|
+
|
|
3050
|
+
cur = prev = NULL;
|
|
3051
|
+
while ((cur = gvl_PQgetResult(conn)) != NULL) {
|
|
3052
|
+
int status;
|
|
3053
|
+
|
|
3054
|
+
if (prev) PQclear(prev);
|
|
3055
|
+
prev = cur;
|
|
3056
|
+
|
|
3057
|
+
status = PQresultStatus(cur);
|
|
3058
|
+
if (status == PGRES_COPY_OUT || status == PGRES_COPY_IN || status == PGRES_COPY_BOTH)
|
|
3059
|
+
break;
|
|
3060
|
+
}
|
|
3061
|
+
|
|
3062
|
+
if (prev) {
|
|
3063
|
+
rb_pgresult = pg_new_result( prev, self );
|
|
3064
|
+
pg_result_check(rb_pgresult);
|
|
3065
|
+
}
|
|
3066
|
+
|
|
3067
|
+
return rb_pgresult;
|
|
3068
|
+
}
|
|
3069
|
+
|
|
3049
3070
|
/*
|
|
3050
3071
|
* call-seq:
|
|
3051
3072
|
* conn.get_last_result( ) -> PG::Result
|
|
@@ -3056,27 +3077,36 @@ pgconn_block( int argc, VALUE *argv, VALUE self ) {
|
|
|
3056
3077
|
* returns the last non-NULL result, or +nil+ if no
|
|
3057
3078
|
* results are available.
|
|
3058
3079
|
*
|
|
3080
|
+
* If the last result contains a bad result_status, an
|
|
3081
|
+
* appropriate exception is raised.
|
|
3082
|
+
*
|
|
3059
3083
|
* This function is similar to #get_result
|
|
3060
3084
|
* except that it is designed to get one and only
|
|
3061
|
-
* one result.
|
|
3085
|
+
* one result and that it checks the result state.
|
|
3062
3086
|
*/
|
|
3063
3087
|
static VALUE
|
|
3064
|
-
|
|
3088
|
+
pgconn_async_get_last_result(VALUE self)
|
|
3065
3089
|
{
|
|
3066
3090
|
PGconn *conn = pg_get_pgconn(self);
|
|
3067
3091
|
VALUE rb_pgresult = Qnil;
|
|
3068
3092
|
PGresult *cur, *prev;
|
|
3069
3093
|
|
|
3070
|
-
|
|
3071
|
-
|
|
3072
|
-
while ((cur = gvl_PQgetResult(conn)) != NULL) {
|
|
3094
|
+
cur = prev = NULL;
|
|
3095
|
+
for(;;) {
|
|
3073
3096
|
int status;
|
|
3074
3097
|
|
|
3098
|
+
/* wait for input (without blocking) before reading each result */
|
|
3099
|
+
wait_socket_readable(self, NULL, get_result_readable);
|
|
3100
|
+
|
|
3101
|
+
cur = gvl_PQgetResult(conn);
|
|
3102
|
+
if (cur == NULL)
|
|
3103
|
+
break;
|
|
3104
|
+
|
|
3075
3105
|
if (prev) PQclear(prev);
|
|
3076
3106
|
prev = cur;
|
|
3077
3107
|
|
|
3078
3108
|
status = PQresultStatus(cur);
|
|
3079
|
-
if (status == PGRES_COPY_OUT || status == PGRES_COPY_IN)
|
|
3109
|
+
if (status == PGRES_COPY_OUT || status == PGRES_COPY_IN || status == PGRES_COPY_BOTH)
|
|
3080
3110
|
break;
|
|
3081
3111
|
}
|
|
3082
3112
|
|
|
@@ -3100,22 +3130,60 @@ static VALUE
|
|
|
3100
3130
|
pgconn_discard_results(VALUE self)
|
|
3101
3131
|
{
|
|
3102
3132
|
PGconn *conn = pg_get_pgconn(self);
|
|
3133
|
+
VALUE socket_io;
|
|
3103
3134
|
|
|
3104
|
-
|
|
3105
|
-
|
|
3106
|
-
|
|
3135
|
+
if( PQtransactionStatus(conn) == PQTRANS_IDLE ) {
|
|
3136
|
+
return Qnil;
|
|
3137
|
+
}
|
|
3138
|
+
|
|
3139
|
+
socket_io = pgconn_socket_io(self);
|
|
3140
|
+
|
|
3141
|
+
for(;;) {
|
|
3142
|
+
PGresult *cur;
|
|
3143
|
+
int status;
|
|
3144
|
+
|
|
3145
|
+
/* pgconn_block() raises an exception in case of errors.
|
|
3146
|
+
* To avoid this call pg_rb_io_wait() and PQconsumeInput() without rb_raise().
|
|
3147
|
+
*/
|
|
3148
|
+
while( gvl_PQisBusy(conn) ){
|
|
3149
|
+
pg_rb_io_wait(socket_io, RB_INT2NUM(PG_RUBY_IO_READABLE), Qnil);
|
|
3150
|
+
if ( PQconsumeInput(conn) == 0 ) {
|
|
3151
|
+
pgconn_close_socket_io(self);
|
|
3152
|
+
return Qfalse;
|
|
3153
|
+
}
|
|
3154
|
+
}
|
|
3155
|
+
|
|
3156
|
+
cur = gvl_PQgetResult(conn);
|
|
3157
|
+
if( cur == NULL) break;
|
|
3158
|
+
|
|
3159
|
+
status = PQresultStatus(cur);
|
|
3107
3160
|
PQclear(cur);
|
|
3108
3161
|
if (status == PGRES_COPY_IN){
|
|
3109
3162
|
gvl_PQputCopyEnd(conn, "COPY terminated by new PQexec");
|
|
3110
3163
|
}
|
|
3111
3164
|
if (status == PGRES_COPY_OUT){
|
|
3112
|
-
|
|
3113
|
-
|
|
3114
|
-
|
|
3165
|
+
for(;;) {
|
|
3166
|
+
char *buffer = NULL;
|
|
3167
|
+
int st = gvl_PQgetCopyData(conn, &buffer, 1);
|
|
3168
|
+
if( st == 0 ) {
|
|
3169
|
+
/* would block -> wait for readable data */
|
|
3170
|
+
pg_rb_io_wait(socket_io, RB_INT2NUM(PG_RUBY_IO_READABLE), Qnil);
|
|
3171
|
+
if ( PQconsumeInput(conn) == 0 ) {
|
|
3172
|
+
pgconn_close_socket_io(self);
|
|
3173
|
+
return Qfalse;
|
|
3174
|
+
}
|
|
3175
|
+
} else if( st > 0 ) {
|
|
3176
|
+
/* some data retrieved -> discard it */
|
|
3177
|
+
PQfreemem(buffer);
|
|
3178
|
+
} else {
|
|
3179
|
+
/* no more data */
|
|
3180
|
+
break;
|
|
3181
|
+
}
|
|
3182
|
+
}
|
|
3115
3183
|
}
|
|
3116
3184
|
}
|
|
3117
3185
|
|
|
3118
|
-
return
|
|
3186
|
+
return Qtrue;
|
|
3119
3187
|
}
|
|
3120
3188
|
|
|
3121
3189
|
/*
|
|
@@ -3138,6 +3206,7 @@ pgconn_discard_results(VALUE self)
|
|
|
3138
3206
|
* #exec is an alias for #async_exec which is almost identical to #sync_exec .
|
|
3139
3207
|
* #sync_exec is implemented on the simpler synchronous command processing API of libpq, whereas
|
|
3140
3208
|
* #async_exec is implemented on the asynchronous API and on ruby's IO mechanisms.
|
|
3209
|
+
* Only #async_exec is compatible to <tt>Fiber.scheduler</tt> based asynchronous IO processing introduced in ruby-3.0.
|
|
3141
3210
|
* Both methods ensure that other threads can process while waiting for the server to
|
|
3142
3211
|
* complete the request, but #sync_exec blocks all signals to be processed until the query is finished.
|
|
3143
3212
|
* This is most notably visible by a delayed reaction to Control+C.
|
|
@@ -3152,8 +3221,7 @@ pgconn_async_exec(int argc, VALUE *argv, VALUE self)
|
|
|
3152
3221
|
|
|
3153
3222
|
pgconn_discard_results( self );
|
|
3154
3223
|
pgconn_send_query( argc, argv, self );
|
|
3155
|
-
|
|
3156
|
-
rb_pgresult = pgconn_get_last_result( self );
|
|
3224
|
+
rb_pgresult = pgconn_async_get_last_result( self );
|
|
3157
3225
|
|
|
3158
3226
|
if ( rb_block_given_p() ) {
|
|
3159
3227
|
return rb_ensure( rb_yield, rb_pgresult, pg_result_clear, rb_pgresult );
|
|
@@ -3182,7 +3250,7 @@ pgconn_async_exec(int argc, VALUE *argv, VALUE self)
|
|
|
3182
3250
|
* or, it may be a String. If it is a string, that is equivalent to the hash:
|
|
3183
3251
|
* { :value => <string value>, :type => 0, :format => 0 }
|
|
3184
3252
|
*
|
|
3185
|
-
* PostgreSQL bind parameters are represented as $1, $
|
|
3253
|
+
* PostgreSQL bind parameters are represented as $1, $2, $3, etc.,
|
|
3186
3254
|
* inside the SQL query. The 0th element of the +params+ array is bound
|
|
3187
3255
|
* to $1, the 1st element is bound to $2, etc. +nil+ is treated as +NULL+.
|
|
3188
3256
|
*
|
|
@@ -3225,8 +3293,7 @@ pgconn_async_exec_params(int argc, VALUE *argv, VALUE self)
|
|
|
3225
3293
|
} else {
|
|
3226
3294
|
pgconn_send_query_params( argc, argv, self );
|
|
3227
3295
|
}
|
|
3228
|
-
|
|
3229
|
-
rb_pgresult = pgconn_get_last_result( self );
|
|
3296
|
+
rb_pgresult = pgconn_async_get_last_result( self );
|
|
3230
3297
|
|
|
3231
3298
|
if ( rb_block_given_p() ) {
|
|
3232
3299
|
return rb_ensure( rb_yield, rb_pgresult, pg_result_clear, rb_pgresult );
|
|
@@ -3252,7 +3319,7 @@ pgconn_async_exec_params(int argc, VALUE *argv, VALUE self)
|
|
|
3252
3319
|
*
|
|
3253
3320
|
* For example: "SELECT $1::int"
|
|
3254
3321
|
*
|
|
3255
|
-
* PostgreSQL bind parameters are represented as $1, $
|
|
3322
|
+
* PostgreSQL bind parameters are represented as $1, $2, $3, etc.,
|
|
3256
3323
|
* inside the SQL query.
|
|
3257
3324
|
*
|
|
3258
3325
|
* See also corresponding {libpq function}[https://www.postgresql.org/docs/current/libpq-exec.html#LIBPQ-PQPREPARE].
|
|
@@ -3264,8 +3331,7 @@ pgconn_async_prepare(int argc, VALUE *argv, VALUE self)
|
|
|
3264
3331
|
|
|
3265
3332
|
pgconn_discard_results( self );
|
|
3266
3333
|
pgconn_send_prepare( argc, argv, self );
|
|
3267
|
-
|
|
3268
|
-
rb_pgresult = pgconn_get_last_result( self );
|
|
3334
|
+
rb_pgresult = pgconn_async_get_last_result( self );
|
|
3269
3335
|
|
|
3270
3336
|
if ( rb_block_given_p() ) {
|
|
3271
3337
|
return rb_ensure( rb_yield, rb_pgresult, pg_result_clear, rb_pgresult );
|
|
@@ -3292,7 +3358,7 @@ pgconn_async_prepare(int argc, VALUE *argv, VALUE self)
|
|
|
3292
3358
|
* or, it may be a String. If it is a string, that is equivalent to the hash:
|
|
3293
3359
|
* { :value => <string value>, :format => 0 }
|
|
3294
3360
|
*
|
|
3295
|
-
* PostgreSQL bind parameters are represented as $1, $
|
|
3361
|
+
* PostgreSQL bind parameters are represented as $1, $2, $3, etc.,
|
|
3296
3362
|
* inside the SQL query. The 0th element of the +params+ array is bound
|
|
3297
3363
|
* to $1, the 1st element is bound to $2, etc. +nil+ is treated as +NULL+.
|
|
3298
3364
|
*
|
|
@@ -3318,8 +3384,7 @@ pgconn_async_exec_prepared(int argc, VALUE *argv, VALUE self)
|
|
|
3318
3384
|
|
|
3319
3385
|
pgconn_discard_results( self );
|
|
3320
3386
|
pgconn_send_query_prepared( argc, argv, self );
|
|
3321
|
-
|
|
3322
|
-
rb_pgresult = pgconn_get_last_result( self );
|
|
3387
|
+
rb_pgresult = pgconn_async_get_last_result( self );
|
|
3323
3388
|
|
|
3324
3389
|
if ( rb_block_given_p() ) {
|
|
3325
3390
|
return rb_ensure( rb_yield, rb_pgresult, pg_result_clear, rb_pgresult );
|
|
@@ -3343,8 +3408,7 @@ pgconn_async_describe_portal(VALUE self, VALUE portal)
|
|
|
3343
3408
|
|
|
3344
3409
|
pgconn_discard_results( self );
|
|
3345
3410
|
pgconn_send_describe_portal( self, portal );
|
|
3346
|
-
|
|
3347
|
-
rb_pgresult = pgconn_get_last_result( self );
|
|
3411
|
+
rb_pgresult = pgconn_async_get_last_result( self );
|
|
3348
3412
|
|
|
3349
3413
|
if ( rb_block_given_p() ) {
|
|
3350
3414
|
return rb_ensure( rb_yield, rb_pgresult, pg_result_clear, rb_pgresult );
|
|
@@ -3368,8 +3432,7 @@ pgconn_async_describe_prepared(VALUE self, VALUE stmt_name)
|
|
|
3368
3432
|
|
|
3369
3433
|
pgconn_discard_results( self );
|
|
3370
3434
|
pgconn_send_describe_prepared( self, stmt_name );
|
|
3371
|
-
|
|
3372
|
-
rb_pgresult = pgconn_get_last_result( self );
|
|
3435
|
+
rb_pgresult = pgconn_async_get_last_result( self );
|
|
3373
3436
|
|
|
3374
3437
|
if ( rb_block_given_p() ) {
|
|
3375
3438
|
return rb_ensure( rb_yield, rb_pgresult, pg_result_clear, rb_pgresult );
|
|
@@ -3457,6 +3520,122 @@ pgconn_ssl_attribute_names(VALUE self)
|
|
|
3457
3520
|
#endif
|
|
3458
3521
|
|
|
3459
3522
|
|
|
3523
|
+
#ifdef HAVE_PQENTERPIPELINEMODE
|
|
3524
|
+
/*
|
|
3525
|
+
* call-seq:
|
|
3526
|
+
* conn.pipeline_status -> Integer
|
|
3527
|
+
*
|
|
3528
|
+
* Returns the current pipeline mode status of the libpq connection.
|
|
3529
|
+
*
|
|
3530
|
+
* PQpipelineStatus can return one of the following values:
|
|
3531
|
+
*
|
|
3532
|
+
* * PQ_PIPELINE_ON - The libpq connection is in pipeline mode.
|
|
3533
|
+
* * PQ_PIPELINE_OFF - The libpq connection is not in pipeline mode.
|
|
3534
|
+
* * PQ_PIPELINE_ABORTED - The libpq connection is in pipeline mode and an error occurred while processing the current pipeline.
|
|
3535
|
+
* The aborted flag is cleared when PQgetResult returns a result of type PGRES_PIPELINE_SYNC.
|
|
3536
|
+
*
|
|
3537
|
+
* Available since PostgreSQL-14
|
|
3538
|
+
*/
|
|
3539
|
+
static VALUE
|
|
3540
|
+
pgconn_pipeline_status(VALUE self)
|
|
3541
|
+
{
|
|
3542
|
+
int res = PQpipelineStatus(pg_get_pgconn(self));
|
|
3543
|
+
return INT2FIX(res);
|
|
3544
|
+
}
|
|
3545
|
+
|
|
3546
|
+
|
|
3547
|
+
/*
|
|
3548
|
+
* call-seq:
|
|
3549
|
+
* conn.enter_pipeline_mode -> nil
|
|
3550
|
+
*
|
|
3551
|
+
* Causes a connection to enter pipeline mode if it is currently idle or already in pipeline mode.
|
|
3552
|
+
*
|
|
3553
|
+
* Raises PG::Error and has no effect if the connection is not currently idle, i.e., it has a result ready, or it is waiting for more input from the server, etc.
|
|
3554
|
+
* This function does not actually send anything to the server, it just changes the libpq connection state.
|
|
3555
|
+
*
|
|
3556
|
+
* Available since PostgreSQL-14
|
|
3557
|
+
*/
|
|
3558
|
+
static VALUE
|
|
3559
|
+
pgconn_enter_pipeline_mode(VALUE self)
|
|
3560
|
+
{
|
|
3561
|
+
PGconn *conn = pg_get_pgconn(self);
|
|
3562
|
+
int res = PQenterPipelineMode(conn);
|
|
3563
|
+
if( res != 1 )
|
|
3564
|
+
pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(conn));
|
|
3565
|
+
|
|
3566
|
+
return Qnil;
|
|
3567
|
+
}
|
|
3568
|
+
|
|
3569
|
+
/*
|
|
3570
|
+
* call-seq:
|
|
3571
|
+
* conn.exit_pipeline_mode -> nil
|
|
3572
|
+
*
|
|
3573
|
+
* Causes a connection to exit pipeline mode if it is currently in pipeline mode with an empty queue and no pending results.
|
|
3574
|
+
*
|
|
3575
|
+
* Takes no action if not in pipeline mode.
|
|
3576
|
+
* Raises PG::Error if the current statement isn't finished processing, or PQgetResult has not been called to collect results from all previously sent query.
|
|
3577
|
+
*
|
|
3578
|
+
* Available since PostgreSQL-14
|
|
3579
|
+
*/
|
|
3580
|
+
static VALUE
|
|
3581
|
+
pgconn_exit_pipeline_mode(VALUE self)
|
|
3582
|
+
{
|
|
3583
|
+
PGconn *conn = pg_get_pgconn(self);
|
|
3584
|
+
int res = PQexitPipelineMode(conn);
|
|
3585
|
+
if( res != 1 )
|
|
3586
|
+
pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(conn));
|
|
3587
|
+
|
|
3588
|
+
return Qnil;
|
|
3589
|
+
}
|
|
3590
|
+
|
|
3591
|
+
|
|
3592
|
+
/*
|
|
3593
|
+
* call-seq:
|
|
3594
|
+
* conn.pipeline_sync -> nil
|
|
3595
|
+
*
|
|
3596
|
+
* Marks a synchronization point in a pipeline by sending a sync message and flushing the send buffer.
|
|
3597
|
+
* This serves as the delimiter of an implicit transaction and an error recovery point; see Section 34.5.1.3 of the PostgreSQL documentation.
|
|
3598
|
+
*
|
|
3599
|
+
* Raises PG::Error if the connection is not in pipeline mode or sending a sync message failed.
|
|
3600
|
+
*
|
|
3601
|
+
* Available since PostgreSQL-14
|
|
3602
|
+
*/
|
|
3603
|
+
static VALUE
|
|
3604
|
+
pgconn_pipeline_sync(VALUE self)
|
|
3605
|
+
{
|
|
3606
|
+
PGconn *conn = pg_get_pgconn(self);
|
|
3607
|
+
int res = PQpipelineSync(conn);
|
|
3608
|
+
if( res != 1 )
|
|
3609
|
+
pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(conn));
|
|
3610
|
+
|
|
3611
|
+
return Qnil;
|
|
3612
|
+
}
|
|
3613
|
+
|
|
3614
|
+
/*
|
|
3615
|
+
* call-seq:
|
|
3616
|
+
* conn.pipeline_sync -> nil
|
|
3617
|
+
*
|
|
3618
|
+
* Sends a request for the server to flush its output buffer.
|
|
3619
|
+
*
|
|
3620
|
+
* The server flushes its output buffer automatically as a result of Connection#pipeline_sync being called, or on any request when not in pipeline mode.
|
|
3621
|
+
* This function is useful to cause the server to flush its output buffer in pipeline mode without establishing a synchronization point.
|
|
3622
|
+
* Note that the request is not itself flushed to the server automatically; use Connection#flush if necessary.
|
|
3623
|
+
*
|
|
3624
|
+
* Available since PostgreSQL-14
|
|
3625
|
+
*/
|
|
3626
|
+
static VALUE
|
|
3627
|
+
pgconn_send_flush_request(VALUE self)
|
|
3628
|
+
{
|
|
3629
|
+
PGconn *conn = pg_get_pgconn(self);
|
|
3630
|
+
int res = PQsendFlushRequest(conn);
|
|
3631
|
+
if( res != 1 )
|
|
3632
|
+
pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(conn));
|
|
3633
|
+
|
|
3634
|
+
return Qnil;
|
|
3635
|
+
}
|
|
3636
|
+
|
|
3637
|
+
#endif
|
|
3638
|
+
|
|
3460
3639
|
/**************************************************************************
|
|
3461
3640
|
* LARGE OBJECT SUPPORT
|
|
3462
3641
|
**************************************************************************/
|
|
@@ -3483,7 +3662,7 @@ pgconn_locreat(int argc, VALUE *argv, VALUE self)
|
|
|
3483
3662
|
|
|
3484
3663
|
lo_oid = lo_creat(conn, mode);
|
|
3485
3664
|
if (lo_oid == 0)
|
|
3486
|
-
|
|
3665
|
+
pg_raise_conn_error( rb_ePGerror, self, "lo_creat failed");
|
|
3487
3666
|
|
|
3488
3667
|
return UINT2NUM(lo_oid);
|
|
3489
3668
|
}
|
|
@@ -3504,7 +3683,7 @@ pgconn_locreate(VALUE self, VALUE in_lo_oid)
|
|
|
3504
3683
|
|
|
3505
3684
|
ret = lo_create(conn, lo_oid);
|
|
3506
3685
|
if (ret == InvalidOid)
|
|
3507
|
-
|
|
3686
|
+
pg_raise_conn_error( rb_ePGerror, self, "lo_create failed");
|
|
3508
3687
|
|
|
3509
3688
|
return UINT2NUM(ret);
|
|
3510
3689
|
}
|
|
@@ -3528,7 +3707,7 @@ pgconn_loimport(VALUE self, VALUE filename)
|
|
|
3528
3707
|
|
|
3529
3708
|
lo_oid = lo_import(conn, StringValueCStr(filename));
|
|
3530
3709
|
if (lo_oid == 0) {
|
|
3531
|
-
|
|
3710
|
+
pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(conn));
|
|
3532
3711
|
}
|
|
3533
3712
|
return UINT2NUM(lo_oid);
|
|
3534
3713
|
}
|
|
@@ -3549,7 +3728,7 @@ pgconn_loexport(VALUE self, VALUE lo_oid, VALUE filename)
|
|
|
3549
3728
|
oid = NUM2UINT(lo_oid);
|
|
3550
3729
|
|
|
3551
3730
|
if (lo_export(conn, oid, StringValueCStr(filename)) < 0) {
|
|
3552
|
-
|
|
3731
|
+
pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(conn));
|
|
3553
3732
|
}
|
|
3554
3733
|
return Qnil;
|
|
3555
3734
|
}
|
|
@@ -3580,7 +3759,7 @@ pgconn_loopen(int argc, VALUE *argv, VALUE self)
|
|
|
3580
3759
|
mode = NUM2INT(nmode);
|
|
3581
3760
|
|
|
3582
3761
|
if((fd = lo_open(conn, lo_oid, mode)) < 0) {
|
|
3583
|
-
|
|
3762
|
+
pg_raise_conn_error( rb_ePGerror, self, "can't open large object: %s", PQerrorMessage(conn));
|
|
3584
3763
|
}
|
|
3585
3764
|
return INT2FIX(fd);
|
|
3586
3765
|
}
|
|
@@ -3602,11 +3781,11 @@ pgconn_lowrite(VALUE self, VALUE in_lo_desc, VALUE buffer)
|
|
|
3602
3781
|
Check_Type(buffer, T_STRING);
|
|
3603
3782
|
|
|
3604
3783
|
if( RSTRING_LEN(buffer) < 0) {
|
|
3605
|
-
|
|
3784
|
+
pg_raise_conn_error( rb_ePGerror, self, "write buffer zero string");
|
|
3606
3785
|
}
|
|
3607
3786
|
if((n = lo_write(conn, fd, StringValuePtr(buffer),
|
|
3608
3787
|
RSTRING_LEN(buffer))) < 0) {
|
|
3609
|
-
|
|
3788
|
+
pg_raise_conn_error( rb_ePGerror, self, "lo_write failed: %s", PQerrorMessage(conn));
|
|
3610
3789
|
}
|
|
3611
3790
|
|
|
3612
3791
|
return INT2FIX(n);
|
|
@@ -3629,16 +3808,12 @@ pgconn_loread(VALUE self, VALUE in_lo_desc, VALUE in_len)
|
|
|
3629
3808
|
VALUE str;
|
|
3630
3809
|
char *buffer;
|
|
3631
3810
|
|
|
3632
|
-
|
|
3633
|
-
|
|
3634
|
-
rb_raise(rb_eNoMemError, "ALLOC failed!");
|
|
3635
|
-
|
|
3636
|
-
if (len < 0){
|
|
3637
|
-
rb_raise(rb_ePGerror,"nagative length %d given", len);
|
|
3638
|
-
}
|
|
3811
|
+
if (len < 0)
|
|
3812
|
+
pg_raise_conn_error( rb_ePGerror, self, "negative length %d given", len);
|
|
3639
3813
|
|
|
3814
|
+
buffer = ALLOC_N(char, len);
|
|
3640
3815
|
if((ret = lo_read(conn, lo_desc, buffer, len)) < 0)
|
|
3641
|
-
|
|
3816
|
+
pg_raise_conn_error( rb_ePGerror, self, "lo_read failed");
|
|
3642
3817
|
|
|
3643
3818
|
if(ret == 0) {
|
|
3644
3819
|
xfree(buffer);
|
|
@@ -3668,7 +3843,7 @@ pgconn_lolseek(VALUE self, VALUE in_lo_desc, VALUE offset, VALUE whence)
|
|
|
3668
3843
|
int ret;
|
|
3669
3844
|
|
|
3670
3845
|
if((ret = lo_lseek(conn, lo_desc, NUM2INT(offset), NUM2INT(whence))) < 0) {
|
|
3671
|
-
|
|
3846
|
+
pg_raise_conn_error( rb_ePGerror, self, "lo_lseek failed");
|
|
3672
3847
|
}
|
|
3673
3848
|
|
|
3674
3849
|
return INT2FIX(ret);
|
|
@@ -3688,7 +3863,7 @@ pgconn_lotell(VALUE self, VALUE in_lo_desc)
|
|
|
3688
3863
|
int lo_desc = NUM2INT(in_lo_desc);
|
|
3689
3864
|
|
|
3690
3865
|
if((position = lo_tell(conn, lo_desc)) < 0)
|
|
3691
|
-
|
|
3866
|
+
pg_raise_conn_error( rb_ePGerror, self, "lo_tell failed");
|
|
3692
3867
|
|
|
3693
3868
|
return INT2FIX(position);
|
|
3694
3869
|
}
|
|
@@ -3707,7 +3882,7 @@ pgconn_lotruncate(VALUE self, VALUE in_lo_desc, VALUE in_len)
|
|
|
3707
3882
|
size_t len = NUM2INT(in_len);
|
|
3708
3883
|
|
|
3709
3884
|
if(lo_truncate(conn,lo_desc,len) < 0)
|
|
3710
|
-
|
|
3885
|
+
pg_raise_conn_error( rb_ePGerror, self, "lo_truncate failed");
|
|
3711
3886
|
|
|
3712
3887
|
return Qnil;
|
|
3713
3888
|
}
|
|
@@ -3725,7 +3900,7 @@ pgconn_loclose(VALUE self, VALUE in_lo_desc)
|
|
|
3725
3900
|
int lo_desc = NUM2INT(in_lo_desc);
|
|
3726
3901
|
|
|
3727
3902
|
if(lo_close(conn,lo_desc) < 0)
|
|
3728
|
-
|
|
3903
|
+
pg_raise_conn_error( rb_ePGerror, self, "lo_close failed");
|
|
3729
3904
|
|
|
3730
3905
|
return Qnil;
|
|
3731
3906
|
}
|
|
@@ -3743,7 +3918,7 @@ pgconn_lounlink(VALUE self, VALUE in_oid)
|
|
|
3743
3918
|
Oid oid = NUM2UINT(in_oid);
|
|
3744
3919
|
|
|
3745
3920
|
if(lo_unlink(conn,oid) < 0)
|
|
3746
|
-
|
|
3921
|
+
pg_raise_conn_error( rb_ePGerror, self, "lo_unlink failed");
|
|
3747
3922
|
|
|
3748
3923
|
return Qnil;
|
|
3749
3924
|
}
|
|
@@ -3801,11 +3976,11 @@ static VALUE
|
|
|
3801
3976
|
pgconn_internal_encoding_set(VALUE self, VALUE enc)
|
|
3802
3977
|
{
|
|
3803
3978
|
if (NIL_P(enc)) {
|
|
3804
|
-
|
|
3979
|
+
pgconn_sync_set_client_encoding( self, rb_usascii_str_new_cstr("SQL_ASCII") );
|
|
3805
3980
|
return enc;
|
|
3806
3981
|
}
|
|
3807
3982
|
else if ( TYPE(enc) == T_STRING && strcasecmp("JOHAB", StringValueCStr(enc)) == 0 ) {
|
|
3808
|
-
|
|
3983
|
+
pgconn_sync_set_client_encoding(self, rb_usascii_str_new_cstr("JOHAB"));
|
|
3809
3984
|
return enc;
|
|
3810
3985
|
}
|
|
3811
3986
|
else {
|
|
@@ -3843,16 +4018,33 @@ pgconn_external_encoding(VALUE self)
|
|
|
3843
4018
|
return rb_enc_from_encoding( enc );
|
|
3844
4019
|
}
|
|
3845
4020
|
|
|
4021
|
+
/*
|
|
4022
|
+
* call-seq:
|
|
4023
|
+
* conn.set_client_encoding( encoding )
|
|
4024
|
+
*
|
|
4025
|
+
* Sets the client encoding to the _encoding_ String.
|
|
4026
|
+
*/
|
|
4027
|
+
static VALUE
|
|
4028
|
+
pgconn_async_set_client_encoding(VALUE self, VALUE encname)
|
|
4029
|
+
{
|
|
4030
|
+
VALUE query_format, query;
|
|
4031
|
+
|
|
4032
|
+
Check_Type(encname, T_STRING);
|
|
4033
|
+
query_format = rb_str_new_cstr("set client_encoding to '%s'");
|
|
4034
|
+
query = rb_funcall(query_format, rb_intern("%"), 1, encname);
|
|
4035
|
+
|
|
4036
|
+
pgconn_async_exec(1, &query, self);
|
|
4037
|
+
pgconn_set_internal_encoding_index( self );
|
|
4038
|
+
|
|
4039
|
+
return Qnil;
|
|
4040
|
+
}
|
|
3846
4041
|
|
|
3847
4042
|
static VALUE
|
|
3848
4043
|
pgconn_set_client_encoding_async1( VALUE args )
|
|
3849
4044
|
{
|
|
3850
4045
|
VALUE self = ((VALUE*)args)[0];
|
|
3851
4046
|
VALUE encname = ((VALUE*)args)[1];
|
|
3852
|
-
|
|
3853
|
-
VALUE query = rb_funcall(query_format, rb_intern("%"), 1, encname);
|
|
3854
|
-
|
|
3855
|
-
pgconn_async_exec(1, &query, self);
|
|
4047
|
+
pgconn_async_set_client_encoding(self, encname);
|
|
3856
4048
|
return 0;
|
|
3857
4049
|
}
|
|
3858
4050
|
|
|
@@ -3867,9 +4059,9 @@ pgconn_set_client_encoding_async2( VALUE arg, VALUE ex )
|
|
|
3867
4059
|
|
|
3868
4060
|
|
|
3869
4061
|
static VALUE
|
|
3870
|
-
pgconn_set_client_encoding_async( VALUE self,
|
|
4062
|
+
pgconn_set_client_encoding_async( VALUE self, VALUE encname )
|
|
3871
4063
|
{
|
|
3872
|
-
VALUE args[] = { self,
|
|
4064
|
+
VALUE args[] = { self, encname };
|
|
3873
4065
|
return rb_rescue(pgconn_set_client_encoding_async1, (VALUE)&args, pgconn_set_client_encoding_async2, Qnil);
|
|
3874
4066
|
}
|
|
3875
4067
|
|
|
@@ -3891,10 +4083,9 @@ pgconn_set_default_encoding( VALUE self )
|
|
|
3891
4083
|
|
|
3892
4084
|
if (( enc = rb_default_internal_encoding() )) {
|
|
3893
4085
|
encname = pg_get_rb_encoding_as_pg_encoding( enc );
|
|
3894
|
-
if ( pgconn_set_client_encoding_async(self, encname) != 0 )
|
|
4086
|
+
if ( pgconn_set_client_encoding_async(self, rb_str_new_cstr(encname)) != 0 )
|
|
3895
4087
|
rb_warning( "Failed to set the default_internal encoding to %s: '%s'",
|
|
3896
4088
|
encname, PQerrorMessage(conn) );
|
|
3897
|
-
pgconn_set_internal_encoding_index( self );
|
|
3898
4089
|
return rb_enc_from_encoding( enc );
|
|
3899
4090
|
} else {
|
|
3900
4091
|
pgconn_set_internal_encoding_index( self );
|
|
@@ -3916,12 +4107,12 @@ static VALUE
|
|
|
3916
4107
|
pgconn_type_map_for_queries_set(VALUE self, VALUE typemap)
|
|
3917
4108
|
{
|
|
3918
4109
|
t_pg_connection *this = pg_get_connection( self );
|
|
4110
|
+
t_typemap *tm;
|
|
4111
|
+
UNUSED(tm);
|
|
4112
|
+
|
|
4113
|
+
/* Check type of method param */
|
|
4114
|
+
TypedData_Get_Struct(typemap, t_typemap, &pg_typemap_type, tm);
|
|
3919
4115
|
|
|
3920
|
-
if ( !rb_obj_is_kind_of(typemap, rb_cTypeMap) ) {
|
|
3921
|
-
rb_raise( rb_eTypeError, "wrong argument type %s (expected kind of PG::TypeMap)",
|
|
3922
|
-
rb_obj_classname( typemap ) );
|
|
3923
|
-
}
|
|
3924
|
-
Check_Type(typemap, T_DATA);
|
|
3925
4116
|
this->type_map_for_queries = typemap;
|
|
3926
4117
|
|
|
3927
4118
|
return typemap;
|
|
@@ -3956,12 +4147,10 @@ static VALUE
|
|
|
3956
4147
|
pgconn_type_map_for_results_set(VALUE self, VALUE typemap)
|
|
3957
4148
|
{
|
|
3958
4149
|
t_pg_connection *this = pg_get_connection( self );
|
|
4150
|
+
t_typemap *tm;
|
|
4151
|
+
UNUSED(tm);
|
|
3959
4152
|
|
|
3960
|
-
|
|
3961
|
-
rb_raise( rb_eTypeError, "wrong argument type %s (expected kind of PG::TypeMap)",
|
|
3962
|
-
rb_obj_classname( typemap ) );
|
|
3963
|
-
}
|
|
3964
|
-
Check_Type(typemap, T_DATA);
|
|
4153
|
+
TypedData_Get_Struct(typemap, t_typemap, &pg_typemap_type, tm);
|
|
3965
4154
|
this->type_map_for_results = typemap;
|
|
3966
4155
|
|
|
3967
4156
|
return typemap;
|
|
@@ -3996,20 +4185,19 @@ pgconn_type_map_for_results_get(VALUE self)
|
|
|
3996
4185
|
*
|
|
3997
4186
|
*/
|
|
3998
4187
|
static VALUE
|
|
3999
|
-
pgconn_encoder_for_put_copy_data_set(VALUE self, VALUE
|
|
4188
|
+
pgconn_encoder_for_put_copy_data_set(VALUE self, VALUE encoder)
|
|
4000
4189
|
{
|
|
4001
4190
|
t_pg_connection *this = pg_get_connection( self );
|
|
4002
4191
|
|
|
4003
|
-
if(
|
|
4004
|
-
|
|
4005
|
-
|
|
4006
|
-
|
|
4007
|
-
|
|
4008
|
-
Check_Type(typemap, T_DATA);
|
|
4192
|
+
if( encoder != Qnil ){
|
|
4193
|
+
t_pg_coder *co;
|
|
4194
|
+
UNUSED(co);
|
|
4195
|
+
/* Check argument type */
|
|
4196
|
+
TypedData_Get_Struct(encoder, t_pg_coder, &pg_coder_type, co);
|
|
4009
4197
|
}
|
|
4010
|
-
this->encoder_for_put_copy_data =
|
|
4198
|
+
this->encoder_for_put_copy_data = encoder;
|
|
4011
4199
|
|
|
4012
|
-
return
|
|
4200
|
+
return encoder;
|
|
4013
4201
|
}
|
|
4014
4202
|
|
|
4015
4203
|
/*
|
|
@@ -4045,20 +4233,19 @@ pgconn_encoder_for_put_copy_data_get(VALUE self)
|
|
|
4045
4233
|
*
|
|
4046
4234
|
*/
|
|
4047
4235
|
static VALUE
|
|
4048
|
-
pgconn_decoder_for_get_copy_data_set(VALUE self, VALUE
|
|
4236
|
+
pgconn_decoder_for_get_copy_data_set(VALUE self, VALUE decoder)
|
|
4049
4237
|
{
|
|
4050
4238
|
t_pg_connection *this = pg_get_connection( self );
|
|
4051
4239
|
|
|
4052
|
-
if(
|
|
4053
|
-
|
|
4054
|
-
|
|
4055
|
-
|
|
4056
|
-
|
|
4057
|
-
Check_Type(typemap, T_DATA);
|
|
4240
|
+
if( decoder != Qnil ){
|
|
4241
|
+
t_pg_coder *co;
|
|
4242
|
+
UNUSED(co);
|
|
4243
|
+
/* Check argument type */
|
|
4244
|
+
TypedData_Get_Struct(decoder, t_pg_coder, &pg_coder_type, co);
|
|
4058
4245
|
}
|
|
4059
|
-
this->decoder_for_get_copy_data =
|
|
4246
|
+
this->decoder_for_get_copy_data = decoder;
|
|
4060
4247
|
|
|
4061
|
-
return
|
|
4248
|
+
return decoder;
|
|
4062
4249
|
}
|
|
4063
4250
|
|
|
4064
4251
|
/*
|
|
@@ -4138,9 +4325,10 @@ pgconn_field_name_type_get(VALUE self)
|
|
|
4138
4325
|
* Document-class: PG::Connection
|
|
4139
4326
|
*/
|
|
4140
4327
|
void
|
|
4141
|
-
init_pg_connection()
|
|
4328
|
+
init_pg_connection(void)
|
|
4142
4329
|
{
|
|
4143
4330
|
s_id_encode = rb_intern("encode");
|
|
4331
|
+
s_id_autoclose_set = rb_intern("autoclose=");
|
|
4144
4332
|
sym_type = ID2SYM(rb_intern("type"));
|
|
4145
4333
|
sym_format = ID2SYM(rb_intern("format"));
|
|
4146
4334
|
sym_value = ID2SYM(rb_intern("value"));
|
|
@@ -4156,10 +4344,6 @@ init_pg_connection()
|
|
|
4156
4344
|
/****** PG::Connection CLASS METHODS ******/
|
|
4157
4345
|
rb_define_alloc_func( rb_cPGconn, pgconn_s_allocate );
|
|
4158
4346
|
|
|
4159
|
-
SINGLETON_ALIAS(rb_cPGconn, "connect", "new");
|
|
4160
|
-
SINGLETON_ALIAS(rb_cPGconn, "open", "new");
|
|
4161
|
-
SINGLETON_ALIAS(rb_cPGconn, "setdb", "new");
|
|
4162
|
-
SINGLETON_ALIAS(rb_cPGconn, "setdblogin", "new");
|
|
4163
4347
|
rb_define_singleton_method(rb_cPGconn, "escape_string", pgconn_s_escape, 1);
|
|
4164
4348
|
SINGLETON_ALIAS(rb_cPGconn, "escape", "escape_string");
|
|
4165
4349
|
rb_define_singleton_method(rb_cPGconn, "escape_bytea", pgconn_s_escape_bytea, 1);
|
|
@@ -4168,14 +4352,15 @@ init_pg_connection()
|
|
|
4168
4352
|
rb_define_singleton_method(rb_cPGconn, "quote_ident", pgconn_s_quote_ident, 1);
|
|
4169
4353
|
rb_define_singleton_method(rb_cPGconn, "connect_start", pgconn_s_connect_start, -1);
|
|
4170
4354
|
rb_define_singleton_method(rb_cPGconn, "conndefaults", pgconn_s_conndefaults, 0);
|
|
4171
|
-
rb_define_singleton_method(rb_cPGconn, "
|
|
4355
|
+
rb_define_singleton_method(rb_cPGconn, "conninfo_parse", pgconn_s_conninfo_parse, 1);
|
|
4356
|
+
rb_define_singleton_method(rb_cPGconn, "sync_ping", pgconn_s_sync_ping, -1);
|
|
4357
|
+
rb_define_singleton_method(rb_cPGconn, "sync_connect", pgconn_s_sync_connect, -1);
|
|
4172
4358
|
|
|
4173
4359
|
/****** PG::Connection INSTANCE METHODS: Connection Control ******/
|
|
4174
|
-
rb_define_method(rb_cPGconn, "initialize", pgconn_init, -1);
|
|
4175
4360
|
rb_define_method(rb_cPGconn, "connect_poll", pgconn_connect_poll, 0);
|
|
4176
4361
|
rb_define_method(rb_cPGconn, "finish", pgconn_finish, 0);
|
|
4177
4362
|
rb_define_method(rb_cPGconn, "finished?", pgconn_finished_p, 0);
|
|
4178
|
-
rb_define_method(rb_cPGconn, "
|
|
4363
|
+
rb_define_method(rb_cPGconn, "sync_reset", pgconn_sync_reset, 0);
|
|
4179
4364
|
rb_define_method(rb_cPGconn, "reset_start", pgconn_reset_start, 0);
|
|
4180
4365
|
rb_define_method(rb_cPGconn, "reset_poll", pgconn_reset_poll, 0);
|
|
4181
4366
|
rb_define_alias(rb_cPGconn, "close", "finish");
|
|
@@ -4185,11 +4370,12 @@ init_pg_connection()
|
|
|
4185
4370
|
rb_define_method(rb_cPGconn, "user", pgconn_user, 0);
|
|
4186
4371
|
rb_define_method(rb_cPGconn, "pass", pgconn_pass, 0);
|
|
4187
4372
|
rb_define_method(rb_cPGconn, "host", pgconn_host, 0);
|
|
4373
|
+
#if defined(HAVE_PQRESULTMEMORYSIZE)
|
|
4374
|
+
rb_define_method(rb_cPGconn, "hostaddr", pgconn_hostaddr, 0);
|
|
4375
|
+
#endif
|
|
4188
4376
|
rb_define_method(rb_cPGconn, "port", pgconn_port, 0);
|
|
4189
4377
|
rb_define_method(rb_cPGconn, "tty", pgconn_tty, 0);
|
|
4190
|
-
#ifdef HAVE_PQCONNINFO
|
|
4191
4378
|
rb_define_method(rb_cPGconn, "conninfo", pgconn_conninfo, 0);
|
|
4192
|
-
#endif
|
|
4193
4379
|
rb_define_method(rb_cPGconn, "options", pgconn_options, 0);
|
|
4194
4380
|
rb_define_method(rb_cPGconn, "status", pgconn_status, 0);
|
|
4195
4381
|
rb_define_method(rb_cPGconn, "transaction_status", pgconn_transaction_status, 0);
|
|
@@ -4200,17 +4386,18 @@ init_pg_connection()
|
|
|
4200
4386
|
rb_define_method(rb_cPGconn, "socket", pgconn_socket, 0);
|
|
4201
4387
|
rb_define_method(rb_cPGconn, "socket_io", pgconn_socket_io, 0);
|
|
4202
4388
|
rb_define_method(rb_cPGconn, "backend_pid", pgconn_backend_pid, 0);
|
|
4389
|
+
rb_define_method(rb_cPGconn, "backend_key", pgconn_backend_key, 0);
|
|
4203
4390
|
rb_define_method(rb_cPGconn, "connection_needs_password", pgconn_connection_needs_password, 0);
|
|
4204
4391
|
rb_define_method(rb_cPGconn, "connection_used_password", pgconn_connection_used_password, 0);
|
|
4205
4392
|
/* rb_define_method(rb_cPGconn, "getssl", pgconn_getssl, 0); */
|
|
4206
4393
|
|
|
4207
4394
|
/****** PG::Connection INSTANCE METHODS: Command Execution ******/
|
|
4208
|
-
rb_define_method(rb_cPGconn, "sync_exec",
|
|
4209
|
-
rb_define_method(rb_cPGconn, "sync_exec_params",
|
|
4210
|
-
rb_define_method(rb_cPGconn, "sync_prepare",
|
|
4211
|
-
rb_define_method(rb_cPGconn, "sync_exec_prepared",
|
|
4212
|
-
rb_define_method(rb_cPGconn, "sync_describe_prepared",
|
|
4213
|
-
rb_define_method(rb_cPGconn, "sync_describe_portal",
|
|
4395
|
+
rb_define_method(rb_cPGconn, "sync_exec", pgconn_sync_exec, -1);
|
|
4396
|
+
rb_define_method(rb_cPGconn, "sync_exec_params", pgconn_sync_exec_params, -1);
|
|
4397
|
+
rb_define_method(rb_cPGconn, "sync_prepare", pgconn_sync_prepare, -1);
|
|
4398
|
+
rb_define_method(rb_cPGconn, "sync_exec_prepared", pgconn_sync_exec_prepared, -1);
|
|
4399
|
+
rb_define_method(rb_cPGconn, "sync_describe_prepared", pgconn_sync_describe_prepared, 1);
|
|
4400
|
+
rb_define_method(rb_cPGconn, "sync_describe_portal", pgconn_sync_describe_portal, 1);
|
|
4214
4401
|
|
|
4215
4402
|
rb_define_method(rb_cPGconn, "exec", pgconn_async_exec, -1);
|
|
4216
4403
|
rb_define_method(rb_cPGconn, "exec_params", pgconn_async_exec_params, -1);
|
|
@@ -4243,25 +4430,26 @@ init_pg_connection()
|
|
|
4243
4430
|
rb_define_method(rb_cPGconn, "send_query_prepared", pgconn_send_query_prepared, -1);
|
|
4244
4431
|
rb_define_method(rb_cPGconn, "send_describe_prepared", pgconn_send_describe_prepared, 1);
|
|
4245
4432
|
rb_define_method(rb_cPGconn, "send_describe_portal", pgconn_send_describe_portal, 1);
|
|
4246
|
-
rb_define_method(rb_cPGconn, "
|
|
4433
|
+
rb_define_method(rb_cPGconn, "sync_get_result", pgconn_sync_get_result, 0);
|
|
4247
4434
|
rb_define_method(rb_cPGconn, "consume_input", pgconn_consume_input, 0);
|
|
4248
4435
|
rb_define_method(rb_cPGconn, "is_busy", pgconn_is_busy, 0);
|
|
4249
|
-
rb_define_method(rb_cPGconn, "
|
|
4250
|
-
rb_define_method(rb_cPGconn, "
|
|
4251
|
-
|
|
4252
|
-
rb_define_method(rb_cPGconn, "flush",
|
|
4436
|
+
rb_define_method(rb_cPGconn, "sync_setnonblocking", pgconn_sync_setnonblocking, 1);
|
|
4437
|
+
rb_define_method(rb_cPGconn, "sync_isnonblocking", pgconn_sync_isnonblocking, 0);
|
|
4438
|
+
rb_define_method(rb_cPGconn, "sync_flush", pgconn_sync_flush, 0);
|
|
4439
|
+
rb_define_method(rb_cPGconn, "flush", pgconn_async_flush, 0);
|
|
4440
|
+
rb_define_alias(rb_cPGconn, "async_flush", "flush");
|
|
4253
4441
|
rb_define_method(rb_cPGconn, "discard_results", pgconn_discard_results, 0);
|
|
4254
4442
|
|
|
4255
4443
|
/****** PG::Connection INSTANCE METHODS: Cancelling Queries in Progress ******/
|
|
4256
|
-
rb_define_method(rb_cPGconn, "
|
|
4444
|
+
rb_define_method(rb_cPGconn, "sync_cancel", pgconn_sync_cancel, 0);
|
|
4257
4445
|
|
|
4258
4446
|
/****** PG::Connection INSTANCE METHODS: NOTIFY ******/
|
|
4259
4447
|
rb_define_method(rb_cPGconn, "notifies", pgconn_notifies, 0);
|
|
4260
4448
|
|
|
4261
4449
|
/****** PG::Connection INSTANCE METHODS: COPY ******/
|
|
4262
|
-
rb_define_method(rb_cPGconn, "
|
|
4263
|
-
rb_define_method(rb_cPGconn, "
|
|
4264
|
-
rb_define_method(rb_cPGconn, "
|
|
4450
|
+
rb_define_method(rb_cPGconn, "sync_put_copy_data", pgconn_sync_put_copy_data, -1);
|
|
4451
|
+
rb_define_method(rb_cPGconn, "sync_put_copy_end", pgconn_sync_put_copy_end, -1);
|
|
4452
|
+
rb_define_method(rb_cPGconn, "sync_get_copy_data", pgconn_sync_get_copy_data, -1);
|
|
4265
4453
|
|
|
4266
4454
|
/****** PG::Connection INSTANCE METHODS: Control Functions ******/
|
|
4267
4455
|
rb_define_method(rb_cPGconn, "set_error_verbosity", pgconn_set_error_verbosity, 1);
|
|
@@ -4277,16 +4465,20 @@ init_pg_connection()
|
|
|
4277
4465
|
|
|
4278
4466
|
/****** PG::Connection INSTANCE METHODS: Other ******/
|
|
4279
4467
|
rb_define_method(rb_cPGconn, "get_client_encoding", pgconn_get_client_encoding, 0);
|
|
4280
|
-
rb_define_method(rb_cPGconn, "
|
|
4468
|
+
rb_define_method(rb_cPGconn, "sync_set_client_encoding", pgconn_sync_set_client_encoding, 1);
|
|
4469
|
+
rb_define_method(rb_cPGconn, "set_client_encoding", pgconn_async_set_client_encoding, 1);
|
|
4470
|
+
rb_define_alias(rb_cPGconn, "async_set_client_encoding", "set_client_encoding");
|
|
4281
4471
|
rb_define_alias(rb_cPGconn, "client_encoding=", "set_client_encoding");
|
|
4282
|
-
rb_define_method(rb_cPGconn, "transaction", pgconn_transaction, 0);
|
|
4283
4472
|
rb_define_method(rb_cPGconn, "block", pgconn_block, -1);
|
|
4473
|
+
rb_define_private_method(rb_cPGconn, "flush_data=", pgconn_flush_data_set, 1);
|
|
4284
4474
|
rb_define_method(rb_cPGconn, "wait_for_notify", pgconn_wait_for_notify, -1);
|
|
4285
4475
|
rb_define_alias(rb_cPGconn, "notifies_wait", "wait_for_notify");
|
|
4286
4476
|
rb_define_method(rb_cPGconn, "quote_ident", pgconn_s_quote_ident, 1);
|
|
4287
|
-
rb_define_method(rb_cPGconn, "
|
|
4477
|
+
rb_define_method(rb_cPGconn, "sync_get_last_result", pgconn_sync_get_last_result, 0);
|
|
4478
|
+
rb_define_method(rb_cPGconn, "get_last_result", pgconn_async_get_last_result, 0);
|
|
4479
|
+
rb_define_alias(rb_cPGconn, "async_get_last_result", "get_last_result");
|
|
4288
4480
|
#ifdef HAVE_PQENCRYPTPASSWORDCONN
|
|
4289
|
-
rb_define_method(rb_cPGconn, "
|
|
4481
|
+
rb_define_method(rb_cPGconn, "sync_encrypt_password", pgconn_sync_encrypt_password, -1);
|
|
4290
4482
|
#endif
|
|
4291
4483
|
|
|
4292
4484
|
#ifdef HAVE_PQSSLATTRIBUTE
|
|
@@ -4295,6 +4487,14 @@ init_pg_connection()
|
|
|
4295
4487
|
rb_define_method(rb_cPGconn, "ssl_attribute_names", pgconn_ssl_attribute_names, 0);
|
|
4296
4488
|
#endif
|
|
4297
4489
|
|
|
4490
|
+
#ifdef HAVE_PQENTERPIPELINEMODE
|
|
4491
|
+
rb_define_method(rb_cPGconn, "pipeline_status", pgconn_pipeline_status, 0);
|
|
4492
|
+
rb_define_method(rb_cPGconn, "enter_pipeline_mode", pgconn_enter_pipeline_mode, 0);
|
|
4493
|
+
rb_define_method(rb_cPGconn, "exit_pipeline_mode", pgconn_exit_pipeline_mode, 0);
|
|
4494
|
+
rb_define_method(rb_cPGconn, "pipeline_sync", pgconn_pipeline_sync, 0);
|
|
4495
|
+
rb_define_method(rb_cPGconn, "send_flush_request", pgconn_send_flush_request, 0);
|
|
4496
|
+
#endif
|
|
4497
|
+
|
|
4298
4498
|
/****** PG::Connection INSTANCE METHODS: Large Object Support ******/
|
|
4299
4499
|
rb_define_method(rb_cPGconn, "lo_creat", pgconn_locreat, -1);
|
|
4300
4500
|
rb_define_alias(rb_cPGconn, "locreat", "lo_creat");
|