pg 1.2.3 → 1.5.3
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 +137 -0
- data/.gitignore +22 -0
- data/.hgsigs +34 -0
- data/.hgtags +41 -0
- data/.irbrc +23 -0
- data/.pryrc +23 -0
- data/.tm_properties +21 -0
- data/.travis.yml +49 -0
- data/Gemfile +14 -0
- data/History.md +876 -0
- data/Manifest.txt +0 -1
- data/README.ja.md +276 -0
- data/README.md +286 -0
- data/Rakefile +33 -135
- data/Rakefile.cross +12 -13
- data/certs/ged.pem +24 -0
- data/certs/larskanis-2022.pem +26 -0
- data/certs/larskanis-2023.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 +100 -25
- data/ext/gvl_wrappers.c +4 -0
- data/ext/gvl_wrappers.h +23 -0
- data/ext/pg.c +72 -57
- data/ext/pg.h +28 -4
- 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 +996 -697
- 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 +198 -0
- data/lib/pg/basic_type_map_for_results.rb +104 -0
- data/lib/pg/basic_type_registry.rb +299 -0
- data/lib/pg/binary_decoder/date.rb +9 -0
- data/lib/pg/binary_decoder/timestamp.rb +26 -0
- data/lib/pg/binary_encoder/timestamp.rb +20 -0
- data/lib/pg/coder.rb +15 -13
- data/lib/pg/connection.rb +743 -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/translation/.po4a-version +7 -0
- data/translation/po/all.pot +910 -0
- data/translation/po/ja.po +1047 -0
- data/translation/po4a.cfg +12 -0
- data.tar.gz.sig +0 -0
- metadata +142 -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,15 +555,8 @@ 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) );
|
|
@@ -589,7 +578,7 @@ pgconn_reset_start(VALUE self)
|
|
|
589
578
|
{
|
|
590
579
|
pgconn_close_socket_io( self );
|
|
591
580
|
if(gvl_PQresetStart(pg_get_pgconn(self)) == 0)
|
|
592
|
-
|
|
581
|
+
pg_raise_conn_error( rb_eUnableToSend, self, "reset has failed");
|
|
593
582
|
return Qnil;
|
|
594
583
|
}
|
|
595
584
|
|
|
@@ -606,6 +595,9 @@ pgconn_reset_poll(VALUE self)
|
|
|
606
595
|
{
|
|
607
596
|
PostgresPollingStatusType status;
|
|
608
597
|
status = gvl_PQresetPoll(pg_get_pgconn(self));
|
|
598
|
+
|
|
599
|
+
pgconn_close_socket_io(self);
|
|
600
|
+
|
|
609
601
|
return INT2FIX((int)status);
|
|
610
602
|
}
|
|
611
603
|
|
|
@@ -656,7 +648,18 @@ pgconn_pass(VALUE self)
|
|
|
656
648
|
* call-seq:
|
|
657
649
|
* conn.host()
|
|
658
650
|
*
|
|
659
|
-
* Returns the
|
|
651
|
+
* Returns the server host name of the active connection.
|
|
652
|
+
* This can be a host name, an IP address, or a directory path if the connection is via Unix socket.
|
|
653
|
+
* (The path case can be distinguished because it will always be an absolute path, beginning with +/+ .)
|
|
654
|
+
*
|
|
655
|
+
* If the connection parameters specified both host and hostaddr, then +host+ will return the host information.
|
|
656
|
+
* If only hostaddr was specified, then that is returned.
|
|
657
|
+
* If multiple hosts were specified in the connection parameters, +host+ returns the host actually connected to.
|
|
658
|
+
*
|
|
659
|
+
* If there is an error producing the host information (perhaps if the connection has not been fully established or there was an error), it returns an empty string.
|
|
660
|
+
*
|
|
661
|
+
* If multiple hosts were specified in the connection parameters, it is not possible to rely on the result of +host+ until the connection is established.
|
|
662
|
+
* The status of the connection can be checked using the function Connection#status .
|
|
660
663
|
*/
|
|
661
664
|
static VALUE
|
|
662
665
|
pgconn_host(VALUE self)
|
|
@@ -666,6 +669,26 @@ pgconn_host(VALUE self)
|
|
|
666
669
|
return rb_str_new2(host);
|
|
667
670
|
}
|
|
668
671
|
|
|
672
|
+
/* PQhostaddr() appeared in PostgreSQL-12 together with PQresultMemorySize() */
|
|
673
|
+
#if defined(HAVE_PQRESULTMEMORYSIZE)
|
|
674
|
+
/*
|
|
675
|
+
* call-seq:
|
|
676
|
+
* conn.hostaddr()
|
|
677
|
+
*
|
|
678
|
+
* Returns the server IP address of the active connection.
|
|
679
|
+
* This can be the address that a host name resolved to, or an IP address provided through the hostaddr parameter.
|
|
680
|
+
* If there is an error producing the host information (perhaps if the connection has not been fully established or there was an error), it returns an empty string.
|
|
681
|
+
*
|
|
682
|
+
*/
|
|
683
|
+
static VALUE
|
|
684
|
+
pgconn_hostaddr(VALUE self)
|
|
685
|
+
{
|
|
686
|
+
char *host = PQhostaddr(pg_get_pgconn(self));
|
|
687
|
+
if (!host) return Qnil;
|
|
688
|
+
return rb_str_new2(host);
|
|
689
|
+
}
|
|
690
|
+
#endif
|
|
691
|
+
|
|
669
692
|
/*
|
|
670
693
|
* call-seq:
|
|
671
694
|
* conn.port()
|
|
@@ -676,21 +699,22 @@ static VALUE
|
|
|
676
699
|
pgconn_port(VALUE self)
|
|
677
700
|
{
|
|
678
701
|
char* port = PQport(pg_get_pgconn(self));
|
|
679
|
-
|
|
702
|
+
if (!port || port[0] == '\0')
|
|
703
|
+
return INT2NUM(DEF_PGPORT);
|
|
704
|
+
else
|
|
705
|
+
return INT2NUM(atoi(port));
|
|
680
706
|
}
|
|
681
707
|
|
|
682
708
|
/*
|
|
683
709
|
* call-seq:
|
|
684
710
|
* conn.tty()
|
|
685
711
|
*
|
|
686
|
-
*
|
|
712
|
+
* Obsolete function.
|
|
687
713
|
*/
|
|
688
714
|
static VALUE
|
|
689
715
|
pgconn_tty(VALUE self)
|
|
690
716
|
{
|
|
691
|
-
|
|
692
|
-
if (!tty) return Qnil;
|
|
693
|
-
return rb_str_new2(tty);
|
|
717
|
+
return rb_str_new2("");
|
|
694
718
|
}
|
|
695
719
|
|
|
696
720
|
/*
|
|
@@ -708,7 +732,6 @@ pgconn_options(VALUE self)
|
|
|
708
732
|
}
|
|
709
733
|
|
|
710
734
|
|
|
711
|
-
#ifdef HAVE_PQCONNINFO
|
|
712
735
|
/*
|
|
713
736
|
* call-seq:
|
|
714
737
|
* conn.conninfo -> hash
|
|
@@ -728,14 +751,24 @@ pgconn_conninfo( VALUE self )
|
|
|
728
751
|
|
|
729
752
|
return array;
|
|
730
753
|
}
|
|
731
|
-
#endif
|
|
732
754
|
|
|
733
755
|
|
|
734
756
|
/*
|
|
735
757
|
* call-seq:
|
|
736
758
|
* conn.status()
|
|
737
759
|
*
|
|
738
|
-
* Returns status of connection
|
|
760
|
+
* Returns the status of the connection, which is one:
|
|
761
|
+
* PG::Constants::CONNECTION_OK
|
|
762
|
+
* PG::Constants::CONNECTION_BAD
|
|
763
|
+
*
|
|
764
|
+
* ... and other constants of kind PG::Constants::CONNECTION_*
|
|
765
|
+
*
|
|
766
|
+
* This method returns the status of the last command from memory.
|
|
767
|
+
* It doesn't do any socket access hence is not suitable to test the connectivity.
|
|
768
|
+
* See check_socket for a way to verify the socket state.
|
|
769
|
+
*
|
|
770
|
+
* Example:
|
|
771
|
+
* PG.constants.grep(/CONNECTION_/).find{|c| PG.const_get(c) == conn.status} # => :CONNECTION_OK
|
|
739
772
|
*/
|
|
740
773
|
static VALUE
|
|
741
774
|
pgconn_status(VALUE self)
|
|
@@ -823,7 +856,10 @@ pgconn_server_version(VALUE self)
|
|
|
823
856
|
* call-seq:
|
|
824
857
|
* conn.error_message -> String
|
|
825
858
|
*
|
|
826
|
-
* Returns the error message
|
|
859
|
+
* Returns the error message most recently generated by an operation on the connection.
|
|
860
|
+
*
|
|
861
|
+
* Nearly all libpq functions will set a message for conn.error_message if they fail.
|
|
862
|
+
* Note that by libpq convention, a nonempty error_message result can consist of multiple lines, and will include a trailing newline.
|
|
827
863
|
*/
|
|
828
864
|
static VALUE
|
|
829
865
|
pgconn_error_message(VALUE self)
|
|
@@ -857,7 +893,8 @@ pgconn_socket(VALUE self)
|
|
|
857
893
|
pg_deprecated(4, ("conn.socket is deprecated and should be replaced by conn.socket_io"));
|
|
858
894
|
|
|
859
895
|
if( (sd = PQsocket(pg_get_pgconn(self))) < 0)
|
|
860
|
-
|
|
896
|
+
pg_raise_conn_error( rb_eConnectionBad, self, "PQsocket() can't get socket descriptor");
|
|
897
|
+
|
|
861
898
|
return INT2NUM(sd);
|
|
862
899
|
}
|
|
863
900
|
|
|
@@ -865,40 +902,47 @@ pgconn_socket(VALUE self)
|
|
|
865
902
|
* call-seq:
|
|
866
903
|
* conn.socket_io() -> IO
|
|
867
904
|
*
|
|
868
|
-
* Fetch
|
|
869
|
-
* This object can be used for IO.select to wait for events while running
|
|
870
|
-
*
|
|
905
|
+
* Fetch an IO object created from the Connection's underlying socket.
|
|
906
|
+
* This object can be used per <tt>socket_io.wait_readable</tt>, <tt>socket_io.wait_writable</tt> or for <tt>IO.select</tt> to wait for events while running asynchronous API calls.
|
|
907
|
+
* <tt>IO#wait_*able</tt> is is <tt>Fiber.scheduler</tt> compatible in contrast to <tt>IO.select</tt>.
|
|
908
|
+
*
|
|
909
|
+
* The IO object can change while the connection is established, but is memorized afterwards.
|
|
910
|
+
* So be sure not to cache the IO object, but repeat calling <tt>conn.socket_io</tt> instead.
|
|
871
911
|
*
|
|
872
|
-
* Using this
|
|
873
|
-
* being closed by Ruby when an IO created using <tt>IO.for_fd(conn.socket)</tt>
|
|
874
|
-
* goes out of scope. In contrast to #socket, it also works on Windows.
|
|
912
|
+
* Using this method also works on Windows in contrast to using #socket .
|
|
913
|
+
* It also avoids the problem of the underlying connection being closed by Ruby when an IO created using <tt>IO.for_fd(conn.socket)</tt> goes out of scope.
|
|
875
914
|
*/
|
|
876
915
|
static VALUE
|
|
877
916
|
pgconn_socket_io(VALUE self)
|
|
878
917
|
{
|
|
879
918
|
int sd;
|
|
880
919
|
int ruby_sd;
|
|
881
|
-
ID id_autoclose = rb_intern("autoclose=");
|
|
882
920
|
t_pg_connection *this = pg_get_connection_safe( self );
|
|
921
|
+
VALUE cSocket;
|
|
883
922
|
VALUE socket_io = this->socket_io;
|
|
884
923
|
|
|
885
924
|
if ( !RTEST(socket_io) ) {
|
|
886
|
-
if( (sd = PQsocket(this->pgconn)) < 0)
|
|
887
|
-
|
|
925
|
+
if( (sd = PQsocket(this->pgconn)) < 0){
|
|
926
|
+
pg_raise_conn_error( rb_eConnectionBad, self, "PQsocket() can't get socket descriptor");
|
|
927
|
+
}
|
|
888
928
|
|
|
889
929
|
#ifdef _WIN32
|
|
890
930
|
ruby_sd = rb_w32_wrap_io_handle((HANDLE)(intptr_t)sd, O_RDWR|O_BINARY|O_NOINHERIT);
|
|
931
|
+
if( ruby_sd == -1 )
|
|
932
|
+
pg_raise_conn_error( rb_eConnectionBad, self, "Could not wrap win32 socket handle");
|
|
933
|
+
|
|
891
934
|
this->ruby_sd = ruby_sd;
|
|
892
935
|
#else
|
|
893
936
|
ruby_sd = sd;
|
|
894
937
|
#endif
|
|
895
938
|
|
|
896
|
-
|
|
939
|
+
cSocket = rb_const_get(rb_cObject, rb_intern("BasicSocket"));
|
|
940
|
+
socket_io = rb_funcall( cSocket, rb_intern("for_fd"), 1, INT2NUM(ruby_sd));
|
|
897
941
|
|
|
898
942
|
/* Disable autoclose feature */
|
|
899
|
-
rb_funcall( socket_io,
|
|
943
|
+
rb_funcall( socket_io, s_id_autoclose_set, 1, Qfalse );
|
|
900
944
|
|
|
901
|
-
this->socket_io
|
|
945
|
+
RB_OBJ_WRITE(self, &this->socket_io, socket_io);
|
|
902
946
|
}
|
|
903
947
|
|
|
904
948
|
return socket_io;
|
|
@@ -918,6 +962,51 @@ pgconn_backend_pid(VALUE self)
|
|
|
918
962
|
return INT2NUM(PQbackendPID(pg_get_pgconn(self)));
|
|
919
963
|
}
|
|
920
964
|
|
|
965
|
+
typedef struct
|
|
966
|
+
{
|
|
967
|
+
struct sockaddr_storage addr;
|
|
968
|
+
socklen_t salen;
|
|
969
|
+
} SockAddr;
|
|
970
|
+
|
|
971
|
+
/* Copy of struct pg_cancel from libpq-int.h
|
|
972
|
+
*
|
|
973
|
+
* See https://github.com/postgres/postgres/blame/master/src/interfaces/libpq/libpq-int.h#L577-L586
|
|
974
|
+
*/
|
|
975
|
+
struct pg_cancel
|
|
976
|
+
{
|
|
977
|
+
SockAddr raddr; /* Remote address */
|
|
978
|
+
int be_pid; /* PID of backend --- needed for cancels */
|
|
979
|
+
int be_key; /* key of backend --- needed for cancels */
|
|
980
|
+
};
|
|
981
|
+
|
|
982
|
+
/*
|
|
983
|
+
* call-seq:
|
|
984
|
+
* conn.backend_key() -> Integer
|
|
985
|
+
*
|
|
986
|
+
* Returns the key of the backend server process for this connection.
|
|
987
|
+
* This key can be used to cancel queries on the server.
|
|
988
|
+
*/
|
|
989
|
+
static VALUE
|
|
990
|
+
pgconn_backend_key(VALUE self)
|
|
991
|
+
{
|
|
992
|
+
int be_key;
|
|
993
|
+
struct pg_cancel *cancel;
|
|
994
|
+
PGconn *conn = pg_get_pgconn(self);
|
|
995
|
+
|
|
996
|
+
cancel = (struct pg_cancel*)PQgetCancel(conn);
|
|
997
|
+
if(cancel == NULL)
|
|
998
|
+
pg_raise_conn_error( rb_ePGerror, self, "Invalid connection!");
|
|
999
|
+
|
|
1000
|
+
if( cancel->be_pid != PQbackendPID(conn) )
|
|
1001
|
+
rb_raise(rb_ePGerror,"Unexpected binary struct layout - please file a bug report at ruby-pg!");
|
|
1002
|
+
|
|
1003
|
+
be_key = cancel->be_key;
|
|
1004
|
+
|
|
1005
|
+
PQfreeCancel(cancel);
|
|
1006
|
+
|
|
1007
|
+
return INT2NUM(be_key);
|
|
1008
|
+
}
|
|
1009
|
+
|
|
921
1010
|
/*
|
|
922
1011
|
* call-seq:
|
|
923
1012
|
* conn.connection_needs_password() -> Boolean
|
|
@@ -948,7 +1037,7 @@ pgconn_connection_used_password(VALUE self)
|
|
|
948
1037
|
/* :TODO: get_ssl */
|
|
949
1038
|
|
|
950
1039
|
|
|
951
|
-
static VALUE
|
|
1040
|
+
static VALUE pgconn_sync_exec_params( int, VALUE *, VALUE );
|
|
952
1041
|
|
|
953
1042
|
/*
|
|
954
1043
|
* call-seq:
|
|
@@ -962,11 +1051,11 @@ static VALUE pgconn_exec_params( int, VALUE *, VALUE );
|
|
|
962
1051
|
* However #async_exec has two advantages:
|
|
963
1052
|
*
|
|
964
1053
|
* 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
|
-
*
|
|
1054
|
+
* 2. Ruby VM gets notified about IO blocked operations and can pass them through <tt>Fiber.scheduler</tt>.
|
|
1055
|
+
* So only <tt>async_*</tt> methods are compatible to event based schedulers like the async gem.
|
|
967
1056
|
*/
|
|
968
1057
|
static VALUE
|
|
969
|
-
|
|
1058
|
+
pgconn_sync_exec(int argc, VALUE *argv, VALUE self)
|
|
970
1059
|
{
|
|
971
1060
|
t_pg_connection *this = pg_get_connection_safe( self );
|
|
972
1061
|
PGresult *result = NULL;
|
|
@@ -987,7 +1076,7 @@ pgconn_exec(int argc, VALUE *argv, VALUE self)
|
|
|
987
1076
|
pg_deprecated(0, ("forwarding exec to exec_params is deprecated"));
|
|
988
1077
|
|
|
989
1078
|
/* Otherwise, just call #exec_params instead for backward-compatibility */
|
|
990
|
-
return
|
|
1079
|
+
return pgconn_sync_exec_params( argc, argv, self );
|
|
991
1080
|
|
|
992
1081
|
}
|
|
993
1082
|
|
|
@@ -1019,7 +1108,7 @@ struct query_params_data {
|
|
|
1019
1108
|
* Filled by alloc_query_params()
|
|
1020
1109
|
*/
|
|
1021
1110
|
|
|
1022
|
-
/* Wraps the pointer of allocated memory, if function parameters
|
|
1111
|
+
/* Wraps the pointer of allocated memory, if function parameters don't
|
|
1023
1112
|
* fit in the memory_pool below.
|
|
1024
1113
|
*/
|
|
1025
1114
|
VALUE heap_pool;
|
|
@@ -1037,7 +1126,7 @@ struct query_params_data {
|
|
|
1037
1126
|
Oid *types;
|
|
1038
1127
|
|
|
1039
1128
|
/* This array takes the string values for the timeframe of the query,
|
|
1040
|
-
* if param value
|
|
1129
|
+
* if param value conversion is required
|
|
1041
1130
|
*/
|
|
1042
1131
|
VALUE gc_array;
|
|
1043
1132
|
|
|
@@ -1051,8 +1140,9 @@ struct query_params_data {
|
|
|
1051
1140
|
};
|
|
1052
1141
|
|
|
1053
1142
|
static void
|
|
1054
|
-
free_typecast_heap_chain(
|
|
1143
|
+
free_typecast_heap_chain(void *_chain_entry)
|
|
1055
1144
|
{
|
|
1145
|
+
struct linked_typecast_data *chain_entry = (struct linked_typecast_data *)_chain_entry;
|
|
1056
1146
|
while(chain_entry){
|
|
1057
1147
|
struct linked_typecast_data *next = chain_entry->next;
|
|
1058
1148
|
xfree(chain_entry);
|
|
@@ -1060,6 +1150,18 @@ free_typecast_heap_chain(struct linked_typecast_data *chain_entry)
|
|
|
1060
1150
|
}
|
|
1061
1151
|
}
|
|
1062
1152
|
|
|
1153
|
+
static const rb_data_type_t pg_typecast_buffer_type = {
|
|
1154
|
+
"PG::Connection typecast buffer chain",
|
|
1155
|
+
{
|
|
1156
|
+
(RUBY_DATA_FUNC) NULL,
|
|
1157
|
+
free_typecast_heap_chain,
|
|
1158
|
+
(size_t (*)(const void *))NULL,
|
|
1159
|
+
},
|
|
1160
|
+
0,
|
|
1161
|
+
0,
|
|
1162
|
+
RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
|
|
1163
|
+
};
|
|
1164
|
+
|
|
1063
1165
|
static char *
|
|
1064
1166
|
alloc_typecast_buf( VALUE *typecast_heap_chain, int len )
|
|
1065
1167
|
{
|
|
@@ -1070,17 +1172,28 @@ alloc_typecast_buf( VALUE *typecast_heap_chain, int len )
|
|
|
1070
1172
|
/* Did we already wrap a memory chain per T_DATA object? */
|
|
1071
1173
|
if( NIL_P( *typecast_heap_chain ) ){
|
|
1072
1174
|
/* Leave free'ing of the buffer chain to the GC, when paramsData has left the stack */
|
|
1073
|
-
*typecast_heap_chain =
|
|
1175
|
+
*typecast_heap_chain = TypedData_Wrap_Struct( rb_cObject, &pg_typecast_buffer_type, allocated );
|
|
1074
1176
|
allocated->next = NULL;
|
|
1075
1177
|
} else {
|
|
1076
1178
|
/* Append to the chain */
|
|
1077
|
-
allocated->next =
|
|
1078
|
-
|
|
1179
|
+
allocated->next = RTYPEDDATA_DATA( *typecast_heap_chain );
|
|
1180
|
+
RTYPEDDATA_DATA( *typecast_heap_chain ) = allocated;
|
|
1079
1181
|
}
|
|
1080
1182
|
|
|
1081
1183
|
return &allocated->data[0];
|
|
1082
1184
|
}
|
|
1083
1185
|
|
|
1186
|
+
static const rb_data_type_t pg_query_heap_pool_type = {
|
|
1187
|
+
"PG::Connection query heap pool",
|
|
1188
|
+
{
|
|
1189
|
+
(RUBY_DATA_FUNC) NULL,
|
|
1190
|
+
RUBY_TYPED_DEFAULT_FREE,
|
|
1191
|
+
(size_t (*)(const void *))NULL,
|
|
1192
|
+
},
|
|
1193
|
+
0,
|
|
1194
|
+
0,
|
|
1195
|
+
RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
|
|
1196
|
+
};
|
|
1084
1197
|
|
|
1085
1198
|
static int
|
|
1086
1199
|
alloc_query_params(struct query_params_data *paramsData)
|
|
@@ -1095,7 +1208,7 @@ alloc_query_params(struct query_params_data *paramsData)
|
|
|
1095
1208
|
|
|
1096
1209
|
Check_Type(paramsData->params, T_ARRAY);
|
|
1097
1210
|
|
|
1098
|
-
p_typemap =
|
|
1211
|
+
p_typemap = RTYPEDDATA_DATA( paramsData->typemap );
|
|
1099
1212
|
p_typemap->funcs.fit_to_query( paramsData->typemap, paramsData->params );
|
|
1100
1213
|
|
|
1101
1214
|
paramsData->heap_pool = Qnil;
|
|
@@ -1114,7 +1227,7 @@ alloc_query_params(struct query_params_data *paramsData)
|
|
|
1114
1227
|
/* Allocate one combined memory pool for all possible function parameters */
|
|
1115
1228
|
memory_pool = (char*)xmalloc( required_pool_size );
|
|
1116
1229
|
/* Leave free'ing of the buffer to the GC, when paramsData has left the stack */
|
|
1117
|
-
paramsData->heap_pool =
|
|
1230
|
+
paramsData->heap_pool = TypedData_Wrap_Struct( rb_cObject, &pg_query_heap_pool_type, memory_pool );
|
|
1118
1231
|
required_pool_size = 0;
|
|
1119
1232
|
}else{
|
|
1120
1233
|
/* Use stack memory for function parameters */
|
|
@@ -1227,12 +1340,11 @@ pgconn_query_assign_typemap( VALUE self, struct query_params_data *paramsData )
|
|
|
1227
1340
|
/* Use default typemap for queries. It's type is checked when assigned. */
|
|
1228
1341
|
paramsData->typemap = pg_get_connection(self)->type_map_for_queries;
|
|
1229
1342
|
}else{
|
|
1343
|
+
t_typemap *tm;
|
|
1344
|
+
UNUSED(tm);
|
|
1345
|
+
|
|
1230
1346
|
/* 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 );
|
|
1347
|
+
TypedData_Get_Struct(paramsData->typemap, t_typemap, &pg_typemap_type, tm);
|
|
1236
1348
|
}
|
|
1237
1349
|
}
|
|
1238
1350
|
|
|
@@ -1246,7 +1358,7 @@ pgconn_query_assign_typemap( VALUE self, struct query_params_data *paramsData )
|
|
|
1246
1358
|
* It's not recommended to use explicit sync or async variants but #exec_params instead, unless you have a good reason to do so.
|
|
1247
1359
|
*/
|
|
1248
1360
|
static VALUE
|
|
1249
|
-
|
|
1361
|
+
pgconn_sync_exec_params( int argc, VALUE *argv, VALUE self )
|
|
1250
1362
|
{
|
|
1251
1363
|
t_pg_connection *this = pg_get_connection_safe( self );
|
|
1252
1364
|
PGresult *result = NULL;
|
|
@@ -1266,7 +1378,7 @@ pgconn_exec_params( int argc, VALUE *argv, VALUE self )
|
|
|
1266
1378
|
*/
|
|
1267
1379
|
if ( NIL_P(paramsData.params) ) {
|
|
1268
1380
|
pg_deprecated(1, ("forwarding exec_params to exec is deprecated"));
|
|
1269
|
-
return
|
|
1381
|
+
return pgconn_sync_exec( 1, argv, self );
|
|
1270
1382
|
}
|
|
1271
1383
|
pgconn_query_assign_typemap( self, ¶msData );
|
|
1272
1384
|
|
|
@@ -1297,7 +1409,7 @@ pgconn_exec_params( int argc, VALUE *argv, VALUE self )
|
|
|
1297
1409
|
* It's not recommended to use explicit sync or async variants but #prepare instead, unless you have a good reason to do so.
|
|
1298
1410
|
*/
|
|
1299
1411
|
static VALUE
|
|
1300
|
-
|
|
1412
|
+
pgconn_sync_prepare(int argc, VALUE *argv, VALUE self)
|
|
1301
1413
|
{
|
|
1302
1414
|
t_pg_connection *this = pg_get_connection_safe( self );
|
|
1303
1415
|
PGresult *result = NULL;
|
|
@@ -1346,7 +1458,7 @@ pgconn_prepare(int argc, VALUE *argv, VALUE self)
|
|
|
1346
1458
|
* It's not recommended to use explicit sync or async variants but #exec_prepared instead, unless you have a good reason to do so.
|
|
1347
1459
|
*/
|
|
1348
1460
|
static VALUE
|
|
1349
|
-
|
|
1461
|
+
pgconn_sync_exec_prepared(int argc, VALUE *argv, VALUE self)
|
|
1350
1462
|
{
|
|
1351
1463
|
t_pg_connection *this = pg_get_connection_safe( self );
|
|
1352
1464
|
PGresult *result = NULL;
|
|
@@ -1391,7 +1503,7 @@ pgconn_exec_prepared(int argc, VALUE *argv, VALUE self)
|
|
|
1391
1503
|
* It's not recommended to use explicit sync or async variants but #describe_prepared instead, unless you have a good reason to do so.
|
|
1392
1504
|
*/
|
|
1393
1505
|
static VALUE
|
|
1394
|
-
|
|
1506
|
+
pgconn_sync_describe_prepared(VALUE self, VALUE stmt_name)
|
|
1395
1507
|
{
|
|
1396
1508
|
PGresult *result;
|
|
1397
1509
|
VALUE rb_pgresult;
|
|
@@ -1419,8 +1531,7 @@ pgconn_describe_prepared(VALUE self, VALUE stmt_name)
|
|
|
1419
1531
|
* It's not recommended to use explicit sync or async variants but #describe_portal instead, unless you have a good reason to do so.
|
|
1420
1532
|
*/
|
|
1421
1533
|
static VALUE
|
|
1422
|
-
|
|
1423
|
-
VALUE self, stmt_name;
|
|
1534
|
+
pgconn_sync_describe_portal(VALUE self, VALUE stmt_name)
|
|
1424
1535
|
{
|
|
1425
1536
|
PGresult *result;
|
|
1426
1537
|
VALUE rb_pgresult;
|
|
@@ -1454,6 +1565,9 @@ pgconn_describe_portal(self, stmt_name)
|
|
|
1454
1565
|
* * +PGRES_NONFATAL_ERROR+
|
|
1455
1566
|
* * +PGRES_FATAL_ERROR+
|
|
1456
1567
|
* * +PGRES_COPY_BOTH+
|
|
1568
|
+
* * +PGRES_SINGLE_TUPLE+
|
|
1569
|
+
* * +PGRES_PIPELINE_SYNC+
|
|
1570
|
+
* * +PGRES_PIPELINE_ABORTED+
|
|
1457
1571
|
*/
|
|
1458
1572
|
static VALUE
|
|
1459
1573
|
pgconn_make_empty_pgresult(VALUE self, VALUE status)
|
|
@@ -1509,9 +1623,9 @@ pgconn_s_escape(VALUE self, VALUE string)
|
|
|
1509
1623
|
if( !singleton ) {
|
|
1510
1624
|
size = PQescapeStringConn(pg_get_pgconn(self), RSTRING_PTR(result),
|
|
1511
1625
|
RSTRING_PTR(string), RSTRING_LEN(string), &error);
|
|
1512
|
-
if(error)
|
|
1513
|
-
|
|
1514
|
-
|
|
1626
|
+
if(error)
|
|
1627
|
+
pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(pg_get_pgconn(self)));
|
|
1628
|
+
|
|
1515
1629
|
} else {
|
|
1516
1630
|
size = PQescapeString(RSTRING_PTR(result), RSTRING_PTR(string), RSTRING_LEN(string));
|
|
1517
1631
|
}
|
|
@@ -1607,7 +1721,6 @@ pgconn_escape_literal(VALUE self, VALUE string)
|
|
|
1607
1721
|
{
|
|
1608
1722
|
t_pg_connection *this = pg_get_connection_safe( self );
|
|
1609
1723
|
char *escaped = NULL;
|
|
1610
|
-
VALUE error;
|
|
1611
1724
|
VALUE result = Qnil;
|
|
1612
1725
|
int enc_idx = this->enc_idx;
|
|
1613
1726
|
|
|
@@ -1618,12 +1731,8 @@ pgconn_escape_literal(VALUE self, VALUE string)
|
|
|
1618
1731
|
|
|
1619
1732
|
escaped = PQescapeLiteral(this->pgconn, RSTRING_PTR(string), RSTRING_LEN(string));
|
|
1620
1733
|
if (escaped == NULL)
|
|
1621
|
-
|
|
1622
|
-
|
|
1623
|
-
rb_iv_set(error, "@connection", self);
|
|
1624
|
-
rb_exc_raise(error);
|
|
1625
|
-
return Qnil;
|
|
1626
|
-
}
|
|
1734
|
+
pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(this->pgconn));
|
|
1735
|
+
|
|
1627
1736
|
result = rb_str_new2(escaped);
|
|
1628
1737
|
PQfreemem(escaped);
|
|
1629
1738
|
PG_ENCODING_SET_NOCHECK(result, enc_idx);
|
|
@@ -1646,7 +1755,6 @@ pgconn_escape_identifier(VALUE self, VALUE string)
|
|
|
1646
1755
|
{
|
|
1647
1756
|
t_pg_connection *this = pg_get_connection_safe( self );
|
|
1648
1757
|
char *escaped = NULL;
|
|
1649
|
-
VALUE error;
|
|
1650
1758
|
VALUE result = Qnil;
|
|
1651
1759
|
int enc_idx = this->enc_idx;
|
|
1652
1760
|
|
|
@@ -1657,12 +1765,8 @@ pgconn_escape_identifier(VALUE self, VALUE string)
|
|
|
1657
1765
|
|
|
1658
1766
|
escaped = PQescapeIdentifier(this->pgconn, RSTRING_PTR(string), RSTRING_LEN(string));
|
|
1659
1767
|
if (escaped == NULL)
|
|
1660
|
-
|
|
1661
|
-
|
|
1662
|
-
rb_iv_set(error, "@connection", self);
|
|
1663
|
-
rb_exc_raise(error);
|
|
1664
|
-
return Qnil;
|
|
1665
|
-
}
|
|
1768
|
+
pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(this->pgconn));
|
|
1769
|
+
|
|
1666
1770
|
result = rb_str_new2(escaped);
|
|
1667
1771
|
PQfreemem(escaped);
|
|
1668
1772
|
PG_ENCODING_SET_NOCHECK(result, enc_idx);
|
|
@@ -1710,14 +1814,10 @@ static VALUE
|
|
|
1710
1814
|
pgconn_set_single_row_mode(VALUE self)
|
|
1711
1815
|
{
|
|
1712
1816
|
PGconn *conn = pg_get_pgconn(self);
|
|
1713
|
-
VALUE error;
|
|
1714
1817
|
|
|
1818
|
+
rb_check_frozen(self);
|
|
1715
1819
|
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
|
-
}
|
|
1820
|
+
pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(conn));
|
|
1721
1821
|
|
|
1722
1822
|
return self;
|
|
1723
1823
|
}
|
|
@@ -1741,15 +1841,13 @@ static VALUE
|
|
|
1741
1841
|
pgconn_send_query(int argc, VALUE *argv, VALUE self)
|
|
1742
1842
|
{
|
|
1743
1843
|
t_pg_connection *this = pg_get_connection_safe( self );
|
|
1744
|
-
VALUE error;
|
|
1745
1844
|
|
|
1746
1845
|
/* If called with no or nil parameters, use PQexec for compatibility */
|
|
1747
1846
|
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
|
-
}
|
|
1847
|
+
if(gvl_PQsendQuery(this->pgconn, pg_cstr_enc(argv[0], this->enc_idx)) == 0)
|
|
1848
|
+
pg_raise_conn_error( rb_eUnableToSend, self, "%s", PQerrorMessage(this->pgconn));
|
|
1849
|
+
|
|
1850
|
+
pgconn_wait_for_flush( self );
|
|
1753
1851
|
return Qnil;
|
|
1754
1852
|
}
|
|
1755
1853
|
|
|
@@ -1779,7 +1877,7 @@ pgconn_send_query(int argc, VALUE *argv, VALUE self)
|
|
|
1779
1877
|
* or, it may be a String. If it is a string, that is equivalent to the hash:
|
|
1780
1878
|
* { :value => <string value>, :type => 0, :format => 0 }
|
|
1781
1879
|
*
|
|
1782
|
-
* PostgreSQL bind parameters are represented as $1, $
|
|
1880
|
+
* PostgreSQL bind parameters are represented as $1, $2, $3, etc.,
|
|
1783
1881
|
* inside the SQL query. The 0th element of the +params+ array is bound
|
|
1784
1882
|
* to $1, the 1st element is bound to $2, etc. +nil+ is treated as +NULL+.
|
|
1785
1883
|
*
|
|
@@ -1805,7 +1903,6 @@ pgconn_send_query_params(int argc, VALUE *argv, VALUE self)
|
|
|
1805
1903
|
t_pg_connection *this = pg_get_connection_safe( self );
|
|
1806
1904
|
int result;
|
|
1807
1905
|
VALUE command, in_res_fmt;
|
|
1808
|
-
VALUE error;
|
|
1809
1906
|
int nParams;
|
|
1810
1907
|
int resultFormat;
|
|
1811
1908
|
struct query_params_data paramsData = { this->enc_idx };
|
|
@@ -1822,11 +1919,10 @@ pgconn_send_query_params(int argc, VALUE *argv, VALUE self)
|
|
|
1822
1919
|
|
|
1823
1920
|
free_query_params( ¶msData );
|
|
1824
1921
|
|
|
1825
|
-
if(result == 0)
|
|
1826
|
-
|
|
1827
|
-
|
|
1828
|
-
|
|
1829
|
-
}
|
|
1922
|
+
if(result == 0)
|
|
1923
|
+
pg_raise_conn_error( rb_eUnableToSend, self, "%s", PQerrorMessage(this->pgconn));
|
|
1924
|
+
|
|
1925
|
+
pgconn_wait_for_flush( self );
|
|
1830
1926
|
return Qnil;
|
|
1831
1927
|
}
|
|
1832
1928
|
|
|
@@ -1847,7 +1943,7 @@ pgconn_send_query_params(int argc, VALUE *argv, VALUE self)
|
|
|
1847
1943
|
*
|
|
1848
1944
|
* For example: "SELECT $1::int"
|
|
1849
1945
|
*
|
|
1850
|
-
* PostgreSQL bind parameters are represented as $1, $
|
|
1946
|
+
* PostgreSQL bind parameters are represented as $1, $2, $3, etc.,
|
|
1851
1947
|
* inside the SQL query.
|
|
1852
1948
|
*/
|
|
1853
1949
|
static VALUE
|
|
@@ -1857,7 +1953,6 @@ pgconn_send_prepare(int argc, VALUE *argv, VALUE self)
|
|
|
1857
1953
|
int result;
|
|
1858
1954
|
VALUE name, command, in_paramtypes;
|
|
1859
1955
|
VALUE param;
|
|
1860
|
-
VALUE error;
|
|
1861
1956
|
int i = 0;
|
|
1862
1957
|
int nParams = 0;
|
|
1863
1958
|
Oid *paramTypes = NULL;
|
|
@@ -1886,10 +1981,9 @@ pgconn_send_prepare(int argc, VALUE *argv, VALUE self)
|
|
|
1886
1981
|
xfree(paramTypes);
|
|
1887
1982
|
|
|
1888
1983
|
if(result == 0) {
|
|
1889
|
-
|
|
1890
|
-
rb_iv_set(error, "@connection", self);
|
|
1891
|
-
rb_exc_raise(error);
|
|
1984
|
+
pg_raise_conn_error( rb_eUnableToSend, self, "%s", PQerrorMessage(this->pgconn));
|
|
1892
1985
|
}
|
|
1986
|
+
pgconn_wait_for_flush( self );
|
|
1893
1987
|
return Qnil;
|
|
1894
1988
|
}
|
|
1895
1989
|
|
|
@@ -1911,7 +2005,7 @@ pgconn_send_prepare(int argc, VALUE *argv, VALUE self)
|
|
|
1911
2005
|
* or, it may be a String. If it is a string, that is equivalent to the hash:
|
|
1912
2006
|
* { :value => <string value>, :format => 0 }
|
|
1913
2007
|
*
|
|
1914
|
-
* PostgreSQL bind parameters are represented as $1, $
|
|
2008
|
+
* PostgreSQL bind parameters are represented as $1, $2, $3, etc.,
|
|
1915
2009
|
* inside the SQL query. The 0th element of the +params+ array is bound
|
|
1916
2010
|
* to $1, the 1st element is bound to $2, etc. +nil+ is treated as +NULL+.
|
|
1917
2011
|
*
|
|
@@ -1931,7 +2025,6 @@ pgconn_send_query_prepared(int argc, VALUE *argv, VALUE self)
|
|
|
1931
2025
|
t_pg_connection *this = pg_get_connection_safe( self );
|
|
1932
2026
|
int result;
|
|
1933
2027
|
VALUE name, in_res_fmt;
|
|
1934
|
-
VALUE error;
|
|
1935
2028
|
int nParams;
|
|
1936
2029
|
int resultFormat;
|
|
1937
2030
|
struct query_params_data paramsData = { this->enc_idx };
|
|
@@ -1941,7 +2034,6 @@ pgconn_send_query_prepared(int argc, VALUE *argv, VALUE self)
|
|
|
1941
2034
|
|
|
1942
2035
|
if(NIL_P(paramsData.params)) {
|
|
1943
2036
|
paramsData.params = rb_ary_new2(0);
|
|
1944
|
-
resultFormat = 0;
|
|
1945
2037
|
}
|
|
1946
2038
|
pgconn_query_assign_typemap( self, ¶msData );
|
|
1947
2039
|
|
|
@@ -1954,11 +2046,10 @@ pgconn_send_query_prepared(int argc, VALUE *argv, VALUE self)
|
|
|
1954
2046
|
|
|
1955
2047
|
free_query_params( ¶msData );
|
|
1956
2048
|
|
|
1957
|
-
if(result == 0)
|
|
1958
|
-
|
|
1959
|
-
|
|
1960
|
-
|
|
1961
|
-
}
|
|
2049
|
+
if(result == 0)
|
|
2050
|
+
pg_raise_conn_error( rb_eUnableToSend, self, "%s", PQerrorMessage(this->pgconn));
|
|
2051
|
+
|
|
2052
|
+
pgconn_wait_for_flush( self );
|
|
1962
2053
|
return Qnil;
|
|
1963
2054
|
}
|
|
1964
2055
|
|
|
@@ -1972,14 +2063,12 @@ pgconn_send_query_prepared(int argc, VALUE *argv, VALUE self)
|
|
|
1972
2063
|
static VALUE
|
|
1973
2064
|
pgconn_send_describe_prepared(VALUE self, VALUE stmt_name)
|
|
1974
2065
|
{
|
|
1975
|
-
VALUE error;
|
|
1976
2066
|
t_pg_connection *this = pg_get_connection_safe( self );
|
|
1977
2067
|
/* returns 0 on failure */
|
|
1978
|
-
if(gvl_PQsendDescribePrepared(this->pgconn, pg_cstr_enc(stmt_name, this->enc_idx)) == 0)
|
|
1979
|
-
|
|
1980
|
-
|
|
1981
|
-
|
|
1982
|
-
}
|
|
2068
|
+
if(gvl_PQsendDescribePrepared(this->pgconn, pg_cstr_enc(stmt_name, this->enc_idx)) == 0)
|
|
2069
|
+
pg_raise_conn_error( rb_eUnableToSend, self, "%s", PQerrorMessage(this->pgconn));
|
|
2070
|
+
|
|
2071
|
+
pgconn_wait_for_flush( self );
|
|
1983
2072
|
return Qnil;
|
|
1984
2073
|
}
|
|
1985
2074
|
|
|
@@ -1994,36 +2083,18 @@ pgconn_send_describe_prepared(VALUE self, VALUE stmt_name)
|
|
|
1994
2083
|
static VALUE
|
|
1995
2084
|
pgconn_send_describe_portal(VALUE self, VALUE portal)
|
|
1996
2085
|
{
|
|
1997
|
-
VALUE error;
|
|
1998
2086
|
t_pg_connection *this = pg_get_connection_safe( self );
|
|
1999
2087
|
/* returns 0 on failure */
|
|
2000
|
-
if(gvl_PQsendDescribePortal(this->pgconn, pg_cstr_enc(portal, this->enc_idx)) == 0)
|
|
2001
|
-
|
|
2002
|
-
|
|
2003
|
-
|
|
2004
|
-
}
|
|
2088
|
+
if(gvl_PQsendDescribePortal(this->pgconn, pg_cstr_enc(portal, this->enc_idx)) == 0)
|
|
2089
|
+
pg_raise_conn_error( rb_eUnableToSend, self, "%s", PQerrorMessage(this->pgconn));
|
|
2090
|
+
|
|
2091
|
+
pgconn_wait_for_flush( self );
|
|
2005
2092
|
return Qnil;
|
|
2006
2093
|
}
|
|
2007
2094
|
|
|
2008
2095
|
|
|
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
2096
|
static VALUE
|
|
2026
|
-
|
|
2097
|
+
pgconn_sync_get_result(VALUE self)
|
|
2027
2098
|
{
|
|
2028
2099
|
PGconn *conn = pg_get_pgconn(self);
|
|
2029
2100
|
PGresult *result;
|
|
@@ -2049,17 +2120,15 @@ pgconn_get_result(VALUE self)
|
|
|
2049
2120
|
* or *notifies* to see if the state has changed.
|
|
2050
2121
|
*/
|
|
2051
2122
|
static VALUE
|
|
2052
|
-
pgconn_consume_input(self)
|
|
2053
|
-
VALUE self;
|
|
2123
|
+
pgconn_consume_input(VALUE self)
|
|
2054
2124
|
{
|
|
2055
|
-
VALUE error;
|
|
2056
2125
|
PGconn *conn = pg_get_pgconn(self);
|
|
2057
2126
|
/* returns 0 on error */
|
|
2058
2127
|
if(PQconsumeInput(conn) == 0) {
|
|
2059
|
-
|
|
2060
|
-
|
|
2061
|
-
rb_exc_raise(error);
|
|
2128
|
+
pgconn_close_socket_io(self);
|
|
2129
|
+
pg_raise_conn_error( rb_eConnectionBad, self, "%s", PQerrorMessage(conn));
|
|
2062
2130
|
}
|
|
2131
|
+
|
|
2063
2132
|
return Qnil;
|
|
2064
2133
|
}
|
|
2065
2134
|
|
|
@@ -2068,38 +2137,20 @@ pgconn_consume_input(self)
|
|
|
2068
2137
|
* conn.is_busy() -> Boolean
|
|
2069
2138
|
*
|
|
2070
2139
|
* Returns +true+ if a command is busy, that is, if
|
|
2071
|
-
*
|
|
2140
|
+
* #get_result would block. Otherwise returns +false+.
|
|
2072
2141
|
*/
|
|
2073
2142
|
static VALUE
|
|
2074
|
-
pgconn_is_busy(self)
|
|
2075
|
-
VALUE self;
|
|
2143
|
+
pgconn_is_busy(VALUE self)
|
|
2076
2144
|
{
|
|
2077
2145
|
return gvl_PQisBusy(pg_get_pgconn(self)) ? Qtrue : Qfalse;
|
|
2078
2146
|
}
|
|
2079
2147
|
|
|
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
2148
|
static VALUE
|
|
2097
|
-
|
|
2098
|
-
VALUE self, state;
|
|
2149
|
+
pgconn_sync_setnonblocking(VALUE self, VALUE state)
|
|
2099
2150
|
{
|
|
2100
2151
|
int arg;
|
|
2101
|
-
VALUE error;
|
|
2102
2152
|
PGconn *conn = pg_get_pgconn(self);
|
|
2153
|
+
rb_check_frozen(self);
|
|
2103
2154
|
if(state == Qtrue)
|
|
2104
2155
|
arg = 1;
|
|
2105
2156
|
else if (state == Qfalse)
|
|
@@ -2107,67 +2158,32 @@ pgconn_setnonblocking(self, state)
|
|
|
2107
2158
|
else
|
|
2108
2159
|
rb_raise(rb_eArgError, "Boolean value expected");
|
|
2109
2160
|
|
|
2110
|
-
if(PQsetnonblocking(conn, arg) == -1)
|
|
2111
|
-
|
|
2112
|
-
|
|
2113
|
-
rb_exc_raise(error);
|
|
2114
|
-
}
|
|
2161
|
+
if(PQsetnonblocking(conn, arg) == -1)
|
|
2162
|
+
pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(conn));
|
|
2163
|
+
|
|
2115
2164
|
return Qnil;
|
|
2116
2165
|
}
|
|
2117
2166
|
|
|
2118
2167
|
|
|
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
2168
|
static VALUE
|
|
2127
|
-
|
|
2128
|
-
VALUE self;
|
|
2169
|
+
pgconn_sync_isnonblocking(VALUE self)
|
|
2129
2170
|
{
|
|
2130
2171
|
return PQisnonblocking(pg_get_pgconn(self)) ? Qtrue : Qfalse;
|
|
2131
2172
|
}
|
|
2132
2173
|
|
|
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
2174
|
static VALUE
|
|
2144
|
-
|
|
2145
|
-
VALUE self;
|
|
2175
|
+
pgconn_sync_flush(VALUE self)
|
|
2146
2176
|
{
|
|
2147
2177
|
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
|
-
}
|
|
2178
|
+
int ret = PQflush(conn);
|
|
2179
|
+
if(ret == -1)
|
|
2180
|
+
pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(conn));
|
|
2181
|
+
|
|
2156
2182
|
return (ret) ? Qfalse : Qtrue;
|
|
2157
2183
|
}
|
|
2158
2184
|
|
|
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
2185
|
static VALUE
|
|
2170
|
-
|
|
2186
|
+
pgconn_sync_cancel(VALUE self)
|
|
2171
2187
|
{
|
|
2172
2188
|
char errbuf[256];
|
|
2173
2189
|
PGcancel *cancel;
|
|
@@ -2176,9 +2192,9 @@ pgconn_cancel(VALUE self)
|
|
|
2176
2192
|
|
|
2177
2193
|
cancel = PQgetCancel(pg_get_pgconn(self));
|
|
2178
2194
|
if(cancel == NULL)
|
|
2179
|
-
|
|
2195
|
+
pg_raise_conn_error( rb_ePGerror, self, "Invalid connection!");
|
|
2180
2196
|
|
|
2181
|
-
ret = gvl_PQcancel(cancel, errbuf,
|
|
2197
|
+
ret = gvl_PQcancel(cancel, errbuf, sizeof(errbuf));
|
|
2182
2198
|
if(ret == 1)
|
|
2183
2199
|
retval = Qnil;
|
|
2184
2200
|
else
|
|
@@ -2229,55 +2245,63 @@ pgconn_notifies(VALUE self)
|
|
|
2229
2245
|
return hash;
|
|
2230
2246
|
}
|
|
2231
2247
|
|
|
2232
|
-
|
|
2233
|
-
|
|
2234
|
-
/*
|
|
2235
|
-
*
|
|
2236
|
-
* instead of rb_wait_for_single_fd().
|
|
2248
|
+
#if defined(_WIN32)
|
|
2249
|
+
|
|
2250
|
+
/* We use a specialized implementation of rb_io_wait() on Windows.
|
|
2251
|
+
* This is because rb_io_wait() and rb_wait_for_single_fd() are very slow on Windows.
|
|
2237
2252
|
*/
|
|
2238
2253
|
|
|
2254
|
+
#if defined(HAVE_RUBY_FIBER_SCHEDULER_H)
|
|
2255
|
+
#include <ruby/fiber/scheduler.h>
|
|
2256
|
+
#endif
|
|
2257
|
+
|
|
2258
|
+
typedef enum {
|
|
2259
|
+
PG_RUBY_IO_READABLE = RB_WAITFD_IN,
|
|
2260
|
+
PG_RUBY_IO_WRITABLE = RB_WAITFD_OUT,
|
|
2261
|
+
PG_RUBY_IO_PRIORITY = RB_WAITFD_PRI,
|
|
2262
|
+
} pg_rb_io_event_t;
|
|
2263
|
+
|
|
2239
2264
|
int rb_w32_wait_events( HANDLE *events, int num, DWORD timeout );
|
|
2240
2265
|
|
|
2241
|
-
static
|
|
2242
|
-
|
|
2243
|
-
|
|
2244
|
-
|
|
2245
|
-
|
|
2266
|
+
static VALUE
|
|
2267
|
+
pg_rb_thread_io_wait(VALUE io, VALUE events, VALUE timeout) {
|
|
2268
|
+
rb_io_t *fptr;
|
|
2269
|
+
struct timeval ptimeout;
|
|
2270
|
+
|
|
2246
2271
|
struct timeval aborttime={0,0}, currtime, waittime;
|
|
2247
2272
|
DWORD timeout_milisec = INFINITE;
|
|
2248
|
-
|
|
2249
|
-
WSAEVENT hEvent;
|
|
2273
|
+
HANDLE hEvent = WSACreateEvent();
|
|
2250
2274
|
|
|
2251
|
-
|
|
2252
|
-
|
|
2253
|
-
|
|
2254
|
-
hEvent = WSACreateEvent();
|
|
2275
|
+
long rb_events = NUM2UINT(events);
|
|
2276
|
+
long w32_events = 0;
|
|
2277
|
+
DWORD wait_ret;
|
|
2255
2278
|
|
|
2256
|
-
|
|
2257
|
-
if(
|
|
2258
|
-
|
|
2259
|
-
|
|
2260
|
-
}
|
|
2279
|
+
GetOpenFile((io), fptr);
|
|
2280
|
+
if( !NIL_P(timeout) ){
|
|
2281
|
+
ptimeout.tv_sec = (time_t)(NUM2DBL(timeout));
|
|
2282
|
+
ptimeout.tv_usec = (time_t)((NUM2DBL(timeout) - (double)ptimeout.tv_sec) * 1e6);
|
|
2261
2283
|
|
|
2262
|
-
if ( ptimeout ) {
|
|
2263
2284
|
gettimeofday(&currtime, NULL);
|
|
2264
|
-
timeradd(&currtime, ptimeout, &aborttime);
|
|
2285
|
+
timeradd(&currtime, &ptimeout, &aborttime);
|
|
2265
2286
|
}
|
|
2266
2287
|
|
|
2267
|
-
|
|
2268
|
-
|
|
2288
|
+
if(rb_events & PG_RUBY_IO_READABLE) w32_events |= FD_READ | FD_ACCEPT | FD_CLOSE;
|
|
2289
|
+
if(rb_events & PG_RUBY_IO_WRITABLE) w32_events |= FD_WRITE | FD_CONNECT;
|
|
2290
|
+
if(rb_events & PG_RUBY_IO_PRIORITY) w32_events |= FD_OOB;
|
|
2291
|
+
|
|
2292
|
+
for(;;) {
|
|
2293
|
+
if ( WSAEventSelect(_get_osfhandle(fptr->fd), hEvent, w32_events) == SOCKET_ERROR ) {
|
|
2269
2294
|
WSACloseEvent( hEvent );
|
|
2270
2295
|
rb_raise( rb_eConnectionBad, "WSAEventSelect socket error: %d", WSAGetLastError() );
|
|
2271
2296
|
}
|
|
2272
2297
|
|
|
2273
|
-
if (
|
|
2298
|
+
if ( !NIL_P(timeout) ) {
|
|
2274
2299
|
gettimeofday(&currtime, NULL);
|
|
2275
2300
|
timersub(&aborttime, &currtime, &waittime);
|
|
2276
2301
|
timeout_milisec = (DWORD)( waittime.tv_sec * 1e3 + waittime.tv_usec / 1e3 );
|
|
2277
2302
|
}
|
|
2278
2303
|
|
|
2279
|
-
|
|
2280
|
-
if( !ptimeout || (waittime.tv_sec >= 0 && waittime.tv_usec >= 0) ){
|
|
2304
|
+
if( NIL_P(timeout) || (waittime.tv_sec >= 0 && waittime.tv_usec >= 0) ){
|
|
2281
2305
|
/* Wait for the socket to become readable before checking again */
|
|
2282
2306
|
wait_ret = rb_w32_wait_events( &hEvent, 1, timeout_milisec );
|
|
2283
2307
|
} else {
|
|
@@ -2286,9 +2310,11 @@ wait_socket_readable( PGconn *conn, struct timeval *ptimeout, void *(*is_readabl
|
|
|
2286
2310
|
|
|
2287
2311
|
if ( wait_ret == WAIT_TIMEOUT ) {
|
|
2288
2312
|
WSACloseEvent( hEvent );
|
|
2289
|
-
return
|
|
2313
|
+
return UINT2NUM(0);
|
|
2290
2314
|
} else if ( wait_ret == WAIT_OBJECT_0 ) {
|
|
2315
|
+
WSACloseEvent( hEvent );
|
|
2291
2316
|
/* The event we were waiting for. */
|
|
2317
|
+
return UINT2NUM(rb_events);
|
|
2292
2318
|
} else if ( wait_ret == WAIT_OBJECT_0 + 1) {
|
|
2293
2319
|
/* This indicates interruption from timer thread, GC, exception
|
|
2294
2320
|
* from other threads etc... */
|
|
@@ -2300,36 +2326,66 @@ wait_socket_readable( PGconn *conn, struct timeval *ptimeout, void *(*is_readabl
|
|
|
2300
2326
|
WSACloseEvent( hEvent );
|
|
2301
2327
|
rb_raise( rb_eConnectionBad, "Wait on socket abandoned (WaitForMultipleObjects)" );
|
|
2302
2328
|
}
|
|
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
2329
|
}
|
|
2330
|
+
}
|
|
2310
2331
|
|
|
2311
|
-
|
|
2312
|
-
|
|
2332
|
+
static VALUE
|
|
2333
|
+
pg_rb_io_wait(VALUE io, VALUE events, VALUE timeout) {
|
|
2334
|
+
#if defined(HAVE_RUBY_FIBER_SCHEDULER_H)
|
|
2335
|
+
/* We don't support Fiber.scheduler on Windows ruby-3.0 because there is no fast way to check whether a scheduler is active.
|
|
2336
|
+
* Fortunatelly ruby-3.1 offers a C-API for it.
|
|
2337
|
+
*/
|
|
2338
|
+
VALUE scheduler = rb_fiber_scheduler_current();
|
|
2339
|
+
|
|
2340
|
+
if (!NIL_P(scheduler)) {
|
|
2341
|
+
return rb_io_wait(io, events, timeout);
|
|
2342
|
+
}
|
|
2343
|
+
#endif
|
|
2344
|
+
return pg_rb_thread_io_wait(io, events, timeout);
|
|
2313
2345
|
}
|
|
2314
2346
|
|
|
2347
|
+
#elif defined(HAVE_RB_IO_WAIT)
|
|
2348
|
+
|
|
2349
|
+
/* Use our own function and constants names, to avoid conflicts with truffleruby-head on its road to ruby-3.0 compatibility. */
|
|
2350
|
+
#define pg_rb_io_wait rb_io_wait
|
|
2351
|
+
#define PG_RUBY_IO_READABLE RUBY_IO_READABLE
|
|
2352
|
+
#define PG_RUBY_IO_WRITABLE RUBY_IO_WRITABLE
|
|
2353
|
+
#define PG_RUBY_IO_PRIORITY RUBY_IO_PRIORITY
|
|
2354
|
+
|
|
2315
2355
|
#else
|
|
2356
|
+
/* For compat with ruby < 3.0 */
|
|
2316
2357
|
|
|
2317
|
-
|
|
2358
|
+
typedef enum {
|
|
2359
|
+
PG_RUBY_IO_READABLE = RB_WAITFD_IN,
|
|
2360
|
+
PG_RUBY_IO_WRITABLE = RB_WAITFD_OUT,
|
|
2361
|
+
PG_RUBY_IO_PRIORITY = RB_WAITFD_PRI,
|
|
2362
|
+
} pg_rb_io_event_t;
|
|
2363
|
+
|
|
2364
|
+
static VALUE
|
|
2365
|
+
pg_rb_io_wait(VALUE io, VALUE events, VALUE timeout) {
|
|
2366
|
+
rb_io_t *fptr;
|
|
2367
|
+
struct timeval waittime;
|
|
2368
|
+
int res;
|
|
2369
|
+
|
|
2370
|
+
GetOpenFile((io), fptr);
|
|
2371
|
+
if( !NIL_P(timeout) ){
|
|
2372
|
+
waittime.tv_sec = (time_t)(NUM2DBL(timeout));
|
|
2373
|
+
waittime.tv_usec = (time_t)((NUM2DBL(timeout) - (double)waittime.tv_sec) * 1e6);
|
|
2374
|
+
}
|
|
2375
|
+
res = rb_wait_for_single_fd(fptr->fd, NUM2UINT(events), NIL_P(timeout) ? NULL : &waittime);
|
|
2376
|
+
|
|
2377
|
+
return UINT2NUM(res);
|
|
2378
|
+
}
|
|
2379
|
+
#endif
|
|
2318
2380
|
|
|
2319
2381
|
static void *
|
|
2320
|
-
wait_socket_readable(
|
|
2382
|
+
wait_socket_readable( VALUE self, struct timeval *ptimeout, void *(*is_readable)(PGconn *))
|
|
2321
2383
|
{
|
|
2322
|
-
|
|
2323
|
-
int ret;
|
|
2384
|
+
VALUE ret;
|
|
2324
2385
|
void *retval;
|
|
2325
2386
|
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) );
|
|
2387
|
+
VALUE wait_timeout = Qnil;
|
|
2388
|
+
PGconn *conn = pg_get_pgconn(self);
|
|
2333
2389
|
|
|
2334
2390
|
if ( ptimeout ) {
|
|
2335
2391
|
gettimeofday(&currtime, NULL);
|
|
@@ -2340,36 +2396,81 @@ wait_socket_readable( PGconn *conn, struct timeval *ptimeout, void *(*is_readabl
|
|
|
2340
2396
|
if ( ptimeout ) {
|
|
2341
2397
|
gettimeofday(&currtime, NULL);
|
|
2342
2398
|
timersub(&aborttime, &currtime, &waittime);
|
|
2399
|
+
wait_timeout = DBL2NUM((double)(waittime.tv_sec) + (double)(waittime.tv_usec) / 1000000.0);
|
|
2343
2400
|
}
|
|
2344
2401
|
|
|
2345
2402
|
/* Is the given timeout valid? */
|
|
2346
2403
|
if( !ptimeout || (waittime.tv_sec >= 0 && waittime.tv_usec >= 0) ){
|
|
2404
|
+
VALUE socket_io;
|
|
2405
|
+
|
|
2406
|
+
/* before we wait for data, make sure everything has been sent */
|
|
2407
|
+
pgconn_async_flush(self);
|
|
2408
|
+
if ((retval=is_readable(conn)))
|
|
2409
|
+
return retval;
|
|
2410
|
+
|
|
2411
|
+
socket_io = pgconn_socket_io(self);
|
|
2347
2412
|
/* Wait for the socket to become readable before checking again */
|
|
2348
|
-
ret =
|
|
2413
|
+
ret = pg_rb_io_wait(socket_io, RB_INT2NUM(PG_RUBY_IO_READABLE), wait_timeout);
|
|
2349
2414
|
} else {
|
|
2350
|
-
ret =
|
|
2351
|
-
}
|
|
2352
|
-
|
|
2353
|
-
if ( ret < 0 ){
|
|
2354
|
-
rb_sys_fail( "rb_wait_for_single_fd()" );
|
|
2415
|
+
ret = Qfalse;
|
|
2355
2416
|
}
|
|
2356
2417
|
|
|
2357
2418
|
/* Return false if the select() timed out */
|
|
2358
|
-
if ( ret ==
|
|
2419
|
+
if ( ret == Qfalse ){
|
|
2359
2420
|
return NULL;
|
|
2360
2421
|
}
|
|
2361
2422
|
|
|
2362
2423
|
/* Check for connection errors (PQisBusy is true on connection errors) */
|
|
2363
2424
|
if ( PQconsumeInput(conn) == 0 ){
|
|
2364
|
-
|
|
2425
|
+
pgconn_close_socket_io(self);
|
|
2426
|
+
pg_raise_conn_error(rb_eConnectionBad, self, "PQconsumeInput() %s", PQerrorMessage(conn));
|
|
2365
2427
|
}
|
|
2366
2428
|
}
|
|
2367
2429
|
|
|
2368
2430
|
return retval;
|
|
2369
2431
|
}
|
|
2370
2432
|
|
|
2433
|
+
/*
|
|
2434
|
+
* call-seq:
|
|
2435
|
+
* conn.flush() -> Boolean
|
|
2436
|
+
*
|
|
2437
|
+
* Attempts to flush any queued output data to the server.
|
|
2438
|
+
* Returns +true+ if data is successfully flushed, +false+
|
|
2439
|
+
* if not. It can only return +false+ if connection is
|
|
2440
|
+
* in nonblocking mode.
|
|
2441
|
+
* Raises PG::Error if some other failure occurred.
|
|
2442
|
+
*/
|
|
2443
|
+
static VALUE
|
|
2444
|
+
pgconn_async_flush(VALUE self)
|
|
2445
|
+
{
|
|
2446
|
+
while( pgconn_sync_flush(self) == Qfalse ){
|
|
2447
|
+
/* wait for the socket to become read- or write-ready */
|
|
2448
|
+
int events;
|
|
2449
|
+
VALUE socket_io = pgconn_socket_io(self);
|
|
2450
|
+
events = RB_NUM2INT(pg_rb_io_wait(socket_io, RB_INT2NUM(PG_RUBY_IO_READABLE | PG_RUBY_IO_WRITABLE), Qnil));
|
|
2451
|
+
|
|
2452
|
+
if (events & PG_RUBY_IO_READABLE){
|
|
2453
|
+
pgconn_consume_input(self);
|
|
2454
|
+
}
|
|
2455
|
+
}
|
|
2456
|
+
return Qtrue;
|
|
2457
|
+
}
|
|
2458
|
+
|
|
2459
|
+
static VALUE
|
|
2460
|
+
pgconn_wait_for_flush( VALUE self ){
|
|
2461
|
+
if( !pg_get_connection_safe(self)->flush_data )
|
|
2462
|
+
return Qnil;
|
|
2463
|
+
|
|
2464
|
+
return pgconn_async_flush(self);
|
|
2465
|
+
}
|
|
2371
2466
|
|
|
2372
|
-
|
|
2467
|
+
static VALUE
|
|
2468
|
+
pgconn_flush_data_set( VALUE self, VALUE enabled ){
|
|
2469
|
+
t_pg_connection *conn = pg_get_connection(self);
|
|
2470
|
+
rb_check_frozen(self);
|
|
2471
|
+
conn->flush_data = RTEST(enabled);
|
|
2472
|
+
return enabled;
|
|
2473
|
+
}
|
|
2373
2474
|
|
|
2374
2475
|
static void *
|
|
2375
2476
|
notify_readable(PGconn *conn)
|
|
@@ -2408,7 +2509,7 @@ pgconn_wait_for_notify(int argc, VALUE *argv, VALUE self)
|
|
|
2408
2509
|
ptimeout = &timeout;
|
|
2409
2510
|
}
|
|
2410
2511
|
|
|
2411
|
-
pnotification = (PGnotify*) wait_socket_readable(
|
|
2512
|
+
pnotification = (PGnotify*) wait_socket_readable( self, ptimeout, notify_readable);
|
|
2412
2513
|
|
|
2413
2514
|
/* Return nil if the select timed out */
|
|
2414
2515
|
if ( !pnotification ) return Qnil;
|
|
@@ -2429,28 +2530,8 @@ pgconn_wait_for_notify(int argc, VALUE *argv, VALUE self)
|
|
|
2429
2530
|
}
|
|
2430
2531
|
|
|
2431
2532
|
|
|
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
2533
|
static VALUE
|
|
2453
|
-
|
|
2534
|
+
pgconn_sync_put_copy_data(int argc, VALUE *argv, VALUE self)
|
|
2454
2535
|
{
|
|
2455
2536
|
int ret;
|
|
2456
2537
|
int len;
|
|
@@ -2467,13 +2548,11 @@ pgconn_put_copy_data(int argc, VALUE *argv, VALUE self)
|
|
|
2467
2548
|
if( NIL_P(this->encoder_for_put_copy_data) ){
|
|
2468
2549
|
buffer = value;
|
|
2469
2550
|
} else {
|
|
2470
|
-
p_coder =
|
|
2551
|
+
p_coder = RTYPEDDATA_DATA( this->encoder_for_put_copy_data );
|
|
2471
2552
|
}
|
|
2472
|
-
} else if( rb_obj_is_kind_of(encoder, rb_cPG_Coder) ) {
|
|
2473
|
-
Data_Get_Struct( encoder, t_pg_coder, p_coder );
|
|
2474
2553
|
} else {
|
|
2475
|
-
|
|
2476
|
-
|
|
2554
|
+
/* Check argument type and use argument encoder */
|
|
2555
|
+
TypedData_Get_Struct(encoder, t_pg_coder, &pg_coder_type, p_coder);
|
|
2477
2556
|
}
|
|
2478
2557
|
|
|
2479
2558
|
if( p_coder ){
|
|
@@ -2496,36 +2575,19 @@ pgconn_put_copy_data(int argc, VALUE *argv, VALUE self)
|
|
|
2496
2575
|
Check_Type(buffer, T_STRING);
|
|
2497
2576
|
|
|
2498
2577
|
ret = gvl_PQputCopyData(this->pgconn, RSTRING_PTR(buffer), RSTRING_LENINT(buffer));
|
|
2499
|
-
if(ret == -1)
|
|
2500
|
-
|
|
2501
|
-
|
|
2502
|
-
rb_exc_raise(error);
|
|
2503
|
-
}
|
|
2578
|
+
if(ret == -1)
|
|
2579
|
+
pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(this->pgconn));
|
|
2580
|
+
|
|
2504
2581
|
RB_GC_GUARD(intermediate);
|
|
2505
2582
|
RB_GC_GUARD(buffer);
|
|
2506
2583
|
|
|
2507
2584
|
return (ret) ? Qtrue : Qfalse;
|
|
2508
2585
|
}
|
|
2509
2586
|
|
|
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
2587
|
static VALUE
|
|
2525
|
-
|
|
2588
|
+
pgconn_sync_put_copy_end(int argc, VALUE *argv, VALUE self)
|
|
2526
2589
|
{
|
|
2527
2590
|
VALUE str;
|
|
2528
|
-
VALUE error;
|
|
2529
2591
|
int ret;
|
|
2530
2592
|
const char *error_message = NULL;
|
|
2531
2593
|
t_pg_connection *this = pg_get_connection_safe( self );
|
|
@@ -2536,38 +2598,16 @@ pgconn_put_copy_end(int argc, VALUE *argv, VALUE self)
|
|
|
2536
2598
|
error_message = pg_cstr_enc(str, this->enc_idx);
|
|
2537
2599
|
|
|
2538
2600
|
ret = gvl_PQputCopyEnd(this->pgconn, error_message);
|
|
2539
|
-
if(ret == -1)
|
|
2540
|
-
|
|
2541
|
-
|
|
2542
|
-
rb_exc_raise(error);
|
|
2543
|
-
}
|
|
2601
|
+
if(ret == -1)
|
|
2602
|
+
pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(this->pgconn));
|
|
2603
|
+
|
|
2544
2604
|
return (ret) ? Qtrue : Qfalse;
|
|
2545
2605
|
}
|
|
2546
2606
|
|
|
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
2607
|
static VALUE
|
|
2567
|
-
|
|
2608
|
+
pgconn_sync_get_copy_data(int argc, VALUE *argv, VALUE self )
|
|
2568
2609
|
{
|
|
2569
2610
|
VALUE async_in;
|
|
2570
|
-
VALUE error;
|
|
2571
2611
|
VALUE result;
|
|
2572
2612
|
int ret;
|
|
2573
2613
|
char *buffer;
|
|
@@ -2579,20 +2619,16 @@ pgconn_get_copy_data(int argc, VALUE *argv, VALUE self )
|
|
|
2579
2619
|
|
|
2580
2620
|
if( NIL_P(decoder) ){
|
|
2581
2621
|
if( !NIL_P(this->decoder_for_get_copy_data) ){
|
|
2582
|
-
p_coder =
|
|
2622
|
+
p_coder = RTYPEDDATA_DATA( this->decoder_for_get_copy_data );
|
|
2583
2623
|
}
|
|
2584
|
-
} else if( rb_obj_is_kind_of(decoder, rb_cPG_Coder) ) {
|
|
2585
|
-
Data_Get_Struct( decoder, t_pg_coder, p_coder );
|
|
2586
2624
|
} else {
|
|
2587
|
-
|
|
2588
|
-
|
|
2625
|
+
/* Check argument type and use argument decoder */
|
|
2626
|
+
TypedData_Get_Struct(decoder, t_pg_coder, &pg_coder_type, p_coder);
|
|
2589
2627
|
}
|
|
2590
2628
|
|
|
2591
2629
|
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);
|
|
2630
|
+
if(ret == -2){ /* error */
|
|
2631
|
+
pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(this->pgconn));
|
|
2596
2632
|
}
|
|
2597
2633
|
if(ret == -1) { /* No data left */
|
|
2598
2634
|
return Qnil;
|
|
@@ -2686,6 +2722,7 @@ pgconn_trace(VALUE self, VALUE stream)
|
|
|
2686
2722
|
VALUE new_file;
|
|
2687
2723
|
t_pg_connection *this = pg_get_connection_safe( self );
|
|
2688
2724
|
|
|
2725
|
+
rb_check_frozen(self);
|
|
2689
2726
|
if(!rb_respond_to(stream,rb_intern("fileno")))
|
|
2690
2727
|
rb_raise(rb_eArgError, "stream does not respond to method: fileno");
|
|
2691
2728
|
|
|
@@ -2707,7 +2744,7 @@ pgconn_trace(VALUE self, VALUE stream)
|
|
|
2707
2744
|
rb_raise(rb_eArgError, "stream is not writable");
|
|
2708
2745
|
|
|
2709
2746
|
new_file = rb_funcall(rb_cIO, rb_intern("new"), 1, INT2NUM(new_fd));
|
|
2710
|
-
this->trace_stream
|
|
2747
|
+
RB_OBJ_WRITE(self, &this->trace_stream, new_file);
|
|
2711
2748
|
|
|
2712
2749
|
PQtrace(this->pgconn, new_fp);
|
|
2713
2750
|
return Qnil;
|
|
@@ -2726,7 +2763,7 @@ pgconn_untrace(VALUE self)
|
|
|
2726
2763
|
|
|
2727
2764
|
PQuntrace(this->pgconn);
|
|
2728
2765
|
rb_funcall(this->trace_stream, rb_intern("close"), 0);
|
|
2729
|
-
this->trace_stream
|
|
2766
|
+
RB_OBJ_WRITE(self, &this->trace_stream, Qnil);
|
|
2730
2767
|
return Qnil;
|
|
2731
2768
|
}
|
|
2732
2769
|
|
|
@@ -2785,13 +2822,14 @@ pgconn_set_notice_receiver(VALUE self)
|
|
|
2785
2822
|
VALUE proc, old_proc;
|
|
2786
2823
|
t_pg_connection *this = pg_get_connection_safe( self );
|
|
2787
2824
|
|
|
2825
|
+
rb_check_frozen(self);
|
|
2788
2826
|
/* If default_notice_receiver is unset, assume that the current
|
|
2789
2827
|
* notice receiver is the default, and save it to a global variable.
|
|
2790
2828
|
* This should not be a problem because the default receiver is
|
|
2791
2829
|
* always the same, so won't vary among connections.
|
|
2792
2830
|
*/
|
|
2793
|
-
if(default_notice_receiver == NULL)
|
|
2794
|
-
default_notice_receiver = PQsetNoticeReceiver(this->pgconn, NULL, NULL);
|
|
2831
|
+
if(this->default_notice_receiver == NULL)
|
|
2832
|
+
this->default_notice_receiver = PQsetNoticeReceiver(this->pgconn, NULL, NULL);
|
|
2795
2833
|
|
|
2796
2834
|
old_proc = this->notice_receiver;
|
|
2797
2835
|
if( rb_block_given_p() ) {
|
|
@@ -2800,10 +2838,10 @@ pgconn_set_notice_receiver(VALUE self)
|
|
|
2800
2838
|
} else {
|
|
2801
2839
|
/* if no block is given, set back to default */
|
|
2802
2840
|
proc = Qnil;
|
|
2803
|
-
PQsetNoticeReceiver(this->pgconn, default_notice_receiver, NULL);
|
|
2841
|
+
PQsetNoticeReceiver(this->pgconn, this->default_notice_receiver, NULL);
|
|
2804
2842
|
}
|
|
2805
2843
|
|
|
2806
|
-
this->notice_receiver
|
|
2844
|
+
RB_OBJ_WRITE(self, &this->notice_receiver, proc);
|
|
2807
2845
|
return old_proc;
|
|
2808
2846
|
}
|
|
2809
2847
|
|
|
@@ -2818,10 +2856,10 @@ notice_processor_proxy(void *arg, const char *message)
|
|
|
2818
2856
|
VALUE self = (VALUE)arg;
|
|
2819
2857
|
t_pg_connection *this = pg_get_connection( self );
|
|
2820
2858
|
|
|
2821
|
-
if (this->
|
|
2859
|
+
if (this->notice_processor != Qnil) {
|
|
2822
2860
|
VALUE message_str = rb_str_new2(message);
|
|
2823
2861
|
PG_ENCODING_SET_NOCHECK( message_str, this->enc_idx );
|
|
2824
|
-
rb_funcall(this->
|
|
2862
|
+
rb_funcall(this->notice_processor, rb_intern("call"), 1, message_str);
|
|
2825
2863
|
}
|
|
2826
2864
|
return;
|
|
2827
2865
|
}
|
|
@@ -2830,7 +2868,7 @@ notice_processor_proxy(void *arg, const char *message)
|
|
|
2830
2868
|
* call-seq:
|
|
2831
2869
|
* conn.set_notice_processor {|message| ... } -> Proc
|
|
2832
2870
|
*
|
|
2833
|
-
* See #set_notice_receiver for the
|
|
2871
|
+
* See #set_notice_receiver for the description of what this and the
|
|
2834
2872
|
* notice_processor methods do.
|
|
2835
2873
|
*
|
|
2836
2874
|
* This function takes a new block to act as the notice processor and returns
|
|
@@ -2845,25 +2883,26 @@ pgconn_set_notice_processor(VALUE self)
|
|
|
2845
2883
|
VALUE proc, old_proc;
|
|
2846
2884
|
t_pg_connection *this = pg_get_connection_safe( self );
|
|
2847
2885
|
|
|
2886
|
+
rb_check_frozen(self);
|
|
2848
2887
|
/* If default_notice_processor is unset, assume that the current
|
|
2849
2888
|
* notice processor is the default, and save it to a global variable.
|
|
2850
2889
|
* This should not be a problem because the default processor is
|
|
2851
2890
|
* always the same, so won't vary among connections.
|
|
2852
2891
|
*/
|
|
2853
|
-
if(default_notice_processor == NULL)
|
|
2854
|
-
default_notice_processor = PQsetNoticeProcessor(this->pgconn, NULL, NULL);
|
|
2892
|
+
if(this->default_notice_processor == NULL)
|
|
2893
|
+
this->default_notice_processor = PQsetNoticeProcessor(this->pgconn, NULL, NULL);
|
|
2855
2894
|
|
|
2856
|
-
old_proc = this->
|
|
2895
|
+
old_proc = this->notice_processor;
|
|
2857
2896
|
if( rb_block_given_p() ) {
|
|
2858
2897
|
proc = rb_block_proc();
|
|
2859
2898
|
PQsetNoticeProcessor(this->pgconn, gvl_notice_processor_proxy, (void *)self);
|
|
2860
2899
|
} else {
|
|
2861
2900
|
/* if no block is given, set back to default */
|
|
2862
2901
|
proc = Qnil;
|
|
2863
|
-
PQsetNoticeProcessor(this->pgconn, default_notice_processor, NULL);
|
|
2902
|
+
PQsetNoticeProcessor(this->pgconn, this->default_notice_processor, NULL);
|
|
2864
2903
|
}
|
|
2865
2904
|
|
|
2866
|
-
this->
|
|
2905
|
+
RB_OBJ_WRITE(self, &this->notice_processor, proc);
|
|
2867
2906
|
return old_proc;
|
|
2868
2907
|
}
|
|
2869
2908
|
|
|
@@ -2884,68 +2923,28 @@ pgconn_get_client_encoding(VALUE self)
|
|
|
2884
2923
|
|
|
2885
2924
|
/*
|
|
2886
2925
|
* call-seq:
|
|
2887
|
-
* conn.
|
|
2926
|
+
* conn.sync_set_client_encoding( encoding )
|
|
2888
2927
|
*
|
|
2889
|
-
*
|
|
2928
|
+
* This function has the same behavior as #async_set_client_encoding, but is implemented using the synchronous command processing API of libpq.
|
|
2929
|
+
* See #async_exec for the differences between the two API variants.
|
|
2930
|
+
* It's not recommended to use explicit sync or async variants but #set_client_encoding instead, unless you have a good reason to do so.
|
|
2890
2931
|
*/
|
|
2891
2932
|
static VALUE
|
|
2892
|
-
|
|
2933
|
+
pgconn_sync_set_client_encoding(VALUE self, VALUE str)
|
|
2893
2934
|
{
|
|
2894
2935
|
PGconn *conn = pg_get_pgconn( self );
|
|
2895
2936
|
|
|
2937
|
+
rb_check_frozen(self);
|
|
2896
2938
|
Check_Type(str, T_STRING);
|
|
2897
2939
|
|
|
2898
|
-
if ( (gvl_PQsetClientEncoding(conn, StringValueCStr(str))) == -1 )
|
|
2899
|
-
|
|
2900
|
-
|
|
2940
|
+
if ( (gvl_PQsetClientEncoding(conn, StringValueCStr(str))) == -1 )
|
|
2941
|
+
pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(conn));
|
|
2942
|
+
|
|
2901
2943
|
pgconn_set_internal_encoding_index( self );
|
|
2902
2944
|
|
|
2903
2945
|
return Qnil;
|
|
2904
2946
|
}
|
|
2905
2947
|
|
|
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
2948
|
|
|
2950
2949
|
/*
|
|
2951
2950
|
* call-seq:
|
|
@@ -3020,10 +3019,8 @@ get_result_readable(PGconn *conn)
|
|
|
3020
3019
|
* If +true+ is returned, +conn.is_busy+ will return +false+
|
|
3021
3020
|
* and +conn.get_result+ will not block.
|
|
3022
3021
|
*/
|
|
3023
|
-
|
|
3022
|
+
VALUE
|
|
3024
3023
|
pgconn_block( int argc, VALUE *argv, VALUE self ) {
|
|
3025
|
-
PGconn *conn = pg_get_pgconn( self );
|
|
3026
|
-
|
|
3027
3024
|
struct timeval timeout;
|
|
3028
3025
|
struct timeval *ptimeout = NULL;
|
|
3029
3026
|
VALUE timeout_in;
|
|
@@ -3037,7 +3034,7 @@ pgconn_block( int argc, VALUE *argv, VALUE self ) {
|
|
|
3037
3034
|
ptimeout = &timeout;
|
|
3038
3035
|
}
|
|
3039
3036
|
|
|
3040
|
-
ret = wait_socket_readable(
|
|
3037
|
+
ret = wait_socket_readable( self, ptimeout, get_result_readable);
|
|
3041
3038
|
|
|
3042
3039
|
if( !ret )
|
|
3043
3040
|
return Qfalse;
|
|
@@ -3046,6 +3043,42 @@ pgconn_block( int argc, VALUE *argv, VALUE self ) {
|
|
|
3046
3043
|
}
|
|
3047
3044
|
|
|
3048
3045
|
|
|
3046
|
+
/*
|
|
3047
|
+
* call-seq:
|
|
3048
|
+
* conn.sync_get_last_result( ) -> PG::Result
|
|
3049
|
+
*
|
|
3050
|
+
* This function has the same behavior as #async_get_last_result, but is implemented using the synchronous command processing API of libpq.
|
|
3051
|
+
* See #async_exec for the differences between the two API variants.
|
|
3052
|
+
* It's not recommended to use explicit sync or async variants but #get_last_result instead, unless you have a good reason to do so.
|
|
3053
|
+
*/
|
|
3054
|
+
static VALUE
|
|
3055
|
+
pgconn_sync_get_last_result(VALUE self)
|
|
3056
|
+
{
|
|
3057
|
+
PGconn *conn = pg_get_pgconn(self);
|
|
3058
|
+
VALUE rb_pgresult = Qnil;
|
|
3059
|
+
PGresult *cur, *prev;
|
|
3060
|
+
|
|
3061
|
+
|
|
3062
|
+
cur = prev = NULL;
|
|
3063
|
+
while ((cur = gvl_PQgetResult(conn)) != NULL) {
|
|
3064
|
+
int status;
|
|
3065
|
+
|
|
3066
|
+
if (prev) PQclear(prev);
|
|
3067
|
+
prev = cur;
|
|
3068
|
+
|
|
3069
|
+
status = PQresultStatus(cur);
|
|
3070
|
+
if (status == PGRES_COPY_OUT || status == PGRES_COPY_IN || status == PGRES_COPY_BOTH)
|
|
3071
|
+
break;
|
|
3072
|
+
}
|
|
3073
|
+
|
|
3074
|
+
if (prev) {
|
|
3075
|
+
rb_pgresult = pg_new_result( prev, self );
|
|
3076
|
+
pg_result_check(rb_pgresult);
|
|
3077
|
+
}
|
|
3078
|
+
|
|
3079
|
+
return rb_pgresult;
|
|
3080
|
+
}
|
|
3081
|
+
|
|
3049
3082
|
/*
|
|
3050
3083
|
* call-seq:
|
|
3051
3084
|
* conn.get_last_result( ) -> PG::Result
|
|
@@ -3056,27 +3089,36 @@ pgconn_block( int argc, VALUE *argv, VALUE self ) {
|
|
|
3056
3089
|
* returns the last non-NULL result, or +nil+ if no
|
|
3057
3090
|
* results are available.
|
|
3058
3091
|
*
|
|
3092
|
+
* If the last result contains a bad result_status, an
|
|
3093
|
+
* appropriate exception is raised.
|
|
3094
|
+
*
|
|
3059
3095
|
* This function is similar to #get_result
|
|
3060
3096
|
* except that it is designed to get one and only
|
|
3061
|
-
* one result.
|
|
3097
|
+
* one result and that it checks the result state.
|
|
3062
3098
|
*/
|
|
3063
3099
|
static VALUE
|
|
3064
|
-
|
|
3100
|
+
pgconn_async_get_last_result(VALUE self)
|
|
3065
3101
|
{
|
|
3066
3102
|
PGconn *conn = pg_get_pgconn(self);
|
|
3067
3103
|
VALUE rb_pgresult = Qnil;
|
|
3068
3104
|
PGresult *cur, *prev;
|
|
3069
3105
|
|
|
3070
|
-
|
|
3071
3106
|
cur = prev = NULL;
|
|
3072
|
-
|
|
3107
|
+
for(;;) {
|
|
3073
3108
|
int status;
|
|
3074
3109
|
|
|
3110
|
+
/* wait for input (without blocking) before reading each result */
|
|
3111
|
+
wait_socket_readable(self, NULL, get_result_readable);
|
|
3112
|
+
|
|
3113
|
+
cur = gvl_PQgetResult(conn);
|
|
3114
|
+
if (cur == NULL)
|
|
3115
|
+
break;
|
|
3116
|
+
|
|
3075
3117
|
if (prev) PQclear(prev);
|
|
3076
3118
|
prev = cur;
|
|
3077
3119
|
|
|
3078
3120
|
status = PQresultStatus(cur);
|
|
3079
|
-
if (status == PGRES_COPY_OUT || status == PGRES_COPY_IN)
|
|
3121
|
+
if (status == PGRES_COPY_OUT || status == PGRES_COPY_IN || status == PGRES_COPY_BOTH)
|
|
3080
3122
|
break;
|
|
3081
3123
|
}
|
|
3082
3124
|
|
|
@@ -3093,29 +3135,91 @@ pgconn_get_last_result(VALUE self)
|
|
|
3093
3135
|
* conn.discard_results()
|
|
3094
3136
|
*
|
|
3095
3137
|
* Silently discard any prior query result that application didn't eat.
|
|
3096
|
-
* This is
|
|
3097
|
-
*
|
|
3138
|
+
* This is internally used prior to Connection#exec and sibling methods.
|
|
3139
|
+
* It doesn't raise an exception on connection errors, but returns +false+ instead.
|
|
3140
|
+
*
|
|
3141
|
+
* Returns:
|
|
3142
|
+
* * +nil+ when the connection is already idle
|
|
3143
|
+
* * +true+ when some results have been discarded
|
|
3144
|
+
* * +false+ when a failure occured and the connection was closed
|
|
3145
|
+
*
|
|
3098
3146
|
*/
|
|
3099
3147
|
static VALUE
|
|
3100
3148
|
pgconn_discard_results(VALUE self)
|
|
3101
3149
|
{
|
|
3102
3150
|
PGconn *conn = pg_get_pgconn(self);
|
|
3151
|
+
VALUE socket_io;
|
|
3152
|
+
|
|
3153
|
+
switch( PQtransactionStatus(conn) ) {
|
|
3154
|
+
case PQTRANS_IDLE:
|
|
3155
|
+
case PQTRANS_INTRANS:
|
|
3156
|
+
case PQTRANS_INERROR:
|
|
3157
|
+
return Qnil;
|
|
3158
|
+
default:;
|
|
3159
|
+
}
|
|
3103
3160
|
|
|
3104
|
-
|
|
3105
|
-
|
|
3106
|
-
|
|
3161
|
+
socket_io = pgconn_socket_io(self);
|
|
3162
|
+
|
|
3163
|
+
for(;;) {
|
|
3164
|
+
PGresult *cur;
|
|
3165
|
+
int status;
|
|
3166
|
+
|
|
3167
|
+
/* pgconn_block() raises an exception in case of errors.
|
|
3168
|
+
* To avoid this call pg_rb_io_wait() and PQconsumeInput() without rb_raise().
|
|
3169
|
+
*/
|
|
3170
|
+
while( gvl_PQisBusy(conn) ){
|
|
3171
|
+
int events;
|
|
3172
|
+
|
|
3173
|
+
switch( PQflush(conn) ) {
|
|
3174
|
+
case 1:
|
|
3175
|
+
events = RB_NUM2INT(pg_rb_io_wait(socket_io, RB_INT2NUM(PG_RUBY_IO_READABLE | PG_RUBY_IO_WRITABLE), Qnil));
|
|
3176
|
+
if (events & PG_RUBY_IO_READABLE){
|
|
3177
|
+
if ( PQconsumeInput(conn) == 0 ) goto error;
|
|
3178
|
+
}
|
|
3179
|
+
break;
|
|
3180
|
+
case 0:
|
|
3181
|
+
pg_rb_io_wait(socket_io, RB_INT2NUM(PG_RUBY_IO_READABLE), Qnil);
|
|
3182
|
+
if ( PQconsumeInput(conn) == 0 ) goto error;
|
|
3183
|
+
break;
|
|
3184
|
+
default:
|
|
3185
|
+
goto error;
|
|
3186
|
+
}
|
|
3187
|
+
}
|
|
3188
|
+
|
|
3189
|
+
cur = gvl_PQgetResult(conn);
|
|
3190
|
+
if( cur == NULL) break;
|
|
3191
|
+
|
|
3192
|
+
status = PQresultStatus(cur);
|
|
3107
3193
|
PQclear(cur);
|
|
3108
3194
|
if (status == PGRES_COPY_IN){
|
|
3109
|
-
gvl_PQputCopyEnd(conn, "COPY terminated by new
|
|
3195
|
+
while( gvl_PQputCopyEnd(conn, "COPY terminated by new query or discard_results") == 0 ){
|
|
3196
|
+
pgconn_async_flush(self);
|
|
3197
|
+
}
|
|
3110
3198
|
}
|
|
3111
3199
|
if (status == PGRES_COPY_OUT){
|
|
3112
|
-
|
|
3113
|
-
|
|
3114
|
-
|
|
3200
|
+
for(;;) {
|
|
3201
|
+
char *buffer = NULL;
|
|
3202
|
+
int st = gvl_PQgetCopyData(conn, &buffer, 1);
|
|
3203
|
+
if( st == 0 ) {
|
|
3204
|
+
/* would block -> wait for readable data */
|
|
3205
|
+
pg_rb_io_wait(socket_io, RB_INT2NUM(PG_RUBY_IO_READABLE), Qnil);
|
|
3206
|
+
if ( PQconsumeInput(conn) == 0 ) goto error;
|
|
3207
|
+
} else if( st > 0 ) {
|
|
3208
|
+
/* some data retrieved -> discard it */
|
|
3209
|
+
PQfreemem(buffer);
|
|
3210
|
+
} else {
|
|
3211
|
+
/* no more data */
|
|
3212
|
+
break;
|
|
3213
|
+
}
|
|
3214
|
+
}
|
|
3115
3215
|
}
|
|
3116
3216
|
}
|
|
3117
3217
|
|
|
3118
|
-
return
|
|
3218
|
+
return Qtrue;
|
|
3219
|
+
|
|
3220
|
+
error:
|
|
3221
|
+
pgconn_close_socket_io(self);
|
|
3222
|
+
return Qfalse;
|
|
3119
3223
|
}
|
|
3120
3224
|
|
|
3121
3225
|
/*
|
|
@@ -3138,6 +3242,7 @@ pgconn_discard_results(VALUE self)
|
|
|
3138
3242
|
* #exec is an alias for #async_exec which is almost identical to #sync_exec .
|
|
3139
3243
|
* #sync_exec is implemented on the simpler synchronous command processing API of libpq, whereas
|
|
3140
3244
|
* #async_exec is implemented on the asynchronous API and on ruby's IO mechanisms.
|
|
3245
|
+
* Only #async_exec is compatible to <tt>Fiber.scheduler</tt> based asynchronous IO processing introduced in ruby-3.0.
|
|
3141
3246
|
* Both methods ensure that other threads can process while waiting for the server to
|
|
3142
3247
|
* complete the request, but #sync_exec blocks all signals to be processed until the query is finished.
|
|
3143
3248
|
* This is most notably visible by a delayed reaction to Control+C.
|
|
@@ -3152,8 +3257,7 @@ pgconn_async_exec(int argc, VALUE *argv, VALUE self)
|
|
|
3152
3257
|
|
|
3153
3258
|
pgconn_discard_results( self );
|
|
3154
3259
|
pgconn_send_query( argc, argv, self );
|
|
3155
|
-
|
|
3156
|
-
rb_pgresult = pgconn_get_last_result( self );
|
|
3260
|
+
rb_pgresult = pgconn_async_get_last_result( self );
|
|
3157
3261
|
|
|
3158
3262
|
if ( rb_block_given_p() ) {
|
|
3159
3263
|
return rb_ensure( rb_yield, rb_pgresult, pg_result_clear, rb_pgresult );
|
|
@@ -3182,7 +3286,7 @@ pgconn_async_exec(int argc, VALUE *argv, VALUE self)
|
|
|
3182
3286
|
* or, it may be a String. If it is a string, that is equivalent to the hash:
|
|
3183
3287
|
* { :value => <string value>, :type => 0, :format => 0 }
|
|
3184
3288
|
*
|
|
3185
|
-
* PostgreSQL bind parameters are represented as $1, $
|
|
3289
|
+
* PostgreSQL bind parameters are represented as $1, $2, $3, etc.,
|
|
3186
3290
|
* inside the SQL query. The 0th element of the +params+ array is bound
|
|
3187
3291
|
* to $1, the 1st element is bound to $2, etc. +nil+ is treated as +NULL+.
|
|
3188
3292
|
*
|
|
@@ -3225,8 +3329,7 @@ pgconn_async_exec_params(int argc, VALUE *argv, VALUE self)
|
|
|
3225
3329
|
} else {
|
|
3226
3330
|
pgconn_send_query_params( argc, argv, self );
|
|
3227
3331
|
}
|
|
3228
|
-
|
|
3229
|
-
rb_pgresult = pgconn_get_last_result( self );
|
|
3332
|
+
rb_pgresult = pgconn_async_get_last_result( self );
|
|
3230
3333
|
|
|
3231
3334
|
if ( rb_block_given_p() ) {
|
|
3232
3335
|
return rb_ensure( rb_yield, rb_pgresult, pg_result_clear, rb_pgresult );
|
|
@@ -3252,7 +3355,7 @@ pgconn_async_exec_params(int argc, VALUE *argv, VALUE self)
|
|
|
3252
3355
|
*
|
|
3253
3356
|
* For example: "SELECT $1::int"
|
|
3254
3357
|
*
|
|
3255
|
-
* PostgreSQL bind parameters are represented as $1, $
|
|
3358
|
+
* PostgreSQL bind parameters are represented as $1, $2, $3, etc.,
|
|
3256
3359
|
* inside the SQL query.
|
|
3257
3360
|
*
|
|
3258
3361
|
* See also corresponding {libpq function}[https://www.postgresql.org/docs/current/libpq-exec.html#LIBPQ-PQPREPARE].
|
|
@@ -3264,8 +3367,7 @@ pgconn_async_prepare(int argc, VALUE *argv, VALUE self)
|
|
|
3264
3367
|
|
|
3265
3368
|
pgconn_discard_results( self );
|
|
3266
3369
|
pgconn_send_prepare( argc, argv, self );
|
|
3267
|
-
|
|
3268
|
-
rb_pgresult = pgconn_get_last_result( self );
|
|
3370
|
+
rb_pgresult = pgconn_async_get_last_result( self );
|
|
3269
3371
|
|
|
3270
3372
|
if ( rb_block_given_p() ) {
|
|
3271
3373
|
return rb_ensure( rb_yield, rb_pgresult, pg_result_clear, rb_pgresult );
|
|
@@ -3292,7 +3394,7 @@ pgconn_async_prepare(int argc, VALUE *argv, VALUE self)
|
|
|
3292
3394
|
* or, it may be a String. If it is a string, that is equivalent to the hash:
|
|
3293
3395
|
* { :value => <string value>, :format => 0 }
|
|
3294
3396
|
*
|
|
3295
|
-
* PostgreSQL bind parameters are represented as $1, $
|
|
3397
|
+
* PostgreSQL bind parameters are represented as $1, $2, $3, etc.,
|
|
3296
3398
|
* inside the SQL query. The 0th element of the +params+ array is bound
|
|
3297
3399
|
* to $1, the 1st element is bound to $2, etc. +nil+ is treated as +NULL+.
|
|
3298
3400
|
*
|
|
@@ -3318,8 +3420,7 @@ pgconn_async_exec_prepared(int argc, VALUE *argv, VALUE self)
|
|
|
3318
3420
|
|
|
3319
3421
|
pgconn_discard_results( self );
|
|
3320
3422
|
pgconn_send_query_prepared( argc, argv, self );
|
|
3321
|
-
|
|
3322
|
-
rb_pgresult = pgconn_get_last_result( self );
|
|
3423
|
+
rb_pgresult = pgconn_async_get_last_result( self );
|
|
3323
3424
|
|
|
3324
3425
|
if ( rb_block_given_p() ) {
|
|
3325
3426
|
return rb_ensure( rb_yield, rb_pgresult, pg_result_clear, rb_pgresult );
|
|
@@ -3343,8 +3444,7 @@ pgconn_async_describe_portal(VALUE self, VALUE portal)
|
|
|
3343
3444
|
|
|
3344
3445
|
pgconn_discard_results( self );
|
|
3345
3446
|
pgconn_send_describe_portal( self, portal );
|
|
3346
|
-
|
|
3347
|
-
rb_pgresult = pgconn_get_last_result( self );
|
|
3447
|
+
rb_pgresult = pgconn_async_get_last_result( self );
|
|
3348
3448
|
|
|
3349
3449
|
if ( rb_block_given_p() ) {
|
|
3350
3450
|
return rb_ensure( rb_yield, rb_pgresult, pg_result_clear, rb_pgresult );
|
|
@@ -3368,8 +3468,7 @@ pgconn_async_describe_prepared(VALUE self, VALUE stmt_name)
|
|
|
3368
3468
|
|
|
3369
3469
|
pgconn_discard_results( self );
|
|
3370
3470
|
pgconn_send_describe_prepared( self, stmt_name );
|
|
3371
|
-
|
|
3372
|
-
rb_pgresult = pgconn_get_last_result( self );
|
|
3471
|
+
rb_pgresult = pgconn_async_get_last_result( self );
|
|
3373
3472
|
|
|
3374
3473
|
if ( rb_block_given_p() ) {
|
|
3375
3474
|
return rb_ensure( rb_yield, rb_pgresult, pg_result_clear, rb_pgresult );
|
|
@@ -3457,10 +3556,134 @@ pgconn_ssl_attribute_names(VALUE self)
|
|
|
3457
3556
|
#endif
|
|
3458
3557
|
|
|
3459
3558
|
|
|
3559
|
+
#ifdef HAVE_PQENTERPIPELINEMODE
|
|
3560
|
+
/*
|
|
3561
|
+
* call-seq:
|
|
3562
|
+
* conn.pipeline_status -> Integer
|
|
3563
|
+
*
|
|
3564
|
+
* Returns the current pipeline mode status of the libpq connection.
|
|
3565
|
+
*
|
|
3566
|
+
* PQpipelineStatus can return one of the following values:
|
|
3567
|
+
*
|
|
3568
|
+
* * PQ_PIPELINE_ON - The libpq connection is in pipeline mode.
|
|
3569
|
+
* * PQ_PIPELINE_OFF - The libpq connection is not in pipeline mode.
|
|
3570
|
+
* * PQ_PIPELINE_ABORTED - The libpq connection is in pipeline mode and an error occurred while processing the current pipeline.
|
|
3571
|
+
* The aborted flag is cleared when PQgetResult returns a result of type PGRES_PIPELINE_SYNC.
|
|
3572
|
+
*
|
|
3573
|
+
* Available since PostgreSQL-14
|
|
3574
|
+
*/
|
|
3575
|
+
static VALUE
|
|
3576
|
+
pgconn_pipeline_status(VALUE self)
|
|
3577
|
+
{
|
|
3578
|
+
int res = PQpipelineStatus(pg_get_pgconn(self));
|
|
3579
|
+
return INT2FIX(res);
|
|
3580
|
+
}
|
|
3581
|
+
|
|
3582
|
+
|
|
3583
|
+
/*
|
|
3584
|
+
* call-seq:
|
|
3585
|
+
* conn.enter_pipeline_mode -> nil
|
|
3586
|
+
*
|
|
3587
|
+
* Causes a connection to enter pipeline mode if it is currently idle or already in pipeline mode.
|
|
3588
|
+
*
|
|
3589
|
+
* Raises PG::Error and has no effect if the connection is not currently idle, i.e., it has a result ready, or it is waiting for more input from the server, etc.
|
|
3590
|
+
* This function does not actually send anything to the server, it just changes the libpq connection state.
|
|
3591
|
+
*
|
|
3592
|
+
* Available since PostgreSQL-14
|
|
3593
|
+
*/
|
|
3594
|
+
static VALUE
|
|
3595
|
+
pgconn_enter_pipeline_mode(VALUE self)
|
|
3596
|
+
{
|
|
3597
|
+
PGconn *conn = pg_get_pgconn(self);
|
|
3598
|
+
int res = PQenterPipelineMode(conn);
|
|
3599
|
+
if( res != 1 )
|
|
3600
|
+
pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(conn));
|
|
3601
|
+
|
|
3602
|
+
return Qnil;
|
|
3603
|
+
}
|
|
3604
|
+
|
|
3605
|
+
/*
|
|
3606
|
+
* call-seq:
|
|
3607
|
+
* conn.exit_pipeline_mode -> nil
|
|
3608
|
+
*
|
|
3609
|
+
* Causes a connection to exit pipeline mode if it is currently in pipeline mode with an empty queue and no pending results.
|
|
3610
|
+
*
|
|
3611
|
+
* Takes no action if not in pipeline mode.
|
|
3612
|
+
* Raises PG::Error if the current statement isn't finished processing, or PQgetResult has not been called to collect results from all previously sent query.
|
|
3613
|
+
*
|
|
3614
|
+
* Available since PostgreSQL-14
|
|
3615
|
+
*/
|
|
3616
|
+
static VALUE
|
|
3617
|
+
pgconn_exit_pipeline_mode(VALUE self)
|
|
3618
|
+
{
|
|
3619
|
+
PGconn *conn = pg_get_pgconn(self);
|
|
3620
|
+
int res = PQexitPipelineMode(conn);
|
|
3621
|
+
if( res != 1 )
|
|
3622
|
+
pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(conn));
|
|
3623
|
+
|
|
3624
|
+
return Qnil;
|
|
3625
|
+
}
|
|
3626
|
+
|
|
3627
|
+
|
|
3628
|
+
/*
|
|
3629
|
+
* call-seq:
|
|
3630
|
+
* conn.pipeline_sync -> nil
|
|
3631
|
+
*
|
|
3632
|
+
* Marks a synchronization point in a pipeline by sending a sync message and flushing the send buffer.
|
|
3633
|
+
* This serves as the delimiter of an implicit transaction and an error recovery point; see Section 34.5.1.3 of the PostgreSQL documentation.
|
|
3634
|
+
*
|
|
3635
|
+
* Raises PG::Error if the connection is not in pipeline mode or sending a sync message failed.
|
|
3636
|
+
*
|
|
3637
|
+
* Available since PostgreSQL-14
|
|
3638
|
+
*/
|
|
3639
|
+
static VALUE
|
|
3640
|
+
pgconn_pipeline_sync(VALUE self)
|
|
3641
|
+
{
|
|
3642
|
+
PGconn *conn = pg_get_pgconn(self);
|
|
3643
|
+
int res = PQpipelineSync(conn);
|
|
3644
|
+
if( res != 1 )
|
|
3645
|
+
pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(conn));
|
|
3646
|
+
|
|
3647
|
+
return Qnil;
|
|
3648
|
+
}
|
|
3649
|
+
|
|
3650
|
+
/*
|
|
3651
|
+
* call-seq:
|
|
3652
|
+
* conn.pipeline_sync -> nil
|
|
3653
|
+
*
|
|
3654
|
+
* Sends a request for the server to flush its output buffer.
|
|
3655
|
+
*
|
|
3656
|
+
* The server flushes its output buffer automatically as a result of Connection#pipeline_sync being called, or on any request when not in pipeline mode.
|
|
3657
|
+
* This function is useful to cause the server to flush its output buffer in pipeline mode without establishing a synchronization point.
|
|
3658
|
+
* Note that the request is not itself flushed to the server automatically; use Connection#flush if necessary.
|
|
3659
|
+
*
|
|
3660
|
+
* Available since PostgreSQL-14
|
|
3661
|
+
*/
|
|
3662
|
+
static VALUE
|
|
3663
|
+
pgconn_send_flush_request(VALUE self)
|
|
3664
|
+
{
|
|
3665
|
+
PGconn *conn = pg_get_pgconn(self);
|
|
3666
|
+
int res = PQsendFlushRequest(conn);
|
|
3667
|
+
if( res != 1 )
|
|
3668
|
+
pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(conn));
|
|
3669
|
+
|
|
3670
|
+
return Qnil;
|
|
3671
|
+
}
|
|
3672
|
+
|
|
3673
|
+
#endif
|
|
3674
|
+
|
|
3460
3675
|
/**************************************************************************
|
|
3461
3676
|
* LARGE OBJECT SUPPORT
|
|
3462
3677
|
**************************************************************************/
|
|
3463
3678
|
|
|
3679
|
+
#define BLOCKING_BEGIN(conn) do { \
|
|
3680
|
+
int old_nonblocking = PQisnonblocking(conn); \
|
|
3681
|
+
PQsetnonblocking(conn, 0);
|
|
3682
|
+
|
|
3683
|
+
#define BLOCKING_END(th) \
|
|
3684
|
+
PQsetnonblocking(conn, old_nonblocking); \
|
|
3685
|
+
} while(0);
|
|
3686
|
+
|
|
3464
3687
|
/*
|
|
3465
3688
|
* call-seq:
|
|
3466
3689
|
* conn.lo_creat( [mode] ) -> Integer
|
|
@@ -3481,9 +3704,12 @@ pgconn_locreat(int argc, VALUE *argv, VALUE self)
|
|
|
3481
3704
|
else
|
|
3482
3705
|
mode = NUM2INT(nmode);
|
|
3483
3706
|
|
|
3484
|
-
|
|
3707
|
+
BLOCKING_BEGIN(conn)
|
|
3708
|
+
lo_oid = lo_creat(conn, mode);
|
|
3709
|
+
BLOCKING_END(conn)
|
|
3710
|
+
|
|
3485
3711
|
if (lo_oid == 0)
|
|
3486
|
-
|
|
3712
|
+
pg_raise_conn_error( rb_ePGerror, self, "lo_creat failed");
|
|
3487
3713
|
|
|
3488
3714
|
return UINT2NUM(lo_oid);
|
|
3489
3715
|
}
|
|
@@ -3504,7 +3730,7 @@ pgconn_locreate(VALUE self, VALUE in_lo_oid)
|
|
|
3504
3730
|
|
|
3505
3731
|
ret = lo_create(conn, lo_oid);
|
|
3506
3732
|
if (ret == InvalidOid)
|
|
3507
|
-
|
|
3733
|
+
pg_raise_conn_error( rb_ePGerror, self, "lo_create failed");
|
|
3508
3734
|
|
|
3509
3735
|
return UINT2NUM(ret);
|
|
3510
3736
|
}
|
|
@@ -3526,9 +3752,12 @@ pgconn_loimport(VALUE self, VALUE filename)
|
|
|
3526
3752
|
|
|
3527
3753
|
Check_Type(filename, T_STRING);
|
|
3528
3754
|
|
|
3529
|
-
|
|
3755
|
+
BLOCKING_BEGIN(conn)
|
|
3756
|
+
lo_oid = lo_import(conn, StringValueCStr(filename));
|
|
3757
|
+
BLOCKING_END(conn)
|
|
3758
|
+
|
|
3530
3759
|
if (lo_oid == 0) {
|
|
3531
|
-
|
|
3760
|
+
pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(conn));
|
|
3532
3761
|
}
|
|
3533
3762
|
return UINT2NUM(lo_oid);
|
|
3534
3763
|
}
|
|
@@ -3544,12 +3773,17 @@ pgconn_loexport(VALUE self, VALUE lo_oid, VALUE filename)
|
|
|
3544
3773
|
{
|
|
3545
3774
|
PGconn *conn = pg_get_pgconn(self);
|
|
3546
3775
|
Oid oid;
|
|
3776
|
+
int ret;
|
|
3547
3777
|
Check_Type(filename, T_STRING);
|
|
3548
3778
|
|
|
3549
3779
|
oid = NUM2UINT(lo_oid);
|
|
3550
3780
|
|
|
3551
|
-
|
|
3552
|
-
|
|
3781
|
+
BLOCKING_BEGIN(conn)
|
|
3782
|
+
ret = lo_export(conn, oid, StringValueCStr(filename));
|
|
3783
|
+
BLOCKING_END(conn)
|
|
3784
|
+
|
|
3785
|
+
if (ret < 0) {
|
|
3786
|
+
pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(conn));
|
|
3553
3787
|
}
|
|
3554
3788
|
return Qnil;
|
|
3555
3789
|
}
|
|
@@ -3579,8 +3813,12 @@ pgconn_loopen(int argc, VALUE *argv, VALUE self)
|
|
|
3579
3813
|
else
|
|
3580
3814
|
mode = NUM2INT(nmode);
|
|
3581
3815
|
|
|
3582
|
-
|
|
3583
|
-
|
|
3816
|
+
BLOCKING_BEGIN(conn)
|
|
3817
|
+
fd = lo_open(conn, lo_oid, mode);
|
|
3818
|
+
BLOCKING_END(conn)
|
|
3819
|
+
|
|
3820
|
+
if(fd < 0) {
|
|
3821
|
+
pg_raise_conn_error( rb_ePGerror, self, "can't open large object: %s", PQerrorMessage(conn));
|
|
3584
3822
|
}
|
|
3585
3823
|
return INT2FIX(fd);
|
|
3586
3824
|
}
|
|
@@ -3602,11 +3840,15 @@ pgconn_lowrite(VALUE self, VALUE in_lo_desc, VALUE buffer)
|
|
|
3602
3840
|
Check_Type(buffer, T_STRING);
|
|
3603
3841
|
|
|
3604
3842
|
if( RSTRING_LEN(buffer) < 0) {
|
|
3605
|
-
|
|
3843
|
+
pg_raise_conn_error( rb_ePGerror, self, "write buffer zero string");
|
|
3606
3844
|
}
|
|
3607
|
-
|
|
3608
|
-
|
|
3609
|
-
|
|
3845
|
+
BLOCKING_BEGIN(conn)
|
|
3846
|
+
n = lo_write(conn, fd, StringValuePtr(buffer),
|
|
3847
|
+
RSTRING_LEN(buffer));
|
|
3848
|
+
BLOCKING_END(conn)
|
|
3849
|
+
|
|
3850
|
+
if(n < 0) {
|
|
3851
|
+
pg_raise_conn_error( rb_ePGerror, self, "lo_write failed: %s", PQerrorMessage(conn));
|
|
3610
3852
|
}
|
|
3611
3853
|
|
|
3612
3854
|
return INT2FIX(n);
|
|
@@ -3629,16 +3871,17 @@ pgconn_loread(VALUE self, VALUE in_lo_desc, VALUE in_len)
|
|
|
3629
3871
|
VALUE str;
|
|
3630
3872
|
char *buffer;
|
|
3631
3873
|
|
|
3632
|
-
|
|
3633
|
-
|
|
3634
|
-
rb_raise(rb_eNoMemError, "ALLOC failed!");
|
|
3874
|
+
if (len < 0)
|
|
3875
|
+
pg_raise_conn_error( rb_ePGerror, self, "negative length %d given", len);
|
|
3635
3876
|
|
|
3636
|
-
|
|
3637
|
-
rb_raise(rb_ePGerror,"nagative length %d given", len);
|
|
3638
|
-
}
|
|
3877
|
+
buffer = ALLOC_N(char, len);
|
|
3639
3878
|
|
|
3640
|
-
|
|
3641
|
-
|
|
3879
|
+
BLOCKING_BEGIN(conn)
|
|
3880
|
+
ret = lo_read(conn, lo_desc, buffer, len);
|
|
3881
|
+
BLOCKING_END(conn)
|
|
3882
|
+
|
|
3883
|
+
if(ret < 0)
|
|
3884
|
+
pg_raise_conn_error( rb_ePGerror, self, "lo_read failed");
|
|
3642
3885
|
|
|
3643
3886
|
if(ret == 0) {
|
|
3644
3887
|
xfree(buffer);
|
|
@@ -3667,8 +3910,12 @@ pgconn_lolseek(VALUE self, VALUE in_lo_desc, VALUE offset, VALUE whence)
|
|
|
3667
3910
|
int lo_desc = NUM2INT(in_lo_desc);
|
|
3668
3911
|
int ret;
|
|
3669
3912
|
|
|
3670
|
-
|
|
3671
|
-
|
|
3913
|
+
BLOCKING_BEGIN(conn)
|
|
3914
|
+
ret = lo_lseek(conn, lo_desc, NUM2INT(offset), NUM2INT(whence));
|
|
3915
|
+
BLOCKING_END(conn)
|
|
3916
|
+
|
|
3917
|
+
if(ret < 0) {
|
|
3918
|
+
pg_raise_conn_error( rb_ePGerror, self, "lo_lseek failed");
|
|
3672
3919
|
}
|
|
3673
3920
|
|
|
3674
3921
|
return INT2FIX(ret);
|
|
@@ -3687,8 +3934,12 @@ pgconn_lotell(VALUE self, VALUE in_lo_desc)
|
|
|
3687
3934
|
PGconn *conn = pg_get_pgconn(self);
|
|
3688
3935
|
int lo_desc = NUM2INT(in_lo_desc);
|
|
3689
3936
|
|
|
3690
|
-
|
|
3691
|
-
|
|
3937
|
+
BLOCKING_BEGIN(conn)
|
|
3938
|
+
position = lo_tell(conn, lo_desc);
|
|
3939
|
+
BLOCKING_END(conn)
|
|
3940
|
+
|
|
3941
|
+
if(position < 0)
|
|
3942
|
+
pg_raise_conn_error( rb_ePGerror, self, "lo_tell failed");
|
|
3692
3943
|
|
|
3693
3944
|
return INT2FIX(position);
|
|
3694
3945
|
}
|
|
@@ -3705,9 +3956,14 @@ pgconn_lotruncate(VALUE self, VALUE in_lo_desc, VALUE in_len)
|
|
|
3705
3956
|
PGconn *conn = pg_get_pgconn(self);
|
|
3706
3957
|
int lo_desc = NUM2INT(in_lo_desc);
|
|
3707
3958
|
size_t len = NUM2INT(in_len);
|
|
3959
|
+
int ret;
|
|
3708
3960
|
|
|
3709
|
-
|
|
3710
|
-
|
|
3961
|
+
BLOCKING_BEGIN(conn)
|
|
3962
|
+
ret = lo_truncate(conn,lo_desc,len);
|
|
3963
|
+
BLOCKING_END(conn)
|
|
3964
|
+
|
|
3965
|
+
if(ret < 0)
|
|
3966
|
+
pg_raise_conn_error( rb_ePGerror, self, "lo_truncate failed");
|
|
3711
3967
|
|
|
3712
3968
|
return Qnil;
|
|
3713
3969
|
}
|
|
@@ -3723,9 +3979,14 @@ pgconn_loclose(VALUE self, VALUE in_lo_desc)
|
|
|
3723
3979
|
{
|
|
3724
3980
|
PGconn *conn = pg_get_pgconn(self);
|
|
3725
3981
|
int lo_desc = NUM2INT(in_lo_desc);
|
|
3982
|
+
int ret;
|
|
3983
|
+
|
|
3984
|
+
BLOCKING_BEGIN(conn)
|
|
3985
|
+
ret = lo_close(conn,lo_desc);
|
|
3986
|
+
BLOCKING_END(conn)
|
|
3726
3987
|
|
|
3727
|
-
if(
|
|
3728
|
-
|
|
3988
|
+
if(ret < 0)
|
|
3989
|
+
pg_raise_conn_error( rb_ePGerror, self, "lo_close failed");
|
|
3729
3990
|
|
|
3730
3991
|
return Qnil;
|
|
3731
3992
|
}
|
|
@@ -3741,9 +4002,14 @@ pgconn_lounlink(VALUE self, VALUE in_oid)
|
|
|
3741
4002
|
{
|
|
3742
4003
|
PGconn *conn = pg_get_pgconn(self);
|
|
3743
4004
|
Oid oid = NUM2UINT(in_oid);
|
|
4005
|
+
int ret;
|
|
4006
|
+
|
|
4007
|
+
BLOCKING_BEGIN(conn)
|
|
4008
|
+
ret = lo_unlink(conn,oid);
|
|
4009
|
+
BLOCKING_END(conn)
|
|
3744
4010
|
|
|
3745
|
-
if(
|
|
3746
|
-
|
|
4011
|
+
if(ret < 0)
|
|
4012
|
+
pg_raise_conn_error( rb_ePGerror, self, "lo_unlink failed");
|
|
3747
4013
|
|
|
3748
4014
|
return Qnil;
|
|
3749
4015
|
}
|
|
@@ -3800,12 +4066,13 @@ static VALUE pgconn_external_encoding(VALUE self);
|
|
|
3800
4066
|
static VALUE
|
|
3801
4067
|
pgconn_internal_encoding_set(VALUE self, VALUE enc)
|
|
3802
4068
|
{
|
|
4069
|
+
rb_check_frozen(self);
|
|
3803
4070
|
if (NIL_P(enc)) {
|
|
3804
|
-
|
|
4071
|
+
pgconn_sync_set_client_encoding( self, rb_usascii_str_new_cstr("SQL_ASCII") );
|
|
3805
4072
|
return enc;
|
|
3806
4073
|
}
|
|
3807
4074
|
else if ( TYPE(enc) == T_STRING && strcasecmp("JOHAB", StringValueCStr(enc)) == 0 ) {
|
|
3808
|
-
|
|
4075
|
+
pgconn_sync_set_client_encoding(self, rb_usascii_str_new_cstr("JOHAB"));
|
|
3809
4076
|
return enc;
|
|
3810
4077
|
}
|
|
3811
4078
|
else {
|
|
@@ -3843,16 +4110,34 @@ pgconn_external_encoding(VALUE self)
|
|
|
3843
4110
|
return rb_enc_from_encoding( enc );
|
|
3844
4111
|
}
|
|
3845
4112
|
|
|
4113
|
+
/*
|
|
4114
|
+
* call-seq:
|
|
4115
|
+
* conn.set_client_encoding( encoding )
|
|
4116
|
+
*
|
|
4117
|
+
* Sets the client encoding to the _encoding_ String.
|
|
4118
|
+
*/
|
|
4119
|
+
static VALUE
|
|
4120
|
+
pgconn_async_set_client_encoding(VALUE self, VALUE encname)
|
|
4121
|
+
{
|
|
4122
|
+
VALUE query_format, query;
|
|
4123
|
+
|
|
4124
|
+
rb_check_frozen(self);
|
|
4125
|
+
Check_Type(encname, T_STRING);
|
|
4126
|
+
query_format = rb_str_new_cstr("set client_encoding to '%s'");
|
|
4127
|
+
query = rb_funcall(query_format, rb_intern("%"), 1, encname);
|
|
4128
|
+
|
|
4129
|
+
pgconn_async_exec(1, &query, self);
|
|
4130
|
+
pgconn_set_internal_encoding_index( self );
|
|
4131
|
+
|
|
4132
|
+
return Qnil;
|
|
4133
|
+
}
|
|
3846
4134
|
|
|
3847
4135
|
static VALUE
|
|
3848
4136
|
pgconn_set_client_encoding_async1( VALUE args )
|
|
3849
4137
|
{
|
|
3850
4138
|
VALUE self = ((VALUE*)args)[0];
|
|
3851
4139
|
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);
|
|
4140
|
+
pgconn_async_set_client_encoding(self, encname);
|
|
3856
4141
|
return 0;
|
|
3857
4142
|
}
|
|
3858
4143
|
|
|
@@ -3867,9 +4152,9 @@ pgconn_set_client_encoding_async2( VALUE arg, VALUE ex )
|
|
|
3867
4152
|
|
|
3868
4153
|
|
|
3869
4154
|
static VALUE
|
|
3870
|
-
pgconn_set_client_encoding_async( VALUE self,
|
|
4155
|
+
pgconn_set_client_encoding_async( VALUE self, VALUE encname )
|
|
3871
4156
|
{
|
|
3872
|
-
VALUE args[] = { self,
|
|
4157
|
+
VALUE args[] = { self, encname };
|
|
3873
4158
|
return rb_rescue(pgconn_set_client_encoding_async1, (VALUE)&args, pgconn_set_client_encoding_async2, Qnil);
|
|
3874
4159
|
}
|
|
3875
4160
|
|
|
@@ -3889,12 +4174,12 @@ pgconn_set_default_encoding( VALUE self )
|
|
|
3889
4174
|
rb_encoding *enc;
|
|
3890
4175
|
const char *encname;
|
|
3891
4176
|
|
|
4177
|
+
rb_check_frozen(self);
|
|
3892
4178
|
if (( enc = rb_default_internal_encoding() )) {
|
|
3893
4179
|
encname = pg_get_rb_encoding_as_pg_encoding( enc );
|
|
3894
|
-
if ( pgconn_set_client_encoding_async(self, encname) != 0 )
|
|
4180
|
+
if ( pgconn_set_client_encoding_async(self, rb_str_new_cstr(encname)) != 0 )
|
|
3895
4181
|
rb_warning( "Failed to set the default_internal encoding to %s: '%s'",
|
|
3896
4182
|
encname, PQerrorMessage(conn) );
|
|
3897
|
-
pgconn_set_internal_encoding_index( self );
|
|
3898
4183
|
return rb_enc_from_encoding( enc );
|
|
3899
4184
|
} else {
|
|
3900
4185
|
pgconn_set_internal_encoding_index( self );
|
|
@@ -3916,13 +4201,14 @@ static VALUE
|
|
|
3916
4201
|
pgconn_type_map_for_queries_set(VALUE self, VALUE typemap)
|
|
3917
4202
|
{
|
|
3918
4203
|
t_pg_connection *this = pg_get_connection( self );
|
|
4204
|
+
t_typemap *tm;
|
|
4205
|
+
UNUSED(tm);
|
|
3919
4206
|
|
|
3920
|
-
|
|
3921
|
-
|
|
3922
|
-
|
|
3923
|
-
|
|
3924
|
-
|
|
3925
|
-
this->type_map_for_queries = typemap;
|
|
4207
|
+
rb_check_frozen(self);
|
|
4208
|
+
/* Check type of method param */
|
|
4209
|
+
TypedData_Get_Struct(typemap, t_typemap, &pg_typemap_type, tm);
|
|
4210
|
+
|
|
4211
|
+
RB_OBJ_WRITE(self, &this->type_map_for_queries, typemap);
|
|
3926
4212
|
|
|
3927
4213
|
return typemap;
|
|
3928
4214
|
}
|
|
@@ -3956,13 +4242,12 @@ static VALUE
|
|
|
3956
4242
|
pgconn_type_map_for_results_set(VALUE self, VALUE typemap)
|
|
3957
4243
|
{
|
|
3958
4244
|
t_pg_connection *this = pg_get_connection( self );
|
|
4245
|
+
t_typemap *tm;
|
|
4246
|
+
UNUSED(tm);
|
|
3959
4247
|
|
|
3960
|
-
|
|
3961
|
-
|
|
3962
|
-
|
|
3963
|
-
}
|
|
3964
|
-
Check_Type(typemap, T_DATA);
|
|
3965
|
-
this->type_map_for_results = typemap;
|
|
4248
|
+
rb_check_frozen(self);
|
|
4249
|
+
TypedData_Get_Struct(typemap, t_typemap, &pg_typemap_type, tm);
|
|
4250
|
+
RB_OBJ_WRITE(self, &this->type_map_for_results, typemap);
|
|
3966
4251
|
|
|
3967
4252
|
return typemap;
|
|
3968
4253
|
}
|
|
@@ -3996,20 +4281,20 @@ pgconn_type_map_for_results_get(VALUE self)
|
|
|
3996
4281
|
*
|
|
3997
4282
|
*/
|
|
3998
4283
|
static VALUE
|
|
3999
|
-
pgconn_encoder_for_put_copy_data_set(VALUE self, VALUE
|
|
4284
|
+
pgconn_encoder_for_put_copy_data_set(VALUE self, VALUE encoder)
|
|
4000
4285
|
{
|
|
4001
4286
|
t_pg_connection *this = pg_get_connection( self );
|
|
4002
4287
|
|
|
4003
|
-
|
|
4004
|
-
|
|
4005
|
-
|
|
4006
|
-
|
|
4007
|
-
|
|
4008
|
-
|
|
4288
|
+
rb_check_frozen(self);
|
|
4289
|
+
if( encoder != Qnil ){
|
|
4290
|
+
t_pg_coder *co;
|
|
4291
|
+
UNUSED(co);
|
|
4292
|
+
/* Check argument type */
|
|
4293
|
+
TypedData_Get_Struct(encoder, t_pg_coder, &pg_coder_type, co);
|
|
4009
4294
|
}
|
|
4010
|
-
this->encoder_for_put_copy_data
|
|
4295
|
+
RB_OBJ_WRITE(self, &this->encoder_for_put_copy_data, encoder);
|
|
4011
4296
|
|
|
4012
|
-
return
|
|
4297
|
+
return encoder;
|
|
4013
4298
|
}
|
|
4014
4299
|
|
|
4015
4300
|
/*
|
|
@@ -4045,20 +4330,20 @@ pgconn_encoder_for_put_copy_data_get(VALUE self)
|
|
|
4045
4330
|
*
|
|
4046
4331
|
*/
|
|
4047
4332
|
static VALUE
|
|
4048
|
-
pgconn_decoder_for_get_copy_data_set(VALUE self, VALUE
|
|
4333
|
+
pgconn_decoder_for_get_copy_data_set(VALUE self, VALUE decoder)
|
|
4049
4334
|
{
|
|
4050
4335
|
t_pg_connection *this = pg_get_connection( self );
|
|
4051
4336
|
|
|
4052
|
-
|
|
4053
|
-
|
|
4054
|
-
|
|
4055
|
-
|
|
4056
|
-
|
|
4057
|
-
|
|
4337
|
+
rb_check_frozen(self);
|
|
4338
|
+
if( decoder != Qnil ){
|
|
4339
|
+
t_pg_coder *co;
|
|
4340
|
+
UNUSED(co);
|
|
4341
|
+
/* Check argument type */
|
|
4342
|
+
TypedData_Get_Struct(decoder, t_pg_coder, &pg_coder_type, co);
|
|
4058
4343
|
}
|
|
4059
|
-
this->decoder_for_get_copy_data
|
|
4344
|
+
RB_OBJ_WRITE(self, &this->decoder_for_get_copy_data, decoder);
|
|
4060
4345
|
|
|
4061
|
-
return
|
|
4346
|
+
return decoder;
|
|
4062
4347
|
}
|
|
4063
4348
|
|
|
4064
4349
|
/*
|
|
@@ -4102,6 +4387,7 @@ pgconn_field_name_type_set(VALUE self, VALUE sym)
|
|
|
4102
4387
|
{
|
|
4103
4388
|
t_pg_connection *this = pg_get_connection( self );
|
|
4104
4389
|
|
|
4390
|
+
rb_check_frozen(self);
|
|
4105
4391
|
this->flags &= ~PG_RESULT_FIELD_NAMES_MASK;
|
|
4106
4392
|
if( sym == sym_symbol ) this->flags |= PG_RESULT_FIELD_NAMES_SYMBOL;
|
|
4107
4393
|
else if ( sym == sym_static_symbol ) this->flags |= PG_RESULT_FIELD_NAMES_STATIC_SYMBOL;
|
|
@@ -4138,9 +4424,10 @@ pgconn_field_name_type_get(VALUE self)
|
|
|
4138
4424
|
* Document-class: PG::Connection
|
|
4139
4425
|
*/
|
|
4140
4426
|
void
|
|
4141
|
-
init_pg_connection()
|
|
4427
|
+
init_pg_connection(void)
|
|
4142
4428
|
{
|
|
4143
4429
|
s_id_encode = rb_intern("encode");
|
|
4430
|
+
s_id_autoclose_set = rb_intern("autoclose=");
|
|
4144
4431
|
sym_type = ID2SYM(rb_intern("type"));
|
|
4145
4432
|
sym_format = ID2SYM(rb_intern("format"));
|
|
4146
4433
|
sym_value = ID2SYM(rb_intern("value"));
|
|
@@ -4156,10 +4443,6 @@ init_pg_connection()
|
|
|
4156
4443
|
/****** PG::Connection CLASS METHODS ******/
|
|
4157
4444
|
rb_define_alloc_func( rb_cPGconn, pgconn_s_allocate );
|
|
4158
4445
|
|
|
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
4446
|
rb_define_singleton_method(rb_cPGconn, "escape_string", pgconn_s_escape, 1);
|
|
4164
4447
|
SINGLETON_ALIAS(rb_cPGconn, "escape", "escape_string");
|
|
4165
4448
|
rb_define_singleton_method(rb_cPGconn, "escape_bytea", pgconn_s_escape_bytea, 1);
|
|
@@ -4168,14 +4451,15 @@ init_pg_connection()
|
|
|
4168
4451
|
rb_define_singleton_method(rb_cPGconn, "quote_ident", pgconn_s_quote_ident, 1);
|
|
4169
4452
|
rb_define_singleton_method(rb_cPGconn, "connect_start", pgconn_s_connect_start, -1);
|
|
4170
4453
|
rb_define_singleton_method(rb_cPGconn, "conndefaults", pgconn_s_conndefaults, 0);
|
|
4171
|
-
rb_define_singleton_method(rb_cPGconn, "
|
|
4454
|
+
rb_define_singleton_method(rb_cPGconn, "conninfo_parse", pgconn_s_conninfo_parse, 1);
|
|
4455
|
+
rb_define_singleton_method(rb_cPGconn, "sync_ping", pgconn_s_sync_ping, -1);
|
|
4456
|
+
rb_define_singleton_method(rb_cPGconn, "sync_connect", pgconn_s_sync_connect, -1);
|
|
4172
4457
|
|
|
4173
4458
|
/****** PG::Connection INSTANCE METHODS: Connection Control ******/
|
|
4174
|
-
rb_define_method(rb_cPGconn, "initialize", pgconn_init, -1);
|
|
4175
4459
|
rb_define_method(rb_cPGconn, "connect_poll", pgconn_connect_poll, 0);
|
|
4176
4460
|
rb_define_method(rb_cPGconn, "finish", pgconn_finish, 0);
|
|
4177
4461
|
rb_define_method(rb_cPGconn, "finished?", pgconn_finished_p, 0);
|
|
4178
|
-
rb_define_method(rb_cPGconn, "
|
|
4462
|
+
rb_define_method(rb_cPGconn, "sync_reset", pgconn_sync_reset, 0);
|
|
4179
4463
|
rb_define_method(rb_cPGconn, "reset_start", pgconn_reset_start, 0);
|
|
4180
4464
|
rb_define_method(rb_cPGconn, "reset_poll", pgconn_reset_poll, 0);
|
|
4181
4465
|
rb_define_alias(rb_cPGconn, "close", "finish");
|
|
@@ -4185,11 +4469,12 @@ init_pg_connection()
|
|
|
4185
4469
|
rb_define_method(rb_cPGconn, "user", pgconn_user, 0);
|
|
4186
4470
|
rb_define_method(rb_cPGconn, "pass", pgconn_pass, 0);
|
|
4187
4471
|
rb_define_method(rb_cPGconn, "host", pgconn_host, 0);
|
|
4472
|
+
#if defined(HAVE_PQRESULTMEMORYSIZE)
|
|
4473
|
+
rb_define_method(rb_cPGconn, "hostaddr", pgconn_hostaddr, 0);
|
|
4474
|
+
#endif
|
|
4188
4475
|
rb_define_method(rb_cPGconn, "port", pgconn_port, 0);
|
|
4189
4476
|
rb_define_method(rb_cPGconn, "tty", pgconn_tty, 0);
|
|
4190
|
-
#ifdef HAVE_PQCONNINFO
|
|
4191
4477
|
rb_define_method(rb_cPGconn, "conninfo", pgconn_conninfo, 0);
|
|
4192
|
-
#endif
|
|
4193
4478
|
rb_define_method(rb_cPGconn, "options", pgconn_options, 0);
|
|
4194
4479
|
rb_define_method(rb_cPGconn, "status", pgconn_status, 0);
|
|
4195
4480
|
rb_define_method(rb_cPGconn, "transaction_status", pgconn_transaction_status, 0);
|
|
@@ -4200,17 +4485,18 @@ init_pg_connection()
|
|
|
4200
4485
|
rb_define_method(rb_cPGconn, "socket", pgconn_socket, 0);
|
|
4201
4486
|
rb_define_method(rb_cPGconn, "socket_io", pgconn_socket_io, 0);
|
|
4202
4487
|
rb_define_method(rb_cPGconn, "backend_pid", pgconn_backend_pid, 0);
|
|
4488
|
+
rb_define_method(rb_cPGconn, "backend_key", pgconn_backend_key, 0);
|
|
4203
4489
|
rb_define_method(rb_cPGconn, "connection_needs_password", pgconn_connection_needs_password, 0);
|
|
4204
4490
|
rb_define_method(rb_cPGconn, "connection_used_password", pgconn_connection_used_password, 0);
|
|
4205
4491
|
/* rb_define_method(rb_cPGconn, "getssl", pgconn_getssl, 0); */
|
|
4206
4492
|
|
|
4207
4493
|
/****** 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",
|
|
4494
|
+
rb_define_method(rb_cPGconn, "sync_exec", pgconn_sync_exec, -1);
|
|
4495
|
+
rb_define_method(rb_cPGconn, "sync_exec_params", pgconn_sync_exec_params, -1);
|
|
4496
|
+
rb_define_method(rb_cPGconn, "sync_prepare", pgconn_sync_prepare, -1);
|
|
4497
|
+
rb_define_method(rb_cPGconn, "sync_exec_prepared", pgconn_sync_exec_prepared, -1);
|
|
4498
|
+
rb_define_method(rb_cPGconn, "sync_describe_prepared", pgconn_sync_describe_prepared, 1);
|
|
4499
|
+
rb_define_method(rb_cPGconn, "sync_describe_portal", pgconn_sync_describe_portal, 1);
|
|
4214
4500
|
|
|
4215
4501
|
rb_define_method(rb_cPGconn, "exec", pgconn_async_exec, -1);
|
|
4216
4502
|
rb_define_method(rb_cPGconn, "exec_params", pgconn_async_exec_params, -1);
|
|
@@ -4243,25 +4529,26 @@ init_pg_connection()
|
|
|
4243
4529
|
rb_define_method(rb_cPGconn, "send_query_prepared", pgconn_send_query_prepared, -1);
|
|
4244
4530
|
rb_define_method(rb_cPGconn, "send_describe_prepared", pgconn_send_describe_prepared, 1);
|
|
4245
4531
|
rb_define_method(rb_cPGconn, "send_describe_portal", pgconn_send_describe_portal, 1);
|
|
4246
|
-
rb_define_method(rb_cPGconn, "
|
|
4532
|
+
rb_define_method(rb_cPGconn, "sync_get_result", pgconn_sync_get_result, 0);
|
|
4247
4533
|
rb_define_method(rb_cPGconn, "consume_input", pgconn_consume_input, 0);
|
|
4248
4534
|
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",
|
|
4535
|
+
rb_define_method(rb_cPGconn, "sync_setnonblocking", pgconn_sync_setnonblocking, 1);
|
|
4536
|
+
rb_define_method(rb_cPGconn, "sync_isnonblocking", pgconn_sync_isnonblocking, 0);
|
|
4537
|
+
rb_define_method(rb_cPGconn, "sync_flush", pgconn_sync_flush, 0);
|
|
4538
|
+
rb_define_method(rb_cPGconn, "flush", pgconn_async_flush, 0);
|
|
4539
|
+
rb_define_alias(rb_cPGconn, "async_flush", "flush");
|
|
4253
4540
|
rb_define_method(rb_cPGconn, "discard_results", pgconn_discard_results, 0);
|
|
4254
4541
|
|
|
4255
4542
|
/****** PG::Connection INSTANCE METHODS: Cancelling Queries in Progress ******/
|
|
4256
|
-
rb_define_method(rb_cPGconn, "
|
|
4543
|
+
rb_define_method(rb_cPGconn, "sync_cancel", pgconn_sync_cancel, 0);
|
|
4257
4544
|
|
|
4258
4545
|
/****** PG::Connection INSTANCE METHODS: NOTIFY ******/
|
|
4259
4546
|
rb_define_method(rb_cPGconn, "notifies", pgconn_notifies, 0);
|
|
4260
4547
|
|
|
4261
4548
|
/****** PG::Connection INSTANCE METHODS: COPY ******/
|
|
4262
|
-
rb_define_method(rb_cPGconn, "
|
|
4263
|
-
rb_define_method(rb_cPGconn, "
|
|
4264
|
-
rb_define_method(rb_cPGconn, "
|
|
4549
|
+
rb_define_method(rb_cPGconn, "sync_put_copy_data", pgconn_sync_put_copy_data, -1);
|
|
4550
|
+
rb_define_method(rb_cPGconn, "sync_put_copy_end", pgconn_sync_put_copy_end, -1);
|
|
4551
|
+
rb_define_method(rb_cPGconn, "sync_get_copy_data", pgconn_sync_get_copy_data, -1);
|
|
4265
4552
|
|
|
4266
4553
|
/****** PG::Connection INSTANCE METHODS: Control Functions ******/
|
|
4267
4554
|
rb_define_method(rb_cPGconn, "set_error_verbosity", pgconn_set_error_verbosity, 1);
|
|
@@ -4277,16 +4564,20 @@ init_pg_connection()
|
|
|
4277
4564
|
|
|
4278
4565
|
/****** PG::Connection INSTANCE METHODS: Other ******/
|
|
4279
4566
|
rb_define_method(rb_cPGconn, "get_client_encoding", pgconn_get_client_encoding, 0);
|
|
4280
|
-
rb_define_method(rb_cPGconn, "
|
|
4567
|
+
rb_define_method(rb_cPGconn, "sync_set_client_encoding", pgconn_sync_set_client_encoding, 1);
|
|
4568
|
+
rb_define_method(rb_cPGconn, "set_client_encoding", pgconn_async_set_client_encoding, 1);
|
|
4569
|
+
rb_define_alias(rb_cPGconn, "async_set_client_encoding", "set_client_encoding");
|
|
4281
4570
|
rb_define_alias(rb_cPGconn, "client_encoding=", "set_client_encoding");
|
|
4282
|
-
rb_define_method(rb_cPGconn, "transaction", pgconn_transaction, 0);
|
|
4283
4571
|
rb_define_method(rb_cPGconn, "block", pgconn_block, -1);
|
|
4572
|
+
rb_define_private_method(rb_cPGconn, "flush_data=", pgconn_flush_data_set, 1);
|
|
4284
4573
|
rb_define_method(rb_cPGconn, "wait_for_notify", pgconn_wait_for_notify, -1);
|
|
4285
4574
|
rb_define_alias(rb_cPGconn, "notifies_wait", "wait_for_notify");
|
|
4286
4575
|
rb_define_method(rb_cPGconn, "quote_ident", pgconn_s_quote_ident, 1);
|
|
4287
|
-
rb_define_method(rb_cPGconn, "
|
|
4576
|
+
rb_define_method(rb_cPGconn, "sync_get_last_result", pgconn_sync_get_last_result, 0);
|
|
4577
|
+
rb_define_method(rb_cPGconn, "get_last_result", pgconn_async_get_last_result, 0);
|
|
4578
|
+
rb_define_alias(rb_cPGconn, "async_get_last_result", "get_last_result");
|
|
4288
4579
|
#ifdef HAVE_PQENCRYPTPASSWORDCONN
|
|
4289
|
-
rb_define_method(rb_cPGconn, "
|
|
4580
|
+
rb_define_method(rb_cPGconn, "sync_encrypt_password", pgconn_sync_encrypt_password, -1);
|
|
4290
4581
|
#endif
|
|
4291
4582
|
|
|
4292
4583
|
#ifdef HAVE_PQSSLATTRIBUTE
|
|
@@ -4295,6 +4586,14 @@ init_pg_connection()
|
|
|
4295
4586
|
rb_define_method(rb_cPGconn, "ssl_attribute_names", pgconn_ssl_attribute_names, 0);
|
|
4296
4587
|
#endif
|
|
4297
4588
|
|
|
4589
|
+
#ifdef HAVE_PQENTERPIPELINEMODE
|
|
4590
|
+
rb_define_method(rb_cPGconn, "pipeline_status", pgconn_pipeline_status, 0);
|
|
4591
|
+
rb_define_method(rb_cPGconn, "enter_pipeline_mode", pgconn_enter_pipeline_mode, 0);
|
|
4592
|
+
rb_define_method(rb_cPGconn, "exit_pipeline_mode", pgconn_exit_pipeline_mode, 0);
|
|
4593
|
+
rb_define_method(rb_cPGconn, "pipeline_sync", pgconn_pipeline_sync, 0);
|
|
4594
|
+
rb_define_method(rb_cPGconn, "send_flush_request", pgconn_send_flush_request, 0);
|
|
4595
|
+
#endif
|
|
4596
|
+
|
|
4298
4597
|
/****** PG::Connection INSTANCE METHODS: Large Object Support ******/
|
|
4299
4598
|
rb_define_method(rb_cPGconn, "lo_creat", pgconn_locreat, -1);
|
|
4300
4599
|
rb_define_alias(rb_cPGconn, "locreat", "lo_creat");
|