pg 1.2.3 → 1.5.6
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 +42 -0
- data/.gems +6 -0
- data/.github/workflows/binary-gems.yml +117 -0
- data/.github/workflows/source-gem.yml +141 -0
- data/.gitignore +22 -0
- data/.hgsigs +34 -0
- data/.hgtags +41 -0
- data/.irbrc +23 -0
- data/.pryrc +23 -0
- data/.tm_properties +21 -0
- data/.travis.yml +49 -0
- data/Gemfile +17 -0
- data/History.md +901 -0
- data/Manifest.txt +0 -1
- data/README.ja.md +300 -0
- data/README.md +286 -0
- data/Rakefile +36 -135
- data/Rakefile.cross +13 -13
- data/certs/ged.pem +24 -0
- data/certs/kanis@comcard.de.pem +20 -0
- data/certs/larskanis-2022.pem +26 -0
- data/certs/larskanis-2023.pem +24 -0
- data/certs/larskanis-2024.pem +24 -0
- data/ext/errorcodes.def +12 -0
- data/ext/errorcodes.rb +0 -0
- data/ext/errorcodes.txt +4 -1
- data/ext/extconf.rb +104 -25
- data/ext/gvl_wrappers.c +4 -0
- data/ext/gvl_wrappers.h +23 -0
- data/ext/pg.c +73 -58
- data/ext/pg.h +28 -5
- data/ext/pg_binary_decoder.c +80 -1
- data/ext/pg_binary_encoder.c +225 -1
- data/ext/pg_coder.c +96 -33
- data/ext/pg_connection.c +1032 -704
- data/ext/pg_copy_coder.c +351 -33
- data/ext/pg_errors.c +1 -1
- data/ext/pg_record_coder.c +50 -19
- data/ext/pg_result.c +177 -64
- data/ext/pg_text_decoder.c +29 -11
- data/ext/pg_text_encoder.c +29 -16
- data/ext/pg_tuple.c +83 -60
- data/ext/pg_type_map.c +44 -10
- data/ext/pg_type_map_all_strings.c +17 -3
- data/ext/pg_type_map_by_class.c +54 -27
- data/ext/pg_type_map_by_column.c +73 -31
- data/ext/pg_type_map_by_mri_type.c +48 -19
- data/ext/pg_type_map_by_oid.c +59 -27
- data/ext/pg_type_map_in_ruby.c +55 -21
- data/ext/pg_util.c +2 -2
- data/lib/pg/basic_type_map_based_on_result.rb +67 -0
- data/lib/pg/basic_type_map_for_queries.rb +202 -0
- data/lib/pg/basic_type_map_for_results.rb +104 -0
- data/lib/pg/basic_type_registry.rb +303 -0
- data/lib/pg/binary_decoder/date.rb +9 -0
- data/lib/pg/binary_decoder/timestamp.rb +26 -0
- data/lib/pg/binary_encoder/timestamp.rb +20 -0
- data/lib/pg/coder.rb +15 -13
- data/lib/pg/connection.rb +752 -83
- data/lib/pg/exceptions.rb +14 -1
- data/lib/pg/text_decoder/date.rb +18 -0
- data/lib/pg/text_decoder/inet.rb +9 -0
- data/lib/pg/text_decoder/json.rb +14 -0
- data/lib/pg/text_decoder/numeric.rb +9 -0
- data/lib/pg/text_decoder/timestamp.rb +30 -0
- data/lib/pg/text_encoder/date.rb +12 -0
- data/lib/pg/text_encoder/inet.rb +28 -0
- data/lib/pg/text_encoder/json.rb +14 -0
- data/lib/pg/text_encoder/numeric.rb +9 -0
- data/lib/pg/text_encoder/timestamp.rb +24 -0
- data/lib/pg/version.rb +4 -0
- data/lib/pg.rb +94 -39
- data/misc/openssl-pg-segfault.rb +31 -0
- data/misc/postgres/History.txt +9 -0
- data/misc/postgres/Manifest.txt +5 -0
- data/misc/postgres/README.txt +21 -0
- data/misc/postgres/Rakefile +21 -0
- data/misc/postgres/lib/postgres.rb +16 -0
- data/misc/ruby-pg/History.txt +9 -0
- data/misc/ruby-pg/Manifest.txt +5 -0
- data/misc/ruby-pg/README.txt +21 -0
- data/misc/ruby-pg/Rakefile +21 -0
- data/misc/ruby-pg/lib/ruby/pg.rb +16 -0
- data/pg.gemspec +34 -0
- data/rakelib/task_extension.rb +46 -0
- data/sample/array_insert.rb +20 -0
- data/sample/async_api.rb +102 -0
- data/sample/async_copyto.rb +39 -0
- data/sample/async_mixed.rb +56 -0
- data/sample/check_conn.rb +21 -0
- data/sample/copydata.rb +71 -0
- data/sample/copyfrom.rb +81 -0
- data/sample/copyto.rb +19 -0
- data/sample/cursor.rb +21 -0
- data/sample/disk_usage_report.rb +177 -0
- data/sample/issue-119.rb +94 -0
- data/sample/losample.rb +69 -0
- data/sample/minimal-testcase.rb +17 -0
- data/sample/notify_wait.rb +72 -0
- data/sample/pg_statistics.rb +285 -0
- data/sample/replication_monitor.rb +222 -0
- data/sample/test_binary_values.rb +33 -0
- data/sample/wal_shipper.rb +434 -0
- data/sample/warehouse_partitions.rb +311 -0
- data.tar.gz.sig +0 -0
- metadata +137 -210
- metadata.gz.sig +0 -0
- data/ChangeLog +0 -0
- data/History.rdoc +0 -578
- data/README.ja.rdoc +0 -13
- data/README.rdoc +0 -213
- data/lib/pg/basic_type_mapping.rb +0 -522
- data/lib/pg/binary_decoder.rb +0 -23
- data/lib/pg/constants.rb +0 -12
- data/lib/pg/text_decoder.rb +0 -46
- data/lib/pg/text_encoder.rb +0 -59
- 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,20 +12,41 @@
|
|
|
12
12
|
|
|
13
13
|
VALUE rb_cPGconn;
|
|
14
14
|
static ID s_id_encode;
|
|
15
|
+
static ID s_id_autoclose_set;
|
|
15
16
|
static VALUE sym_type, sym_format, sym_value;
|
|
16
17
|
static VALUE sym_symbol, sym_string, sym_static_symbol;
|
|
17
18
|
|
|
18
|
-
static PQnoticeReceiver default_notice_receiver = NULL;
|
|
19
|
-
static PQnoticeProcessor default_notice_processor = NULL;
|
|
20
|
-
|
|
21
19
|
static VALUE pgconn_finish( VALUE );
|
|
22
20
|
static VALUE pgconn_set_default_encoding( VALUE self );
|
|
21
|
+
static VALUE pgconn_wait_for_flush( VALUE self );
|
|
23
22
|
static void pgconn_set_internal_encoding_index( VALUE );
|
|
23
|
+
static const rb_data_type_t pg_connection_type;
|
|
24
|
+
static VALUE pgconn_async_flush(VALUE self);
|
|
24
25
|
|
|
25
26
|
/*
|
|
26
27
|
* Global functions
|
|
27
28
|
*/
|
|
28
29
|
|
|
30
|
+
/*
|
|
31
|
+
* Convenience function to raise connection errors
|
|
32
|
+
*/
|
|
33
|
+
#ifdef __GNUC__
|
|
34
|
+
__attribute__((format(printf, 3, 4)))
|
|
35
|
+
#endif
|
|
36
|
+
static void
|
|
37
|
+
pg_raise_conn_error( VALUE klass, VALUE self, const char *format, ...)
|
|
38
|
+
{
|
|
39
|
+
VALUE msg, error;
|
|
40
|
+
va_list ap;
|
|
41
|
+
|
|
42
|
+
va_start(ap, format);
|
|
43
|
+
msg = rb_vsprintf(format, ap);
|
|
44
|
+
va_end(ap);
|
|
45
|
+
error = rb_exc_new_str(klass, msg);
|
|
46
|
+
rb_iv_set(error, "@connection", self);
|
|
47
|
+
rb_exc_raise(error);
|
|
48
|
+
}
|
|
49
|
+
|
|
29
50
|
/*
|
|
30
51
|
* Fetch the PG::Connection object data pointer.
|
|
31
52
|
*/
|
|
@@ -33,7 +54,7 @@ t_pg_connection *
|
|
|
33
54
|
pg_get_connection( VALUE self )
|
|
34
55
|
{
|
|
35
56
|
t_pg_connection *this;
|
|
36
|
-
|
|
57
|
+
TypedData_Get_Struct( self, t_pg_connection, &pg_connection_type, this);
|
|
37
58
|
|
|
38
59
|
return this;
|
|
39
60
|
}
|
|
@@ -46,10 +67,10 @@ static t_pg_connection *
|
|
|
46
67
|
pg_get_connection_safe( VALUE self )
|
|
47
68
|
{
|
|
48
69
|
t_pg_connection *this;
|
|
49
|
-
|
|
70
|
+
TypedData_Get_Struct( self, t_pg_connection, &pg_connection_type, this);
|
|
50
71
|
|
|
51
72
|
if ( !this->pgconn )
|
|
52
|
-
|
|
73
|
+
pg_raise_conn_error( rb_eConnectionBad, self, "connection is closed");
|
|
53
74
|
|
|
54
75
|
return this;
|
|
55
76
|
}
|
|
@@ -65,10 +86,11 @@ PGconn *
|
|
|
65
86
|
pg_get_pgconn( VALUE self )
|
|
66
87
|
{
|
|
67
88
|
t_pg_connection *this;
|
|
68
|
-
|
|
89
|
+
TypedData_Get_Struct( self, t_pg_connection, &pg_connection_type, this);
|
|
69
90
|
|
|
70
|
-
if ( !this->pgconn )
|
|
71
|
-
|
|
91
|
+
if ( !this->pgconn ){
|
|
92
|
+
pg_raise_conn_error( rb_eConnectionBad, self, "connection is closed");
|
|
93
|
+
}
|
|
72
94
|
|
|
73
95
|
return this->pgconn;
|
|
74
96
|
}
|
|
@@ -86,14 +108,13 @@ pgconn_close_socket_io( VALUE self )
|
|
|
86
108
|
|
|
87
109
|
if ( RTEST(socket_io) ) {
|
|
88
110
|
#if defined(_WIN32)
|
|
89
|
-
if( rb_w32_unwrap_io_handle(this->ruby_sd) )
|
|
90
|
-
|
|
91
|
-
}
|
|
111
|
+
if( rb_w32_unwrap_io_handle(this->ruby_sd) )
|
|
112
|
+
pg_raise_conn_error( rb_eConnectionBad, self, "Could not unwrap win32 socket handle");
|
|
92
113
|
#endif
|
|
93
114
|
rb_funcall( socket_io, rb_intern("close"), 0 );
|
|
94
115
|
}
|
|
95
116
|
|
|
96
|
-
this->socket_io
|
|
117
|
+
RB_OBJ_WRITE(self, &this->socket_io, Qnil);
|
|
97
118
|
}
|
|
98
119
|
|
|
99
120
|
|
|
@@ -145,16 +166,31 @@ static const char *pg_cstr_enc(VALUE str, int enc_idx){
|
|
|
145
166
|
* GC Mark function
|
|
146
167
|
*/
|
|
147
168
|
static void
|
|
148
|
-
pgconn_gc_mark(
|
|
169
|
+
pgconn_gc_mark( void *_this )
|
|
170
|
+
{
|
|
171
|
+
t_pg_connection *this = (t_pg_connection *)_this;
|
|
172
|
+
rb_gc_mark_movable( this->socket_io );
|
|
173
|
+
rb_gc_mark_movable( this->notice_receiver );
|
|
174
|
+
rb_gc_mark_movable( this->notice_processor );
|
|
175
|
+
rb_gc_mark_movable( this->type_map_for_queries );
|
|
176
|
+
rb_gc_mark_movable( this->type_map_for_results );
|
|
177
|
+
rb_gc_mark_movable( this->trace_stream );
|
|
178
|
+
rb_gc_mark_movable( this->encoder_for_put_copy_data );
|
|
179
|
+
rb_gc_mark_movable( this->decoder_for_get_copy_data );
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
static void
|
|
183
|
+
pgconn_gc_compact( void *_this )
|
|
149
184
|
{
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
185
|
+
t_pg_connection *this = (t_pg_connection *)_this;
|
|
186
|
+
pg_gc_location( this->socket_io );
|
|
187
|
+
pg_gc_location( this->notice_receiver );
|
|
188
|
+
pg_gc_location( this->notice_processor );
|
|
189
|
+
pg_gc_location( this->type_map_for_queries );
|
|
190
|
+
pg_gc_location( this->type_map_for_results );
|
|
191
|
+
pg_gc_location( this->trace_stream );
|
|
192
|
+
pg_gc_location( this->encoder_for_put_copy_data );
|
|
193
|
+
pg_gc_location( this->decoder_for_get_copy_data );
|
|
158
194
|
}
|
|
159
195
|
|
|
160
196
|
|
|
@@ -162,11 +198,15 @@ pgconn_gc_mark( t_pg_connection *this )
|
|
|
162
198
|
* GC Free function
|
|
163
199
|
*/
|
|
164
200
|
static void
|
|
165
|
-
pgconn_gc_free(
|
|
201
|
+
pgconn_gc_free( void *_this )
|
|
166
202
|
{
|
|
203
|
+
t_pg_connection *this = (t_pg_connection *)_this;
|
|
167
204
|
#if defined(_WIN32)
|
|
168
|
-
if ( RTEST(this->socket_io) )
|
|
169
|
-
rb_w32_unwrap_io_handle(
|
|
205
|
+
if ( RTEST(this->socket_io) ) {
|
|
206
|
+
if( rb_w32_unwrap_io_handle(this->ruby_sd) ){
|
|
207
|
+
rb_warn("pg: Could not unwrap win32 socket handle by garbage collector");
|
|
208
|
+
}
|
|
209
|
+
}
|
|
170
210
|
#endif
|
|
171
211
|
if (this->pgconn != NULL)
|
|
172
212
|
PQfinish( this->pgconn );
|
|
@@ -174,6 +214,29 @@ pgconn_gc_free( t_pg_connection *this )
|
|
|
174
214
|
xfree(this);
|
|
175
215
|
}
|
|
176
216
|
|
|
217
|
+
/*
|
|
218
|
+
* Object Size function
|
|
219
|
+
*/
|
|
220
|
+
static size_t
|
|
221
|
+
pgconn_memsize( const void *_this )
|
|
222
|
+
{
|
|
223
|
+
const t_pg_connection *this = (const t_pg_connection *)_this;
|
|
224
|
+
return sizeof(*this);
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
static const rb_data_type_t pg_connection_type = {
|
|
228
|
+
"PG::Connection",
|
|
229
|
+
{
|
|
230
|
+
pgconn_gc_mark,
|
|
231
|
+
pgconn_gc_free,
|
|
232
|
+
pgconn_memsize,
|
|
233
|
+
pg_compact_callback(pgconn_gc_compact),
|
|
234
|
+
},
|
|
235
|
+
0,
|
|
236
|
+
0,
|
|
237
|
+
RUBY_TYPED_WB_PROTECTED,
|
|
238
|
+
};
|
|
239
|
+
|
|
177
240
|
|
|
178
241
|
/**************************************************************************
|
|
179
242
|
* Class Methods
|
|
@@ -189,93 +252,38 @@ static VALUE
|
|
|
189
252
|
pgconn_s_allocate( VALUE klass )
|
|
190
253
|
{
|
|
191
254
|
t_pg_connection *this;
|
|
192
|
-
VALUE self =
|
|
255
|
+
VALUE self = TypedData_Make_Struct( klass, t_pg_connection, &pg_connection_type, this );
|
|
193
256
|
|
|
194
257
|
this->pgconn = NULL;
|
|
195
|
-
this->socket_io
|
|
196
|
-
this->notice_receiver
|
|
197
|
-
this->notice_processor
|
|
198
|
-
this->type_map_for_queries
|
|
199
|
-
this->type_map_for_results
|
|
200
|
-
this->encoder_for_put_copy_data
|
|
201
|
-
this->decoder_for_get_copy_data
|
|
202
|
-
this->trace_stream
|
|
258
|
+
RB_OBJ_WRITE(self, &this->socket_io, Qnil);
|
|
259
|
+
RB_OBJ_WRITE(self, &this->notice_receiver, Qnil);
|
|
260
|
+
RB_OBJ_WRITE(self, &this->notice_processor, Qnil);
|
|
261
|
+
RB_OBJ_WRITE(self, &this->type_map_for_queries, pg_typemap_all_strings);
|
|
262
|
+
RB_OBJ_WRITE(self, &this->type_map_for_results, pg_typemap_all_strings);
|
|
263
|
+
RB_OBJ_WRITE(self, &this->encoder_for_put_copy_data, Qnil);
|
|
264
|
+
RB_OBJ_WRITE(self, &this->decoder_for_get_copy_data, Qnil);
|
|
265
|
+
RB_OBJ_WRITE(self, &this->trace_stream, Qnil);
|
|
266
|
+
rb_ivar_set(self, rb_intern("@calls_to_put_copy_data"), INT2FIX(0));
|
|
203
267
|
|
|
204
268
|
return self;
|
|
205
269
|
}
|
|
206
270
|
|
|
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
271
|
static VALUE
|
|
261
|
-
|
|
272
|
+
pgconn_s_sync_connect(int argc, VALUE *argv, VALUE klass)
|
|
262
273
|
{
|
|
263
274
|
t_pg_connection *this;
|
|
264
275
|
VALUE conninfo;
|
|
265
|
-
VALUE
|
|
276
|
+
VALUE self = pgconn_s_allocate( klass );
|
|
266
277
|
|
|
267
278
|
this = pg_get_connection( self );
|
|
268
279
|
conninfo = rb_funcall2( rb_cPGconn, rb_intern("parse_connect_args"), argc, argv );
|
|
269
280
|
this->pgconn = gvl_PQconnectdb(StringValueCStr(conninfo));
|
|
270
281
|
|
|
271
282
|
if(this->pgconn == NULL)
|
|
272
|
-
rb_raise(rb_ePGerror, "PQconnectdb() unable to allocate structure");
|
|
283
|
+
rb_raise(rb_ePGerror, "PQconnectdb() unable to allocate PGconn structure");
|
|
273
284
|
|
|
274
|
-
if (PQstatus(this->pgconn) == CONNECTION_BAD)
|
|
275
|
-
|
|
276
|
-
rb_iv_set(error, "@connection", self);
|
|
277
|
-
rb_exc_raise(error);
|
|
278
|
-
}
|
|
285
|
+
if (PQstatus(this->pgconn) == CONNECTION_BAD)
|
|
286
|
+
pg_raise_conn_error( rb_eConnectionBad, self, "%s", PQerrorMessage(this->pgconn));
|
|
279
287
|
|
|
280
288
|
pgconn_set_default_encoding( self );
|
|
281
289
|
|
|
@@ -308,7 +316,6 @@ pgconn_s_connect_start( int argc, VALUE *argv, VALUE klass )
|
|
|
308
316
|
{
|
|
309
317
|
VALUE rb_conn;
|
|
310
318
|
VALUE conninfo;
|
|
311
|
-
VALUE error;
|
|
312
319
|
t_pg_connection *this;
|
|
313
320
|
|
|
314
321
|
/*
|
|
@@ -321,13 +328,10 @@ pgconn_s_connect_start( int argc, VALUE *argv, VALUE klass )
|
|
|
321
328
|
this->pgconn = gvl_PQconnectStart( StringValueCStr(conninfo) );
|
|
322
329
|
|
|
323
330
|
if( this->pgconn == NULL )
|
|
324
|
-
rb_raise(rb_ePGerror, "PQconnectStart() unable to allocate structure");
|
|
331
|
+
rb_raise(rb_ePGerror, "PQconnectStart() unable to allocate PGconn structure");
|
|
325
332
|
|
|
326
|
-
if ( PQstatus(this->pgconn) == CONNECTION_BAD )
|
|
327
|
-
|
|
328
|
-
rb_iv_set(error, "@connection", rb_conn);
|
|
329
|
-
rb_exc_raise(error);
|
|
330
|
-
}
|
|
333
|
+
if ( PQstatus(this->pgconn) == CONNECTION_BAD )
|
|
334
|
+
pg_raise_conn_error( rb_eConnectionBad, rb_conn, "%s", PQerrorMessage(this->pgconn));
|
|
331
335
|
|
|
332
336
|
if ( rb_block_given_p() ) {
|
|
333
337
|
return rb_ensure( rb_yield, rb_conn, pgconn_finish, rb_conn );
|
|
@@ -335,34 +339,14 @@ pgconn_s_connect_start( int argc, VALUE *argv, VALUE klass )
|
|
|
335
339
|
return rb_conn;
|
|
336
340
|
}
|
|
337
341
|
|
|
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
342
|
static VALUE
|
|
359
|
-
|
|
343
|
+
pgconn_s_sync_ping( int argc, VALUE *argv, VALUE klass )
|
|
360
344
|
{
|
|
361
345
|
PGPing ping;
|
|
362
346
|
VALUE conninfo;
|
|
363
347
|
|
|
364
348
|
conninfo = rb_funcall2( klass, rb_intern("parse_connect_args"), argc, argv );
|
|
365
|
-
ping =
|
|
349
|
+
ping = gvl_PQping( StringValueCStr(conninfo) );
|
|
366
350
|
|
|
367
351
|
return INT2FIX((int)ping);
|
|
368
352
|
}
|
|
@@ -403,32 +387,40 @@ pgconn_s_conndefaults(VALUE self)
|
|
|
403
387
|
return array;
|
|
404
388
|
}
|
|
405
389
|
|
|
406
|
-
|
|
407
|
-
#ifdef HAVE_PQENCRYPTPASSWORDCONN
|
|
408
390
|
/*
|
|
409
|
-
*
|
|
410
|
-
* conn.encrypt_password( password, username, algorithm=nil ) -> String
|
|
391
|
+
* Document-method: PG::Connection.conninfo_parse
|
|
411
392
|
*
|
|
412
|
-
*
|
|
413
|
-
*
|
|
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.
|
|
423
|
-
*
|
|
424
|
-
* Return value is the encrypted password.
|
|
425
|
-
* The caller can assume the string doesn't contain any special characters that would require escaping.
|
|
393
|
+
* call-seq:
|
|
394
|
+
* PG::Connection.conninfo_parse(conninfo_string) -> Array
|
|
426
395
|
*
|
|
427
|
-
*
|
|
428
|
-
*
|
|
396
|
+
* Returns parsed connection options from the provided connection string as an array of hashes.
|
|
397
|
+
* Each hash has the same keys as PG::Connection.conndefaults() .
|
|
398
|
+
* The values from the +conninfo_string+ are stored in the +:val+ key.
|
|
429
399
|
*/
|
|
430
400
|
static VALUE
|
|
431
|
-
|
|
401
|
+
pgconn_s_conninfo_parse(VALUE self, VALUE conninfo)
|
|
402
|
+
{
|
|
403
|
+
VALUE array;
|
|
404
|
+
char *errmsg = NULL;
|
|
405
|
+
PQconninfoOption *options = PQconninfoParse(StringValueCStr(conninfo), &errmsg);
|
|
406
|
+
if(errmsg){
|
|
407
|
+
VALUE error = rb_str_new_cstr(errmsg);
|
|
408
|
+
PQfreemem(errmsg);
|
|
409
|
+
rb_raise(rb_ePGerror, "%"PRIsVALUE, error);
|
|
410
|
+
}
|
|
411
|
+
array = pgconn_make_conninfo_array( options );
|
|
412
|
+
|
|
413
|
+
PQconninfoFree(options);
|
|
414
|
+
|
|
415
|
+
UNUSED( self );
|
|
416
|
+
|
|
417
|
+
return array;
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
|
|
421
|
+
#ifdef HAVE_PQENCRYPTPASSWORDCONN
|
|
422
|
+
static VALUE
|
|
423
|
+
pgconn_sync_encrypt_password(int argc, VALUE *argv, VALUE self)
|
|
432
424
|
{
|
|
433
425
|
char *encrypted = NULL;
|
|
434
426
|
VALUE rval = Qnil;
|
|
@@ -445,7 +437,7 @@ pgconn_encrypt_password(int argc, VALUE *argv, VALUE self)
|
|
|
445
437
|
rval = rb_str_new2( encrypted );
|
|
446
438
|
PQfreemem( encrypted );
|
|
447
439
|
} else {
|
|
448
|
-
|
|
440
|
+
pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(conn));
|
|
449
441
|
}
|
|
450
442
|
|
|
451
443
|
return rval;
|
|
@@ -499,17 +491,18 @@ pgconn_s_encrypt_password(VALUE self, VALUE password, VALUE username)
|
|
|
499
491
|
* the asynchronous connection is ready
|
|
500
492
|
*
|
|
501
493
|
* Example:
|
|
502
|
-
*
|
|
503
|
-
*
|
|
494
|
+
* require "io/wait"
|
|
495
|
+
*
|
|
496
|
+
* conn = PG::Connection.connect_start(dbname: 'mydatabase')
|
|
504
497
|
* status = conn.connect_poll
|
|
505
498
|
* while(status != PG::PGRES_POLLING_OK) do
|
|
506
499
|
* # do some work while waiting for the connection to complete
|
|
507
500
|
* if(status == PG::PGRES_POLLING_READING)
|
|
508
|
-
*
|
|
501
|
+
* unless conn.socket_io.wait_readable(10.0)
|
|
509
502
|
* raise "Asynchronous connection timed out!"
|
|
510
503
|
* end
|
|
511
504
|
* elsif(status == PG::PGRES_POLLING_WRITING)
|
|
512
|
-
*
|
|
505
|
+
* unless conn.socket_io.wait_writable(10.0)
|
|
513
506
|
* raise "Asynchronous connection timed out!"
|
|
514
507
|
* end
|
|
515
508
|
* end
|
|
@@ -523,6 +516,9 @@ pgconn_connect_poll(VALUE self)
|
|
|
523
516
|
{
|
|
524
517
|
PostgresPollingStatusType status;
|
|
525
518
|
status = gvl_PQconnectPoll(pg_get_pgconn(self));
|
|
519
|
+
|
|
520
|
+
pgconn_close_socket_io(self);
|
|
521
|
+
|
|
526
522
|
return INT2FIX((int)status);
|
|
527
523
|
}
|
|
528
524
|
|
|
@@ -559,21 +555,35 @@ pgconn_finished_p( VALUE self )
|
|
|
559
555
|
}
|
|
560
556
|
|
|
561
557
|
|
|
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
558
|
static VALUE
|
|
570
|
-
|
|
559
|
+
pgconn_sync_reset( VALUE self )
|
|
571
560
|
{
|
|
572
561
|
pgconn_close_socket_io( self );
|
|
573
562
|
gvl_PQreset( pg_get_pgconn(self) );
|
|
574
563
|
return self;
|
|
575
564
|
}
|
|
576
565
|
|
|
566
|
+
static VALUE
|
|
567
|
+
pgconn_reset_start2( VALUE self, VALUE conninfo )
|
|
568
|
+
{
|
|
569
|
+
t_pg_connection *this = pg_get_connection( self );
|
|
570
|
+
|
|
571
|
+
/* Close old connection */
|
|
572
|
+
pgconn_close_socket_io( self );
|
|
573
|
+
PQfinish( this->pgconn );
|
|
574
|
+
|
|
575
|
+
/* Start new connection */
|
|
576
|
+
this->pgconn = gvl_PQconnectStart( StringValueCStr(conninfo) );
|
|
577
|
+
|
|
578
|
+
if( this->pgconn == NULL )
|
|
579
|
+
rb_raise(rb_ePGerror, "PQconnectStart() unable to allocate PGconn structure");
|
|
580
|
+
|
|
581
|
+
if ( PQstatus(this->pgconn) == CONNECTION_BAD )
|
|
582
|
+
pg_raise_conn_error( rb_eConnectionBad, self, "%s", PQerrorMessage(this->pgconn));
|
|
583
|
+
|
|
584
|
+
return Qnil;
|
|
585
|
+
}
|
|
586
|
+
|
|
577
587
|
/*
|
|
578
588
|
* call-seq:
|
|
579
589
|
* conn.reset_start() -> nil
|
|
@@ -589,7 +599,7 @@ pgconn_reset_start(VALUE self)
|
|
|
589
599
|
{
|
|
590
600
|
pgconn_close_socket_io( self );
|
|
591
601
|
if(gvl_PQresetStart(pg_get_pgconn(self)) == 0)
|
|
592
|
-
|
|
602
|
+
pg_raise_conn_error( rb_eUnableToSend, self, "reset has failed");
|
|
593
603
|
return Qnil;
|
|
594
604
|
}
|
|
595
605
|
|
|
@@ -606,6 +616,9 @@ pgconn_reset_poll(VALUE self)
|
|
|
606
616
|
{
|
|
607
617
|
PostgresPollingStatusType status;
|
|
608
618
|
status = gvl_PQresetPoll(pg_get_pgconn(self));
|
|
619
|
+
|
|
620
|
+
pgconn_close_socket_io(self);
|
|
621
|
+
|
|
609
622
|
return INT2FIX((int)status);
|
|
610
623
|
}
|
|
611
624
|
|
|
@@ -656,7 +669,18 @@ pgconn_pass(VALUE self)
|
|
|
656
669
|
* call-seq:
|
|
657
670
|
* conn.host()
|
|
658
671
|
*
|
|
659
|
-
* Returns the
|
|
672
|
+
* Returns the server host name of the active connection.
|
|
673
|
+
* This can be a host name, an IP address, or a directory path if the connection is via Unix socket.
|
|
674
|
+
* (The path case can be distinguished because it will always be an absolute path, beginning with +/+ .)
|
|
675
|
+
*
|
|
676
|
+
* If the connection parameters specified both host and hostaddr, then +host+ will return the host information.
|
|
677
|
+
* If only hostaddr was specified, then that is returned.
|
|
678
|
+
* If multiple hosts were specified in the connection parameters, +host+ returns the host actually connected to.
|
|
679
|
+
*
|
|
680
|
+
* If there is an error producing the host information (perhaps if the connection has not been fully established or there was an error), it returns an empty string.
|
|
681
|
+
*
|
|
682
|
+
* 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.
|
|
683
|
+
* The status of the connection can be checked using the function Connection#status .
|
|
660
684
|
*/
|
|
661
685
|
static VALUE
|
|
662
686
|
pgconn_host(VALUE self)
|
|
@@ -666,6 +690,26 @@ pgconn_host(VALUE self)
|
|
|
666
690
|
return rb_str_new2(host);
|
|
667
691
|
}
|
|
668
692
|
|
|
693
|
+
/* PQhostaddr() appeared in PostgreSQL-12 together with PQresultMemorySize() */
|
|
694
|
+
#if defined(HAVE_PQRESULTMEMORYSIZE)
|
|
695
|
+
/*
|
|
696
|
+
* call-seq:
|
|
697
|
+
* conn.hostaddr()
|
|
698
|
+
*
|
|
699
|
+
* Returns the server IP address of the active connection.
|
|
700
|
+
* This can be the address that a host name resolved to, or an IP address provided through the hostaddr parameter.
|
|
701
|
+
* 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.
|
|
702
|
+
*
|
|
703
|
+
*/
|
|
704
|
+
static VALUE
|
|
705
|
+
pgconn_hostaddr(VALUE self)
|
|
706
|
+
{
|
|
707
|
+
char *host = PQhostaddr(pg_get_pgconn(self));
|
|
708
|
+
if (!host) return Qnil;
|
|
709
|
+
return rb_str_new2(host);
|
|
710
|
+
}
|
|
711
|
+
#endif
|
|
712
|
+
|
|
669
713
|
/*
|
|
670
714
|
* call-seq:
|
|
671
715
|
* conn.port()
|
|
@@ -676,21 +720,22 @@ static VALUE
|
|
|
676
720
|
pgconn_port(VALUE self)
|
|
677
721
|
{
|
|
678
722
|
char* port = PQport(pg_get_pgconn(self));
|
|
679
|
-
|
|
723
|
+
if (!port || port[0] == '\0')
|
|
724
|
+
return INT2NUM(DEF_PGPORT);
|
|
725
|
+
else
|
|
726
|
+
return INT2NUM(atoi(port));
|
|
680
727
|
}
|
|
681
728
|
|
|
682
729
|
/*
|
|
683
730
|
* call-seq:
|
|
684
731
|
* conn.tty()
|
|
685
732
|
*
|
|
686
|
-
*
|
|
733
|
+
* Obsolete function.
|
|
687
734
|
*/
|
|
688
735
|
static VALUE
|
|
689
736
|
pgconn_tty(VALUE self)
|
|
690
737
|
{
|
|
691
|
-
|
|
692
|
-
if (!tty) return Qnil;
|
|
693
|
-
return rb_str_new2(tty);
|
|
738
|
+
return rb_str_new2("");
|
|
694
739
|
}
|
|
695
740
|
|
|
696
741
|
/*
|
|
@@ -708,7 +753,6 @@ pgconn_options(VALUE self)
|
|
|
708
753
|
}
|
|
709
754
|
|
|
710
755
|
|
|
711
|
-
#ifdef HAVE_PQCONNINFO
|
|
712
756
|
/*
|
|
713
757
|
* call-seq:
|
|
714
758
|
* conn.conninfo -> hash
|
|
@@ -728,14 +772,24 @@ pgconn_conninfo( VALUE self )
|
|
|
728
772
|
|
|
729
773
|
return array;
|
|
730
774
|
}
|
|
731
|
-
#endif
|
|
732
775
|
|
|
733
776
|
|
|
734
777
|
/*
|
|
735
778
|
* call-seq:
|
|
736
779
|
* conn.status()
|
|
737
780
|
*
|
|
738
|
-
* Returns status of connection
|
|
781
|
+
* Returns the status of the connection, which is one:
|
|
782
|
+
* PG::Constants::CONNECTION_OK
|
|
783
|
+
* PG::Constants::CONNECTION_BAD
|
|
784
|
+
*
|
|
785
|
+
* ... and other constants of kind PG::Constants::CONNECTION_*
|
|
786
|
+
*
|
|
787
|
+
* This method returns the status of the last command from memory.
|
|
788
|
+
* It doesn't do any socket access hence is not suitable to test the connectivity.
|
|
789
|
+
* See check_socket for a way to verify the socket state.
|
|
790
|
+
*
|
|
791
|
+
* Example:
|
|
792
|
+
* PG.constants.grep(/CONNECTION_/).find{|c| PG.const_get(c) == conn.status} # => :CONNECTION_OK
|
|
739
793
|
*/
|
|
740
794
|
static VALUE
|
|
741
795
|
pgconn_status(VALUE self)
|
|
@@ -823,7 +877,10 @@ pgconn_server_version(VALUE self)
|
|
|
823
877
|
* call-seq:
|
|
824
878
|
* conn.error_message -> String
|
|
825
879
|
*
|
|
826
|
-
* Returns the error message
|
|
880
|
+
* Returns the error message most recently generated by an operation on the connection.
|
|
881
|
+
*
|
|
882
|
+
* Nearly all libpq functions will set a message for conn.error_message if they fail.
|
|
883
|
+
* Note that by libpq convention, a nonempty error_message result can consist of multiple lines, and will include a trailing newline.
|
|
827
884
|
*/
|
|
828
885
|
static VALUE
|
|
829
886
|
pgconn_error_message(VALUE self)
|
|
@@ -857,7 +914,8 @@ pgconn_socket(VALUE self)
|
|
|
857
914
|
pg_deprecated(4, ("conn.socket is deprecated and should be replaced by conn.socket_io"));
|
|
858
915
|
|
|
859
916
|
if( (sd = PQsocket(pg_get_pgconn(self))) < 0)
|
|
860
|
-
|
|
917
|
+
pg_raise_conn_error( rb_eConnectionBad, self, "PQsocket() can't get socket descriptor");
|
|
918
|
+
|
|
861
919
|
return INT2NUM(sd);
|
|
862
920
|
}
|
|
863
921
|
|
|
@@ -865,40 +923,47 @@ pgconn_socket(VALUE self)
|
|
|
865
923
|
* call-seq:
|
|
866
924
|
* conn.socket_io() -> IO
|
|
867
925
|
*
|
|
868
|
-
* Fetch
|
|
869
|
-
* This object can be used for IO.select to wait for events while running
|
|
870
|
-
*
|
|
926
|
+
* Fetch an IO object created from the Connection's underlying socket.
|
|
927
|
+
* 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.
|
|
928
|
+
* <tt>IO#wait_*able</tt> is is <tt>Fiber.scheduler</tt> compatible in contrast to <tt>IO.select</tt>.
|
|
871
929
|
*
|
|
872
|
-
*
|
|
873
|
-
*
|
|
874
|
-
*
|
|
930
|
+
* The IO object can change while the connection is established, but is memorized afterwards.
|
|
931
|
+
* So be sure not to cache the IO object, but repeat calling <tt>conn.socket_io</tt> instead.
|
|
932
|
+
*
|
|
933
|
+
* Using this method also works on Windows in contrast to using #socket .
|
|
934
|
+
* 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
935
|
*/
|
|
876
936
|
static VALUE
|
|
877
937
|
pgconn_socket_io(VALUE self)
|
|
878
938
|
{
|
|
879
939
|
int sd;
|
|
880
940
|
int ruby_sd;
|
|
881
|
-
ID id_autoclose = rb_intern("autoclose=");
|
|
882
941
|
t_pg_connection *this = pg_get_connection_safe( self );
|
|
942
|
+
VALUE cSocket;
|
|
883
943
|
VALUE socket_io = this->socket_io;
|
|
884
944
|
|
|
885
945
|
if ( !RTEST(socket_io) ) {
|
|
886
|
-
if( (sd = PQsocket(this->pgconn)) < 0)
|
|
887
|
-
|
|
946
|
+
if( (sd = PQsocket(this->pgconn)) < 0){
|
|
947
|
+
pg_raise_conn_error( rb_eConnectionBad, self, "PQsocket() can't get socket descriptor");
|
|
948
|
+
}
|
|
888
949
|
|
|
889
950
|
#ifdef _WIN32
|
|
890
951
|
ruby_sd = rb_w32_wrap_io_handle((HANDLE)(intptr_t)sd, O_RDWR|O_BINARY|O_NOINHERIT);
|
|
952
|
+
if( ruby_sd == -1 )
|
|
953
|
+
pg_raise_conn_error( rb_eConnectionBad, self, "Could not wrap win32 socket handle");
|
|
954
|
+
|
|
891
955
|
this->ruby_sd = ruby_sd;
|
|
892
956
|
#else
|
|
893
957
|
ruby_sd = sd;
|
|
894
958
|
#endif
|
|
895
959
|
|
|
896
|
-
|
|
960
|
+
cSocket = rb_const_get(rb_cObject, rb_intern("BasicSocket"));
|
|
961
|
+
socket_io = rb_funcall( cSocket, rb_intern("for_fd"), 1, INT2NUM(ruby_sd));
|
|
897
962
|
|
|
898
963
|
/* Disable autoclose feature */
|
|
899
|
-
rb_funcall( socket_io,
|
|
964
|
+
rb_funcall( socket_io, s_id_autoclose_set, 1, Qfalse );
|
|
900
965
|
|
|
901
|
-
this->socket_io
|
|
966
|
+
RB_OBJ_WRITE(self, &this->socket_io, socket_io);
|
|
902
967
|
}
|
|
903
968
|
|
|
904
969
|
return socket_io;
|
|
@@ -918,6 +983,51 @@ pgconn_backend_pid(VALUE self)
|
|
|
918
983
|
return INT2NUM(PQbackendPID(pg_get_pgconn(self)));
|
|
919
984
|
}
|
|
920
985
|
|
|
986
|
+
typedef struct
|
|
987
|
+
{
|
|
988
|
+
struct sockaddr_storage addr;
|
|
989
|
+
socklen_t salen;
|
|
990
|
+
} SockAddr;
|
|
991
|
+
|
|
992
|
+
/* Copy of struct pg_cancel from libpq-int.h
|
|
993
|
+
*
|
|
994
|
+
* See https://github.com/postgres/postgres/blame/master/src/interfaces/libpq/libpq-int.h#L577-L586
|
|
995
|
+
*/
|
|
996
|
+
struct pg_cancel
|
|
997
|
+
{
|
|
998
|
+
SockAddr raddr; /* Remote address */
|
|
999
|
+
int be_pid; /* PID of backend --- needed for cancels */
|
|
1000
|
+
int be_key; /* key of backend --- needed for cancels */
|
|
1001
|
+
};
|
|
1002
|
+
|
|
1003
|
+
/*
|
|
1004
|
+
* call-seq:
|
|
1005
|
+
* conn.backend_key() -> Integer
|
|
1006
|
+
*
|
|
1007
|
+
* Returns the key of the backend server process for this connection.
|
|
1008
|
+
* This key can be used to cancel queries on the server.
|
|
1009
|
+
*/
|
|
1010
|
+
static VALUE
|
|
1011
|
+
pgconn_backend_key(VALUE self)
|
|
1012
|
+
{
|
|
1013
|
+
int be_key;
|
|
1014
|
+
struct pg_cancel *cancel;
|
|
1015
|
+
PGconn *conn = pg_get_pgconn(self);
|
|
1016
|
+
|
|
1017
|
+
cancel = (struct pg_cancel*)PQgetCancel(conn);
|
|
1018
|
+
if(cancel == NULL)
|
|
1019
|
+
pg_raise_conn_error( rb_ePGerror, self, "Invalid connection!");
|
|
1020
|
+
|
|
1021
|
+
if( cancel->be_pid != PQbackendPID(conn) )
|
|
1022
|
+
rb_raise(rb_ePGerror,"Unexpected binary struct layout - please file a bug report at ruby-pg!");
|
|
1023
|
+
|
|
1024
|
+
be_key = cancel->be_key;
|
|
1025
|
+
|
|
1026
|
+
PQfreeCancel(cancel);
|
|
1027
|
+
|
|
1028
|
+
return INT2NUM(be_key);
|
|
1029
|
+
}
|
|
1030
|
+
|
|
921
1031
|
/*
|
|
922
1032
|
* call-seq:
|
|
923
1033
|
* conn.connection_needs_password() -> Boolean
|
|
@@ -948,7 +1058,7 @@ pgconn_connection_used_password(VALUE self)
|
|
|
948
1058
|
/* :TODO: get_ssl */
|
|
949
1059
|
|
|
950
1060
|
|
|
951
|
-
static VALUE
|
|
1061
|
+
static VALUE pgconn_sync_exec_params( int, VALUE *, VALUE );
|
|
952
1062
|
|
|
953
1063
|
/*
|
|
954
1064
|
* call-seq:
|
|
@@ -962,11 +1072,11 @@ static VALUE pgconn_exec_params( int, VALUE *, VALUE );
|
|
|
962
1072
|
* However #async_exec has two advantages:
|
|
963
1073
|
*
|
|
964
1074
|
* 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
|
-
*
|
|
1075
|
+
* 2. Ruby VM gets notified about IO blocked operations and can pass them through <tt>Fiber.scheduler</tt>.
|
|
1076
|
+
* So only <tt>async_*</tt> methods are compatible to event based schedulers like the async gem.
|
|
967
1077
|
*/
|
|
968
1078
|
static VALUE
|
|
969
|
-
|
|
1079
|
+
pgconn_sync_exec(int argc, VALUE *argv, VALUE self)
|
|
970
1080
|
{
|
|
971
1081
|
t_pg_connection *this = pg_get_connection_safe( self );
|
|
972
1082
|
PGresult *result = NULL;
|
|
@@ -987,7 +1097,7 @@ pgconn_exec(int argc, VALUE *argv, VALUE self)
|
|
|
987
1097
|
pg_deprecated(0, ("forwarding exec to exec_params is deprecated"));
|
|
988
1098
|
|
|
989
1099
|
/* Otherwise, just call #exec_params instead for backward-compatibility */
|
|
990
|
-
return
|
|
1100
|
+
return pgconn_sync_exec_params( argc, argv, self );
|
|
991
1101
|
|
|
992
1102
|
}
|
|
993
1103
|
|
|
@@ -1019,7 +1129,7 @@ struct query_params_data {
|
|
|
1019
1129
|
* Filled by alloc_query_params()
|
|
1020
1130
|
*/
|
|
1021
1131
|
|
|
1022
|
-
/* Wraps the pointer of allocated memory, if function parameters
|
|
1132
|
+
/* Wraps the pointer of allocated memory, if function parameters don't
|
|
1023
1133
|
* fit in the memory_pool below.
|
|
1024
1134
|
*/
|
|
1025
1135
|
VALUE heap_pool;
|
|
@@ -1037,7 +1147,7 @@ struct query_params_data {
|
|
|
1037
1147
|
Oid *types;
|
|
1038
1148
|
|
|
1039
1149
|
/* This array takes the string values for the timeframe of the query,
|
|
1040
|
-
* if param value
|
|
1150
|
+
* if param value conversion is required
|
|
1041
1151
|
*/
|
|
1042
1152
|
VALUE gc_array;
|
|
1043
1153
|
|
|
@@ -1051,8 +1161,9 @@ struct query_params_data {
|
|
|
1051
1161
|
};
|
|
1052
1162
|
|
|
1053
1163
|
static void
|
|
1054
|
-
free_typecast_heap_chain(
|
|
1164
|
+
free_typecast_heap_chain(void *_chain_entry)
|
|
1055
1165
|
{
|
|
1166
|
+
struct linked_typecast_data *chain_entry = (struct linked_typecast_data *)_chain_entry;
|
|
1056
1167
|
while(chain_entry){
|
|
1057
1168
|
struct linked_typecast_data *next = chain_entry->next;
|
|
1058
1169
|
xfree(chain_entry);
|
|
@@ -1060,6 +1171,18 @@ free_typecast_heap_chain(struct linked_typecast_data *chain_entry)
|
|
|
1060
1171
|
}
|
|
1061
1172
|
}
|
|
1062
1173
|
|
|
1174
|
+
static const rb_data_type_t pg_typecast_buffer_type = {
|
|
1175
|
+
"PG::Connection typecast buffer chain",
|
|
1176
|
+
{
|
|
1177
|
+
(RUBY_DATA_FUNC) NULL,
|
|
1178
|
+
free_typecast_heap_chain,
|
|
1179
|
+
(size_t (*)(const void *))NULL,
|
|
1180
|
+
},
|
|
1181
|
+
0,
|
|
1182
|
+
0,
|
|
1183
|
+
RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
|
|
1184
|
+
};
|
|
1185
|
+
|
|
1063
1186
|
static char *
|
|
1064
1187
|
alloc_typecast_buf( VALUE *typecast_heap_chain, int len )
|
|
1065
1188
|
{
|
|
@@ -1070,17 +1193,28 @@ alloc_typecast_buf( VALUE *typecast_heap_chain, int len )
|
|
|
1070
1193
|
/* Did we already wrap a memory chain per T_DATA object? */
|
|
1071
1194
|
if( NIL_P( *typecast_heap_chain ) ){
|
|
1072
1195
|
/* Leave free'ing of the buffer chain to the GC, when paramsData has left the stack */
|
|
1073
|
-
*typecast_heap_chain =
|
|
1196
|
+
*typecast_heap_chain = TypedData_Wrap_Struct( rb_cObject, &pg_typecast_buffer_type, allocated );
|
|
1074
1197
|
allocated->next = NULL;
|
|
1075
1198
|
} else {
|
|
1076
1199
|
/* Append to the chain */
|
|
1077
|
-
allocated->next =
|
|
1078
|
-
|
|
1200
|
+
allocated->next = RTYPEDDATA_DATA( *typecast_heap_chain );
|
|
1201
|
+
RTYPEDDATA_DATA( *typecast_heap_chain ) = allocated;
|
|
1079
1202
|
}
|
|
1080
1203
|
|
|
1081
1204
|
return &allocated->data[0];
|
|
1082
1205
|
}
|
|
1083
1206
|
|
|
1207
|
+
static const rb_data_type_t pg_query_heap_pool_type = {
|
|
1208
|
+
"PG::Connection query heap pool",
|
|
1209
|
+
{
|
|
1210
|
+
(RUBY_DATA_FUNC) NULL,
|
|
1211
|
+
RUBY_TYPED_DEFAULT_FREE,
|
|
1212
|
+
(size_t (*)(const void *))NULL,
|
|
1213
|
+
},
|
|
1214
|
+
0,
|
|
1215
|
+
0,
|
|
1216
|
+
RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
|
|
1217
|
+
};
|
|
1084
1218
|
|
|
1085
1219
|
static int
|
|
1086
1220
|
alloc_query_params(struct query_params_data *paramsData)
|
|
@@ -1095,7 +1229,7 @@ alloc_query_params(struct query_params_data *paramsData)
|
|
|
1095
1229
|
|
|
1096
1230
|
Check_Type(paramsData->params, T_ARRAY);
|
|
1097
1231
|
|
|
1098
|
-
p_typemap =
|
|
1232
|
+
p_typemap = RTYPEDDATA_DATA( paramsData->typemap );
|
|
1099
1233
|
p_typemap->funcs.fit_to_query( paramsData->typemap, paramsData->params );
|
|
1100
1234
|
|
|
1101
1235
|
paramsData->heap_pool = Qnil;
|
|
@@ -1114,7 +1248,7 @@ alloc_query_params(struct query_params_data *paramsData)
|
|
|
1114
1248
|
/* Allocate one combined memory pool for all possible function parameters */
|
|
1115
1249
|
memory_pool = (char*)xmalloc( required_pool_size );
|
|
1116
1250
|
/* Leave free'ing of the buffer to the GC, when paramsData has left the stack */
|
|
1117
|
-
paramsData->heap_pool =
|
|
1251
|
+
paramsData->heap_pool = TypedData_Wrap_Struct( rb_cObject, &pg_query_heap_pool_type, memory_pool );
|
|
1118
1252
|
required_pool_size = 0;
|
|
1119
1253
|
}else{
|
|
1120
1254
|
/* Use stack memory for function parameters */
|
|
@@ -1227,12 +1361,11 @@ pgconn_query_assign_typemap( VALUE self, struct query_params_data *paramsData )
|
|
|
1227
1361
|
/* Use default typemap for queries. It's type is checked when assigned. */
|
|
1228
1362
|
paramsData->typemap = pg_get_connection(self)->type_map_for_queries;
|
|
1229
1363
|
}else{
|
|
1364
|
+
t_typemap *tm;
|
|
1365
|
+
UNUSED(tm);
|
|
1366
|
+
|
|
1230
1367
|
/* 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 );
|
|
1368
|
+
TypedData_Get_Struct(paramsData->typemap, t_typemap, &pg_typemap_type, tm);
|
|
1236
1369
|
}
|
|
1237
1370
|
}
|
|
1238
1371
|
|
|
@@ -1246,7 +1379,7 @@ pgconn_query_assign_typemap( VALUE self, struct query_params_data *paramsData )
|
|
|
1246
1379
|
* 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
1380
|
*/
|
|
1248
1381
|
static VALUE
|
|
1249
|
-
|
|
1382
|
+
pgconn_sync_exec_params( int argc, VALUE *argv, VALUE self )
|
|
1250
1383
|
{
|
|
1251
1384
|
t_pg_connection *this = pg_get_connection_safe( self );
|
|
1252
1385
|
PGresult *result = NULL;
|
|
@@ -1266,7 +1399,7 @@ pgconn_exec_params( int argc, VALUE *argv, VALUE self )
|
|
|
1266
1399
|
*/
|
|
1267
1400
|
if ( NIL_P(paramsData.params) ) {
|
|
1268
1401
|
pg_deprecated(1, ("forwarding exec_params to exec is deprecated"));
|
|
1269
|
-
return
|
|
1402
|
+
return pgconn_sync_exec( 1, argv, self );
|
|
1270
1403
|
}
|
|
1271
1404
|
pgconn_query_assign_typemap( self, ¶msData );
|
|
1272
1405
|
|
|
@@ -1297,7 +1430,7 @@ pgconn_exec_params( int argc, VALUE *argv, VALUE self )
|
|
|
1297
1430
|
* It's not recommended to use explicit sync or async variants but #prepare instead, unless you have a good reason to do so.
|
|
1298
1431
|
*/
|
|
1299
1432
|
static VALUE
|
|
1300
|
-
|
|
1433
|
+
pgconn_sync_prepare(int argc, VALUE *argv, VALUE self)
|
|
1301
1434
|
{
|
|
1302
1435
|
t_pg_connection *this = pg_get_connection_safe( self );
|
|
1303
1436
|
PGresult *result = NULL;
|
|
@@ -1346,7 +1479,7 @@ pgconn_prepare(int argc, VALUE *argv, VALUE self)
|
|
|
1346
1479
|
* 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
1480
|
*/
|
|
1348
1481
|
static VALUE
|
|
1349
|
-
|
|
1482
|
+
pgconn_sync_exec_prepared(int argc, VALUE *argv, VALUE self)
|
|
1350
1483
|
{
|
|
1351
1484
|
t_pg_connection *this = pg_get_connection_safe( self );
|
|
1352
1485
|
PGresult *result = NULL;
|
|
@@ -1391,7 +1524,7 @@ pgconn_exec_prepared(int argc, VALUE *argv, VALUE self)
|
|
|
1391
1524
|
* 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
1525
|
*/
|
|
1393
1526
|
static VALUE
|
|
1394
|
-
|
|
1527
|
+
pgconn_sync_describe_prepared(VALUE self, VALUE stmt_name)
|
|
1395
1528
|
{
|
|
1396
1529
|
PGresult *result;
|
|
1397
1530
|
VALUE rb_pgresult;
|
|
@@ -1419,8 +1552,7 @@ pgconn_describe_prepared(VALUE self, VALUE stmt_name)
|
|
|
1419
1552
|
* 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
1553
|
*/
|
|
1421
1554
|
static VALUE
|
|
1422
|
-
|
|
1423
|
-
VALUE self, stmt_name;
|
|
1555
|
+
pgconn_sync_describe_portal(VALUE self, VALUE stmt_name)
|
|
1424
1556
|
{
|
|
1425
1557
|
PGresult *result;
|
|
1426
1558
|
VALUE rb_pgresult;
|
|
@@ -1454,6 +1586,9 @@ pgconn_describe_portal(self, stmt_name)
|
|
|
1454
1586
|
* * +PGRES_NONFATAL_ERROR+
|
|
1455
1587
|
* * +PGRES_FATAL_ERROR+
|
|
1456
1588
|
* * +PGRES_COPY_BOTH+
|
|
1589
|
+
* * +PGRES_SINGLE_TUPLE+
|
|
1590
|
+
* * +PGRES_PIPELINE_SYNC+
|
|
1591
|
+
* * +PGRES_PIPELINE_ABORTED+
|
|
1457
1592
|
*/
|
|
1458
1593
|
static VALUE
|
|
1459
1594
|
pgconn_make_empty_pgresult(VALUE self, VALUE status)
|
|
@@ -1509,9 +1644,9 @@ pgconn_s_escape(VALUE self, VALUE string)
|
|
|
1509
1644
|
if( !singleton ) {
|
|
1510
1645
|
size = PQescapeStringConn(pg_get_pgconn(self), RSTRING_PTR(result),
|
|
1511
1646
|
RSTRING_PTR(string), RSTRING_LEN(string), &error);
|
|
1512
|
-
if(error)
|
|
1513
|
-
|
|
1514
|
-
|
|
1647
|
+
if(error)
|
|
1648
|
+
pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(pg_get_pgconn(self)));
|
|
1649
|
+
|
|
1515
1650
|
} else {
|
|
1516
1651
|
size = PQescapeString(RSTRING_PTR(result), RSTRING_PTR(string), RSTRING_LEN(string));
|
|
1517
1652
|
}
|
|
@@ -1607,7 +1742,6 @@ pgconn_escape_literal(VALUE self, VALUE string)
|
|
|
1607
1742
|
{
|
|
1608
1743
|
t_pg_connection *this = pg_get_connection_safe( self );
|
|
1609
1744
|
char *escaped = NULL;
|
|
1610
|
-
VALUE error;
|
|
1611
1745
|
VALUE result = Qnil;
|
|
1612
1746
|
int enc_idx = this->enc_idx;
|
|
1613
1747
|
|
|
@@ -1618,12 +1752,8 @@ pgconn_escape_literal(VALUE self, VALUE string)
|
|
|
1618
1752
|
|
|
1619
1753
|
escaped = PQescapeLiteral(this->pgconn, RSTRING_PTR(string), RSTRING_LEN(string));
|
|
1620
1754
|
if (escaped == NULL)
|
|
1621
|
-
|
|
1622
|
-
|
|
1623
|
-
rb_iv_set(error, "@connection", self);
|
|
1624
|
-
rb_exc_raise(error);
|
|
1625
|
-
return Qnil;
|
|
1626
|
-
}
|
|
1755
|
+
pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(this->pgconn));
|
|
1756
|
+
|
|
1627
1757
|
result = rb_str_new2(escaped);
|
|
1628
1758
|
PQfreemem(escaped);
|
|
1629
1759
|
PG_ENCODING_SET_NOCHECK(result, enc_idx);
|
|
@@ -1646,7 +1776,6 @@ pgconn_escape_identifier(VALUE self, VALUE string)
|
|
|
1646
1776
|
{
|
|
1647
1777
|
t_pg_connection *this = pg_get_connection_safe( self );
|
|
1648
1778
|
char *escaped = NULL;
|
|
1649
|
-
VALUE error;
|
|
1650
1779
|
VALUE result = Qnil;
|
|
1651
1780
|
int enc_idx = this->enc_idx;
|
|
1652
1781
|
|
|
@@ -1657,12 +1786,8 @@ pgconn_escape_identifier(VALUE self, VALUE string)
|
|
|
1657
1786
|
|
|
1658
1787
|
escaped = PQescapeIdentifier(this->pgconn, RSTRING_PTR(string), RSTRING_LEN(string));
|
|
1659
1788
|
if (escaped == NULL)
|
|
1660
|
-
|
|
1661
|
-
|
|
1662
|
-
rb_iv_set(error, "@connection", self);
|
|
1663
|
-
rb_exc_raise(error);
|
|
1664
|
-
return Qnil;
|
|
1665
|
-
}
|
|
1789
|
+
pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(this->pgconn));
|
|
1790
|
+
|
|
1666
1791
|
result = rb_str_new2(escaped);
|
|
1667
1792
|
PQfreemem(escaped);
|
|
1668
1793
|
PG_ENCODING_SET_NOCHECK(result, enc_idx);
|
|
@@ -1710,14 +1835,10 @@ static VALUE
|
|
|
1710
1835
|
pgconn_set_single_row_mode(VALUE self)
|
|
1711
1836
|
{
|
|
1712
1837
|
PGconn *conn = pg_get_pgconn(self);
|
|
1713
|
-
VALUE error;
|
|
1714
1838
|
|
|
1839
|
+
rb_check_frozen(self);
|
|
1715
1840
|
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
|
-
}
|
|
1841
|
+
pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(conn));
|
|
1721
1842
|
|
|
1722
1843
|
return self;
|
|
1723
1844
|
}
|
|
@@ -1741,15 +1862,13 @@ static VALUE
|
|
|
1741
1862
|
pgconn_send_query(int argc, VALUE *argv, VALUE self)
|
|
1742
1863
|
{
|
|
1743
1864
|
t_pg_connection *this = pg_get_connection_safe( self );
|
|
1744
|
-
VALUE error;
|
|
1745
1865
|
|
|
1746
1866
|
/* If called with no or nil parameters, use PQexec for compatibility */
|
|
1747
1867
|
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
|
-
}
|
|
1868
|
+
if(gvl_PQsendQuery(this->pgconn, pg_cstr_enc(argv[0], this->enc_idx)) == 0)
|
|
1869
|
+
pg_raise_conn_error( rb_eUnableToSend, self, "%s", PQerrorMessage(this->pgconn));
|
|
1870
|
+
|
|
1871
|
+
pgconn_wait_for_flush( self );
|
|
1753
1872
|
return Qnil;
|
|
1754
1873
|
}
|
|
1755
1874
|
|
|
@@ -1779,7 +1898,7 @@ pgconn_send_query(int argc, VALUE *argv, VALUE self)
|
|
|
1779
1898
|
* or, it may be a String. If it is a string, that is equivalent to the hash:
|
|
1780
1899
|
* { :value => <string value>, :type => 0, :format => 0 }
|
|
1781
1900
|
*
|
|
1782
|
-
* PostgreSQL bind parameters are represented as $1, $
|
|
1901
|
+
* PostgreSQL bind parameters are represented as $1, $2, $3, etc.,
|
|
1783
1902
|
* inside the SQL query. The 0th element of the +params+ array is bound
|
|
1784
1903
|
* to $1, the 1st element is bound to $2, etc. +nil+ is treated as +NULL+.
|
|
1785
1904
|
*
|
|
@@ -1805,7 +1924,6 @@ pgconn_send_query_params(int argc, VALUE *argv, VALUE self)
|
|
|
1805
1924
|
t_pg_connection *this = pg_get_connection_safe( self );
|
|
1806
1925
|
int result;
|
|
1807
1926
|
VALUE command, in_res_fmt;
|
|
1808
|
-
VALUE error;
|
|
1809
1927
|
int nParams;
|
|
1810
1928
|
int resultFormat;
|
|
1811
1929
|
struct query_params_data paramsData = { this->enc_idx };
|
|
@@ -1822,11 +1940,10 @@ pgconn_send_query_params(int argc, VALUE *argv, VALUE self)
|
|
|
1822
1940
|
|
|
1823
1941
|
free_query_params( ¶msData );
|
|
1824
1942
|
|
|
1825
|
-
if(result == 0)
|
|
1826
|
-
|
|
1827
|
-
|
|
1828
|
-
|
|
1829
|
-
}
|
|
1943
|
+
if(result == 0)
|
|
1944
|
+
pg_raise_conn_error( rb_eUnableToSend, self, "%s", PQerrorMessage(this->pgconn));
|
|
1945
|
+
|
|
1946
|
+
pgconn_wait_for_flush( self );
|
|
1830
1947
|
return Qnil;
|
|
1831
1948
|
}
|
|
1832
1949
|
|
|
@@ -1847,7 +1964,7 @@ pgconn_send_query_params(int argc, VALUE *argv, VALUE self)
|
|
|
1847
1964
|
*
|
|
1848
1965
|
* For example: "SELECT $1::int"
|
|
1849
1966
|
*
|
|
1850
|
-
* PostgreSQL bind parameters are represented as $1, $
|
|
1967
|
+
* PostgreSQL bind parameters are represented as $1, $2, $3, etc.,
|
|
1851
1968
|
* inside the SQL query.
|
|
1852
1969
|
*/
|
|
1853
1970
|
static VALUE
|
|
@@ -1857,7 +1974,6 @@ pgconn_send_prepare(int argc, VALUE *argv, VALUE self)
|
|
|
1857
1974
|
int result;
|
|
1858
1975
|
VALUE name, command, in_paramtypes;
|
|
1859
1976
|
VALUE param;
|
|
1860
|
-
VALUE error;
|
|
1861
1977
|
int i = 0;
|
|
1862
1978
|
int nParams = 0;
|
|
1863
1979
|
Oid *paramTypes = NULL;
|
|
@@ -1886,10 +2002,9 @@ pgconn_send_prepare(int argc, VALUE *argv, VALUE self)
|
|
|
1886
2002
|
xfree(paramTypes);
|
|
1887
2003
|
|
|
1888
2004
|
if(result == 0) {
|
|
1889
|
-
|
|
1890
|
-
rb_iv_set(error, "@connection", self);
|
|
1891
|
-
rb_exc_raise(error);
|
|
2005
|
+
pg_raise_conn_error( rb_eUnableToSend, self, "%s", PQerrorMessage(this->pgconn));
|
|
1892
2006
|
}
|
|
2007
|
+
pgconn_wait_for_flush( self );
|
|
1893
2008
|
return Qnil;
|
|
1894
2009
|
}
|
|
1895
2010
|
|
|
@@ -1911,7 +2026,7 @@ pgconn_send_prepare(int argc, VALUE *argv, VALUE self)
|
|
|
1911
2026
|
* or, it may be a String. If it is a string, that is equivalent to the hash:
|
|
1912
2027
|
* { :value => <string value>, :format => 0 }
|
|
1913
2028
|
*
|
|
1914
|
-
* PostgreSQL bind parameters are represented as $1, $
|
|
2029
|
+
* PostgreSQL bind parameters are represented as $1, $2, $3, etc.,
|
|
1915
2030
|
* inside the SQL query. The 0th element of the +params+ array is bound
|
|
1916
2031
|
* to $1, the 1st element is bound to $2, etc. +nil+ is treated as +NULL+.
|
|
1917
2032
|
*
|
|
@@ -1931,7 +2046,6 @@ pgconn_send_query_prepared(int argc, VALUE *argv, VALUE self)
|
|
|
1931
2046
|
t_pg_connection *this = pg_get_connection_safe( self );
|
|
1932
2047
|
int result;
|
|
1933
2048
|
VALUE name, in_res_fmt;
|
|
1934
|
-
VALUE error;
|
|
1935
2049
|
int nParams;
|
|
1936
2050
|
int resultFormat;
|
|
1937
2051
|
struct query_params_data paramsData = { this->enc_idx };
|
|
@@ -1941,7 +2055,6 @@ pgconn_send_query_prepared(int argc, VALUE *argv, VALUE self)
|
|
|
1941
2055
|
|
|
1942
2056
|
if(NIL_P(paramsData.params)) {
|
|
1943
2057
|
paramsData.params = rb_ary_new2(0);
|
|
1944
|
-
resultFormat = 0;
|
|
1945
2058
|
}
|
|
1946
2059
|
pgconn_query_assign_typemap( self, ¶msData );
|
|
1947
2060
|
|
|
@@ -1954,11 +2067,10 @@ pgconn_send_query_prepared(int argc, VALUE *argv, VALUE self)
|
|
|
1954
2067
|
|
|
1955
2068
|
free_query_params( ¶msData );
|
|
1956
2069
|
|
|
1957
|
-
if(result == 0)
|
|
1958
|
-
|
|
1959
|
-
|
|
1960
|
-
|
|
1961
|
-
}
|
|
2070
|
+
if(result == 0)
|
|
2071
|
+
pg_raise_conn_error( rb_eUnableToSend, self, "%s", PQerrorMessage(this->pgconn));
|
|
2072
|
+
|
|
2073
|
+
pgconn_wait_for_flush( self );
|
|
1962
2074
|
return Qnil;
|
|
1963
2075
|
}
|
|
1964
2076
|
|
|
@@ -1972,14 +2084,12 @@ pgconn_send_query_prepared(int argc, VALUE *argv, VALUE self)
|
|
|
1972
2084
|
static VALUE
|
|
1973
2085
|
pgconn_send_describe_prepared(VALUE self, VALUE stmt_name)
|
|
1974
2086
|
{
|
|
1975
|
-
VALUE error;
|
|
1976
2087
|
t_pg_connection *this = pg_get_connection_safe( self );
|
|
1977
2088
|
/* returns 0 on failure */
|
|
1978
|
-
if(gvl_PQsendDescribePrepared(this->pgconn, pg_cstr_enc(stmt_name, this->enc_idx)) == 0)
|
|
1979
|
-
|
|
1980
|
-
|
|
1981
|
-
|
|
1982
|
-
}
|
|
2089
|
+
if(gvl_PQsendDescribePrepared(this->pgconn, pg_cstr_enc(stmt_name, this->enc_idx)) == 0)
|
|
2090
|
+
pg_raise_conn_error( rb_eUnableToSend, self, "%s", PQerrorMessage(this->pgconn));
|
|
2091
|
+
|
|
2092
|
+
pgconn_wait_for_flush( self );
|
|
1983
2093
|
return Qnil;
|
|
1984
2094
|
}
|
|
1985
2095
|
|
|
@@ -1994,36 +2104,18 @@ pgconn_send_describe_prepared(VALUE self, VALUE stmt_name)
|
|
|
1994
2104
|
static VALUE
|
|
1995
2105
|
pgconn_send_describe_portal(VALUE self, VALUE portal)
|
|
1996
2106
|
{
|
|
1997
|
-
VALUE error;
|
|
1998
2107
|
t_pg_connection *this = pg_get_connection_safe( self );
|
|
1999
2108
|
/* returns 0 on failure */
|
|
2000
|
-
if(gvl_PQsendDescribePortal(this->pgconn, pg_cstr_enc(portal, this->enc_idx)) == 0)
|
|
2001
|
-
|
|
2002
|
-
|
|
2003
|
-
|
|
2004
|
-
}
|
|
2109
|
+
if(gvl_PQsendDescribePortal(this->pgconn, pg_cstr_enc(portal, this->enc_idx)) == 0)
|
|
2110
|
+
pg_raise_conn_error( rb_eUnableToSend, self, "%s", PQerrorMessage(this->pgconn));
|
|
2111
|
+
|
|
2112
|
+
pgconn_wait_for_flush( self );
|
|
2005
2113
|
return Qnil;
|
|
2006
2114
|
}
|
|
2007
2115
|
|
|
2008
2116
|
|
|
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
2117
|
static VALUE
|
|
2026
|
-
|
|
2118
|
+
pgconn_sync_get_result(VALUE self)
|
|
2027
2119
|
{
|
|
2028
2120
|
PGconn *conn = pg_get_pgconn(self);
|
|
2029
2121
|
PGresult *result;
|
|
@@ -2049,17 +2141,15 @@ pgconn_get_result(VALUE self)
|
|
|
2049
2141
|
* or *notifies* to see if the state has changed.
|
|
2050
2142
|
*/
|
|
2051
2143
|
static VALUE
|
|
2052
|
-
pgconn_consume_input(self)
|
|
2053
|
-
VALUE self;
|
|
2144
|
+
pgconn_consume_input(VALUE self)
|
|
2054
2145
|
{
|
|
2055
|
-
VALUE error;
|
|
2056
2146
|
PGconn *conn = pg_get_pgconn(self);
|
|
2057
2147
|
/* returns 0 on error */
|
|
2058
2148
|
if(PQconsumeInput(conn) == 0) {
|
|
2059
|
-
|
|
2060
|
-
|
|
2061
|
-
rb_exc_raise(error);
|
|
2149
|
+
pgconn_close_socket_io(self);
|
|
2150
|
+
pg_raise_conn_error( rb_eConnectionBad, self, "%s", PQerrorMessage(conn));
|
|
2062
2151
|
}
|
|
2152
|
+
|
|
2063
2153
|
return Qnil;
|
|
2064
2154
|
}
|
|
2065
2155
|
|
|
@@ -2068,38 +2158,20 @@ pgconn_consume_input(self)
|
|
|
2068
2158
|
* conn.is_busy() -> Boolean
|
|
2069
2159
|
*
|
|
2070
2160
|
* Returns +true+ if a command is busy, that is, if
|
|
2071
|
-
*
|
|
2161
|
+
* #get_result would block. Otherwise returns +false+.
|
|
2072
2162
|
*/
|
|
2073
2163
|
static VALUE
|
|
2074
|
-
pgconn_is_busy(self)
|
|
2075
|
-
VALUE self;
|
|
2164
|
+
pgconn_is_busy(VALUE self)
|
|
2076
2165
|
{
|
|
2077
2166
|
return gvl_PQisBusy(pg_get_pgconn(self)) ? Qtrue : Qfalse;
|
|
2078
2167
|
}
|
|
2079
2168
|
|
|
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
2169
|
static VALUE
|
|
2097
|
-
|
|
2098
|
-
VALUE self, state;
|
|
2170
|
+
pgconn_sync_setnonblocking(VALUE self, VALUE state)
|
|
2099
2171
|
{
|
|
2100
2172
|
int arg;
|
|
2101
|
-
VALUE error;
|
|
2102
2173
|
PGconn *conn = pg_get_pgconn(self);
|
|
2174
|
+
rb_check_frozen(self);
|
|
2103
2175
|
if(state == Qtrue)
|
|
2104
2176
|
arg = 1;
|
|
2105
2177
|
else if (state == Qfalse)
|
|
@@ -2107,67 +2179,32 @@ pgconn_setnonblocking(self, state)
|
|
|
2107
2179
|
else
|
|
2108
2180
|
rb_raise(rb_eArgError, "Boolean value expected");
|
|
2109
2181
|
|
|
2110
|
-
if(PQsetnonblocking(conn, arg) == -1)
|
|
2111
|
-
|
|
2112
|
-
|
|
2113
|
-
rb_exc_raise(error);
|
|
2114
|
-
}
|
|
2182
|
+
if(PQsetnonblocking(conn, arg) == -1)
|
|
2183
|
+
pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(conn));
|
|
2184
|
+
|
|
2115
2185
|
return Qnil;
|
|
2116
2186
|
}
|
|
2117
2187
|
|
|
2118
2188
|
|
|
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
2189
|
static VALUE
|
|
2127
|
-
|
|
2128
|
-
VALUE self;
|
|
2190
|
+
pgconn_sync_isnonblocking(VALUE self)
|
|
2129
2191
|
{
|
|
2130
2192
|
return PQisnonblocking(pg_get_pgconn(self)) ? Qtrue : Qfalse;
|
|
2131
2193
|
}
|
|
2132
2194
|
|
|
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
2195
|
static VALUE
|
|
2144
|
-
|
|
2145
|
-
VALUE self;
|
|
2196
|
+
pgconn_sync_flush(VALUE self)
|
|
2146
2197
|
{
|
|
2147
2198
|
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
|
-
}
|
|
2199
|
+
int ret = PQflush(conn);
|
|
2200
|
+
if(ret == -1)
|
|
2201
|
+
pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(conn));
|
|
2202
|
+
|
|
2156
2203
|
return (ret) ? Qfalse : Qtrue;
|
|
2157
2204
|
}
|
|
2158
2205
|
|
|
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
2206
|
static VALUE
|
|
2170
|
-
|
|
2207
|
+
pgconn_sync_cancel(VALUE self)
|
|
2171
2208
|
{
|
|
2172
2209
|
char errbuf[256];
|
|
2173
2210
|
PGcancel *cancel;
|
|
@@ -2176,9 +2213,9 @@ pgconn_cancel(VALUE self)
|
|
|
2176
2213
|
|
|
2177
2214
|
cancel = PQgetCancel(pg_get_pgconn(self));
|
|
2178
2215
|
if(cancel == NULL)
|
|
2179
|
-
|
|
2216
|
+
pg_raise_conn_error( rb_ePGerror, self, "Invalid connection!");
|
|
2180
2217
|
|
|
2181
|
-
ret = gvl_PQcancel(cancel, errbuf,
|
|
2218
|
+
ret = gvl_PQcancel(cancel, errbuf, sizeof(errbuf));
|
|
2182
2219
|
if(ret == 1)
|
|
2183
2220
|
retval = Qnil;
|
|
2184
2221
|
else
|
|
@@ -2229,55 +2266,63 @@ pgconn_notifies(VALUE self)
|
|
|
2229
2266
|
return hash;
|
|
2230
2267
|
}
|
|
2231
2268
|
|
|
2232
|
-
|
|
2233
|
-
|
|
2234
|
-
/*
|
|
2235
|
-
*
|
|
2236
|
-
* instead of rb_wait_for_single_fd().
|
|
2269
|
+
#if defined(_WIN32)
|
|
2270
|
+
|
|
2271
|
+
/* We use a specialized implementation of rb_io_wait() on Windows.
|
|
2272
|
+
* This is because rb_io_wait() and rb_wait_for_single_fd() are very slow on Windows.
|
|
2237
2273
|
*/
|
|
2238
2274
|
|
|
2275
|
+
#if defined(HAVE_RUBY_FIBER_SCHEDULER_H)
|
|
2276
|
+
#include <ruby/fiber/scheduler.h>
|
|
2277
|
+
#endif
|
|
2278
|
+
|
|
2279
|
+
typedef enum {
|
|
2280
|
+
PG_RUBY_IO_READABLE = RB_WAITFD_IN,
|
|
2281
|
+
PG_RUBY_IO_WRITABLE = RB_WAITFD_OUT,
|
|
2282
|
+
PG_RUBY_IO_PRIORITY = RB_WAITFD_PRI,
|
|
2283
|
+
} pg_rb_io_event_t;
|
|
2284
|
+
|
|
2239
2285
|
int rb_w32_wait_events( HANDLE *events, int num, DWORD timeout );
|
|
2240
2286
|
|
|
2241
|
-
static
|
|
2242
|
-
|
|
2243
|
-
|
|
2244
|
-
|
|
2245
|
-
|
|
2287
|
+
static VALUE
|
|
2288
|
+
pg_rb_thread_io_wait(VALUE io, VALUE events, VALUE timeout) {
|
|
2289
|
+
rb_io_t *fptr;
|
|
2290
|
+
struct timeval ptimeout;
|
|
2291
|
+
|
|
2246
2292
|
struct timeval aborttime={0,0}, currtime, waittime;
|
|
2247
2293
|
DWORD timeout_milisec = INFINITE;
|
|
2248
|
-
|
|
2249
|
-
WSAEVENT hEvent;
|
|
2250
|
-
|
|
2251
|
-
if ( sd < 0 )
|
|
2252
|
-
rb_raise(rb_eConnectionBad, "PQsocket() can't get socket descriptor");
|
|
2294
|
+
HANDLE hEvent = WSACreateEvent();
|
|
2253
2295
|
|
|
2254
|
-
|
|
2296
|
+
long rb_events = NUM2UINT(events);
|
|
2297
|
+
long w32_events = 0;
|
|
2298
|
+
DWORD wait_ret;
|
|
2255
2299
|
|
|
2256
|
-
|
|
2257
|
-
if(
|
|
2258
|
-
|
|
2259
|
-
|
|
2260
|
-
}
|
|
2300
|
+
GetOpenFile((io), fptr);
|
|
2301
|
+
if( !NIL_P(timeout) ){
|
|
2302
|
+
ptimeout.tv_sec = (time_t)(NUM2DBL(timeout));
|
|
2303
|
+
ptimeout.tv_usec = (time_t)((NUM2DBL(timeout) - (double)ptimeout.tv_sec) * 1e6);
|
|
2261
2304
|
|
|
2262
|
-
if ( ptimeout ) {
|
|
2263
2305
|
gettimeofday(&currtime, NULL);
|
|
2264
|
-
timeradd(&currtime, ptimeout, &aborttime);
|
|
2306
|
+
timeradd(&currtime, &ptimeout, &aborttime);
|
|
2265
2307
|
}
|
|
2266
2308
|
|
|
2267
|
-
|
|
2268
|
-
|
|
2309
|
+
if(rb_events & PG_RUBY_IO_READABLE) w32_events |= FD_READ | FD_ACCEPT | FD_CLOSE;
|
|
2310
|
+
if(rb_events & PG_RUBY_IO_WRITABLE) w32_events |= FD_WRITE | FD_CONNECT;
|
|
2311
|
+
if(rb_events & PG_RUBY_IO_PRIORITY) w32_events |= FD_OOB;
|
|
2312
|
+
|
|
2313
|
+
for(;;) {
|
|
2314
|
+
if ( WSAEventSelect(_get_osfhandle(fptr->fd), hEvent, w32_events) == SOCKET_ERROR ) {
|
|
2269
2315
|
WSACloseEvent( hEvent );
|
|
2270
2316
|
rb_raise( rb_eConnectionBad, "WSAEventSelect socket error: %d", WSAGetLastError() );
|
|
2271
2317
|
}
|
|
2272
2318
|
|
|
2273
|
-
if (
|
|
2319
|
+
if ( !NIL_P(timeout) ) {
|
|
2274
2320
|
gettimeofday(&currtime, NULL);
|
|
2275
2321
|
timersub(&aborttime, &currtime, &waittime);
|
|
2276
2322
|
timeout_milisec = (DWORD)( waittime.tv_sec * 1e3 + waittime.tv_usec / 1e3 );
|
|
2277
2323
|
}
|
|
2278
2324
|
|
|
2279
|
-
|
|
2280
|
-
if( !ptimeout || (waittime.tv_sec >= 0 && waittime.tv_usec >= 0) ){
|
|
2325
|
+
if( NIL_P(timeout) || (waittime.tv_sec >= 0 && waittime.tv_usec >= 0) ){
|
|
2281
2326
|
/* Wait for the socket to become readable before checking again */
|
|
2282
2327
|
wait_ret = rb_w32_wait_events( &hEvent, 1, timeout_milisec );
|
|
2283
2328
|
} else {
|
|
@@ -2286,9 +2331,11 @@ wait_socket_readable( PGconn *conn, struct timeval *ptimeout, void *(*is_readabl
|
|
|
2286
2331
|
|
|
2287
2332
|
if ( wait_ret == WAIT_TIMEOUT ) {
|
|
2288
2333
|
WSACloseEvent( hEvent );
|
|
2289
|
-
return
|
|
2334
|
+
return UINT2NUM(0);
|
|
2290
2335
|
} else if ( wait_ret == WAIT_OBJECT_0 ) {
|
|
2336
|
+
WSACloseEvent( hEvent );
|
|
2291
2337
|
/* The event we were waiting for. */
|
|
2338
|
+
return UINT2NUM(rb_events);
|
|
2292
2339
|
} else if ( wait_ret == WAIT_OBJECT_0 + 1) {
|
|
2293
2340
|
/* This indicates interruption from timer thread, GC, exception
|
|
2294
2341
|
* from other threads etc... */
|
|
@@ -2300,36 +2347,66 @@ wait_socket_readable( PGconn *conn, struct timeval *ptimeout, void *(*is_readabl
|
|
|
2300
2347
|
WSACloseEvent( hEvent );
|
|
2301
2348
|
rb_raise( rb_eConnectionBad, "Wait on socket abandoned (WaitForMultipleObjects)" );
|
|
2302
2349
|
}
|
|
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
2350
|
}
|
|
2351
|
+
}
|
|
2310
2352
|
|
|
2311
|
-
|
|
2312
|
-
|
|
2353
|
+
static VALUE
|
|
2354
|
+
pg_rb_io_wait(VALUE io, VALUE events, VALUE timeout) {
|
|
2355
|
+
#if defined(HAVE_RUBY_FIBER_SCHEDULER_H)
|
|
2356
|
+
/* We don't support Fiber.scheduler on Windows ruby-3.0 because there is no fast way to check whether a scheduler is active.
|
|
2357
|
+
* Fortunatelly ruby-3.1 offers a C-API for it.
|
|
2358
|
+
*/
|
|
2359
|
+
VALUE scheduler = rb_fiber_scheduler_current();
|
|
2360
|
+
|
|
2361
|
+
if (!NIL_P(scheduler)) {
|
|
2362
|
+
return rb_io_wait(io, events, timeout);
|
|
2363
|
+
}
|
|
2364
|
+
#endif
|
|
2365
|
+
return pg_rb_thread_io_wait(io, events, timeout);
|
|
2313
2366
|
}
|
|
2314
2367
|
|
|
2368
|
+
#elif defined(HAVE_RB_IO_WAIT)
|
|
2369
|
+
|
|
2370
|
+
/* Use our own function and constants names, to avoid conflicts with truffleruby-head on its road to ruby-3.0 compatibility. */
|
|
2371
|
+
#define pg_rb_io_wait rb_io_wait
|
|
2372
|
+
#define PG_RUBY_IO_READABLE RUBY_IO_READABLE
|
|
2373
|
+
#define PG_RUBY_IO_WRITABLE RUBY_IO_WRITABLE
|
|
2374
|
+
#define PG_RUBY_IO_PRIORITY RUBY_IO_PRIORITY
|
|
2375
|
+
|
|
2315
2376
|
#else
|
|
2377
|
+
/* For compat with ruby < 3.0 */
|
|
2316
2378
|
|
|
2317
|
-
|
|
2379
|
+
typedef enum {
|
|
2380
|
+
PG_RUBY_IO_READABLE = RB_WAITFD_IN,
|
|
2381
|
+
PG_RUBY_IO_WRITABLE = RB_WAITFD_OUT,
|
|
2382
|
+
PG_RUBY_IO_PRIORITY = RB_WAITFD_PRI,
|
|
2383
|
+
} pg_rb_io_event_t;
|
|
2384
|
+
|
|
2385
|
+
static VALUE
|
|
2386
|
+
pg_rb_io_wait(VALUE io, VALUE events, VALUE timeout) {
|
|
2387
|
+
rb_io_t *fptr;
|
|
2388
|
+
struct timeval waittime;
|
|
2389
|
+
int res;
|
|
2390
|
+
|
|
2391
|
+
GetOpenFile((io), fptr);
|
|
2392
|
+
if( !NIL_P(timeout) ){
|
|
2393
|
+
waittime.tv_sec = (time_t)(NUM2DBL(timeout));
|
|
2394
|
+
waittime.tv_usec = (time_t)((NUM2DBL(timeout) - (double)waittime.tv_sec) * 1e6);
|
|
2395
|
+
}
|
|
2396
|
+
res = rb_wait_for_single_fd(fptr->fd, NUM2UINT(events), NIL_P(timeout) ? NULL : &waittime);
|
|
2397
|
+
|
|
2398
|
+
return UINT2NUM(res);
|
|
2399
|
+
}
|
|
2400
|
+
#endif
|
|
2318
2401
|
|
|
2319
2402
|
static void *
|
|
2320
|
-
wait_socket_readable(
|
|
2403
|
+
wait_socket_readable( VALUE self, struct timeval *ptimeout, void *(*is_readable)(PGconn *))
|
|
2321
2404
|
{
|
|
2322
|
-
|
|
2323
|
-
int ret;
|
|
2405
|
+
VALUE ret;
|
|
2324
2406
|
void *retval;
|
|
2325
2407
|
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) );
|
|
2408
|
+
VALUE wait_timeout = Qnil;
|
|
2409
|
+
PGconn *conn = pg_get_pgconn(self);
|
|
2333
2410
|
|
|
2334
2411
|
if ( ptimeout ) {
|
|
2335
2412
|
gettimeofday(&currtime, NULL);
|
|
@@ -2340,36 +2417,81 @@ wait_socket_readable( PGconn *conn, struct timeval *ptimeout, void *(*is_readabl
|
|
|
2340
2417
|
if ( ptimeout ) {
|
|
2341
2418
|
gettimeofday(&currtime, NULL);
|
|
2342
2419
|
timersub(&aborttime, &currtime, &waittime);
|
|
2420
|
+
wait_timeout = DBL2NUM((double)(waittime.tv_sec) + (double)(waittime.tv_usec) / 1000000.0);
|
|
2343
2421
|
}
|
|
2344
2422
|
|
|
2345
2423
|
/* Is the given timeout valid? */
|
|
2346
2424
|
if( !ptimeout || (waittime.tv_sec >= 0 && waittime.tv_usec >= 0) ){
|
|
2425
|
+
VALUE socket_io;
|
|
2426
|
+
|
|
2427
|
+
/* before we wait for data, make sure everything has been sent */
|
|
2428
|
+
pgconn_async_flush(self);
|
|
2429
|
+
if ((retval=is_readable(conn)))
|
|
2430
|
+
return retval;
|
|
2431
|
+
|
|
2432
|
+
socket_io = pgconn_socket_io(self);
|
|
2347
2433
|
/* Wait for the socket to become readable before checking again */
|
|
2348
|
-
ret =
|
|
2434
|
+
ret = pg_rb_io_wait(socket_io, RB_INT2NUM(PG_RUBY_IO_READABLE), wait_timeout);
|
|
2349
2435
|
} else {
|
|
2350
|
-
ret =
|
|
2351
|
-
}
|
|
2352
|
-
|
|
2353
|
-
if ( ret < 0 ){
|
|
2354
|
-
rb_sys_fail( "rb_wait_for_single_fd()" );
|
|
2436
|
+
ret = Qfalse;
|
|
2355
2437
|
}
|
|
2356
2438
|
|
|
2357
2439
|
/* Return false if the select() timed out */
|
|
2358
|
-
if ( ret ==
|
|
2440
|
+
if ( ret == Qfalse ){
|
|
2359
2441
|
return NULL;
|
|
2360
2442
|
}
|
|
2361
2443
|
|
|
2362
2444
|
/* Check for connection errors (PQisBusy is true on connection errors) */
|
|
2363
2445
|
if ( PQconsumeInput(conn) == 0 ){
|
|
2364
|
-
|
|
2446
|
+
pgconn_close_socket_io(self);
|
|
2447
|
+
pg_raise_conn_error(rb_eConnectionBad, self, "PQconsumeInput() %s", PQerrorMessage(conn));
|
|
2365
2448
|
}
|
|
2366
2449
|
}
|
|
2367
2450
|
|
|
2368
2451
|
return retval;
|
|
2369
2452
|
}
|
|
2370
2453
|
|
|
2454
|
+
/*
|
|
2455
|
+
* call-seq:
|
|
2456
|
+
* conn.flush() -> Boolean
|
|
2457
|
+
*
|
|
2458
|
+
* Attempts to flush any queued output data to the server.
|
|
2459
|
+
* Returns +true+ if data is successfully flushed, +false+
|
|
2460
|
+
* if not. It can only return +false+ if connection is
|
|
2461
|
+
* in nonblocking mode.
|
|
2462
|
+
* Raises PG::Error if some other failure occurred.
|
|
2463
|
+
*/
|
|
2464
|
+
static VALUE
|
|
2465
|
+
pgconn_async_flush(VALUE self)
|
|
2466
|
+
{
|
|
2467
|
+
while( pgconn_sync_flush(self) == Qfalse ){
|
|
2468
|
+
/* wait for the socket to become read- or write-ready */
|
|
2469
|
+
int events;
|
|
2470
|
+
VALUE socket_io = pgconn_socket_io(self);
|
|
2471
|
+
events = RB_NUM2INT(pg_rb_io_wait(socket_io, RB_INT2NUM(PG_RUBY_IO_READABLE | PG_RUBY_IO_WRITABLE), Qnil));
|
|
2371
2472
|
|
|
2372
|
-
|
|
2473
|
+
if (events & PG_RUBY_IO_READABLE){
|
|
2474
|
+
pgconn_consume_input(self);
|
|
2475
|
+
}
|
|
2476
|
+
}
|
|
2477
|
+
return Qtrue;
|
|
2478
|
+
}
|
|
2479
|
+
|
|
2480
|
+
static VALUE
|
|
2481
|
+
pgconn_wait_for_flush( VALUE self ){
|
|
2482
|
+
if( !pg_get_connection_safe(self)->flush_data )
|
|
2483
|
+
return Qnil;
|
|
2484
|
+
|
|
2485
|
+
return pgconn_async_flush(self);
|
|
2486
|
+
}
|
|
2487
|
+
|
|
2488
|
+
static VALUE
|
|
2489
|
+
pgconn_flush_data_set( VALUE self, VALUE enabled ){
|
|
2490
|
+
t_pg_connection *conn = pg_get_connection(self);
|
|
2491
|
+
rb_check_frozen(self);
|
|
2492
|
+
conn->flush_data = RTEST(enabled);
|
|
2493
|
+
return enabled;
|
|
2494
|
+
}
|
|
2373
2495
|
|
|
2374
2496
|
static void *
|
|
2375
2497
|
notify_readable(PGconn *conn)
|
|
@@ -2408,7 +2530,7 @@ pgconn_wait_for_notify(int argc, VALUE *argv, VALUE self)
|
|
|
2408
2530
|
ptimeout = &timeout;
|
|
2409
2531
|
}
|
|
2410
2532
|
|
|
2411
|
-
pnotification = (PGnotify*) wait_socket_readable(
|
|
2533
|
+
pnotification = (PGnotify*) wait_socket_readable( self, ptimeout, notify_readable);
|
|
2412
2534
|
|
|
2413
2535
|
/* Return nil if the select timed out */
|
|
2414
2536
|
if ( !pnotification ) return Qnil;
|
|
@@ -2429,28 +2551,8 @@ pgconn_wait_for_notify(int argc, VALUE *argv, VALUE self)
|
|
|
2429
2551
|
}
|
|
2430
2552
|
|
|
2431
2553
|
|
|
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
2554
|
static VALUE
|
|
2453
|
-
|
|
2555
|
+
pgconn_sync_put_copy_data(int argc, VALUE *argv, VALUE self)
|
|
2454
2556
|
{
|
|
2455
2557
|
int ret;
|
|
2456
2558
|
int len;
|
|
@@ -2467,13 +2569,11 @@ pgconn_put_copy_data(int argc, VALUE *argv, VALUE self)
|
|
|
2467
2569
|
if( NIL_P(this->encoder_for_put_copy_data) ){
|
|
2468
2570
|
buffer = value;
|
|
2469
2571
|
} else {
|
|
2470
|
-
p_coder =
|
|
2572
|
+
p_coder = RTYPEDDATA_DATA( this->encoder_for_put_copy_data );
|
|
2471
2573
|
}
|
|
2472
|
-
} else if( rb_obj_is_kind_of(encoder, rb_cPG_Coder) ) {
|
|
2473
|
-
Data_Get_Struct( encoder, t_pg_coder, p_coder );
|
|
2474
2574
|
} else {
|
|
2475
|
-
|
|
2476
|
-
|
|
2575
|
+
/* Check argument type and use argument encoder */
|
|
2576
|
+
TypedData_Get_Struct(encoder, t_pg_coder, &pg_coder_type, p_coder);
|
|
2477
2577
|
}
|
|
2478
2578
|
|
|
2479
2579
|
if( p_coder ){
|
|
@@ -2496,36 +2596,19 @@ pgconn_put_copy_data(int argc, VALUE *argv, VALUE self)
|
|
|
2496
2596
|
Check_Type(buffer, T_STRING);
|
|
2497
2597
|
|
|
2498
2598
|
ret = gvl_PQputCopyData(this->pgconn, RSTRING_PTR(buffer), RSTRING_LENINT(buffer));
|
|
2499
|
-
if(ret == -1)
|
|
2500
|
-
|
|
2501
|
-
|
|
2502
|
-
rb_exc_raise(error);
|
|
2503
|
-
}
|
|
2599
|
+
if(ret == -1)
|
|
2600
|
+
pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(this->pgconn));
|
|
2601
|
+
|
|
2504
2602
|
RB_GC_GUARD(intermediate);
|
|
2505
2603
|
RB_GC_GUARD(buffer);
|
|
2506
2604
|
|
|
2507
2605
|
return (ret) ? Qtrue : Qfalse;
|
|
2508
2606
|
}
|
|
2509
2607
|
|
|
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
2608
|
static VALUE
|
|
2525
|
-
|
|
2609
|
+
pgconn_sync_put_copy_end(int argc, VALUE *argv, VALUE self)
|
|
2526
2610
|
{
|
|
2527
2611
|
VALUE str;
|
|
2528
|
-
VALUE error;
|
|
2529
2612
|
int ret;
|
|
2530
2613
|
const char *error_message = NULL;
|
|
2531
2614
|
t_pg_connection *this = pg_get_connection_safe( self );
|
|
@@ -2536,38 +2619,16 @@ pgconn_put_copy_end(int argc, VALUE *argv, VALUE self)
|
|
|
2536
2619
|
error_message = pg_cstr_enc(str, this->enc_idx);
|
|
2537
2620
|
|
|
2538
2621
|
ret = gvl_PQputCopyEnd(this->pgconn, error_message);
|
|
2539
|
-
if(ret == -1)
|
|
2540
|
-
|
|
2541
|
-
|
|
2542
|
-
rb_exc_raise(error);
|
|
2543
|
-
}
|
|
2622
|
+
if(ret == -1)
|
|
2623
|
+
pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(this->pgconn));
|
|
2624
|
+
|
|
2544
2625
|
return (ret) ? Qtrue : Qfalse;
|
|
2545
2626
|
}
|
|
2546
2627
|
|
|
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
2628
|
static VALUE
|
|
2567
|
-
|
|
2629
|
+
pgconn_sync_get_copy_data(int argc, VALUE *argv, VALUE self )
|
|
2568
2630
|
{
|
|
2569
2631
|
VALUE async_in;
|
|
2570
|
-
VALUE error;
|
|
2571
2632
|
VALUE result;
|
|
2572
2633
|
int ret;
|
|
2573
2634
|
char *buffer;
|
|
@@ -2579,20 +2640,16 @@ pgconn_get_copy_data(int argc, VALUE *argv, VALUE self )
|
|
|
2579
2640
|
|
|
2580
2641
|
if( NIL_P(decoder) ){
|
|
2581
2642
|
if( !NIL_P(this->decoder_for_get_copy_data) ){
|
|
2582
|
-
p_coder =
|
|
2643
|
+
p_coder = RTYPEDDATA_DATA( this->decoder_for_get_copy_data );
|
|
2583
2644
|
}
|
|
2584
|
-
} else if( rb_obj_is_kind_of(decoder, rb_cPG_Coder) ) {
|
|
2585
|
-
Data_Get_Struct( decoder, t_pg_coder, p_coder );
|
|
2586
2645
|
} else {
|
|
2587
|
-
|
|
2588
|
-
|
|
2646
|
+
/* Check argument type and use argument decoder */
|
|
2647
|
+
TypedData_Get_Struct(decoder, t_pg_coder, &pg_coder_type, p_coder);
|
|
2589
2648
|
}
|
|
2590
2649
|
|
|
2591
2650
|
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);
|
|
2651
|
+
if(ret == -2){ /* error */
|
|
2652
|
+
pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(this->pgconn));
|
|
2596
2653
|
}
|
|
2597
2654
|
if(ret == -1) { /* No data left */
|
|
2598
2655
|
return Qnil;
|
|
@@ -2686,6 +2743,7 @@ pgconn_trace(VALUE self, VALUE stream)
|
|
|
2686
2743
|
VALUE new_file;
|
|
2687
2744
|
t_pg_connection *this = pg_get_connection_safe( self );
|
|
2688
2745
|
|
|
2746
|
+
rb_check_frozen(self);
|
|
2689
2747
|
if(!rb_respond_to(stream,rb_intern("fileno")))
|
|
2690
2748
|
rb_raise(rb_eArgError, "stream does not respond to method: fileno");
|
|
2691
2749
|
|
|
@@ -2707,7 +2765,7 @@ pgconn_trace(VALUE self, VALUE stream)
|
|
|
2707
2765
|
rb_raise(rb_eArgError, "stream is not writable");
|
|
2708
2766
|
|
|
2709
2767
|
new_file = rb_funcall(rb_cIO, rb_intern("new"), 1, INT2NUM(new_fd));
|
|
2710
|
-
this->trace_stream
|
|
2768
|
+
RB_OBJ_WRITE(self, &this->trace_stream, new_file);
|
|
2711
2769
|
|
|
2712
2770
|
PQtrace(this->pgconn, new_fp);
|
|
2713
2771
|
return Qnil;
|
|
@@ -2726,7 +2784,7 @@ pgconn_untrace(VALUE self)
|
|
|
2726
2784
|
|
|
2727
2785
|
PQuntrace(this->pgconn);
|
|
2728
2786
|
rb_funcall(this->trace_stream, rb_intern("close"), 0);
|
|
2729
|
-
this->trace_stream
|
|
2787
|
+
RB_OBJ_WRITE(self, &this->trace_stream, Qnil);
|
|
2730
2788
|
return Qnil;
|
|
2731
2789
|
}
|
|
2732
2790
|
|
|
@@ -2785,13 +2843,14 @@ pgconn_set_notice_receiver(VALUE self)
|
|
|
2785
2843
|
VALUE proc, old_proc;
|
|
2786
2844
|
t_pg_connection *this = pg_get_connection_safe( self );
|
|
2787
2845
|
|
|
2846
|
+
rb_check_frozen(self);
|
|
2788
2847
|
/* If default_notice_receiver is unset, assume that the current
|
|
2789
2848
|
* notice receiver is the default, and save it to a global variable.
|
|
2790
2849
|
* This should not be a problem because the default receiver is
|
|
2791
2850
|
* always the same, so won't vary among connections.
|
|
2792
2851
|
*/
|
|
2793
|
-
if(default_notice_receiver == NULL)
|
|
2794
|
-
default_notice_receiver = PQsetNoticeReceiver(this->pgconn, NULL, NULL);
|
|
2852
|
+
if(this->default_notice_receiver == NULL)
|
|
2853
|
+
this->default_notice_receiver = PQsetNoticeReceiver(this->pgconn, NULL, NULL);
|
|
2795
2854
|
|
|
2796
2855
|
old_proc = this->notice_receiver;
|
|
2797
2856
|
if( rb_block_given_p() ) {
|
|
@@ -2800,10 +2859,10 @@ pgconn_set_notice_receiver(VALUE self)
|
|
|
2800
2859
|
} else {
|
|
2801
2860
|
/* if no block is given, set back to default */
|
|
2802
2861
|
proc = Qnil;
|
|
2803
|
-
PQsetNoticeReceiver(this->pgconn, default_notice_receiver, NULL);
|
|
2862
|
+
PQsetNoticeReceiver(this->pgconn, this->default_notice_receiver, NULL);
|
|
2804
2863
|
}
|
|
2805
2864
|
|
|
2806
|
-
this->notice_receiver
|
|
2865
|
+
RB_OBJ_WRITE(self, &this->notice_receiver, proc);
|
|
2807
2866
|
return old_proc;
|
|
2808
2867
|
}
|
|
2809
2868
|
|
|
@@ -2818,10 +2877,10 @@ notice_processor_proxy(void *arg, const char *message)
|
|
|
2818
2877
|
VALUE self = (VALUE)arg;
|
|
2819
2878
|
t_pg_connection *this = pg_get_connection( self );
|
|
2820
2879
|
|
|
2821
|
-
if (this->
|
|
2880
|
+
if (this->notice_processor != Qnil) {
|
|
2822
2881
|
VALUE message_str = rb_str_new2(message);
|
|
2823
2882
|
PG_ENCODING_SET_NOCHECK( message_str, this->enc_idx );
|
|
2824
|
-
rb_funcall(this->
|
|
2883
|
+
rb_funcall(this->notice_processor, rb_intern("call"), 1, message_str);
|
|
2825
2884
|
}
|
|
2826
2885
|
return;
|
|
2827
2886
|
}
|
|
@@ -2830,7 +2889,7 @@ notice_processor_proxy(void *arg, const char *message)
|
|
|
2830
2889
|
* call-seq:
|
|
2831
2890
|
* conn.set_notice_processor {|message| ... } -> Proc
|
|
2832
2891
|
*
|
|
2833
|
-
* See #set_notice_receiver for the
|
|
2892
|
+
* See #set_notice_receiver for the description of what this and the
|
|
2834
2893
|
* notice_processor methods do.
|
|
2835
2894
|
*
|
|
2836
2895
|
* This function takes a new block to act as the notice processor and returns
|
|
@@ -2845,25 +2904,26 @@ pgconn_set_notice_processor(VALUE self)
|
|
|
2845
2904
|
VALUE proc, old_proc;
|
|
2846
2905
|
t_pg_connection *this = pg_get_connection_safe( self );
|
|
2847
2906
|
|
|
2907
|
+
rb_check_frozen(self);
|
|
2848
2908
|
/* If default_notice_processor is unset, assume that the current
|
|
2849
2909
|
* notice processor is the default, and save it to a global variable.
|
|
2850
2910
|
* This should not be a problem because the default processor is
|
|
2851
2911
|
* always the same, so won't vary among connections.
|
|
2852
2912
|
*/
|
|
2853
|
-
if(default_notice_processor == NULL)
|
|
2854
|
-
default_notice_processor = PQsetNoticeProcessor(this->pgconn, NULL, NULL);
|
|
2913
|
+
if(this->default_notice_processor == NULL)
|
|
2914
|
+
this->default_notice_processor = PQsetNoticeProcessor(this->pgconn, NULL, NULL);
|
|
2855
2915
|
|
|
2856
|
-
old_proc = this->
|
|
2916
|
+
old_proc = this->notice_processor;
|
|
2857
2917
|
if( rb_block_given_p() ) {
|
|
2858
2918
|
proc = rb_block_proc();
|
|
2859
2919
|
PQsetNoticeProcessor(this->pgconn, gvl_notice_processor_proxy, (void *)self);
|
|
2860
2920
|
} else {
|
|
2861
2921
|
/* if no block is given, set back to default */
|
|
2862
2922
|
proc = Qnil;
|
|
2863
|
-
PQsetNoticeProcessor(this->pgconn, default_notice_processor, NULL);
|
|
2923
|
+
PQsetNoticeProcessor(this->pgconn, this->default_notice_processor, NULL);
|
|
2864
2924
|
}
|
|
2865
2925
|
|
|
2866
|
-
this->
|
|
2926
|
+
RB_OBJ_WRITE(self, &this->notice_processor, proc);
|
|
2867
2927
|
return old_proc;
|
|
2868
2928
|
}
|
|
2869
2929
|
|
|
@@ -2884,68 +2944,28 @@ pgconn_get_client_encoding(VALUE self)
|
|
|
2884
2944
|
|
|
2885
2945
|
/*
|
|
2886
2946
|
* call-seq:
|
|
2887
|
-
* conn.
|
|
2947
|
+
* conn.sync_set_client_encoding( encoding )
|
|
2888
2948
|
*
|
|
2889
|
-
*
|
|
2949
|
+
* This function has the same behavior as #async_set_client_encoding, but is implemented using the synchronous command processing API of libpq.
|
|
2950
|
+
* See #async_exec for the differences between the two API variants.
|
|
2951
|
+
* 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
2952
|
*/
|
|
2891
2953
|
static VALUE
|
|
2892
|
-
|
|
2954
|
+
pgconn_sync_set_client_encoding(VALUE self, VALUE str)
|
|
2893
2955
|
{
|
|
2894
2956
|
PGconn *conn = pg_get_pgconn( self );
|
|
2895
2957
|
|
|
2958
|
+
rb_check_frozen(self);
|
|
2896
2959
|
Check_Type(str, T_STRING);
|
|
2897
2960
|
|
|
2898
|
-
if ( (gvl_PQsetClientEncoding(conn, StringValueCStr(str))) == -1 )
|
|
2899
|
-
|
|
2900
|
-
|
|
2961
|
+
if ( (gvl_PQsetClientEncoding(conn, StringValueCStr(str))) == -1 )
|
|
2962
|
+
pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(conn));
|
|
2963
|
+
|
|
2901
2964
|
pgconn_set_internal_encoding_index( self );
|
|
2902
2965
|
|
|
2903
2966
|
return Qnil;
|
|
2904
2967
|
}
|
|
2905
2968
|
|
|
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
2969
|
|
|
2950
2970
|
/*
|
|
2951
2971
|
* call-seq:
|
|
@@ -3020,10 +3040,8 @@ get_result_readable(PGconn *conn)
|
|
|
3020
3040
|
* If +true+ is returned, +conn.is_busy+ will return +false+
|
|
3021
3041
|
* and +conn.get_result+ will not block.
|
|
3022
3042
|
*/
|
|
3023
|
-
|
|
3043
|
+
VALUE
|
|
3024
3044
|
pgconn_block( int argc, VALUE *argv, VALUE self ) {
|
|
3025
|
-
PGconn *conn = pg_get_pgconn( self );
|
|
3026
|
-
|
|
3027
3045
|
struct timeval timeout;
|
|
3028
3046
|
struct timeval *ptimeout = NULL;
|
|
3029
3047
|
VALUE timeout_in;
|
|
@@ -3037,7 +3055,7 @@ pgconn_block( int argc, VALUE *argv, VALUE self ) {
|
|
|
3037
3055
|
ptimeout = &timeout;
|
|
3038
3056
|
}
|
|
3039
3057
|
|
|
3040
|
-
ret = wait_socket_readable(
|
|
3058
|
+
ret = wait_socket_readable( self, ptimeout, get_result_readable);
|
|
3041
3059
|
|
|
3042
3060
|
if( !ret )
|
|
3043
3061
|
return Qfalse;
|
|
@@ -3046,6 +3064,42 @@ pgconn_block( int argc, VALUE *argv, VALUE self ) {
|
|
|
3046
3064
|
}
|
|
3047
3065
|
|
|
3048
3066
|
|
|
3067
|
+
/*
|
|
3068
|
+
* call-seq:
|
|
3069
|
+
* conn.sync_get_last_result( ) -> PG::Result
|
|
3070
|
+
*
|
|
3071
|
+
* This function has the same behavior as #async_get_last_result, but is implemented using the synchronous command processing API of libpq.
|
|
3072
|
+
* See #async_exec for the differences between the two API variants.
|
|
3073
|
+
* 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.
|
|
3074
|
+
*/
|
|
3075
|
+
static VALUE
|
|
3076
|
+
pgconn_sync_get_last_result(VALUE self)
|
|
3077
|
+
{
|
|
3078
|
+
PGconn *conn = pg_get_pgconn(self);
|
|
3079
|
+
VALUE rb_pgresult = Qnil;
|
|
3080
|
+
PGresult *cur, *prev;
|
|
3081
|
+
|
|
3082
|
+
|
|
3083
|
+
cur = prev = NULL;
|
|
3084
|
+
while ((cur = gvl_PQgetResult(conn)) != NULL) {
|
|
3085
|
+
int status;
|
|
3086
|
+
|
|
3087
|
+
if (prev) PQclear(prev);
|
|
3088
|
+
prev = cur;
|
|
3089
|
+
|
|
3090
|
+
status = PQresultStatus(cur);
|
|
3091
|
+
if (status == PGRES_COPY_OUT || status == PGRES_COPY_IN || status == PGRES_COPY_BOTH)
|
|
3092
|
+
break;
|
|
3093
|
+
}
|
|
3094
|
+
|
|
3095
|
+
if (prev) {
|
|
3096
|
+
rb_pgresult = pg_new_result( prev, self );
|
|
3097
|
+
pg_result_check(rb_pgresult);
|
|
3098
|
+
}
|
|
3099
|
+
|
|
3100
|
+
return rb_pgresult;
|
|
3101
|
+
}
|
|
3102
|
+
|
|
3049
3103
|
/*
|
|
3050
3104
|
* call-seq:
|
|
3051
3105
|
* conn.get_last_result( ) -> PG::Result
|
|
@@ -3056,27 +3110,36 @@ pgconn_block( int argc, VALUE *argv, VALUE self ) {
|
|
|
3056
3110
|
* returns the last non-NULL result, or +nil+ if no
|
|
3057
3111
|
* results are available.
|
|
3058
3112
|
*
|
|
3113
|
+
* If the last result contains a bad result_status, an
|
|
3114
|
+
* appropriate exception is raised.
|
|
3115
|
+
*
|
|
3059
3116
|
* This function is similar to #get_result
|
|
3060
3117
|
* except that it is designed to get one and only
|
|
3061
|
-
* one result.
|
|
3118
|
+
* one result and that it checks the result state.
|
|
3062
3119
|
*/
|
|
3063
3120
|
static VALUE
|
|
3064
|
-
|
|
3121
|
+
pgconn_async_get_last_result(VALUE self)
|
|
3065
3122
|
{
|
|
3066
3123
|
PGconn *conn = pg_get_pgconn(self);
|
|
3067
3124
|
VALUE rb_pgresult = Qnil;
|
|
3068
3125
|
PGresult *cur, *prev;
|
|
3069
3126
|
|
|
3070
|
-
|
|
3071
3127
|
cur = prev = NULL;
|
|
3072
|
-
|
|
3128
|
+
for(;;) {
|
|
3073
3129
|
int status;
|
|
3074
3130
|
|
|
3131
|
+
/* wait for input (without blocking) before reading each result */
|
|
3132
|
+
wait_socket_readable(self, NULL, get_result_readable);
|
|
3133
|
+
|
|
3134
|
+
cur = gvl_PQgetResult(conn);
|
|
3135
|
+
if (cur == NULL)
|
|
3136
|
+
break;
|
|
3137
|
+
|
|
3075
3138
|
if (prev) PQclear(prev);
|
|
3076
3139
|
prev = cur;
|
|
3077
3140
|
|
|
3078
3141
|
status = PQresultStatus(cur);
|
|
3079
|
-
if (status == PGRES_COPY_OUT || status == PGRES_COPY_IN)
|
|
3142
|
+
if (status == PGRES_COPY_OUT || status == PGRES_COPY_IN || status == PGRES_COPY_BOTH)
|
|
3080
3143
|
break;
|
|
3081
3144
|
}
|
|
3082
3145
|
|
|
@@ -3093,29 +3156,91 @@ pgconn_get_last_result(VALUE self)
|
|
|
3093
3156
|
* conn.discard_results()
|
|
3094
3157
|
*
|
|
3095
3158
|
* Silently discard any prior query result that application didn't eat.
|
|
3096
|
-
* This is
|
|
3097
|
-
*
|
|
3159
|
+
* This is internally used prior to Connection#exec and sibling methods.
|
|
3160
|
+
* It doesn't raise an exception on connection errors, but returns +false+ instead.
|
|
3161
|
+
*
|
|
3162
|
+
* Returns:
|
|
3163
|
+
* * +nil+ when the connection is already idle
|
|
3164
|
+
* * +true+ when some results have been discarded
|
|
3165
|
+
* * +false+ when a failure occured and the connection was closed
|
|
3166
|
+
*
|
|
3098
3167
|
*/
|
|
3099
3168
|
static VALUE
|
|
3100
3169
|
pgconn_discard_results(VALUE self)
|
|
3101
3170
|
{
|
|
3102
3171
|
PGconn *conn = pg_get_pgconn(self);
|
|
3172
|
+
VALUE socket_io;
|
|
3173
|
+
|
|
3174
|
+
switch( PQtransactionStatus(conn) ) {
|
|
3175
|
+
case PQTRANS_IDLE:
|
|
3176
|
+
case PQTRANS_INTRANS:
|
|
3177
|
+
case PQTRANS_INERROR:
|
|
3178
|
+
return Qnil;
|
|
3179
|
+
default:;
|
|
3180
|
+
}
|
|
3103
3181
|
|
|
3104
|
-
|
|
3105
|
-
|
|
3106
|
-
|
|
3182
|
+
socket_io = pgconn_socket_io(self);
|
|
3183
|
+
|
|
3184
|
+
for(;;) {
|
|
3185
|
+
PGresult *cur;
|
|
3186
|
+
int status;
|
|
3187
|
+
|
|
3188
|
+
/* pgconn_block() raises an exception in case of errors.
|
|
3189
|
+
* To avoid this call pg_rb_io_wait() and PQconsumeInput() without rb_raise().
|
|
3190
|
+
*/
|
|
3191
|
+
while( gvl_PQisBusy(conn) ){
|
|
3192
|
+
int events;
|
|
3193
|
+
|
|
3194
|
+
switch( PQflush(conn) ) {
|
|
3195
|
+
case 1:
|
|
3196
|
+
events = RB_NUM2INT(pg_rb_io_wait(socket_io, RB_INT2NUM(PG_RUBY_IO_READABLE | PG_RUBY_IO_WRITABLE), Qnil));
|
|
3197
|
+
if (events & PG_RUBY_IO_READABLE){
|
|
3198
|
+
if ( PQconsumeInput(conn) == 0 ) goto error;
|
|
3199
|
+
}
|
|
3200
|
+
break;
|
|
3201
|
+
case 0:
|
|
3202
|
+
pg_rb_io_wait(socket_io, RB_INT2NUM(PG_RUBY_IO_READABLE), Qnil);
|
|
3203
|
+
if ( PQconsumeInput(conn) == 0 ) goto error;
|
|
3204
|
+
break;
|
|
3205
|
+
default:
|
|
3206
|
+
goto error;
|
|
3207
|
+
}
|
|
3208
|
+
}
|
|
3209
|
+
|
|
3210
|
+
cur = gvl_PQgetResult(conn);
|
|
3211
|
+
if( cur == NULL) break;
|
|
3212
|
+
|
|
3213
|
+
status = PQresultStatus(cur);
|
|
3107
3214
|
PQclear(cur);
|
|
3108
3215
|
if (status == PGRES_COPY_IN){
|
|
3109
|
-
gvl_PQputCopyEnd(conn, "COPY terminated by new
|
|
3216
|
+
while( gvl_PQputCopyEnd(conn, "COPY terminated by new query or discard_results") == 0 ){
|
|
3217
|
+
pgconn_async_flush(self);
|
|
3218
|
+
}
|
|
3110
3219
|
}
|
|
3111
3220
|
if (status == PGRES_COPY_OUT){
|
|
3112
|
-
|
|
3113
|
-
|
|
3114
|
-
|
|
3221
|
+
for(;;) {
|
|
3222
|
+
char *buffer = NULL;
|
|
3223
|
+
int st = gvl_PQgetCopyData(conn, &buffer, 1);
|
|
3224
|
+
if( st == 0 ) {
|
|
3225
|
+
/* would block -> wait for readable data */
|
|
3226
|
+
pg_rb_io_wait(socket_io, RB_INT2NUM(PG_RUBY_IO_READABLE), Qnil);
|
|
3227
|
+
if ( PQconsumeInput(conn) == 0 ) goto error;
|
|
3228
|
+
} else if( st > 0 ) {
|
|
3229
|
+
/* some data retrieved -> discard it */
|
|
3230
|
+
PQfreemem(buffer);
|
|
3231
|
+
} else {
|
|
3232
|
+
/* no more data */
|
|
3233
|
+
break;
|
|
3234
|
+
}
|
|
3235
|
+
}
|
|
3115
3236
|
}
|
|
3116
3237
|
}
|
|
3117
3238
|
|
|
3118
|
-
return
|
|
3239
|
+
return Qtrue;
|
|
3240
|
+
|
|
3241
|
+
error:
|
|
3242
|
+
pgconn_close_socket_io(self);
|
|
3243
|
+
return Qfalse;
|
|
3119
3244
|
}
|
|
3120
3245
|
|
|
3121
3246
|
/*
|
|
@@ -3138,6 +3263,7 @@ pgconn_discard_results(VALUE self)
|
|
|
3138
3263
|
* #exec is an alias for #async_exec which is almost identical to #sync_exec .
|
|
3139
3264
|
* #sync_exec is implemented on the simpler synchronous command processing API of libpq, whereas
|
|
3140
3265
|
* #async_exec is implemented on the asynchronous API and on ruby's IO mechanisms.
|
|
3266
|
+
* Only #async_exec is compatible to <tt>Fiber.scheduler</tt> based asynchronous IO processing introduced in ruby-3.0.
|
|
3141
3267
|
* Both methods ensure that other threads can process while waiting for the server to
|
|
3142
3268
|
* complete the request, but #sync_exec blocks all signals to be processed until the query is finished.
|
|
3143
3269
|
* This is most notably visible by a delayed reaction to Control+C.
|
|
@@ -3152,8 +3278,7 @@ pgconn_async_exec(int argc, VALUE *argv, VALUE self)
|
|
|
3152
3278
|
|
|
3153
3279
|
pgconn_discard_results( self );
|
|
3154
3280
|
pgconn_send_query( argc, argv, self );
|
|
3155
|
-
|
|
3156
|
-
rb_pgresult = pgconn_get_last_result( self );
|
|
3281
|
+
rb_pgresult = pgconn_async_get_last_result( self );
|
|
3157
3282
|
|
|
3158
3283
|
if ( rb_block_given_p() ) {
|
|
3159
3284
|
return rb_ensure( rb_yield, rb_pgresult, pg_result_clear, rb_pgresult );
|
|
@@ -3182,7 +3307,7 @@ pgconn_async_exec(int argc, VALUE *argv, VALUE self)
|
|
|
3182
3307
|
* or, it may be a String. If it is a string, that is equivalent to the hash:
|
|
3183
3308
|
* { :value => <string value>, :type => 0, :format => 0 }
|
|
3184
3309
|
*
|
|
3185
|
-
* PostgreSQL bind parameters are represented as $1, $
|
|
3310
|
+
* PostgreSQL bind parameters are represented as $1, $2, $3, etc.,
|
|
3186
3311
|
* inside the SQL query. The 0th element of the +params+ array is bound
|
|
3187
3312
|
* to $1, the 1st element is bound to $2, etc. +nil+ is treated as +NULL+.
|
|
3188
3313
|
*
|
|
@@ -3225,8 +3350,7 @@ pgconn_async_exec_params(int argc, VALUE *argv, VALUE self)
|
|
|
3225
3350
|
} else {
|
|
3226
3351
|
pgconn_send_query_params( argc, argv, self );
|
|
3227
3352
|
}
|
|
3228
|
-
|
|
3229
|
-
rb_pgresult = pgconn_get_last_result( self );
|
|
3353
|
+
rb_pgresult = pgconn_async_get_last_result( self );
|
|
3230
3354
|
|
|
3231
3355
|
if ( rb_block_given_p() ) {
|
|
3232
3356
|
return rb_ensure( rb_yield, rb_pgresult, pg_result_clear, rb_pgresult );
|
|
@@ -3252,7 +3376,7 @@ pgconn_async_exec_params(int argc, VALUE *argv, VALUE self)
|
|
|
3252
3376
|
*
|
|
3253
3377
|
* For example: "SELECT $1::int"
|
|
3254
3378
|
*
|
|
3255
|
-
* PostgreSQL bind parameters are represented as $1, $
|
|
3379
|
+
* PostgreSQL bind parameters are represented as $1, $2, $3, etc.,
|
|
3256
3380
|
* inside the SQL query.
|
|
3257
3381
|
*
|
|
3258
3382
|
* See also corresponding {libpq function}[https://www.postgresql.org/docs/current/libpq-exec.html#LIBPQ-PQPREPARE].
|
|
@@ -3264,8 +3388,7 @@ pgconn_async_prepare(int argc, VALUE *argv, VALUE self)
|
|
|
3264
3388
|
|
|
3265
3389
|
pgconn_discard_results( self );
|
|
3266
3390
|
pgconn_send_prepare( argc, argv, self );
|
|
3267
|
-
|
|
3268
|
-
rb_pgresult = pgconn_get_last_result( self );
|
|
3391
|
+
rb_pgresult = pgconn_async_get_last_result( self );
|
|
3269
3392
|
|
|
3270
3393
|
if ( rb_block_given_p() ) {
|
|
3271
3394
|
return rb_ensure( rb_yield, rb_pgresult, pg_result_clear, rb_pgresult );
|
|
@@ -3292,7 +3415,7 @@ pgconn_async_prepare(int argc, VALUE *argv, VALUE self)
|
|
|
3292
3415
|
* or, it may be a String. If it is a string, that is equivalent to the hash:
|
|
3293
3416
|
* { :value => <string value>, :format => 0 }
|
|
3294
3417
|
*
|
|
3295
|
-
* PostgreSQL bind parameters are represented as $1, $
|
|
3418
|
+
* PostgreSQL bind parameters are represented as $1, $2, $3, etc.,
|
|
3296
3419
|
* inside the SQL query. The 0th element of the +params+ array is bound
|
|
3297
3420
|
* to $1, the 1st element is bound to $2, etc. +nil+ is treated as +NULL+.
|
|
3298
3421
|
*
|
|
@@ -3318,8 +3441,7 @@ pgconn_async_exec_prepared(int argc, VALUE *argv, VALUE self)
|
|
|
3318
3441
|
|
|
3319
3442
|
pgconn_discard_results( self );
|
|
3320
3443
|
pgconn_send_query_prepared( argc, argv, self );
|
|
3321
|
-
|
|
3322
|
-
rb_pgresult = pgconn_get_last_result( self );
|
|
3444
|
+
rb_pgresult = pgconn_async_get_last_result( self );
|
|
3323
3445
|
|
|
3324
3446
|
if ( rb_block_given_p() ) {
|
|
3325
3447
|
return rb_ensure( rb_yield, rb_pgresult, pg_result_clear, rb_pgresult );
|
|
@@ -3343,8 +3465,7 @@ pgconn_async_describe_portal(VALUE self, VALUE portal)
|
|
|
3343
3465
|
|
|
3344
3466
|
pgconn_discard_results( self );
|
|
3345
3467
|
pgconn_send_describe_portal( self, portal );
|
|
3346
|
-
|
|
3347
|
-
rb_pgresult = pgconn_get_last_result( self );
|
|
3468
|
+
rb_pgresult = pgconn_async_get_last_result( self );
|
|
3348
3469
|
|
|
3349
3470
|
if ( rb_block_given_p() ) {
|
|
3350
3471
|
return rb_ensure( rb_yield, rb_pgresult, pg_result_clear, rb_pgresult );
|
|
@@ -3368,8 +3489,7 @@ pgconn_async_describe_prepared(VALUE self, VALUE stmt_name)
|
|
|
3368
3489
|
|
|
3369
3490
|
pgconn_discard_results( self );
|
|
3370
3491
|
pgconn_send_describe_prepared( self, stmt_name );
|
|
3371
|
-
|
|
3372
|
-
rb_pgresult = pgconn_get_last_result( self );
|
|
3492
|
+
rb_pgresult = pgconn_async_get_last_result( self );
|
|
3373
3493
|
|
|
3374
3494
|
if ( rb_block_given_p() ) {
|
|
3375
3495
|
return rb_ensure( rb_yield, rb_pgresult, pg_result_clear, rb_pgresult );
|
|
@@ -3457,10 +3577,134 @@ pgconn_ssl_attribute_names(VALUE self)
|
|
|
3457
3577
|
#endif
|
|
3458
3578
|
|
|
3459
3579
|
|
|
3580
|
+
#ifdef HAVE_PQENTERPIPELINEMODE
|
|
3581
|
+
/*
|
|
3582
|
+
* call-seq:
|
|
3583
|
+
* conn.pipeline_status -> Integer
|
|
3584
|
+
*
|
|
3585
|
+
* Returns the current pipeline mode status of the libpq connection.
|
|
3586
|
+
*
|
|
3587
|
+
* PQpipelineStatus can return one of the following values:
|
|
3588
|
+
*
|
|
3589
|
+
* * PQ_PIPELINE_ON - The libpq connection is in pipeline mode.
|
|
3590
|
+
* * PQ_PIPELINE_OFF - The libpq connection is not in pipeline mode.
|
|
3591
|
+
* * PQ_PIPELINE_ABORTED - The libpq connection is in pipeline mode and an error occurred while processing the current pipeline.
|
|
3592
|
+
* The aborted flag is cleared when PQgetResult returns a result of type PGRES_PIPELINE_SYNC.
|
|
3593
|
+
*
|
|
3594
|
+
* Available since PostgreSQL-14
|
|
3595
|
+
*/
|
|
3596
|
+
static VALUE
|
|
3597
|
+
pgconn_pipeline_status(VALUE self)
|
|
3598
|
+
{
|
|
3599
|
+
int res = PQpipelineStatus(pg_get_pgconn(self));
|
|
3600
|
+
return INT2FIX(res);
|
|
3601
|
+
}
|
|
3602
|
+
|
|
3603
|
+
|
|
3604
|
+
/*
|
|
3605
|
+
* call-seq:
|
|
3606
|
+
* conn.enter_pipeline_mode -> nil
|
|
3607
|
+
*
|
|
3608
|
+
* Causes a connection to enter pipeline mode if it is currently idle or already in pipeline mode.
|
|
3609
|
+
*
|
|
3610
|
+
* 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.
|
|
3611
|
+
* This function does not actually send anything to the server, it just changes the libpq connection state.
|
|
3612
|
+
*
|
|
3613
|
+
* Available since PostgreSQL-14
|
|
3614
|
+
*/
|
|
3615
|
+
static VALUE
|
|
3616
|
+
pgconn_enter_pipeline_mode(VALUE self)
|
|
3617
|
+
{
|
|
3618
|
+
PGconn *conn = pg_get_pgconn(self);
|
|
3619
|
+
int res = PQenterPipelineMode(conn);
|
|
3620
|
+
if( res != 1 )
|
|
3621
|
+
pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(conn));
|
|
3622
|
+
|
|
3623
|
+
return Qnil;
|
|
3624
|
+
}
|
|
3625
|
+
|
|
3626
|
+
/*
|
|
3627
|
+
* call-seq:
|
|
3628
|
+
* conn.exit_pipeline_mode -> nil
|
|
3629
|
+
*
|
|
3630
|
+
* Causes a connection to exit pipeline mode if it is currently in pipeline mode with an empty queue and no pending results.
|
|
3631
|
+
*
|
|
3632
|
+
* Takes no action if not in pipeline mode.
|
|
3633
|
+
* 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.
|
|
3634
|
+
*
|
|
3635
|
+
* Available since PostgreSQL-14
|
|
3636
|
+
*/
|
|
3637
|
+
static VALUE
|
|
3638
|
+
pgconn_exit_pipeline_mode(VALUE self)
|
|
3639
|
+
{
|
|
3640
|
+
PGconn *conn = pg_get_pgconn(self);
|
|
3641
|
+
int res = PQexitPipelineMode(conn);
|
|
3642
|
+
if( res != 1 )
|
|
3643
|
+
pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(conn));
|
|
3644
|
+
|
|
3645
|
+
return Qnil;
|
|
3646
|
+
}
|
|
3647
|
+
|
|
3648
|
+
|
|
3649
|
+
/*
|
|
3650
|
+
* call-seq:
|
|
3651
|
+
* conn.pipeline_sync -> nil
|
|
3652
|
+
*
|
|
3653
|
+
* Marks a synchronization point in a pipeline by sending a sync message and flushing the send buffer.
|
|
3654
|
+
* This serves as the delimiter of an implicit transaction and an error recovery point; see Section 34.5.1.3 of the PostgreSQL documentation.
|
|
3655
|
+
*
|
|
3656
|
+
* Raises PG::Error if the connection is not in pipeline mode or sending a sync message failed.
|
|
3657
|
+
*
|
|
3658
|
+
* Available since PostgreSQL-14
|
|
3659
|
+
*/
|
|
3660
|
+
static VALUE
|
|
3661
|
+
pgconn_pipeline_sync(VALUE self)
|
|
3662
|
+
{
|
|
3663
|
+
PGconn *conn = pg_get_pgconn(self);
|
|
3664
|
+
int res = PQpipelineSync(conn);
|
|
3665
|
+
if( res != 1 )
|
|
3666
|
+
pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(conn));
|
|
3667
|
+
|
|
3668
|
+
return Qnil;
|
|
3669
|
+
}
|
|
3670
|
+
|
|
3671
|
+
/*
|
|
3672
|
+
* call-seq:
|
|
3673
|
+
* conn.pipeline_sync -> nil
|
|
3674
|
+
*
|
|
3675
|
+
* Sends a request for the server to flush its output buffer.
|
|
3676
|
+
*
|
|
3677
|
+
* 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.
|
|
3678
|
+
* This function is useful to cause the server to flush its output buffer in pipeline mode without establishing a synchronization point.
|
|
3679
|
+
* Note that the request is not itself flushed to the server automatically; use Connection#flush if necessary.
|
|
3680
|
+
*
|
|
3681
|
+
* Available since PostgreSQL-14
|
|
3682
|
+
*/
|
|
3683
|
+
static VALUE
|
|
3684
|
+
pgconn_send_flush_request(VALUE self)
|
|
3685
|
+
{
|
|
3686
|
+
PGconn *conn = pg_get_pgconn(self);
|
|
3687
|
+
int res = PQsendFlushRequest(conn);
|
|
3688
|
+
if( res != 1 )
|
|
3689
|
+
pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(conn));
|
|
3690
|
+
|
|
3691
|
+
return Qnil;
|
|
3692
|
+
}
|
|
3693
|
+
|
|
3694
|
+
#endif
|
|
3695
|
+
|
|
3460
3696
|
/**************************************************************************
|
|
3461
3697
|
* LARGE OBJECT SUPPORT
|
|
3462
3698
|
**************************************************************************/
|
|
3463
3699
|
|
|
3700
|
+
#define BLOCKING_BEGIN(conn) do { \
|
|
3701
|
+
int old_nonblocking = PQisnonblocking(conn); \
|
|
3702
|
+
PQsetnonblocking(conn, 0);
|
|
3703
|
+
|
|
3704
|
+
#define BLOCKING_END(th) \
|
|
3705
|
+
PQsetnonblocking(conn, old_nonblocking); \
|
|
3706
|
+
} while(0);
|
|
3707
|
+
|
|
3464
3708
|
/*
|
|
3465
3709
|
* call-seq:
|
|
3466
3710
|
* conn.lo_creat( [mode] ) -> Integer
|
|
@@ -3481,9 +3725,12 @@ pgconn_locreat(int argc, VALUE *argv, VALUE self)
|
|
|
3481
3725
|
else
|
|
3482
3726
|
mode = NUM2INT(nmode);
|
|
3483
3727
|
|
|
3484
|
-
|
|
3728
|
+
BLOCKING_BEGIN(conn)
|
|
3729
|
+
lo_oid = lo_creat(conn, mode);
|
|
3730
|
+
BLOCKING_END(conn)
|
|
3731
|
+
|
|
3485
3732
|
if (lo_oid == 0)
|
|
3486
|
-
|
|
3733
|
+
pg_raise_conn_error( rb_ePGerror, self, "lo_creat failed");
|
|
3487
3734
|
|
|
3488
3735
|
return UINT2NUM(lo_oid);
|
|
3489
3736
|
}
|
|
@@ -3504,7 +3751,7 @@ pgconn_locreate(VALUE self, VALUE in_lo_oid)
|
|
|
3504
3751
|
|
|
3505
3752
|
ret = lo_create(conn, lo_oid);
|
|
3506
3753
|
if (ret == InvalidOid)
|
|
3507
|
-
|
|
3754
|
+
pg_raise_conn_error( rb_ePGerror, self, "lo_create failed");
|
|
3508
3755
|
|
|
3509
3756
|
return UINT2NUM(ret);
|
|
3510
3757
|
}
|
|
@@ -3526,9 +3773,12 @@ pgconn_loimport(VALUE self, VALUE filename)
|
|
|
3526
3773
|
|
|
3527
3774
|
Check_Type(filename, T_STRING);
|
|
3528
3775
|
|
|
3529
|
-
|
|
3776
|
+
BLOCKING_BEGIN(conn)
|
|
3777
|
+
lo_oid = lo_import(conn, StringValueCStr(filename));
|
|
3778
|
+
BLOCKING_END(conn)
|
|
3779
|
+
|
|
3530
3780
|
if (lo_oid == 0) {
|
|
3531
|
-
|
|
3781
|
+
pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(conn));
|
|
3532
3782
|
}
|
|
3533
3783
|
return UINT2NUM(lo_oid);
|
|
3534
3784
|
}
|
|
@@ -3544,12 +3794,17 @@ pgconn_loexport(VALUE self, VALUE lo_oid, VALUE filename)
|
|
|
3544
3794
|
{
|
|
3545
3795
|
PGconn *conn = pg_get_pgconn(self);
|
|
3546
3796
|
Oid oid;
|
|
3797
|
+
int ret;
|
|
3547
3798
|
Check_Type(filename, T_STRING);
|
|
3548
3799
|
|
|
3549
3800
|
oid = NUM2UINT(lo_oid);
|
|
3550
3801
|
|
|
3551
|
-
|
|
3552
|
-
|
|
3802
|
+
BLOCKING_BEGIN(conn)
|
|
3803
|
+
ret = lo_export(conn, oid, StringValueCStr(filename));
|
|
3804
|
+
BLOCKING_END(conn)
|
|
3805
|
+
|
|
3806
|
+
if (ret < 0) {
|
|
3807
|
+
pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(conn));
|
|
3553
3808
|
}
|
|
3554
3809
|
return Qnil;
|
|
3555
3810
|
}
|
|
@@ -3579,8 +3834,12 @@ pgconn_loopen(int argc, VALUE *argv, VALUE self)
|
|
|
3579
3834
|
else
|
|
3580
3835
|
mode = NUM2INT(nmode);
|
|
3581
3836
|
|
|
3582
|
-
|
|
3583
|
-
|
|
3837
|
+
BLOCKING_BEGIN(conn)
|
|
3838
|
+
fd = lo_open(conn, lo_oid, mode);
|
|
3839
|
+
BLOCKING_END(conn)
|
|
3840
|
+
|
|
3841
|
+
if(fd < 0) {
|
|
3842
|
+
pg_raise_conn_error( rb_ePGerror, self, "can't open large object: %s", PQerrorMessage(conn));
|
|
3584
3843
|
}
|
|
3585
3844
|
return INT2FIX(fd);
|
|
3586
3845
|
}
|
|
@@ -3602,11 +3861,15 @@ pgconn_lowrite(VALUE self, VALUE in_lo_desc, VALUE buffer)
|
|
|
3602
3861
|
Check_Type(buffer, T_STRING);
|
|
3603
3862
|
|
|
3604
3863
|
if( RSTRING_LEN(buffer) < 0) {
|
|
3605
|
-
|
|
3864
|
+
pg_raise_conn_error( rb_ePGerror, self, "write buffer zero string");
|
|
3606
3865
|
}
|
|
3607
|
-
|
|
3608
|
-
|
|
3609
|
-
|
|
3866
|
+
BLOCKING_BEGIN(conn)
|
|
3867
|
+
n = lo_write(conn, fd, StringValuePtr(buffer),
|
|
3868
|
+
RSTRING_LEN(buffer));
|
|
3869
|
+
BLOCKING_END(conn)
|
|
3870
|
+
|
|
3871
|
+
if(n < 0) {
|
|
3872
|
+
pg_raise_conn_error( rb_ePGerror, self, "lo_write failed: %s", PQerrorMessage(conn));
|
|
3610
3873
|
}
|
|
3611
3874
|
|
|
3612
3875
|
return INT2FIX(n);
|
|
@@ -3629,16 +3892,17 @@ pgconn_loread(VALUE self, VALUE in_lo_desc, VALUE in_len)
|
|
|
3629
3892
|
VALUE str;
|
|
3630
3893
|
char *buffer;
|
|
3631
3894
|
|
|
3632
|
-
|
|
3633
|
-
|
|
3634
|
-
rb_raise(rb_eNoMemError, "ALLOC failed!");
|
|
3895
|
+
if (len < 0)
|
|
3896
|
+
pg_raise_conn_error( rb_ePGerror, self, "negative length %d given", len);
|
|
3635
3897
|
|
|
3636
|
-
|
|
3637
|
-
|
|
3638
|
-
|
|
3898
|
+
buffer = ALLOC_N(char, len);
|
|
3899
|
+
|
|
3900
|
+
BLOCKING_BEGIN(conn)
|
|
3901
|
+
ret = lo_read(conn, lo_desc, buffer, len);
|
|
3902
|
+
BLOCKING_END(conn)
|
|
3639
3903
|
|
|
3640
|
-
if(
|
|
3641
|
-
|
|
3904
|
+
if(ret < 0)
|
|
3905
|
+
pg_raise_conn_error( rb_ePGerror, self, "lo_read failed");
|
|
3642
3906
|
|
|
3643
3907
|
if(ret == 0) {
|
|
3644
3908
|
xfree(buffer);
|
|
@@ -3667,8 +3931,12 @@ pgconn_lolseek(VALUE self, VALUE in_lo_desc, VALUE offset, VALUE whence)
|
|
|
3667
3931
|
int lo_desc = NUM2INT(in_lo_desc);
|
|
3668
3932
|
int ret;
|
|
3669
3933
|
|
|
3670
|
-
|
|
3671
|
-
|
|
3934
|
+
BLOCKING_BEGIN(conn)
|
|
3935
|
+
ret = lo_lseek(conn, lo_desc, NUM2INT(offset), NUM2INT(whence));
|
|
3936
|
+
BLOCKING_END(conn)
|
|
3937
|
+
|
|
3938
|
+
if(ret < 0) {
|
|
3939
|
+
pg_raise_conn_error( rb_ePGerror, self, "lo_lseek failed");
|
|
3672
3940
|
}
|
|
3673
3941
|
|
|
3674
3942
|
return INT2FIX(ret);
|
|
@@ -3687,8 +3955,12 @@ pgconn_lotell(VALUE self, VALUE in_lo_desc)
|
|
|
3687
3955
|
PGconn *conn = pg_get_pgconn(self);
|
|
3688
3956
|
int lo_desc = NUM2INT(in_lo_desc);
|
|
3689
3957
|
|
|
3690
|
-
|
|
3691
|
-
|
|
3958
|
+
BLOCKING_BEGIN(conn)
|
|
3959
|
+
position = lo_tell(conn, lo_desc);
|
|
3960
|
+
BLOCKING_END(conn)
|
|
3961
|
+
|
|
3962
|
+
if(position < 0)
|
|
3963
|
+
pg_raise_conn_error( rb_ePGerror, self, "lo_tell failed");
|
|
3692
3964
|
|
|
3693
3965
|
return INT2FIX(position);
|
|
3694
3966
|
}
|
|
@@ -3705,9 +3977,14 @@ pgconn_lotruncate(VALUE self, VALUE in_lo_desc, VALUE in_len)
|
|
|
3705
3977
|
PGconn *conn = pg_get_pgconn(self);
|
|
3706
3978
|
int lo_desc = NUM2INT(in_lo_desc);
|
|
3707
3979
|
size_t len = NUM2INT(in_len);
|
|
3980
|
+
int ret;
|
|
3981
|
+
|
|
3982
|
+
BLOCKING_BEGIN(conn)
|
|
3983
|
+
ret = lo_truncate(conn,lo_desc,len);
|
|
3984
|
+
BLOCKING_END(conn)
|
|
3708
3985
|
|
|
3709
|
-
if(
|
|
3710
|
-
|
|
3986
|
+
if(ret < 0)
|
|
3987
|
+
pg_raise_conn_error( rb_ePGerror, self, "lo_truncate failed");
|
|
3711
3988
|
|
|
3712
3989
|
return Qnil;
|
|
3713
3990
|
}
|
|
@@ -3723,9 +4000,14 @@ pgconn_loclose(VALUE self, VALUE in_lo_desc)
|
|
|
3723
4000
|
{
|
|
3724
4001
|
PGconn *conn = pg_get_pgconn(self);
|
|
3725
4002
|
int lo_desc = NUM2INT(in_lo_desc);
|
|
4003
|
+
int ret;
|
|
4004
|
+
|
|
4005
|
+
BLOCKING_BEGIN(conn)
|
|
4006
|
+
ret = lo_close(conn,lo_desc);
|
|
4007
|
+
BLOCKING_END(conn)
|
|
3726
4008
|
|
|
3727
|
-
if(
|
|
3728
|
-
|
|
4009
|
+
if(ret < 0)
|
|
4010
|
+
pg_raise_conn_error( rb_ePGerror, self, "lo_close failed");
|
|
3729
4011
|
|
|
3730
4012
|
return Qnil;
|
|
3731
4013
|
}
|
|
@@ -3741,9 +4023,14 @@ pgconn_lounlink(VALUE self, VALUE in_oid)
|
|
|
3741
4023
|
{
|
|
3742
4024
|
PGconn *conn = pg_get_pgconn(self);
|
|
3743
4025
|
Oid oid = NUM2UINT(in_oid);
|
|
4026
|
+
int ret;
|
|
4027
|
+
|
|
4028
|
+
BLOCKING_BEGIN(conn)
|
|
4029
|
+
ret = lo_unlink(conn,oid);
|
|
4030
|
+
BLOCKING_END(conn)
|
|
3744
4031
|
|
|
3745
|
-
if(
|
|
3746
|
-
|
|
4032
|
+
if(ret < 0)
|
|
4033
|
+
pg_raise_conn_error( rb_ePGerror, self, "lo_unlink failed");
|
|
3747
4034
|
|
|
3748
4035
|
return Qnil;
|
|
3749
4036
|
}
|
|
@@ -3800,12 +4087,13 @@ static VALUE pgconn_external_encoding(VALUE self);
|
|
|
3800
4087
|
static VALUE
|
|
3801
4088
|
pgconn_internal_encoding_set(VALUE self, VALUE enc)
|
|
3802
4089
|
{
|
|
4090
|
+
rb_check_frozen(self);
|
|
3803
4091
|
if (NIL_P(enc)) {
|
|
3804
|
-
|
|
4092
|
+
pgconn_sync_set_client_encoding( self, rb_usascii_str_new_cstr("SQL_ASCII") );
|
|
3805
4093
|
return enc;
|
|
3806
4094
|
}
|
|
3807
4095
|
else if ( TYPE(enc) == T_STRING && strcasecmp("JOHAB", StringValueCStr(enc)) == 0 ) {
|
|
3808
|
-
|
|
4096
|
+
pgconn_sync_set_client_encoding(self, rb_usascii_str_new_cstr("JOHAB"));
|
|
3809
4097
|
return enc;
|
|
3810
4098
|
}
|
|
3811
4099
|
else {
|
|
@@ -3843,16 +4131,34 @@ pgconn_external_encoding(VALUE self)
|
|
|
3843
4131
|
return rb_enc_from_encoding( enc );
|
|
3844
4132
|
}
|
|
3845
4133
|
|
|
4134
|
+
/*
|
|
4135
|
+
* call-seq:
|
|
4136
|
+
* conn.set_client_encoding( encoding )
|
|
4137
|
+
*
|
|
4138
|
+
* Sets the client encoding to the _encoding_ String.
|
|
4139
|
+
*/
|
|
4140
|
+
static VALUE
|
|
4141
|
+
pgconn_async_set_client_encoding(VALUE self, VALUE encname)
|
|
4142
|
+
{
|
|
4143
|
+
VALUE query_format, query;
|
|
4144
|
+
|
|
4145
|
+
rb_check_frozen(self);
|
|
4146
|
+
Check_Type(encname, T_STRING);
|
|
4147
|
+
query_format = rb_str_new_cstr("set client_encoding to '%s'");
|
|
4148
|
+
query = rb_funcall(query_format, rb_intern("%"), 1, encname);
|
|
4149
|
+
|
|
4150
|
+
pgconn_async_exec(1, &query, self);
|
|
4151
|
+
pgconn_set_internal_encoding_index( self );
|
|
4152
|
+
|
|
4153
|
+
return Qnil;
|
|
4154
|
+
}
|
|
3846
4155
|
|
|
3847
4156
|
static VALUE
|
|
3848
4157
|
pgconn_set_client_encoding_async1( VALUE args )
|
|
3849
4158
|
{
|
|
3850
4159
|
VALUE self = ((VALUE*)args)[0];
|
|
3851
4160
|
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);
|
|
4161
|
+
pgconn_async_set_client_encoding(self, encname);
|
|
3856
4162
|
return 0;
|
|
3857
4163
|
}
|
|
3858
4164
|
|
|
@@ -3867,9 +4173,9 @@ pgconn_set_client_encoding_async2( VALUE arg, VALUE ex )
|
|
|
3867
4173
|
|
|
3868
4174
|
|
|
3869
4175
|
static VALUE
|
|
3870
|
-
pgconn_set_client_encoding_async( VALUE self,
|
|
4176
|
+
pgconn_set_client_encoding_async( VALUE self, VALUE encname )
|
|
3871
4177
|
{
|
|
3872
|
-
VALUE args[] = { self,
|
|
4178
|
+
VALUE args[] = { self, encname };
|
|
3873
4179
|
return rb_rescue(pgconn_set_client_encoding_async1, (VALUE)&args, pgconn_set_client_encoding_async2, Qnil);
|
|
3874
4180
|
}
|
|
3875
4181
|
|
|
@@ -3886,16 +4192,23 @@ static VALUE
|
|
|
3886
4192
|
pgconn_set_default_encoding( VALUE self )
|
|
3887
4193
|
{
|
|
3888
4194
|
PGconn *conn = pg_get_pgconn( self );
|
|
3889
|
-
rb_encoding *
|
|
3890
|
-
|
|
3891
|
-
|
|
3892
|
-
if ((
|
|
3893
|
-
|
|
3894
|
-
|
|
3895
|
-
|
|
3896
|
-
|
|
4195
|
+
rb_encoding *rb_enc;
|
|
4196
|
+
|
|
4197
|
+
rb_check_frozen(self);
|
|
4198
|
+
if (( rb_enc = rb_default_internal_encoding() )) {
|
|
4199
|
+
rb_encoding * conn_encoding = pg_conn_enc_get( conn );
|
|
4200
|
+
|
|
4201
|
+
/* Don't set the server encoding, if it's unnecessary.
|
|
4202
|
+
* This is important for connection proxies, who disallow configuration settings.
|
|
4203
|
+
*/
|
|
4204
|
+
if ( conn_encoding != rb_enc ) {
|
|
4205
|
+
const char *encname = pg_get_rb_encoding_as_pg_encoding( rb_enc );
|
|
4206
|
+
if ( pgconn_set_client_encoding_async(self, rb_str_new_cstr(encname)) != 0 )
|
|
4207
|
+
rb_warning( "Failed to set the default_internal encoding to %s: '%s'",
|
|
4208
|
+
encname, PQerrorMessage(conn) );
|
|
4209
|
+
}
|
|
3897
4210
|
pgconn_set_internal_encoding_index( self );
|
|
3898
|
-
return rb_enc_from_encoding(
|
|
4211
|
+
return rb_enc_from_encoding( rb_enc );
|
|
3899
4212
|
} else {
|
|
3900
4213
|
pgconn_set_internal_encoding_index( self );
|
|
3901
4214
|
return Qnil;
|
|
@@ -3916,13 +4229,14 @@ static VALUE
|
|
|
3916
4229
|
pgconn_type_map_for_queries_set(VALUE self, VALUE typemap)
|
|
3917
4230
|
{
|
|
3918
4231
|
t_pg_connection *this = pg_get_connection( self );
|
|
4232
|
+
t_typemap *tm;
|
|
4233
|
+
UNUSED(tm);
|
|
3919
4234
|
|
|
3920
|
-
|
|
3921
|
-
|
|
3922
|
-
|
|
3923
|
-
|
|
3924
|
-
|
|
3925
|
-
this->type_map_for_queries = typemap;
|
|
4235
|
+
rb_check_frozen(self);
|
|
4236
|
+
/* Check type of method param */
|
|
4237
|
+
TypedData_Get_Struct(typemap, t_typemap, &pg_typemap_type, tm);
|
|
4238
|
+
|
|
4239
|
+
RB_OBJ_WRITE(self, &this->type_map_for_queries, typemap);
|
|
3926
4240
|
|
|
3927
4241
|
return typemap;
|
|
3928
4242
|
}
|
|
@@ -3956,13 +4270,12 @@ static VALUE
|
|
|
3956
4270
|
pgconn_type_map_for_results_set(VALUE self, VALUE typemap)
|
|
3957
4271
|
{
|
|
3958
4272
|
t_pg_connection *this = pg_get_connection( self );
|
|
4273
|
+
t_typemap *tm;
|
|
4274
|
+
UNUSED(tm);
|
|
3959
4275
|
|
|
3960
|
-
|
|
3961
|
-
|
|
3962
|
-
|
|
3963
|
-
}
|
|
3964
|
-
Check_Type(typemap, T_DATA);
|
|
3965
|
-
this->type_map_for_results = typemap;
|
|
4276
|
+
rb_check_frozen(self);
|
|
4277
|
+
TypedData_Get_Struct(typemap, t_typemap, &pg_typemap_type, tm);
|
|
4278
|
+
RB_OBJ_WRITE(self, &this->type_map_for_results, typemap);
|
|
3966
4279
|
|
|
3967
4280
|
return typemap;
|
|
3968
4281
|
}
|
|
@@ -3996,20 +4309,20 @@ pgconn_type_map_for_results_get(VALUE self)
|
|
|
3996
4309
|
*
|
|
3997
4310
|
*/
|
|
3998
4311
|
static VALUE
|
|
3999
|
-
pgconn_encoder_for_put_copy_data_set(VALUE self, VALUE
|
|
4312
|
+
pgconn_encoder_for_put_copy_data_set(VALUE self, VALUE encoder)
|
|
4000
4313
|
{
|
|
4001
4314
|
t_pg_connection *this = pg_get_connection( self );
|
|
4002
4315
|
|
|
4003
|
-
|
|
4004
|
-
|
|
4005
|
-
|
|
4006
|
-
|
|
4007
|
-
|
|
4008
|
-
|
|
4316
|
+
rb_check_frozen(self);
|
|
4317
|
+
if( encoder != Qnil ){
|
|
4318
|
+
t_pg_coder *co;
|
|
4319
|
+
UNUSED(co);
|
|
4320
|
+
/* Check argument type */
|
|
4321
|
+
TypedData_Get_Struct(encoder, t_pg_coder, &pg_coder_type, co);
|
|
4009
4322
|
}
|
|
4010
|
-
this->encoder_for_put_copy_data
|
|
4323
|
+
RB_OBJ_WRITE(self, &this->encoder_for_put_copy_data, encoder);
|
|
4011
4324
|
|
|
4012
|
-
return
|
|
4325
|
+
return encoder;
|
|
4013
4326
|
}
|
|
4014
4327
|
|
|
4015
4328
|
/*
|
|
@@ -4045,20 +4358,20 @@ pgconn_encoder_for_put_copy_data_get(VALUE self)
|
|
|
4045
4358
|
*
|
|
4046
4359
|
*/
|
|
4047
4360
|
static VALUE
|
|
4048
|
-
pgconn_decoder_for_get_copy_data_set(VALUE self, VALUE
|
|
4361
|
+
pgconn_decoder_for_get_copy_data_set(VALUE self, VALUE decoder)
|
|
4049
4362
|
{
|
|
4050
4363
|
t_pg_connection *this = pg_get_connection( self );
|
|
4051
4364
|
|
|
4052
|
-
|
|
4053
|
-
|
|
4054
|
-
|
|
4055
|
-
|
|
4056
|
-
|
|
4057
|
-
|
|
4365
|
+
rb_check_frozen(self);
|
|
4366
|
+
if( decoder != Qnil ){
|
|
4367
|
+
t_pg_coder *co;
|
|
4368
|
+
UNUSED(co);
|
|
4369
|
+
/* Check argument type */
|
|
4370
|
+
TypedData_Get_Struct(decoder, t_pg_coder, &pg_coder_type, co);
|
|
4058
4371
|
}
|
|
4059
|
-
this->decoder_for_get_copy_data
|
|
4372
|
+
RB_OBJ_WRITE(self, &this->decoder_for_get_copy_data, decoder);
|
|
4060
4373
|
|
|
4061
|
-
return
|
|
4374
|
+
return decoder;
|
|
4062
4375
|
}
|
|
4063
4376
|
|
|
4064
4377
|
/*
|
|
@@ -4102,6 +4415,7 @@ pgconn_field_name_type_set(VALUE self, VALUE sym)
|
|
|
4102
4415
|
{
|
|
4103
4416
|
t_pg_connection *this = pg_get_connection( self );
|
|
4104
4417
|
|
|
4418
|
+
rb_check_frozen(self);
|
|
4105
4419
|
this->flags &= ~PG_RESULT_FIELD_NAMES_MASK;
|
|
4106
4420
|
if( sym == sym_symbol ) this->flags |= PG_RESULT_FIELD_NAMES_SYMBOL;
|
|
4107
4421
|
else if ( sym == sym_static_symbol ) this->flags |= PG_RESULT_FIELD_NAMES_STATIC_SYMBOL;
|
|
@@ -4138,9 +4452,10 @@ pgconn_field_name_type_get(VALUE self)
|
|
|
4138
4452
|
* Document-class: PG::Connection
|
|
4139
4453
|
*/
|
|
4140
4454
|
void
|
|
4141
|
-
init_pg_connection()
|
|
4455
|
+
init_pg_connection(void)
|
|
4142
4456
|
{
|
|
4143
4457
|
s_id_encode = rb_intern("encode");
|
|
4458
|
+
s_id_autoclose_set = rb_intern("autoclose=");
|
|
4144
4459
|
sym_type = ID2SYM(rb_intern("type"));
|
|
4145
4460
|
sym_format = ID2SYM(rb_intern("format"));
|
|
4146
4461
|
sym_value = ID2SYM(rb_intern("value"));
|
|
@@ -4156,10 +4471,6 @@ init_pg_connection()
|
|
|
4156
4471
|
/****** PG::Connection CLASS METHODS ******/
|
|
4157
4472
|
rb_define_alloc_func( rb_cPGconn, pgconn_s_allocate );
|
|
4158
4473
|
|
|
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
4474
|
rb_define_singleton_method(rb_cPGconn, "escape_string", pgconn_s_escape, 1);
|
|
4164
4475
|
SINGLETON_ALIAS(rb_cPGconn, "escape", "escape_string");
|
|
4165
4476
|
rb_define_singleton_method(rb_cPGconn, "escape_bytea", pgconn_s_escape_bytea, 1);
|
|
@@ -4168,15 +4479,17 @@ init_pg_connection()
|
|
|
4168
4479
|
rb_define_singleton_method(rb_cPGconn, "quote_ident", pgconn_s_quote_ident, 1);
|
|
4169
4480
|
rb_define_singleton_method(rb_cPGconn, "connect_start", pgconn_s_connect_start, -1);
|
|
4170
4481
|
rb_define_singleton_method(rb_cPGconn, "conndefaults", pgconn_s_conndefaults, 0);
|
|
4171
|
-
rb_define_singleton_method(rb_cPGconn, "
|
|
4482
|
+
rb_define_singleton_method(rb_cPGconn, "conninfo_parse", pgconn_s_conninfo_parse, 1);
|
|
4483
|
+
rb_define_singleton_method(rb_cPGconn, "sync_ping", pgconn_s_sync_ping, -1);
|
|
4484
|
+
rb_define_singleton_method(rb_cPGconn, "sync_connect", pgconn_s_sync_connect, -1);
|
|
4172
4485
|
|
|
4173
4486
|
/****** PG::Connection INSTANCE METHODS: Connection Control ******/
|
|
4174
|
-
rb_define_method(rb_cPGconn, "initialize", pgconn_init, -1);
|
|
4175
4487
|
rb_define_method(rb_cPGconn, "connect_poll", pgconn_connect_poll, 0);
|
|
4176
4488
|
rb_define_method(rb_cPGconn, "finish", pgconn_finish, 0);
|
|
4177
4489
|
rb_define_method(rb_cPGconn, "finished?", pgconn_finished_p, 0);
|
|
4178
|
-
rb_define_method(rb_cPGconn, "
|
|
4490
|
+
rb_define_method(rb_cPGconn, "sync_reset", pgconn_sync_reset, 0);
|
|
4179
4491
|
rb_define_method(rb_cPGconn, "reset_start", pgconn_reset_start, 0);
|
|
4492
|
+
rb_define_private_method(rb_cPGconn, "reset_start2", pgconn_reset_start2, 1);
|
|
4180
4493
|
rb_define_method(rb_cPGconn, "reset_poll", pgconn_reset_poll, 0);
|
|
4181
4494
|
rb_define_alias(rb_cPGconn, "close", "finish");
|
|
4182
4495
|
|
|
@@ -4185,11 +4498,12 @@ init_pg_connection()
|
|
|
4185
4498
|
rb_define_method(rb_cPGconn, "user", pgconn_user, 0);
|
|
4186
4499
|
rb_define_method(rb_cPGconn, "pass", pgconn_pass, 0);
|
|
4187
4500
|
rb_define_method(rb_cPGconn, "host", pgconn_host, 0);
|
|
4501
|
+
#if defined(HAVE_PQRESULTMEMORYSIZE)
|
|
4502
|
+
rb_define_method(rb_cPGconn, "hostaddr", pgconn_hostaddr, 0);
|
|
4503
|
+
#endif
|
|
4188
4504
|
rb_define_method(rb_cPGconn, "port", pgconn_port, 0);
|
|
4189
4505
|
rb_define_method(rb_cPGconn, "tty", pgconn_tty, 0);
|
|
4190
|
-
#ifdef HAVE_PQCONNINFO
|
|
4191
4506
|
rb_define_method(rb_cPGconn, "conninfo", pgconn_conninfo, 0);
|
|
4192
|
-
#endif
|
|
4193
4507
|
rb_define_method(rb_cPGconn, "options", pgconn_options, 0);
|
|
4194
4508
|
rb_define_method(rb_cPGconn, "status", pgconn_status, 0);
|
|
4195
4509
|
rb_define_method(rb_cPGconn, "transaction_status", pgconn_transaction_status, 0);
|
|
@@ -4200,17 +4514,18 @@ init_pg_connection()
|
|
|
4200
4514
|
rb_define_method(rb_cPGconn, "socket", pgconn_socket, 0);
|
|
4201
4515
|
rb_define_method(rb_cPGconn, "socket_io", pgconn_socket_io, 0);
|
|
4202
4516
|
rb_define_method(rb_cPGconn, "backend_pid", pgconn_backend_pid, 0);
|
|
4517
|
+
rb_define_method(rb_cPGconn, "backend_key", pgconn_backend_key, 0);
|
|
4203
4518
|
rb_define_method(rb_cPGconn, "connection_needs_password", pgconn_connection_needs_password, 0);
|
|
4204
4519
|
rb_define_method(rb_cPGconn, "connection_used_password", pgconn_connection_used_password, 0);
|
|
4205
4520
|
/* rb_define_method(rb_cPGconn, "getssl", pgconn_getssl, 0); */
|
|
4206
4521
|
|
|
4207
4522
|
/****** 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",
|
|
4523
|
+
rb_define_method(rb_cPGconn, "sync_exec", pgconn_sync_exec, -1);
|
|
4524
|
+
rb_define_method(rb_cPGconn, "sync_exec_params", pgconn_sync_exec_params, -1);
|
|
4525
|
+
rb_define_method(rb_cPGconn, "sync_prepare", pgconn_sync_prepare, -1);
|
|
4526
|
+
rb_define_method(rb_cPGconn, "sync_exec_prepared", pgconn_sync_exec_prepared, -1);
|
|
4527
|
+
rb_define_method(rb_cPGconn, "sync_describe_prepared", pgconn_sync_describe_prepared, 1);
|
|
4528
|
+
rb_define_method(rb_cPGconn, "sync_describe_portal", pgconn_sync_describe_portal, 1);
|
|
4214
4529
|
|
|
4215
4530
|
rb_define_method(rb_cPGconn, "exec", pgconn_async_exec, -1);
|
|
4216
4531
|
rb_define_method(rb_cPGconn, "exec_params", pgconn_async_exec_params, -1);
|
|
@@ -4243,25 +4558,26 @@ init_pg_connection()
|
|
|
4243
4558
|
rb_define_method(rb_cPGconn, "send_query_prepared", pgconn_send_query_prepared, -1);
|
|
4244
4559
|
rb_define_method(rb_cPGconn, "send_describe_prepared", pgconn_send_describe_prepared, 1);
|
|
4245
4560
|
rb_define_method(rb_cPGconn, "send_describe_portal", pgconn_send_describe_portal, 1);
|
|
4246
|
-
rb_define_method(rb_cPGconn, "
|
|
4561
|
+
rb_define_method(rb_cPGconn, "sync_get_result", pgconn_sync_get_result, 0);
|
|
4247
4562
|
rb_define_method(rb_cPGconn, "consume_input", pgconn_consume_input, 0);
|
|
4248
4563
|
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",
|
|
4564
|
+
rb_define_method(rb_cPGconn, "sync_setnonblocking", pgconn_sync_setnonblocking, 1);
|
|
4565
|
+
rb_define_method(rb_cPGconn, "sync_isnonblocking", pgconn_sync_isnonblocking, 0);
|
|
4566
|
+
rb_define_method(rb_cPGconn, "sync_flush", pgconn_sync_flush, 0);
|
|
4567
|
+
rb_define_method(rb_cPGconn, "flush", pgconn_async_flush, 0);
|
|
4568
|
+
rb_define_alias(rb_cPGconn, "async_flush", "flush");
|
|
4253
4569
|
rb_define_method(rb_cPGconn, "discard_results", pgconn_discard_results, 0);
|
|
4254
4570
|
|
|
4255
4571
|
/****** PG::Connection INSTANCE METHODS: Cancelling Queries in Progress ******/
|
|
4256
|
-
rb_define_method(rb_cPGconn, "
|
|
4572
|
+
rb_define_method(rb_cPGconn, "sync_cancel", pgconn_sync_cancel, 0);
|
|
4257
4573
|
|
|
4258
4574
|
/****** PG::Connection INSTANCE METHODS: NOTIFY ******/
|
|
4259
4575
|
rb_define_method(rb_cPGconn, "notifies", pgconn_notifies, 0);
|
|
4260
4576
|
|
|
4261
4577
|
/****** PG::Connection INSTANCE METHODS: COPY ******/
|
|
4262
|
-
rb_define_method(rb_cPGconn, "
|
|
4263
|
-
rb_define_method(rb_cPGconn, "
|
|
4264
|
-
rb_define_method(rb_cPGconn, "
|
|
4578
|
+
rb_define_method(rb_cPGconn, "sync_put_copy_data", pgconn_sync_put_copy_data, -1);
|
|
4579
|
+
rb_define_method(rb_cPGconn, "sync_put_copy_end", pgconn_sync_put_copy_end, -1);
|
|
4580
|
+
rb_define_method(rb_cPGconn, "sync_get_copy_data", pgconn_sync_get_copy_data, -1);
|
|
4265
4581
|
|
|
4266
4582
|
/****** PG::Connection INSTANCE METHODS: Control Functions ******/
|
|
4267
4583
|
rb_define_method(rb_cPGconn, "set_error_verbosity", pgconn_set_error_verbosity, 1);
|
|
@@ -4277,16 +4593,20 @@ init_pg_connection()
|
|
|
4277
4593
|
|
|
4278
4594
|
/****** PG::Connection INSTANCE METHODS: Other ******/
|
|
4279
4595
|
rb_define_method(rb_cPGconn, "get_client_encoding", pgconn_get_client_encoding, 0);
|
|
4280
|
-
rb_define_method(rb_cPGconn, "
|
|
4596
|
+
rb_define_method(rb_cPGconn, "sync_set_client_encoding", pgconn_sync_set_client_encoding, 1);
|
|
4597
|
+
rb_define_method(rb_cPGconn, "set_client_encoding", pgconn_async_set_client_encoding, 1);
|
|
4598
|
+
rb_define_alias(rb_cPGconn, "async_set_client_encoding", "set_client_encoding");
|
|
4281
4599
|
rb_define_alias(rb_cPGconn, "client_encoding=", "set_client_encoding");
|
|
4282
|
-
rb_define_method(rb_cPGconn, "transaction", pgconn_transaction, 0);
|
|
4283
4600
|
rb_define_method(rb_cPGconn, "block", pgconn_block, -1);
|
|
4601
|
+
rb_define_private_method(rb_cPGconn, "flush_data=", pgconn_flush_data_set, 1);
|
|
4284
4602
|
rb_define_method(rb_cPGconn, "wait_for_notify", pgconn_wait_for_notify, -1);
|
|
4285
4603
|
rb_define_alias(rb_cPGconn, "notifies_wait", "wait_for_notify");
|
|
4286
4604
|
rb_define_method(rb_cPGconn, "quote_ident", pgconn_s_quote_ident, 1);
|
|
4287
|
-
rb_define_method(rb_cPGconn, "
|
|
4605
|
+
rb_define_method(rb_cPGconn, "sync_get_last_result", pgconn_sync_get_last_result, 0);
|
|
4606
|
+
rb_define_method(rb_cPGconn, "get_last_result", pgconn_async_get_last_result, 0);
|
|
4607
|
+
rb_define_alias(rb_cPGconn, "async_get_last_result", "get_last_result");
|
|
4288
4608
|
#ifdef HAVE_PQENCRYPTPASSWORDCONN
|
|
4289
|
-
rb_define_method(rb_cPGconn, "
|
|
4609
|
+
rb_define_method(rb_cPGconn, "sync_encrypt_password", pgconn_sync_encrypt_password, -1);
|
|
4290
4610
|
#endif
|
|
4291
4611
|
|
|
4292
4612
|
#ifdef HAVE_PQSSLATTRIBUTE
|
|
@@ -4295,6 +4615,14 @@ init_pg_connection()
|
|
|
4295
4615
|
rb_define_method(rb_cPGconn, "ssl_attribute_names", pgconn_ssl_attribute_names, 0);
|
|
4296
4616
|
#endif
|
|
4297
4617
|
|
|
4618
|
+
#ifdef HAVE_PQENTERPIPELINEMODE
|
|
4619
|
+
rb_define_method(rb_cPGconn, "pipeline_status", pgconn_pipeline_status, 0);
|
|
4620
|
+
rb_define_method(rb_cPGconn, "enter_pipeline_mode", pgconn_enter_pipeline_mode, 0);
|
|
4621
|
+
rb_define_method(rb_cPGconn, "exit_pipeline_mode", pgconn_exit_pipeline_mode, 0);
|
|
4622
|
+
rb_define_method(rb_cPGconn, "pipeline_sync", pgconn_pipeline_sync, 0);
|
|
4623
|
+
rb_define_method(rb_cPGconn, "send_flush_request", pgconn_send_flush_request, 0);
|
|
4624
|
+
#endif
|
|
4625
|
+
|
|
4298
4626
|
/****** PG::Connection INSTANCE METHODS: Large Object Support ******/
|
|
4299
4627
|
rb_define_method(rb_cPGconn, "lo_creat", pgconn_locreat, -1);
|
|
4300
4628
|
rb_define_alias(rb_cPGconn, "locreat", "lo_creat");
|