pg 1.1.4 → 1.5.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- checksums.yaml.gz.sig +0 -0
- data/.appveyor.yml +42 -0
- data/.gems +6 -0
- data/.github/workflows/binary-gems.yml +117 -0
- data/.github/workflows/source-gem.yml +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 +3 -3
- data/README-Windows.rdoc +4 -4
- data/README.ja.md +276 -0
- data/README.md +286 -0
- data/Rakefile +37 -137
- data/Rakefile.cross +62 -62
- data/certs/ged.pem +24 -0
- data/certs/larskanis-2022.pem +26 -0
- data/certs/larskanis-2023.pem +24 -0
- data/ext/errorcodes.def +76 -0
- data/ext/errorcodes.rb +0 -0
- data/ext/errorcodes.txt +21 -2
- data/ext/extconf.rb +101 -26
- data/ext/gvl_wrappers.c +4 -0
- data/ext/gvl_wrappers.h +23 -0
- data/ext/pg.c +203 -151
- data/ext/pg.h +48 -21
- data/ext/pg_binary_decoder.c +89 -10
- data/ext/pg_binary_encoder.c +238 -13
- data/ext/pg_coder.c +109 -34
- data/ext/pg_connection.c +1365 -976
- data/ext/pg_copy_coder.c +356 -35
- data/ext/pg_errors.c +1 -1
- data/ext/pg_record_coder.c +522 -0
- data/ext/pg_result.c +436 -171
- data/ext/pg_text_decoder.c +42 -18
- data/ext/pg_text_encoder.c +201 -56
- data/ext/pg_tuple.c +97 -66
- data/ext/pg_type_map.c +45 -11
- data/ext/pg_type_map_all_strings.c +21 -7
- data/ext/pg_type_map_by_class.c +59 -27
- data/ext/pg_type_map_by_column.c +80 -37
- data/ext/pg_type_map_by_mri_type.c +49 -20
- data/ext/pg_type_map_by_oid.c +62 -29
- data/ext/pg_type_map_in_ruby.c +56 -22
- data/ext/{util.c → pg_util.c} +7 -7
- data/lib/pg/basic_type_map_based_on_result.rb +67 -0
- data/lib/pg/basic_type_map_for_queries.rb +198 -0
- data/lib/pg/basic_type_map_for_results.rb +104 -0
- data/lib/pg/basic_type_registry.rb +299 -0
- data/lib/pg/binary_decoder/date.rb +9 -0
- data/lib/pg/binary_decoder/timestamp.rb +26 -0
- data/lib/pg/binary_encoder/timestamp.rb +20 -0
- data/lib/pg/coder.rb +35 -12
- data/lib/pg/connection.rb +744 -84
- data/lib/pg/exceptions.rb +15 -1
- data/lib/pg/result.rb +13 -1
- data/lib/pg/text_decoder/date.rb +18 -0
- data/lib/pg/text_decoder/inet.rb +9 -0
- data/lib/pg/text_decoder/json.rb +14 -0
- data/lib/pg/text_decoder/numeric.rb +9 -0
- data/lib/pg/text_decoder/timestamp.rb +30 -0
- data/lib/pg/text_encoder/date.rb +12 -0
- data/lib/pg/text_encoder/inet.rb +28 -0
- data/lib/pg/text_encoder/json.rb +14 -0
- data/lib/pg/text_encoder/numeric.rb +9 -0
- data/lib/pg/text_encoder/timestamp.rb +24 -0
- data/lib/pg/type_map_by_column.rb +2 -1
- data/lib/pg/version.rb +4 -0
- data/lib/pg.rb +94 -39
- data/misc/openssl-pg-segfault.rb +31 -0
- data/misc/postgres/History.txt +9 -0
- data/misc/postgres/Manifest.txt +5 -0
- data/misc/postgres/README.txt +21 -0
- data/misc/postgres/Rakefile +21 -0
- data/misc/postgres/lib/postgres.rb +16 -0
- data/misc/ruby-pg/History.txt +9 -0
- data/misc/ruby-pg/Manifest.txt +5 -0
- data/misc/ruby-pg/README.txt +21 -0
- data/misc/ruby-pg/Rakefile +21 -0
- data/misc/ruby-pg/lib/ruby/pg.rb +16 -0
- data/pg.gemspec +34 -0
- data/rakelib/task_extension.rb +46 -0
- data/sample/array_insert.rb +20 -0
- data/sample/async_api.rb +102 -0
- data/sample/async_copyto.rb +39 -0
- data/sample/async_mixed.rb +56 -0
- data/sample/check_conn.rb +21 -0
- data/sample/copydata.rb +71 -0
- data/sample/copyfrom.rb +81 -0
- data/sample/copyto.rb +19 -0
- data/sample/cursor.rb +21 -0
- data/sample/disk_usage_report.rb +177 -0
- data/sample/issue-119.rb +94 -0
- data/sample/losample.rb +69 -0
- data/sample/minimal-testcase.rb +17 -0
- data/sample/notify_wait.rb +72 -0
- data/sample/pg_statistics.rb +285 -0
- data/sample/replication_monitor.rb +222 -0
- data/sample/test_binary_values.rb +33 -0
- data/sample/wal_shipper.rb +434 -0
- data/sample/warehouse_partitions.rb +311 -0
- data/translation/.po4a-version +7 -0
- data/translation/po/all.pot +910 -0
- data/translation/po/ja.po +1047 -0
- data/translation/po4a.cfg +12 -0
- data.tar.gz.sig +0 -0
- metadata +151 -218
- metadata.gz.sig +0 -0
- data/ChangeLog +0 -6595
- data/History.rdoc +0 -492
- data/README.ja.rdoc +0 -14
- data/README.rdoc +0 -178
- data/lib/pg/basic_type_mapping.rb +0 -459
- data/lib/pg/binary_decoder.rb +0 -22
- data/lib/pg/constants.rb +0 -11
- data/lib/pg/text_decoder.rb +0 -47
- data/lib/pg/text_encoder.rb +0 -69
- data/spec/data/expected_trace.out +0 -26
- data/spec/data/random_binary_data +0 -0
- data/spec/helpers.rb +0 -380
- data/spec/pg/basic_type_mapping_spec.rb +0 -508
- data/spec/pg/connection_spec.rb +0 -1872
- data/spec/pg/connection_sync_spec.rb +0 -41
- data/spec/pg/result_spec.rb +0 -491
- data/spec/pg/tuple_spec.rb +0 -280
- data/spec/pg/type_map_by_class_spec.rb +0 -138
- data/spec/pg/type_map_by_column_spec.rb +0 -222
- data/spec/pg/type_map_by_mri_type_spec.rb +0 -136
- data/spec/pg/type_map_by_oid_spec.rb +0 -149
- data/spec/pg/type_map_in_ruby_spec.rb +0 -164
- data/spec/pg/type_map_spec.rb +0 -22
- data/spec/pg/type_spec.rb +0 -949
- data/spec/pg_spec.rb +0 -50
- /data/ext/{util.h → pg_util.h} +0 -0
data/ext/pg_connection.c
CHANGED
@@ -12,19 +12,41 @@
|
|
12
12
|
|
13
13
|
VALUE rb_cPGconn;
|
14
14
|
static ID s_id_encode;
|
15
|
+
static ID s_id_autoclose_set;
|
15
16
|
static VALUE sym_type, sym_format, sym_value;
|
16
|
-
|
17
|
-
static PQnoticeReceiver default_notice_receiver = NULL;
|
18
|
-
static PQnoticeProcessor default_notice_processor = NULL;
|
17
|
+
static VALUE sym_symbol, sym_string, sym_static_symbol;
|
19
18
|
|
20
19
|
static VALUE pgconn_finish( VALUE );
|
21
20
|
static VALUE pgconn_set_default_encoding( VALUE self );
|
22
|
-
|
21
|
+
static VALUE pgconn_wait_for_flush( VALUE self );
|
22
|
+
static void pgconn_set_internal_encoding_index( VALUE );
|
23
|
+
static const rb_data_type_t pg_connection_type;
|
24
|
+
static VALUE pgconn_async_flush(VALUE self);
|
23
25
|
|
24
26
|
/*
|
25
27
|
* Global functions
|
26
28
|
*/
|
27
29
|
|
30
|
+
/*
|
31
|
+
* Convenience function to raise connection errors
|
32
|
+
*/
|
33
|
+
#ifdef __GNUC__
|
34
|
+
__attribute__((format(printf, 3, 4)))
|
35
|
+
#endif
|
36
|
+
static void
|
37
|
+
pg_raise_conn_error( VALUE klass, VALUE self, const char *format, ...)
|
38
|
+
{
|
39
|
+
VALUE msg, error;
|
40
|
+
va_list ap;
|
41
|
+
|
42
|
+
va_start(ap, format);
|
43
|
+
msg = rb_vsprintf(format, ap);
|
44
|
+
va_end(ap);
|
45
|
+
error = rb_exc_new_str(klass, msg);
|
46
|
+
rb_iv_set(error, "@connection", self);
|
47
|
+
rb_exc_raise(error);
|
48
|
+
}
|
49
|
+
|
28
50
|
/*
|
29
51
|
* Fetch the PG::Connection object data pointer.
|
30
52
|
*/
|
@@ -32,7 +54,7 @@ t_pg_connection *
|
|
32
54
|
pg_get_connection( VALUE self )
|
33
55
|
{
|
34
56
|
t_pg_connection *this;
|
35
|
-
|
57
|
+
TypedData_Get_Struct( self, t_pg_connection, &pg_connection_type, this);
|
36
58
|
|
37
59
|
return this;
|
38
60
|
}
|
@@ -45,10 +67,10 @@ static t_pg_connection *
|
|
45
67
|
pg_get_connection_safe( VALUE self )
|
46
68
|
{
|
47
69
|
t_pg_connection *this;
|
48
|
-
|
70
|
+
TypedData_Get_Struct( self, t_pg_connection, &pg_connection_type, this);
|
49
71
|
|
50
72
|
if ( !this->pgconn )
|
51
|
-
|
73
|
+
pg_raise_conn_error( rb_eConnectionBad, self, "connection is closed");
|
52
74
|
|
53
75
|
return this;
|
54
76
|
}
|
@@ -64,10 +86,11 @@ PGconn *
|
|
64
86
|
pg_get_pgconn( VALUE self )
|
65
87
|
{
|
66
88
|
t_pg_connection *this;
|
67
|
-
|
89
|
+
TypedData_Get_Struct( self, t_pg_connection, &pg_connection_type, this);
|
68
90
|
|
69
|
-
if ( !this->pgconn )
|
70
|
-
|
91
|
+
if ( !this->pgconn ){
|
92
|
+
pg_raise_conn_error( rb_eConnectionBad, self, "connection is closed");
|
93
|
+
}
|
71
94
|
|
72
95
|
return this->pgconn;
|
73
96
|
}
|
@@ -85,14 +108,13 @@ pgconn_close_socket_io( VALUE self )
|
|
85
108
|
|
86
109
|
if ( RTEST(socket_io) ) {
|
87
110
|
#if defined(_WIN32)
|
88
|
-
if( rb_w32_unwrap_io_handle(this->ruby_sd) )
|
89
|
-
|
90
|
-
}
|
111
|
+
if( rb_w32_unwrap_io_handle(this->ruby_sd) )
|
112
|
+
pg_raise_conn_error( rb_eConnectionBad, self, "Could not unwrap win32 socket handle");
|
91
113
|
#endif
|
92
114
|
rb_funcall( socket_io, rb_intern("close"), 0 );
|
93
115
|
}
|
94
116
|
|
95
|
-
this->socket_io
|
117
|
+
RB_OBJ_WRITE(self, &this->socket_io, Qnil);
|
96
118
|
}
|
97
119
|
|
98
120
|
|
@@ -144,17 +166,31 @@ static const char *pg_cstr_enc(VALUE str, int enc_idx){
|
|
144
166
|
* GC Mark function
|
145
167
|
*/
|
146
168
|
static void
|
147
|
-
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 )
|
148
184
|
{
|
149
|
-
|
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,100 +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
|
203
|
-
|
204
|
-
this->guess_result_memsize = 1;
|
258
|
+
RB_OBJ_WRITE(self, &this->socket_io, Qnil);
|
259
|
+
RB_OBJ_WRITE(self, &this->notice_receiver, Qnil);
|
260
|
+
RB_OBJ_WRITE(self, &this->notice_processor, Qnil);
|
261
|
+
RB_OBJ_WRITE(self, &this->type_map_for_queries, pg_typemap_all_strings);
|
262
|
+
RB_OBJ_WRITE(self, &this->type_map_for_results, pg_typemap_all_strings);
|
263
|
+
RB_OBJ_WRITE(self, &this->encoder_for_put_copy_data, Qnil);
|
264
|
+
RB_OBJ_WRITE(self, &this->decoder_for_get_copy_data, Qnil);
|
265
|
+
RB_OBJ_WRITE(self, &this->trace_stream, Qnil);
|
266
|
+
rb_ivar_set(self, rb_intern("@calls_to_put_copy_data"), INT2FIX(0));
|
205
267
|
|
206
268
|
return self;
|
207
269
|
}
|
208
270
|
|
209
|
-
|
210
|
-
/*
|
211
|
-
* Document-method: new
|
212
|
-
*
|
213
|
-
* call-seq:
|
214
|
-
* PG::Connection.new -> conn
|
215
|
-
* PG::Connection.new(connection_hash) -> conn
|
216
|
-
* PG::Connection.new(connection_string) -> conn
|
217
|
-
* PG::Connection.new(host, port, options, tty, dbname, user, password) -> conn
|
218
|
-
*
|
219
|
-
* Create a connection to the specified server.
|
220
|
-
*
|
221
|
-
* [+host+]
|
222
|
-
* server hostname
|
223
|
-
* [+hostaddr+]
|
224
|
-
* server address (avoids hostname lookup, overrides +host+)
|
225
|
-
* [+port+]
|
226
|
-
* server port number
|
227
|
-
* [+dbname+]
|
228
|
-
* connecting database name
|
229
|
-
* [+user+]
|
230
|
-
* login user name
|
231
|
-
* [+password+]
|
232
|
-
* login password
|
233
|
-
* [+connect_timeout+]
|
234
|
-
* maximum time to wait for connection to succeed
|
235
|
-
* [+options+]
|
236
|
-
* backend options
|
237
|
-
* [+tty+]
|
238
|
-
* (ignored in newer versions of PostgreSQL)
|
239
|
-
* [+sslmode+]
|
240
|
-
* (disable|allow|prefer|require)
|
241
|
-
* [+krbsrvname+]
|
242
|
-
* kerberos service name
|
243
|
-
* [+gsslib+]
|
244
|
-
* GSS library to use for GSSAPI authentication
|
245
|
-
* [+service+]
|
246
|
-
* service name to use for additional parameters
|
247
|
-
*
|
248
|
-
* Examples:
|
249
|
-
*
|
250
|
-
* # Connect using all defaults
|
251
|
-
* PG::Connection.new
|
252
|
-
*
|
253
|
-
* # As a Hash
|
254
|
-
* PG::Connection.new( :dbname => 'test', :port => 5432 )
|
255
|
-
*
|
256
|
-
* # As a String
|
257
|
-
* PG::Connection.new( "dbname=test port=5432" )
|
258
|
-
*
|
259
|
-
* # As an Array
|
260
|
-
* PG::Connection.new( nil, 5432, nil, nil, 'test', nil, nil )
|
261
|
-
*
|
262
|
-
* If the Ruby default internal encoding is set (i.e., Encoding.default_internal != nil), the
|
263
|
-
* connection will have its +client_encoding+ set accordingly.
|
264
|
-
*
|
265
|
-
* Raises a PG::Error if the connection fails.
|
266
|
-
*/
|
267
271
|
static VALUE
|
268
|
-
|
272
|
+
pgconn_s_sync_connect(int argc, VALUE *argv, VALUE klass)
|
269
273
|
{
|
270
274
|
t_pg_connection *this;
|
271
275
|
VALUE conninfo;
|
272
|
-
VALUE
|
276
|
+
VALUE self = pgconn_s_allocate( klass );
|
273
277
|
|
274
278
|
this = pg_get_connection( self );
|
275
279
|
conninfo = rb_funcall2( rb_cPGconn, rb_intern("parse_connect_args"), argc, argv );
|
276
280
|
this->pgconn = gvl_PQconnectdb(StringValueCStr(conninfo));
|
277
281
|
|
278
282
|
if(this->pgconn == NULL)
|
279
|
-
rb_raise(rb_ePGerror, "PQconnectdb() unable to allocate structure");
|
283
|
+
rb_raise(rb_ePGerror, "PQconnectdb() unable to allocate PGconn structure");
|
280
284
|
|
281
|
-
if (PQstatus(this->pgconn) == CONNECTION_BAD)
|
282
|
-
|
283
|
-
rb_iv_set(error, "@connection", self);
|
284
|
-
rb_exc_raise(error);
|
285
|
-
}
|
285
|
+
if (PQstatus(this->pgconn) == CONNECTION_BAD)
|
286
|
+
pg_raise_conn_error( rb_eConnectionBad, self, "%s", PQerrorMessage(this->pgconn));
|
286
287
|
|
287
288
|
pgconn_set_default_encoding( self );
|
288
289
|
|
@@ -298,14 +299,16 @@ pgconn_init(int argc, VALUE *argv, VALUE self)
|
|
298
299
|
* PG::Connection.connect_start(connection_string) -> conn
|
299
300
|
* PG::Connection.connect_start(host, port, options, tty, dbname, login, password) -> conn
|
300
301
|
*
|
301
|
-
* This is an asynchronous version of PG::Connection.
|
302
|
+
* This is an asynchronous version of PG::Connection.new.
|
302
303
|
*
|
303
304
|
* Use #connect_poll to poll the status of the connection.
|
304
305
|
*
|
305
306
|
* NOTE: this does *not* set the connection's +client_encoding+ for you if
|
306
|
-
* Encoding.default_internal is set. To set it after the connection is established,
|
307
|
+
* +Encoding.default_internal+ is set. To set it after the connection is established,
|
307
308
|
* call #internal_encoding=. You can also set it automatically by setting
|
308
|
-
* ENV['PGCLIENTENCODING']
|
309
|
+
* <code>ENV['PGCLIENTENCODING']</code>, or include the 'options' connection parameter.
|
310
|
+
*
|
311
|
+
* See also the 'sample' directory of this gem and the corresponding {libpq functions}[https://www.postgresql.org/docs/current/libpq-connect.html#LIBPQ-PQCONNECTSTARTPARAMS].
|
309
312
|
*
|
310
313
|
*/
|
311
314
|
static VALUE
|
@@ -313,7 +316,6 @@ pgconn_s_connect_start( int argc, VALUE *argv, VALUE klass )
|
|
313
316
|
{
|
314
317
|
VALUE rb_conn;
|
315
318
|
VALUE conninfo;
|
316
|
-
VALUE error;
|
317
319
|
t_pg_connection *this;
|
318
320
|
|
319
321
|
/*
|
@@ -326,13 +328,10 @@ pgconn_s_connect_start( int argc, VALUE *argv, VALUE klass )
|
|
326
328
|
this->pgconn = gvl_PQconnectStart( StringValueCStr(conninfo) );
|
327
329
|
|
328
330
|
if( this->pgconn == NULL )
|
329
|
-
rb_raise(rb_ePGerror, "PQconnectStart() unable to allocate structure");
|
331
|
+
rb_raise(rb_ePGerror, "PQconnectStart() unable to allocate PGconn structure");
|
330
332
|
|
331
|
-
if ( PQstatus(this->pgconn) == CONNECTION_BAD )
|
332
|
-
|
333
|
-
rb_iv_set(error, "@connection", rb_conn);
|
334
|
-
rb_exc_raise(error);
|
335
|
-
}
|
333
|
+
if ( PQstatus(this->pgconn) == CONNECTION_BAD )
|
334
|
+
pg_raise_conn_error( rb_eConnectionBad, rb_conn, "%s", PQerrorMessage(this->pgconn));
|
336
335
|
|
337
336
|
if ( rb_block_given_p() ) {
|
338
337
|
return rb_ensure( rb_yield, rb_conn, pgconn_finish, rb_conn );
|
@@ -340,34 +339,14 @@ pgconn_s_connect_start( int argc, VALUE *argv, VALUE klass )
|
|
340
339
|
return rb_conn;
|
341
340
|
}
|
342
341
|
|
343
|
-
/*
|
344
|
-
* call-seq:
|
345
|
-
* PG::Connection.ping(connection_hash) -> Integer
|
346
|
-
* PG::Connection.ping(connection_string) -> Integer
|
347
|
-
* PG::Connection.ping(host, port, options, tty, dbname, login, password) -> Integer
|
348
|
-
*
|
349
|
-
* Check server status.
|
350
|
-
*
|
351
|
-
* Returns one of:
|
352
|
-
* [+PQPING_OK+]
|
353
|
-
* server is accepting connections
|
354
|
-
* [+PQPING_REJECT+]
|
355
|
-
* server is alive but rejecting connections
|
356
|
-
* [+PQPING_NO_RESPONSE+]
|
357
|
-
* could not establish connection
|
358
|
-
* [+PQPING_NO_ATTEMPT+]
|
359
|
-
* connection not attempted (bad params)
|
360
|
-
*
|
361
|
-
* Available since PostgreSQL-9.1
|
362
|
-
*/
|
363
342
|
static VALUE
|
364
|
-
|
343
|
+
pgconn_s_sync_ping( int argc, VALUE *argv, VALUE klass )
|
365
344
|
{
|
366
345
|
PGPing ping;
|
367
346
|
VALUE conninfo;
|
368
347
|
|
369
348
|
conninfo = rb_funcall2( klass, rb_intern("parse_connect_args"), argc, argv );
|
370
|
-
ping =
|
349
|
+
ping = gvl_PQping( StringValueCStr(conninfo) );
|
371
350
|
|
372
351
|
return INT2FIX((int)ping);
|
373
352
|
}
|
@@ -408,31 +387,40 @@ pgconn_s_conndefaults(VALUE self)
|
|
408
387
|
return array;
|
409
388
|
}
|
410
389
|
|
411
|
-
|
412
|
-
#ifdef HAVE_PQENCRYPTPASSWORDCONN
|
413
390
|
/*
|
414
|
-
*
|
415
|
-
* conn.encrypt_password( password, username, algorithm=nil ) -> String
|
416
|
-
*
|
417
|
-
* This function is intended to be used by client applications that wish to send commands like <tt>ALTER USER joe PASSWORD 'pwd'</tt>.
|
418
|
-
* It is good practice not to send the original cleartext password in such a command, because it might be exposed in command logs, activity displays, and so on.
|
419
|
-
* Instead, use this function to convert the password to encrypted form before it is sent.
|
391
|
+
* Document-method: PG::Connection.conninfo_parse
|
420
392
|
*
|
421
|
-
*
|
422
|
-
*
|
423
|
-
* 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).
|
424
|
-
* Note that support for +scram-sha-256+ was introduced in PostgreSQL version 10, and will not work correctly with older server versions.
|
425
|
-
* If algorithm is omitted or +nil+, this function will query the server for the current value of the +password_encryption+ setting.
|
426
|
-
* That can block, and will fail if the current transaction is aborted, or if the connection is busy executing another query.
|
427
|
-
* 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.
|
428
|
-
*
|
429
|
-
* Return value is the encrypted password.
|
430
|
-
* 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
|
431
395
|
*
|
432
|
-
*
|
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.
|
433
399
|
*/
|
434
400
|
static VALUE
|
435
|
-
|
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)
|
436
424
|
{
|
437
425
|
char *encrypted = NULL;
|
438
426
|
VALUE rval = Qnil;
|
@@ -448,12 +436,8 @@ pgconn_encrypt_password(int argc, VALUE *argv, VALUE self)
|
|
448
436
|
if ( encrypted ) {
|
449
437
|
rval = rb_str_new2( encrypted );
|
450
438
|
PQfreemem( encrypted );
|
451
|
-
|
452
|
-
OBJ_INFECT( rval, password );
|
453
|
-
OBJ_INFECT( rval, username );
|
454
|
-
OBJ_INFECT( rval, algorithm );
|
455
439
|
} else {
|
456
|
-
|
440
|
+
pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(conn));
|
457
441
|
}
|
458
442
|
|
459
443
|
return rval;
|
@@ -484,9 +468,6 @@ pgconn_s_encrypt_password(VALUE self, VALUE password, VALUE username)
|
|
484
468
|
rval = rb_str_new2( encrypted );
|
485
469
|
PQfreemem( encrypted );
|
486
470
|
|
487
|
-
OBJ_INFECT( rval, password );
|
488
|
-
OBJ_INFECT( rval, username );
|
489
|
-
|
490
471
|
return rval;
|
491
472
|
}
|
492
473
|
|
@@ -510,17 +491,18 @@ pgconn_s_encrypt_password(VALUE self, VALUE password, VALUE username)
|
|
510
491
|
* the asynchronous connection is ready
|
511
492
|
*
|
512
493
|
* Example:
|
513
|
-
*
|
514
|
-
*
|
494
|
+
* require "io/wait"
|
495
|
+
*
|
496
|
+
* conn = PG::Connection.connect_start(dbname: 'mydatabase')
|
515
497
|
* status = conn.connect_poll
|
516
498
|
* while(status != PG::PGRES_POLLING_OK) do
|
517
499
|
* # do some work while waiting for the connection to complete
|
518
500
|
* if(status == PG::PGRES_POLLING_READING)
|
519
|
-
*
|
501
|
+
* unless conn.socket_io.wait_readable(10.0)
|
520
502
|
* raise "Asynchronous connection timed out!"
|
521
503
|
* end
|
522
504
|
* elsif(status == PG::PGRES_POLLING_WRITING)
|
523
|
-
*
|
505
|
+
* unless conn.socket_io.wait_writable(10.0)
|
524
506
|
* raise "Asynchronous connection timed out!"
|
525
507
|
* end
|
526
508
|
* end
|
@@ -534,6 +516,9 @@ pgconn_connect_poll(VALUE self)
|
|
534
516
|
{
|
535
517
|
PostgresPollingStatusType status;
|
536
518
|
status = gvl_PQconnectPoll(pg_get_pgconn(self));
|
519
|
+
|
520
|
+
pgconn_close_socket_io(self);
|
521
|
+
|
537
522
|
return INT2FIX((int)status);
|
538
523
|
}
|
539
524
|
|
@@ -570,15 +555,8 @@ pgconn_finished_p( VALUE self )
|
|
570
555
|
}
|
571
556
|
|
572
557
|
|
573
|
-
/*
|
574
|
-
* call-seq:
|
575
|
-
* conn.reset()
|
576
|
-
*
|
577
|
-
* Resets the backend connection. This method closes the
|
578
|
-
* backend connection and tries to re-connect.
|
579
|
-
*/
|
580
558
|
static VALUE
|
581
|
-
|
559
|
+
pgconn_sync_reset( VALUE self )
|
582
560
|
{
|
583
561
|
pgconn_close_socket_io( self );
|
584
562
|
gvl_PQreset( pg_get_pgconn(self) );
|
@@ -600,7 +578,7 @@ pgconn_reset_start(VALUE self)
|
|
600
578
|
{
|
601
579
|
pgconn_close_socket_io( self );
|
602
580
|
if(gvl_PQresetStart(pg_get_pgconn(self)) == 0)
|
603
|
-
|
581
|
+
pg_raise_conn_error( rb_eUnableToSend, self, "reset has failed");
|
604
582
|
return Qnil;
|
605
583
|
}
|
606
584
|
|
@@ -617,6 +595,9 @@ pgconn_reset_poll(VALUE self)
|
|
617
595
|
{
|
618
596
|
PostgresPollingStatusType status;
|
619
597
|
status = gvl_PQresetPoll(pg_get_pgconn(self));
|
598
|
+
|
599
|
+
pgconn_close_socket_io(self);
|
600
|
+
|
620
601
|
return INT2FIX((int)status);
|
621
602
|
}
|
622
603
|
|
@@ -632,7 +613,7 @@ pgconn_db(VALUE self)
|
|
632
613
|
{
|
633
614
|
char *db = PQdb(pg_get_pgconn(self));
|
634
615
|
if (!db) return Qnil;
|
635
|
-
return
|
616
|
+
return rb_str_new2(db);
|
636
617
|
}
|
637
618
|
|
638
619
|
/*
|
@@ -646,7 +627,7 @@ pgconn_user(VALUE self)
|
|
646
627
|
{
|
647
628
|
char *user = PQuser(pg_get_pgconn(self));
|
648
629
|
if (!user) return Qnil;
|
649
|
-
return
|
630
|
+
return rb_str_new2(user);
|
650
631
|
}
|
651
632
|
|
652
633
|
/*
|
@@ -660,22 +641,53 @@ pgconn_pass(VALUE self)
|
|
660
641
|
{
|
661
642
|
char *user = PQpass(pg_get_pgconn(self));
|
662
643
|
if (!user) return Qnil;
|
663
|
-
return
|
644
|
+
return rb_str_new2(user);
|
664
645
|
}
|
665
646
|
|
666
647
|
/*
|
667
648
|
* call-seq:
|
668
649
|
* conn.host()
|
669
650
|
*
|
670
|
-
* 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 .
|
671
663
|
*/
|
672
664
|
static VALUE
|
673
665
|
pgconn_host(VALUE self)
|
674
666
|
{
|
675
667
|
char *host = PQhost(pg_get_pgconn(self));
|
676
668
|
if (!host) return Qnil;
|
677
|
-
return
|
669
|
+
return rb_str_new2(host);
|
670
|
+
}
|
671
|
+
|
672
|
+
/* PQhostaddr() appeared in PostgreSQL-12 together with PQresultMemorySize() */
|
673
|
+
#if defined(HAVE_PQRESULTMEMORYSIZE)
|
674
|
+
/*
|
675
|
+
* call-seq:
|
676
|
+
* conn.hostaddr()
|
677
|
+
*
|
678
|
+
* Returns the server IP address of the active connection.
|
679
|
+
* This can be the address that a host name resolved to, or an IP address provided through the hostaddr parameter.
|
680
|
+
* If there is an error producing the host information (perhaps if the connection has not been fully established or there was an error), it returns an empty string.
|
681
|
+
*
|
682
|
+
*/
|
683
|
+
static VALUE
|
684
|
+
pgconn_hostaddr(VALUE self)
|
685
|
+
{
|
686
|
+
char *host = PQhostaddr(pg_get_pgconn(self));
|
687
|
+
if (!host) return Qnil;
|
688
|
+
return rb_str_new2(host);
|
678
689
|
}
|
690
|
+
#endif
|
679
691
|
|
680
692
|
/*
|
681
693
|
* call-seq:
|
@@ -687,21 +699,22 @@ static VALUE
|
|
687
699
|
pgconn_port(VALUE self)
|
688
700
|
{
|
689
701
|
char* port = PQport(pg_get_pgconn(self));
|
690
|
-
|
702
|
+
if (!port || port[0] == '\0')
|
703
|
+
return INT2NUM(DEF_PGPORT);
|
704
|
+
else
|
705
|
+
return INT2NUM(atoi(port));
|
691
706
|
}
|
692
707
|
|
693
708
|
/*
|
694
709
|
* call-seq:
|
695
710
|
* conn.tty()
|
696
711
|
*
|
697
|
-
*
|
712
|
+
* Obsolete function.
|
698
713
|
*/
|
699
714
|
static VALUE
|
700
715
|
pgconn_tty(VALUE self)
|
701
716
|
{
|
702
|
-
|
703
|
-
if (!tty) return Qnil;
|
704
|
-
return rb_tainted_str_new2(tty);
|
717
|
+
return rb_str_new2("");
|
705
718
|
}
|
706
719
|
|
707
720
|
/*
|
@@ -715,11 +728,10 @@ pgconn_options(VALUE self)
|
|
715
728
|
{
|
716
729
|
char *options = PQoptions(pg_get_pgconn(self));
|
717
730
|
if (!options) return Qnil;
|
718
|
-
return
|
731
|
+
return rb_str_new2(options);
|
719
732
|
}
|
720
733
|
|
721
734
|
|
722
|
-
#ifdef HAVE_PQCONNINFO
|
723
735
|
/*
|
724
736
|
* call-seq:
|
725
737
|
* conn.conninfo -> hash
|
@@ -739,14 +751,24 @@ pgconn_conninfo( VALUE self )
|
|
739
751
|
|
740
752
|
return array;
|
741
753
|
}
|
742
|
-
#endif
|
743
754
|
|
744
755
|
|
745
756
|
/*
|
746
757
|
* call-seq:
|
747
758
|
* conn.status()
|
748
759
|
*
|
749
|
-
* 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
|
750
772
|
*/
|
751
773
|
static VALUE
|
752
774
|
pgconn_status(VALUE self)
|
@@ -796,7 +818,7 @@ pgconn_parameter_status(VALUE self, VALUE param_name)
|
|
796
818
|
if(ret == NULL)
|
797
819
|
return Qnil;
|
798
820
|
else
|
799
|
-
return
|
821
|
+
return rb_str_new2(ret);
|
800
822
|
}
|
801
823
|
|
802
824
|
/*
|
@@ -834,14 +856,17 @@ pgconn_server_version(VALUE self)
|
|
834
856
|
* call-seq:
|
835
857
|
* conn.error_message -> String
|
836
858
|
*
|
837
|
-
* 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.
|
838
863
|
*/
|
839
864
|
static VALUE
|
840
865
|
pgconn_error_message(VALUE self)
|
841
866
|
{
|
842
867
|
char *error = PQerrorMessage(pg_get_pgconn(self));
|
843
868
|
if (!error) return Qnil;
|
844
|
-
return
|
869
|
+
return rb_str_new2(error);
|
845
870
|
}
|
846
871
|
|
847
872
|
/*
|
@@ -865,8 +890,11 @@ static VALUE
|
|
865
890
|
pgconn_socket(VALUE self)
|
866
891
|
{
|
867
892
|
int sd;
|
893
|
+
pg_deprecated(4, ("conn.socket is deprecated and should be replaced by conn.socket_io"));
|
894
|
+
|
868
895
|
if( (sd = PQsocket(pg_get_pgconn(self))) < 0)
|
869
|
-
|
896
|
+
pg_raise_conn_error( rb_eConnectionBad, self, "PQsocket() can't get socket descriptor");
|
897
|
+
|
870
898
|
return INT2NUM(sd);
|
871
899
|
}
|
872
900
|
|
@@ -874,40 +902,47 @@ pgconn_socket(VALUE self)
|
|
874
902
|
* call-seq:
|
875
903
|
* conn.socket_io() -> IO
|
876
904
|
*
|
877
|
-
* Fetch
|
878
|
-
* This object can be used for IO.select to wait for events while running
|
879
|
-
*
|
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>.
|
880
908
|
*
|
881
|
-
*
|
882
|
-
*
|
883
|
-
*
|
909
|
+
* The IO object can change while the connection is established, but is memorized afterwards.
|
910
|
+
* So be sure not to cache the IO object, but repeat calling <tt>conn.socket_io</tt> instead.
|
911
|
+
*
|
912
|
+
* Using this method also works on Windows in contrast to using #socket .
|
913
|
+
* It also avoids the problem of the underlying connection being closed by Ruby when an IO created using <tt>IO.for_fd(conn.socket)</tt> goes out of scope.
|
884
914
|
*/
|
885
915
|
static VALUE
|
886
916
|
pgconn_socket_io(VALUE self)
|
887
917
|
{
|
888
918
|
int sd;
|
889
919
|
int ruby_sd;
|
890
|
-
ID id_autoclose = rb_intern("autoclose=");
|
891
920
|
t_pg_connection *this = pg_get_connection_safe( self );
|
921
|
+
VALUE cSocket;
|
892
922
|
VALUE socket_io = this->socket_io;
|
893
923
|
|
894
924
|
if ( !RTEST(socket_io) ) {
|
895
|
-
if( (sd = PQsocket(this->pgconn)) < 0)
|
896
|
-
|
925
|
+
if( (sd = PQsocket(this->pgconn)) < 0){
|
926
|
+
pg_raise_conn_error( rb_eConnectionBad, self, "PQsocket() can't get socket descriptor");
|
927
|
+
}
|
897
928
|
|
898
929
|
#ifdef _WIN32
|
899
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
|
+
|
900
934
|
this->ruby_sd = ruby_sd;
|
901
935
|
#else
|
902
936
|
ruby_sd = sd;
|
903
937
|
#endif
|
904
938
|
|
905
|
-
|
939
|
+
cSocket = rb_const_get(rb_cObject, rb_intern("BasicSocket"));
|
940
|
+
socket_io = rb_funcall( cSocket, rb_intern("for_fd"), 1, INT2NUM(ruby_sd));
|
906
941
|
|
907
942
|
/* Disable autoclose feature */
|
908
|
-
rb_funcall( socket_io,
|
943
|
+
rb_funcall( socket_io, s_id_autoclose_set, 1, Qfalse );
|
909
944
|
|
910
|
-
this->socket_io
|
945
|
+
RB_OBJ_WRITE(self, &this->socket_io, socket_io);
|
911
946
|
}
|
912
947
|
|
913
948
|
return socket_io;
|
@@ -927,6 +962,51 @@ pgconn_backend_pid(VALUE self)
|
|
927
962
|
return INT2NUM(PQbackendPID(pg_get_pgconn(self)));
|
928
963
|
}
|
929
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
|
+
|
930
1010
|
/*
|
931
1011
|
* call-seq:
|
932
1012
|
* conn.connection_needs_password() -> Boolean
|
@@ -957,36 +1037,27 @@ pgconn_connection_used_password(VALUE self)
|
|
957
1037
|
/* :TODO: get_ssl */
|
958
1038
|
|
959
1039
|
|
960
|
-
static VALUE
|
1040
|
+
static VALUE pgconn_sync_exec_params( int, VALUE *, VALUE );
|
961
1041
|
|
962
1042
|
/*
|
963
1043
|
* call-seq:
|
964
|
-
* conn.
|
965
|
-
* conn.
|
966
|
-
*
|
967
|
-
* Sends SQL query request specified by _sql_ to PostgreSQL.
|
968
|
-
* On success, it returns a PG::Result instance with all result rows and columns.
|
969
|
-
* On failure, it raises a PG::Error.
|
1044
|
+
* conn.sync_exec(sql) -> PG::Result
|
1045
|
+
* conn.sync_exec(sql) {|pg_result| block }
|
970
1046
|
*
|
971
|
-
*
|
972
|
-
*
|
973
|
-
* argument placeholders are used.
|
1047
|
+
* This function has the same behavior as #async_exec, but is implemented using the synchronous command processing API of libpq.
|
1048
|
+
* It's not recommended to use explicit sync or async variants but #exec instead, unless you have a good reason to do so.
|
974
1049
|
*
|
975
|
-
*
|
976
|
-
*
|
977
|
-
* In this instance, <code>conn.exec</code> returns the value of the block.
|
1050
|
+
* Both #sync_exec and #async_exec release the GVL while waiting for server response, so that concurrent threads will get executed.
|
1051
|
+
* However #async_exec has two advantages:
|
978
1052
|
*
|
979
|
-
* #
|
980
|
-
*
|
981
|
-
*
|
982
|
-
* the query is finished. This is most notably visible by a delayed reaction to Control+C.
|
983
|
-
* Both methods ensure that other threads can process while waiting for the server to
|
984
|
-
* complete the request.
|
1053
|
+
* 1. #async_exec can be aborted by signals (like Ctrl-C), while #exec blocks signal processing until the query is answered.
|
1054
|
+
* 2. Ruby VM gets notified about IO blocked operations and can pass them through <tt>Fiber.scheduler</tt>.
|
1055
|
+
* So only <tt>async_*</tt> methods are compatible to event based schedulers like the async gem.
|
985
1056
|
*/
|
986
1057
|
static VALUE
|
987
|
-
|
1058
|
+
pgconn_sync_exec(int argc, VALUE *argv, VALUE self)
|
988
1059
|
{
|
989
|
-
|
1060
|
+
t_pg_connection *this = pg_get_connection_safe( self );
|
990
1061
|
PGresult *result = NULL;
|
991
1062
|
VALUE rb_pgresult;
|
992
1063
|
|
@@ -994,7 +1065,7 @@ pgconn_exec(int argc, VALUE *argv, VALUE self)
|
|
994
1065
|
if ( argc == 1 || (argc >= 2 && argc <= 4 && NIL_P(argv[1]) )) {
|
995
1066
|
VALUE query_str = argv[0];
|
996
1067
|
|
997
|
-
result = gvl_PQexec(
|
1068
|
+
result = gvl_PQexec(this->pgconn, pg_cstr_enc(query_str, this->enc_idx));
|
998
1069
|
rb_pgresult = pg_new_result(result, self);
|
999
1070
|
pg_result_check(rb_pgresult);
|
1000
1071
|
if (rb_block_given_p()) {
|
@@ -1005,7 +1076,7 @@ pgconn_exec(int argc, VALUE *argv, VALUE self)
|
|
1005
1076
|
pg_deprecated(0, ("forwarding exec to exec_params is deprecated"));
|
1006
1077
|
|
1007
1078
|
/* Otherwise, just call #exec_params instead for backward-compatibility */
|
1008
|
-
return
|
1079
|
+
return pgconn_sync_exec_params( argc, argv, self );
|
1009
1080
|
|
1010
1081
|
}
|
1011
1082
|
|
@@ -1037,7 +1108,7 @@ struct query_params_data {
|
|
1037
1108
|
* Filled by alloc_query_params()
|
1038
1109
|
*/
|
1039
1110
|
|
1040
|
-
/* Wraps the pointer of allocated memory, if function parameters
|
1111
|
+
/* Wraps the pointer of allocated memory, if function parameters don't
|
1041
1112
|
* fit in the memory_pool below.
|
1042
1113
|
*/
|
1043
1114
|
VALUE heap_pool;
|
@@ -1055,7 +1126,7 @@ struct query_params_data {
|
|
1055
1126
|
Oid *types;
|
1056
1127
|
|
1057
1128
|
/* This array takes the string values for the timeframe of the query,
|
1058
|
-
* if param value
|
1129
|
+
* if param value conversion is required
|
1059
1130
|
*/
|
1060
1131
|
VALUE gc_array;
|
1061
1132
|
|
@@ -1069,8 +1140,9 @@ struct query_params_data {
|
|
1069
1140
|
};
|
1070
1141
|
|
1071
1142
|
static void
|
1072
|
-
free_typecast_heap_chain(
|
1143
|
+
free_typecast_heap_chain(void *_chain_entry)
|
1073
1144
|
{
|
1145
|
+
struct linked_typecast_data *chain_entry = (struct linked_typecast_data *)_chain_entry;
|
1074
1146
|
while(chain_entry){
|
1075
1147
|
struct linked_typecast_data *next = chain_entry->next;
|
1076
1148
|
xfree(chain_entry);
|
@@ -1078,6 +1150,18 @@ free_typecast_heap_chain(struct linked_typecast_data *chain_entry)
|
|
1078
1150
|
}
|
1079
1151
|
}
|
1080
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
|
+
|
1081
1165
|
static char *
|
1082
1166
|
alloc_typecast_buf( VALUE *typecast_heap_chain, int len )
|
1083
1167
|
{
|
@@ -1088,17 +1172,28 @@ alloc_typecast_buf( VALUE *typecast_heap_chain, int len )
|
|
1088
1172
|
/* Did we already wrap a memory chain per T_DATA object? */
|
1089
1173
|
if( NIL_P( *typecast_heap_chain ) ){
|
1090
1174
|
/* Leave free'ing of the buffer chain to the GC, when paramsData has left the stack */
|
1091
|
-
*typecast_heap_chain =
|
1175
|
+
*typecast_heap_chain = TypedData_Wrap_Struct( rb_cObject, &pg_typecast_buffer_type, allocated );
|
1092
1176
|
allocated->next = NULL;
|
1093
1177
|
} else {
|
1094
1178
|
/* Append to the chain */
|
1095
|
-
allocated->next =
|
1096
|
-
|
1179
|
+
allocated->next = RTYPEDDATA_DATA( *typecast_heap_chain );
|
1180
|
+
RTYPEDDATA_DATA( *typecast_heap_chain ) = allocated;
|
1097
1181
|
}
|
1098
1182
|
|
1099
1183
|
return &allocated->data[0];
|
1100
1184
|
}
|
1101
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
|
+
};
|
1102
1197
|
|
1103
1198
|
static int
|
1104
1199
|
alloc_query_params(struct query_params_data *paramsData)
|
@@ -1113,7 +1208,7 @@ alloc_query_params(struct query_params_data *paramsData)
|
|
1113
1208
|
|
1114
1209
|
Check_Type(paramsData->params, T_ARRAY);
|
1115
1210
|
|
1116
|
-
p_typemap =
|
1211
|
+
p_typemap = RTYPEDDATA_DATA( paramsData->typemap );
|
1117
1212
|
p_typemap->funcs.fit_to_query( paramsData->typemap, paramsData->params );
|
1118
1213
|
|
1119
1214
|
paramsData->heap_pool = Qnil;
|
@@ -1132,7 +1227,7 @@ alloc_query_params(struct query_params_data *paramsData)
|
|
1132
1227
|
/* Allocate one combined memory pool for all possible function parameters */
|
1133
1228
|
memory_pool = (char*)xmalloc( required_pool_size );
|
1134
1229
|
/* Leave free'ing of the buffer to the GC, when paramsData has left the stack */
|
1135
|
-
paramsData->heap_pool =
|
1230
|
+
paramsData->heap_pool = TypedData_Wrap_Struct( rb_cObject, &pg_query_heap_pool_type, memory_pool );
|
1136
1231
|
required_pool_size = 0;
|
1137
1232
|
}else{
|
1138
1233
|
/* Use stack memory for function parameters */
|
@@ -1245,68 +1340,33 @@ pgconn_query_assign_typemap( VALUE self, struct query_params_data *paramsData )
|
|
1245
1340
|
/* Use default typemap for queries. It's type is checked when assigned. */
|
1246
1341
|
paramsData->typemap = pg_get_connection(self)->type_map_for_queries;
|
1247
1342
|
}else{
|
1343
|
+
t_typemap *tm;
|
1344
|
+
UNUSED(tm);
|
1345
|
+
|
1248
1346
|
/* Check type of method param */
|
1249
|
-
|
1250
|
-
rb_raise( rb_eTypeError, "wrong argument type %s (expected kind of PG::TypeMap)",
|
1251
|
-
rb_obj_classname( paramsData->typemap ) );
|
1252
|
-
}
|
1253
|
-
Check_Type( paramsData->typemap, T_DATA );
|
1347
|
+
TypedData_Get_Struct(paramsData->typemap, t_typemap, &pg_typemap_type, tm);
|
1254
1348
|
}
|
1255
1349
|
}
|
1256
1350
|
|
1257
1351
|
/*
|
1258
1352
|
* call-seq:
|
1259
|
-
* conn.
|
1260
|
-
* conn.
|
1261
|
-
*
|
1262
|
-
* Sends SQL query request specified by +sql+ to PostgreSQL using placeholders
|
1263
|
-
* for parameters.
|
1264
|
-
*
|
1265
|
-
* Returns a PG::Result instance on success. On failure, it raises a PG::Error.
|
1266
|
-
*
|
1267
|
-
* +params+ is an array of the bind parameters for the SQL query.
|
1268
|
-
* Each element of the +params+ array may be either:
|
1269
|
-
* a hash of the form:
|
1270
|
-
* {:value => String (value of bind parameter)
|
1271
|
-
* :type => Integer (oid of type of bind parameter)
|
1272
|
-
* :format => Integer (0 for text, 1 for binary)
|
1273
|
-
* }
|
1274
|
-
* or, it may be a String. If it is a string, that is equivalent to the hash:
|
1275
|
-
* { :value => <string value>, :type => 0, :format => 0 }
|
1353
|
+
* conn.sync_exec_params(sql, params[, result_format[, type_map]] ) -> PG::Result
|
1354
|
+
* conn.sync_exec_params(sql, params[, result_format[, type_map]] ) {|pg_result| block }
|
1276
1355
|
*
|
1277
|
-
*
|
1278
|
-
*
|
1279
|
-
* to
|
1280
|
-
*
|
1281
|
-
* If the types are not specified, they will be inferred by PostgreSQL.
|
1282
|
-
* Instead of specifying type oids, it's recommended to simply add
|
1283
|
-
* explicit casts in the query to ensure that the right type is used.
|
1284
|
-
*
|
1285
|
-
* For example: "SELECT $1::int"
|
1286
|
-
*
|
1287
|
-
* The optional +result_format+ should be 0 for text results, 1
|
1288
|
-
* for binary.
|
1289
|
-
*
|
1290
|
-
* type_map can be a PG::TypeMap derivation (such as PG::BasicTypeMapForQueries).
|
1291
|
-
* This will type cast the params from various Ruby types before transmission
|
1292
|
-
* based on the encoders defined by the type map. When a type encoder is used
|
1293
|
-
* the format and oid of a given bind parameter are retrieved from the encoder
|
1294
|
-
* instead out of the hash form described above.
|
1295
|
-
*
|
1296
|
-
* If the optional code block is given, it will be passed <i>result</i> as an argument,
|
1297
|
-
* and the PG::Result object will automatically be cleared when the block terminates.
|
1298
|
-
* In this instance, <code>conn.exec</code> returns the value of the block.
|
1356
|
+
* This function has the same behavior as #async_exec_params, but is implemented using the synchronous command processing API of libpq.
|
1357
|
+
* See #async_exec for the differences between the two API variants.
|
1358
|
+
* It's not recommended to use explicit sync or async variants but #exec_params instead, unless you have a good reason to do so.
|
1299
1359
|
*/
|
1300
1360
|
static VALUE
|
1301
|
-
|
1361
|
+
pgconn_sync_exec_params( int argc, VALUE *argv, VALUE self )
|
1302
1362
|
{
|
1303
|
-
|
1363
|
+
t_pg_connection *this = pg_get_connection_safe( self );
|
1304
1364
|
PGresult *result = NULL;
|
1305
1365
|
VALUE rb_pgresult;
|
1306
1366
|
VALUE command, in_res_fmt;
|
1307
1367
|
int nParams;
|
1308
1368
|
int resultFormat;
|
1309
|
-
struct query_params_data paramsData = {
|
1369
|
+
struct query_params_data paramsData = { this->enc_idx };
|
1310
1370
|
|
1311
1371
|
/* For compatibility we accept 1 to 4 parameters */
|
1312
1372
|
rb_scan_args(argc, argv, "13", &command, ¶msData.params, &in_res_fmt, ¶msData.typemap);
|
@@ -1318,14 +1378,14 @@ pgconn_exec_params( int argc, VALUE *argv, VALUE self )
|
|
1318
1378
|
*/
|
1319
1379
|
if ( NIL_P(paramsData.params) ) {
|
1320
1380
|
pg_deprecated(1, ("forwarding exec_params to exec is deprecated"));
|
1321
|
-
return
|
1381
|
+
return pgconn_sync_exec( 1, argv, self );
|
1322
1382
|
}
|
1323
1383
|
pgconn_query_assign_typemap( self, ¶msData );
|
1324
1384
|
|
1325
1385
|
resultFormat = NIL_P(in_res_fmt) ? 0 : NUM2INT(in_res_fmt);
|
1326
1386
|
nParams = alloc_query_params( ¶msData );
|
1327
1387
|
|
1328
|
-
result = gvl_PQexecParams(
|
1388
|
+
result = gvl_PQexecParams(this->pgconn, pg_cstr_enc(command, paramsData.enc_idx), nParams, paramsData.types,
|
1329
1389
|
(const char * const *)paramsData.values, paramsData.lengths, paramsData.formats, resultFormat);
|
1330
1390
|
|
1331
1391
|
free_query_params( ¶msData );
|
@@ -1342,28 +1402,16 @@ pgconn_exec_params( int argc, VALUE *argv, VALUE self )
|
|
1342
1402
|
|
1343
1403
|
/*
|
1344
1404
|
* call-seq:
|
1345
|
-
* conn.
|
1346
|
-
*
|
1347
|
-
* Prepares statement _sql_ with name _name_ to be executed later.
|
1348
|
-
* Returns a PG::Result instance on success.
|
1349
|
-
* On failure, it raises a PG::Error.
|
1350
|
-
*
|
1351
|
-
* +param_types+ is an optional parameter to specify the Oids of the
|
1352
|
-
* types of the parameters.
|
1353
|
-
*
|
1354
|
-
* If the types are not specified, they will be inferred by PostgreSQL.
|
1355
|
-
* Instead of specifying type oids, it's recommended to simply add
|
1356
|
-
* explicit casts in the query to ensure that the right type is used.
|
1357
|
-
*
|
1358
|
-
* For example: "SELECT $1::int"
|
1405
|
+
* conn.sync_prepare(stmt_name, sql [, param_types ] ) -> PG::Result
|
1359
1406
|
*
|
1360
|
-
*
|
1361
|
-
*
|
1407
|
+
* This function has the same behavior as #async_prepare, but is implemented using the synchronous command processing API of libpq.
|
1408
|
+
* See #async_exec for the differences between the two API variants.
|
1409
|
+
* It's not recommended to use explicit sync or async variants but #prepare instead, unless you have a good reason to do so.
|
1362
1410
|
*/
|
1363
1411
|
static VALUE
|
1364
|
-
|
1412
|
+
pgconn_sync_prepare(int argc, VALUE *argv, VALUE self)
|
1365
1413
|
{
|
1366
|
-
|
1414
|
+
t_pg_connection *this = pg_get_connection_safe( self );
|
1367
1415
|
PGresult *result = NULL;
|
1368
1416
|
VALUE rb_pgresult;
|
1369
1417
|
VALUE name, command, in_paramtypes;
|
@@ -1373,7 +1421,7 @@ pgconn_prepare(int argc, VALUE *argv, VALUE self)
|
|
1373
1421
|
Oid *paramTypes = NULL;
|
1374
1422
|
const char *name_cstr;
|
1375
1423
|
const char *command_cstr;
|
1376
|
-
int enc_idx =
|
1424
|
+
int enc_idx = this->enc_idx;
|
1377
1425
|
|
1378
1426
|
rb_scan_args(argc, argv, "21", &name, &command, &in_paramtypes);
|
1379
1427
|
name_cstr = pg_cstr_enc(name, enc_idx);
|
@@ -1391,7 +1439,7 @@ pgconn_prepare(int argc, VALUE *argv, VALUE self)
|
|
1391
1439
|
paramTypes[i] = NUM2UINT(param);
|
1392
1440
|
}
|
1393
1441
|
}
|
1394
|
-
result = gvl_PQprepare(
|
1442
|
+
result = gvl_PQprepare(this->pgconn, name_cstr, command_cstr, nParams, paramTypes);
|
1395
1443
|
|
1396
1444
|
xfree(paramTypes);
|
1397
1445
|
|
@@ -1402,49 +1450,23 @@ pgconn_prepare(int argc, VALUE *argv, VALUE self)
|
|
1402
1450
|
|
1403
1451
|
/*
|
1404
1452
|
* call-seq:
|
1405
|
-
* conn.
|
1406
|
-
* conn.
|
1407
|
-
*
|
1408
|
-
* Execute prepared named statement specified by _statement_name_.
|
1409
|
-
* Returns a PG::Result instance on success.
|
1410
|
-
* On failure, it raises a PG::Error.
|
1411
|
-
*
|
1412
|
-
* +params+ is an array of the optional bind parameters for the
|
1413
|
-
* SQL query. Each element of the +params+ array may be either:
|
1414
|
-
* a hash of the form:
|
1415
|
-
* {:value => String (value of bind parameter)
|
1416
|
-
* :format => Integer (0 for text, 1 for binary)
|
1417
|
-
* }
|
1418
|
-
* or, it may be a String. If it is a string, that is equivalent to the hash:
|
1419
|
-
* { :value => <string value>, :format => 0 }
|
1420
|
-
*
|
1421
|
-
* PostgreSQL bind parameters are represented as $1, $1, $2, etc.,
|
1422
|
-
* inside the SQL query. The 0th element of the +params+ array is bound
|
1423
|
-
* to $1, the 1st element is bound to $2, etc. +nil+ is treated as +NULL+.
|
1424
|
-
*
|
1425
|
-
* The optional +result_format+ should be 0 for text results, 1
|
1426
|
-
* for binary.
|
1427
|
-
*
|
1428
|
-
* type_map can be a PG::TypeMap derivation (such as PG::BasicTypeMapForQueries).
|
1429
|
-
* This will type cast the params from various Ruby types before transmission
|
1430
|
-
* based on the encoders defined by the type map. When a type encoder is used
|
1431
|
-
* the format and oid of a given bind parameter are retrieved from the encoder
|
1432
|
-
* instead out of the hash form described above.
|
1453
|
+
* conn.sync_exec_prepared(statement_name [, params, result_format[, type_map]] ) -> PG::Result
|
1454
|
+
* conn.sync_exec_prepared(statement_name [, params, result_format[, type_map]] ) {|pg_result| block }
|
1433
1455
|
*
|
1434
|
-
*
|
1435
|
-
*
|
1436
|
-
*
|
1456
|
+
* This function has the same behavior as #async_exec_prepared, but is implemented using the synchronous command processing API of libpq.
|
1457
|
+
* See #async_exec for the differences between the two API variants.
|
1458
|
+
* It's not recommended to use explicit sync or async variants but #exec_prepared instead, unless you have a good reason to do so.
|
1437
1459
|
*/
|
1438
1460
|
static VALUE
|
1439
|
-
|
1461
|
+
pgconn_sync_exec_prepared(int argc, VALUE *argv, VALUE self)
|
1440
1462
|
{
|
1441
|
-
|
1463
|
+
t_pg_connection *this = pg_get_connection_safe( self );
|
1442
1464
|
PGresult *result = NULL;
|
1443
1465
|
VALUE rb_pgresult;
|
1444
1466
|
VALUE name, in_res_fmt;
|
1445
1467
|
int nParams;
|
1446
1468
|
int resultFormat;
|
1447
|
-
struct query_params_data paramsData = {
|
1469
|
+
struct query_params_data paramsData = { this->enc_idx };
|
1448
1470
|
|
1449
1471
|
rb_scan_args(argc, argv, "13", &name, ¶msData.params, &in_res_fmt, ¶msData.typemap);
|
1450
1472
|
paramsData.with_types = 0;
|
@@ -1457,7 +1479,7 @@ pgconn_exec_prepared(int argc, VALUE *argv, VALUE self)
|
|
1457
1479
|
resultFormat = NIL_P(in_res_fmt) ? 0 : NUM2INT(in_res_fmt);
|
1458
1480
|
nParams = alloc_query_params( ¶msData );
|
1459
1481
|
|
1460
|
-
result = gvl_PQexecPrepared(
|
1482
|
+
result = gvl_PQexecPrepared(this->pgconn, pg_cstr_enc(name, paramsData.enc_idx), nParams,
|
1461
1483
|
(const char * const *)paramsData.values, paramsData.lengths, paramsData.formats,
|
1462
1484
|
resultFormat);
|
1463
1485
|
|
@@ -1474,25 +1496,26 @@ pgconn_exec_prepared(int argc, VALUE *argv, VALUE self)
|
|
1474
1496
|
|
1475
1497
|
/*
|
1476
1498
|
* call-seq:
|
1477
|
-
* conn.
|
1499
|
+
* conn.sync_describe_prepared( statement_name ) -> PG::Result
|
1478
1500
|
*
|
1479
|
-
*
|
1480
|
-
*
|
1501
|
+
* This function has the same behavior as #async_describe_prepared, but is implemented using the synchronous command processing API of libpq.
|
1502
|
+
* See #async_exec for the differences between the two API variants.
|
1503
|
+
* It's not recommended to use explicit sync or async variants but #describe_prepared instead, unless you have a good reason to do so.
|
1481
1504
|
*/
|
1482
1505
|
static VALUE
|
1483
|
-
|
1506
|
+
pgconn_sync_describe_prepared(VALUE self, VALUE stmt_name)
|
1484
1507
|
{
|
1485
1508
|
PGresult *result;
|
1486
1509
|
VALUE rb_pgresult;
|
1487
|
-
|
1510
|
+
t_pg_connection *this = pg_get_connection_safe( self );
|
1488
1511
|
const char *stmt;
|
1489
1512
|
if(NIL_P(stmt_name)) {
|
1490
1513
|
stmt = NULL;
|
1491
1514
|
}
|
1492
1515
|
else {
|
1493
|
-
stmt = pg_cstr_enc(stmt_name,
|
1516
|
+
stmt = pg_cstr_enc(stmt_name, this->enc_idx);
|
1494
1517
|
}
|
1495
|
-
result = gvl_PQdescribePrepared(
|
1518
|
+
result = gvl_PQdescribePrepared(this->pgconn, stmt);
|
1496
1519
|
rb_pgresult = pg_new_result(result, self);
|
1497
1520
|
pg_result_check(rb_pgresult);
|
1498
1521
|
return rb_pgresult;
|
@@ -1501,25 +1524,26 @@ pgconn_describe_prepared(VALUE self, VALUE stmt_name)
|
|
1501
1524
|
|
1502
1525
|
/*
|
1503
1526
|
* call-seq:
|
1504
|
-
* conn.
|
1527
|
+
* conn.sync_describe_portal( portal_name ) -> PG::Result
|
1505
1528
|
*
|
1506
|
-
*
|
1529
|
+
* This function has the same behavior as #async_describe_portal, but is implemented using the synchronous command processing API of libpq.
|
1530
|
+
* See #async_exec for the differences between the two API variants.
|
1531
|
+
* It's not recommended to use explicit sync or async variants but #describe_portal instead, unless you have a good reason to do so.
|
1507
1532
|
*/
|
1508
1533
|
static VALUE
|
1509
|
-
|
1510
|
-
VALUE self, stmt_name;
|
1534
|
+
pgconn_sync_describe_portal(VALUE self, VALUE stmt_name)
|
1511
1535
|
{
|
1512
1536
|
PGresult *result;
|
1513
1537
|
VALUE rb_pgresult;
|
1514
|
-
|
1538
|
+
t_pg_connection *this = pg_get_connection_safe( self );
|
1515
1539
|
const char *stmt;
|
1516
1540
|
if(NIL_P(stmt_name)) {
|
1517
1541
|
stmt = NULL;
|
1518
1542
|
}
|
1519
1543
|
else {
|
1520
|
-
stmt = pg_cstr_enc(stmt_name,
|
1544
|
+
stmt = pg_cstr_enc(stmt_name, this->enc_idx);
|
1521
1545
|
}
|
1522
|
-
result = gvl_PQdescribePortal(
|
1546
|
+
result = gvl_PQdescribePortal(this->pgconn, stmt);
|
1523
1547
|
rb_pgresult = pg_new_result(result, self);
|
1524
1548
|
pg_result_check(rb_pgresult);
|
1525
1549
|
return rb_pgresult;
|
@@ -1541,6 +1565,9 @@ pgconn_describe_portal(self, stmt_name)
|
|
1541
1565
|
* * +PGRES_NONFATAL_ERROR+
|
1542
1566
|
* * +PGRES_FATAL_ERROR+
|
1543
1567
|
* * +PGRES_COPY_BOTH+
|
1568
|
+
* * +PGRES_SINGLE_TUPLE+
|
1569
|
+
* * +PGRES_PIPELINE_SYNC+
|
1570
|
+
* * +PGRES_PIPELINE_ABORTED+
|
1544
1571
|
*/
|
1545
1572
|
static VALUE
|
1546
1573
|
pgconn_make_empty_pgresult(VALUE self, VALUE status)
|
@@ -1566,13 +1593,15 @@ pgconn_make_empty_pgresult(VALUE self, VALUE status)
|
|
1566
1593
|
* Consider using exec_params, which avoids the need for passing values
|
1567
1594
|
* inside of SQL commands.
|
1568
1595
|
*
|
1569
|
-
*
|
1596
|
+
* Character encoding of escaped string will be equal to client encoding of connection.
|
1570
1597
|
*
|
1571
1598
|
* NOTE: This class version of this method can only be used safely in client
|
1572
1599
|
* programs that use a single PostgreSQL connection at a time (in this case it can
|
1573
1600
|
* find out what it needs to know "behind the scenes"). It might give the wrong
|
1574
1601
|
* results if used in programs that use multiple database connections; use the
|
1575
1602
|
* same method on the connection object in such cases.
|
1603
|
+
*
|
1604
|
+
* See also convenience functions #escape_literal and #escape_identifier which also add proper quotes around the string.
|
1576
1605
|
*/
|
1577
1606
|
static VALUE
|
1578
1607
|
pgconn_s_escape(VALUE self, VALUE string)
|
@@ -1584,7 +1613,7 @@ pgconn_s_escape(VALUE self, VALUE string)
|
|
1584
1613
|
int singleton = !rb_obj_is_kind_of(self, rb_cPGconn);
|
1585
1614
|
|
1586
1615
|
StringValueCStr(string);
|
1587
|
-
enc_idx =
|
1616
|
+
enc_idx = singleton ? ENCODING_GET(string) : pg_get_connection(self)->enc_idx;
|
1588
1617
|
if( ENCODING_GET(string) != enc_idx ){
|
1589
1618
|
string = rb_str_export_to_enc(string, rb_enc_from_index(enc_idx));
|
1590
1619
|
}
|
@@ -1594,14 +1623,13 @@ pgconn_s_escape(VALUE self, VALUE string)
|
|
1594
1623
|
if( !singleton ) {
|
1595
1624
|
size = PQescapeStringConn(pg_get_pgconn(self), RSTRING_PTR(result),
|
1596
1625
|
RSTRING_PTR(string), RSTRING_LEN(string), &error);
|
1597
|
-
if(error)
|
1598
|
-
|
1599
|
-
|
1626
|
+
if(error)
|
1627
|
+
pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(pg_get_pgconn(self)));
|
1628
|
+
|
1600
1629
|
} else {
|
1601
1630
|
size = PQescapeString(RSTRING_PTR(result), RSTRING_PTR(string), RSTRING_LEN(string));
|
1602
1631
|
}
|
1603
1632
|
rb_str_set_len(result, size);
|
1604
|
-
OBJ_INFECT(result, string);
|
1605
1633
|
|
1606
1634
|
return result;
|
1607
1635
|
}
|
@@ -1647,7 +1675,6 @@ pgconn_s_escape_bytea(VALUE self, VALUE str)
|
|
1647
1675
|
}
|
1648
1676
|
|
1649
1677
|
ret = rb_str_new((char*)to, to_len - 1);
|
1650
|
-
OBJ_INFECT(ret, str);
|
1651
1678
|
PQfreemem(to);
|
1652
1679
|
return ret;
|
1653
1680
|
}
|
@@ -1677,7 +1704,6 @@ pgconn_s_unescape_bytea(VALUE self, VALUE str)
|
|
1677
1704
|
to = PQunescapeBytea(from, &to_len);
|
1678
1705
|
|
1679
1706
|
ret = rb_str_new((char*)to, to_len);
|
1680
|
-
OBJ_INFECT(ret, str);
|
1681
1707
|
PQfreemem(to);
|
1682
1708
|
return ret;
|
1683
1709
|
}
|
@@ -1688,33 +1714,27 @@ pgconn_s_unescape_bytea(VALUE self, VALUE str)
|
|
1688
1714
|
*
|
1689
1715
|
* Escape an arbitrary String +str+ as a literal.
|
1690
1716
|
*
|
1691
|
-
*
|
1717
|
+
* See also PG::TextEncoder::QuotedLiteral for a type cast integrated version of this function.
|
1692
1718
|
*/
|
1693
1719
|
static VALUE
|
1694
1720
|
pgconn_escape_literal(VALUE self, VALUE string)
|
1695
1721
|
{
|
1696
|
-
|
1722
|
+
t_pg_connection *this = pg_get_connection_safe( self );
|
1697
1723
|
char *escaped = NULL;
|
1698
|
-
VALUE error;
|
1699
1724
|
VALUE result = Qnil;
|
1700
|
-
int enc_idx =
|
1725
|
+
int enc_idx = this->enc_idx;
|
1701
1726
|
|
1702
1727
|
StringValueCStr(string);
|
1703
1728
|
if( ENCODING_GET(string) != enc_idx ){
|
1704
1729
|
string = rb_str_export_to_enc(string, rb_enc_from_index(enc_idx));
|
1705
1730
|
}
|
1706
1731
|
|
1707
|
-
escaped = PQescapeLiteral(
|
1732
|
+
escaped = PQescapeLiteral(this->pgconn, RSTRING_PTR(string), RSTRING_LEN(string));
|
1708
1733
|
if (escaped == NULL)
|
1709
|
-
|
1710
|
-
|
1711
|
-
rb_iv_set(error, "@connection", self);
|
1712
|
-
rb_exc_raise(error);
|
1713
|
-
return Qnil;
|
1714
|
-
}
|
1734
|
+
pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(this->pgconn));
|
1735
|
+
|
1715
1736
|
result = rb_str_new2(escaped);
|
1716
1737
|
PQfreemem(escaped);
|
1717
|
-
OBJ_INFECT(result, string);
|
1718
1738
|
PG_ENCODING_SET_NOCHECK(result, enc_idx);
|
1719
1739
|
|
1720
1740
|
return result;
|
@@ -1729,34 +1749,26 @@ pgconn_escape_literal(VALUE self, VALUE string)
|
|
1729
1749
|
* This method does the same as #quote_ident with a String argument,
|
1730
1750
|
* but it doesn't support an Array argument and it makes use of libpq
|
1731
1751
|
* to process the string.
|
1732
|
-
*
|
1733
|
-
* Available since PostgreSQL-9.0
|
1734
1752
|
*/
|
1735
1753
|
static VALUE
|
1736
1754
|
pgconn_escape_identifier(VALUE self, VALUE string)
|
1737
1755
|
{
|
1738
|
-
|
1756
|
+
t_pg_connection *this = pg_get_connection_safe( self );
|
1739
1757
|
char *escaped = NULL;
|
1740
|
-
VALUE error;
|
1741
1758
|
VALUE result = Qnil;
|
1742
|
-
int enc_idx =
|
1759
|
+
int enc_idx = this->enc_idx;
|
1743
1760
|
|
1744
1761
|
StringValueCStr(string);
|
1745
1762
|
if( ENCODING_GET(string) != enc_idx ){
|
1746
1763
|
string = rb_str_export_to_enc(string, rb_enc_from_index(enc_idx));
|
1747
1764
|
}
|
1748
1765
|
|
1749
|
-
escaped = PQescapeIdentifier(
|
1766
|
+
escaped = PQescapeIdentifier(this->pgconn, RSTRING_PTR(string), RSTRING_LEN(string));
|
1750
1767
|
if (escaped == NULL)
|
1751
|
-
|
1752
|
-
|
1753
|
-
rb_iv_set(error, "@connection", self);
|
1754
|
-
rb_exc_raise(error);
|
1755
|
-
return Qnil;
|
1756
|
-
}
|
1768
|
+
pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(this->pgconn));
|
1769
|
+
|
1757
1770
|
result = rb_str_new2(escaped);
|
1758
1771
|
PQfreemem(escaped);
|
1759
|
-
OBJ_INFECT(result, string);
|
1760
1772
|
PG_ENCODING_SET_NOCHECK(result, enc_idx);
|
1761
1773
|
|
1762
1774
|
return result;
|
@@ -1797,21 +1809,15 @@ pgconn_escape_identifier(VALUE self, VALUE string)
|
|
1797
1809
|
* # do something with the received row
|
1798
1810
|
* end
|
1799
1811
|
* end
|
1800
|
-
*
|
1801
|
-
* Available since PostgreSQL-9.2
|
1802
1812
|
*/
|
1803
1813
|
static VALUE
|
1804
1814
|
pgconn_set_single_row_mode(VALUE self)
|
1805
1815
|
{
|
1806
1816
|
PGconn *conn = pg_get_pgconn(self);
|
1807
|
-
VALUE error;
|
1808
1817
|
|
1818
|
+
rb_check_frozen(self);
|
1809
1819
|
if( PQsetSingleRowMode(conn) == 0 )
|
1810
|
-
|
1811
|
-
error = rb_exc_new2(rb_ePGerror, PQerrorMessage(conn));
|
1812
|
-
rb_iv_set(error, "@connection", self);
|
1813
|
-
rb_exc_raise(error);
|
1814
|
-
}
|
1820
|
+
pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(conn));
|
1815
1821
|
|
1816
1822
|
return self;
|
1817
1823
|
}
|
@@ -1834,16 +1840,14 @@ static VALUE pgconn_send_query_params(int argc, VALUE *argv, VALUE self);
|
|
1834
1840
|
static VALUE
|
1835
1841
|
pgconn_send_query(int argc, VALUE *argv, VALUE self)
|
1836
1842
|
{
|
1837
|
-
|
1838
|
-
VALUE error;
|
1843
|
+
t_pg_connection *this = pg_get_connection_safe( self );
|
1839
1844
|
|
1840
1845
|
/* If called with no or nil parameters, use PQexec for compatibility */
|
1841
1846
|
if ( argc == 1 || (argc >= 2 && argc <= 4 && NIL_P(argv[1]) )) {
|
1842
|
-
if(gvl_PQsendQuery(
|
1843
|
-
|
1844
|
-
|
1845
|
-
|
1846
|
-
}
|
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 );
|
1847
1851
|
return Qnil;
|
1848
1852
|
}
|
1849
1853
|
|
@@ -1873,7 +1877,7 @@ pgconn_send_query(int argc, VALUE *argv, VALUE self)
|
|
1873
1877
|
* or, it may be a String. If it is a string, that is equivalent to the hash:
|
1874
1878
|
* { :value => <string value>, :type => 0, :format => 0 }
|
1875
1879
|
*
|
1876
|
-
* PostgreSQL bind parameters are represented as $1, $
|
1880
|
+
* PostgreSQL bind parameters are represented as $1, $2, $3, etc.,
|
1877
1881
|
* inside the SQL query. The 0th element of the +params+ array is bound
|
1878
1882
|
* to $1, the 1st element is bound to $2, etc. +nil+ is treated as +NULL+.
|
1879
1883
|
*
|
@@ -1886,7 +1890,7 @@ pgconn_send_query(int argc, VALUE *argv, VALUE self)
|
|
1886
1890
|
* The optional +result_format+ should be 0 for text results, 1
|
1887
1891
|
* for binary.
|
1888
1892
|
*
|
1889
|
-
* type_map can be a PG::TypeMap derivation (such as PG::BasicTypeMapForQueries).
|
1893
|
+
* +type_map+ can be a PG::TypeMap derivation (such as PG::BasicTypeMapForQueries).
|
1890
1894
|
* This will type cast the params from various Ruby types before transmission
|
1891
1895
|
* based on the encoders defined by the type map. When a type encoder is used
|
1892
1896
|
* the format and oid of a given bind parameter are retrieved from the encoder
|
@@ -1896,13 +1900,12 @@ pgconn_send_query(int argc, VALUE *argv, VALUE self)
|
|
1896
1900
|
static VALUE
|
1897
1901
|
pgconn_send_query_params(int argc, VALUE *argv, VALUE self)
|
1898
1902
|
{
|
1899
|
-
|
1903
|
+
t_pg_connection *this = pg_get_connection_safe( self );
|
1900
1904
|
int result;
|
1901
1905
|
VALUE command, in_res_fmt;
|
1902
|
-
VALUE error;
|
1903
1906
|
int nParams;
|
1904
1907
|
int resultFormat;
|
1905
|
-
struct query_params_data paramsData = {
|
1908
|
+
struct query_params_data paramsData = { this->enc_idx };
|
1906
1909
|
|
1907
1910
|
rb_scan_args(argc, argv, "22", &command, ¶msData.params, &in_res_fmt, ¶msData.typemap);
|
1908
1911
|
paramsData.with_types = 1;
|
@@ -1911,16 +1914,15 @@ pgconn_send_query_params(int argc, VALUE *argv, VALUE self)
|
|
1911
1914
|
resultFormat = NIL_P(in_res_fmt) ? 0 : NUM2INT(in_res_fmt);
|
1912
1915
|
nParams = alloc_query_params( ¶msData );
|
1913
1916
|
|
1914
|
-
result = gvl_PQsendQueryParams(
|
1917
|
+
result = gvl_PQsendQueryParams(this->pgconn, pg_cstr_enc(command, paramsData.enc_idx), nParams, paramsData.types,
|
1915
1918
|
(const char * const *)paramsData.values, paramsData.lengths, paramsData.formats, resultFormat);
|
1916
1919
|
|
1917
1920
|
free_query_params( ¶msData );
|
1918
1921
|
|
1919
|
-
if(result == 0)
|
1920
|
-
|
1921
|
-
|
1922
|
-
|
1923
|
-
}
|
1922
|
+
if(result == 0)
|
1923
|
+
pg_raise_conn_error( rb_eUnableToSend, self, "%s", PQerrorMessage(this->pgconn));
|
1924
|
+
|
1925
|
+
pgconn_wait_for_flush( self );
|
1924
1926
|
return Qnil;
|
1925
1927
|
}
|
1926
1928
|
|
@@ -1941,23 +1943,22 @@ pgconn_send_query_params(int argc, VALUE *argv, VALUE self)
|
|
1941
1943
|
*
|
1942
1944
|
* For example: "SELECT $1::int"
|
1943
1945
|
*
|
1944
|
-
* PostgreSQL bind parameters are represented as $1, $
|
1946
|
+
* PostgreSQL bind parameters are represented as $1, $2, $3, etc.,
|
1945
1947
|
* inside the SQL query.
|
1946
1948
|
*/
|
1947
1949
|
static VALUE
|
1948
1950
|
pgconn_send_prepare(int argc, VALUE *argv, VALUE self)
|
1949
1951
|
{
|
1950
|
-
|
1952
|
+
t_pg_connection *this = pg_get_connection_safe( self );
|
1951
1953
|
int result;
|
1952
1954
|
VALUE name, command, in_paramtypes;
|
1953
1955
|
VALUE param;
|
1954
|
-
VALUE error;
|
1955
1956
|
int i = 0;
|
1956
1957
|
int nParams = 0;
|
1957
1958
|
Oid *paramTypes = NULL;
|
1958
1959
|
const char *name_cstr;
|
1959
1960
|
const char *command_cstr;
|
1960
|
-
int enc_idx =
|
1961
|
+
int enc_idx = this->enc_idx;
|
1961
1962
|
|
1962
1963
|
rb_scan_args(argc, argv, "21", &name, &command, &in_paramtypes);
|
1963
1964
|
name_cstr = pg_cstr_enc(name, enc_idx);
|
@@ -1975,15 +1976,14 @@ pgconn_send_prepare(int argc, VALUE *argv, VALUE self)
|
|
1975
1976
|
paramTypes[i] = NUM2UINT(param);
|
1976
1977
|
}
|
1977
1978
|
}
|
1978
|
-
result = gvl_PQsendPrepare(
|
1979
|
+
result = gvl_PQsendPrepare(this->pgconn, name_cstr, command_cstr, nParams, paramTypes);
|
1979
1980
|
|
1980
1981
|
xfree(paramTypes);
|
1981
1982
|
|
1982
1983
|
if(result == 0) {
|
1983
|
-
|
1984
|
-
rb_iv_set(error, "@connection", self);
|
1985
|
-
rb_exc_raise(error);
|
1984
|
+
pg_raise_conn_error( rb_eUnableToSend, self, "%s", PQerrorMessage(this->pgconn));
|
1986
1985
|
}
|
1986
|
+
pgconn_wait_for_flush( self );
|
1987
1987
|
return Qnil;
|
1988
1988
|
}
|
1989
1989
|
|
@@ -2005,14 +2005,14 @@ pgconn_send_prepare(int argc, VALUE *argv, VALUE self)
|
|
2005
2005
|
* or, it may be a String. If it is a string, that is equivalent to the hash:
|
2006
2006
|
* { :value => <string value>, :format => 0 }
|
2007
2007
|
*
|
2008
|
-
* PostgreSQL bind parameters are represented as $1, $
|
2008
|
+
* PostgreSQL bind parameters are represented as $1, $2, $3, etc.,
|
2009
2009
|
* inside the SQL query. The 0th element of the +params+ array is bound
|
2010
2010
|
* to $1, the 1st element is bound to $2, etc. +nil+ is treated as +NULL+.
|
2011
2011
|
*
|
2012
2012
|
* The optional +result_format+ should be 0 for text results, 1
|
2013
2013
|
* for binary.
|
2014
2014
|
*
|
2015
|
-
* type_map can be a PG::TypeMap derivation (such as PG::BasicTypeMapForQueries).
|
2015
|
+
* +type_map+ can be a PG::TypeMap derivation (such as PG::BasicTypeMapForQueries).
|
2016
2016
|
* This will type cast the params from various Ruby types before transmission
|
2017
2017
|
* based on the encoders defined by the type map. When a type encoder is used
|
2018
2018
|
* the format and oid of a given bind parameter are retrieved from the encoder
|
@@ -2022,37 +2022,34 @@ pgconn_send_prepare(int argc, VALUE *argv, VALUE self)
|
|
2022
2022
|
static VALUE
|
2023
2023
|
pgconn_send_query_prepared(int argc, VALUE *argv, VALUE self)
|
2024
2024
|
{
|
2025
|
-
|
2025
|
+
t_pg_connection *this = pg_get_connection_safe( self );
|
2026
2026
|
int result;
|
2027
2027
|
VALUE name, in_res_fmt;
|
2028
|
-
VALUE error;
|
2029
2028
|
int nParams;
|
2030
2029
|
int resultFormat;
|
2031
|
-
struct query_params_data paramsData = {
|
2030
|
+
struct query_params_data paramsData = { this->enc_idx };
|
2032
2031
|
|
2033
2032
|
rb_scan_args(argc, argv, "13", &name, ¶msData.params, &in_res_fmt, ¶msData.typemap);
|
2034
2033
|
paramsData.with_types = 0;
|
2035
2034
|
|
2036
2035
|
if(NIL_P(paramsData.params)) {
|
2037
2036
|
paramsData.params = rb_ary_new2(0);
|
2038
|
-
resultFormat = 0;
|
2039
2037
|
}
|
2040
2038
|
pgconn_query_assign_typemap( self, ¶msData );
|
2041
2039
|
|
2042
2040
|
resultFormat = NIL_P(in_res_fmt) ? 0 : NUM2INT(in_res_fmt);
|
2043
2041
|
nParams = alloc_query_params( ¶msData );
|
2044
2042
|
|
2045
|
-
result = gvl_PQsendQueryPrepared(
|
2043
|
+
result = gvl_PQsendQueryPrepared(this->pgconn, pg_cstr_enc(name, paramsData.enc_idx), nParams,
|
2046
2044
|
(const char * const *)paramsData.values, paramsData.lengths, paramsData.formats,
|
2047
2045
|
resultFormat);
|
2048
2046
|
|
2049
2047
|
free_query_params( ¶msData );
|
2050
2048
|
|
2051
|
-
if(result == 0)
|
2052
|
-
|
2053
|
-
|
2054
|
-
|
2055
|
-
}
|
2049
|
+
if(result == 0)
|
2050
|
+
pg_raise_conn_error( rb_eUnableToSend, self, "%s", PQerrorMessage(this->pgconn));
|
2051
|
+
|
2052
|
+
pgconn_wait_for_flush( self );
|
2056
2053
|
return Qnil;
|
2057
2054
|
}
|
2058
2055
|
|
@@ -2066,14 +2063,12 @@ pgconn_send_query_prepared(int argc, VALUE *argv, VALUE self)
|
|
2066
2063
|
static VALUE
|
2067
2064
|
pgconn_send_describe_prepared(VALUE self, VALUE stmt_name)
|
2068
2065
|
{
|
2069
|
-
|
2070
|
-
PGconn *conn = pg_get_pgconn(self);
|
2066
|
+
t_pg_connection *this = pg_get_connection_safe( self );
|
2071
2067
|
/* returns 0 on failure */
|
2072
|
-
if(gvl_PQsendDescribePrepared(
|
2073
|
-
|
2074
|
-
|
2075
|
-
|
2076
|
-
}
|
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 );
|
2077
2072
|
return Qnil;
|
2078
2073
|
}
|
2079
2074
|
|
@@ -2088,36 +2083,18 @@ pgconn_send_describe_prepared(VALUE self, VALUE stmt_name)
|
|
2088
2083
|
static VALUE
|
2089
2084
|
pgconn_send_describe_portal(VALUE self, VALUE portal)
|
2090
2085
|
{
|
2091
|
-
|
2092
|
-
PGconn *conn = pg_get_pgconn(self);
|
2086
|
+
t_pg_connection *this = pg_get_connection_safe( self );
|
2093
2087
|
/* returns 0 on failure */
|
2094
|
-
if(gvl_PQsendDescribePortal(
|
2095
|
-
|
2096
|
-
|
2097
|
-
|
2098
|
-
}
|
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 );
|
2099
2092
|
return Qnil;
|
2100
2093
|
}
|
2101
2094
|
|
2102
2095
|
|
2103
|
-
/*
|
2104
|
-
* call-seq:
|
2105
|
-
* conn.get_result() -> PG::Result
|
2106
|
-
* conn.get_result() {|pg_result| block }
|
2107
|
-
*
|
2108
|
-
* Blocks waiting for the next result from a call to
|
2109
|
-
* #send_query (or another asynchronous command), and returns
|
2110
|
-
* it. Returns +nil+ if no more results are available.
|
2111
|
-
*
|
2112
|
-
* Note: call this function repeatedly until it returns +nil+, or else
|
2113
|
-
* you will not be able to issue further commands.
|
2114
|
-
*
|
2115
|
-
* If the optional code block is given, it will be passed <i>result</i> as an argument,
|
2116
|
-
* and the PG::Result object will automatically be cleared when the block terminates.
|
2117
|
-
* In this instance, <code>conn.exec</code> returns the value of the block.
|
2118
|
-
*/
|
2119
2096
|
static VALUE
|
2120
|
-
|
2097
|
+
pgconn_sync_get_result(VALUE self)
|
2121
2098
|
{
|
2122
2099
|
PGconn *conn = pg_get_pgconn(self);
|
2123
2100
|
PGresult *result;
|
@@ -2143,17 +2120,15 @@ pgconn_get_result(VALUE self)
|
|
2143
2120
|
* or *notifies* to see if the state has changed.
|
2144
2121
|
*/
|
2145
2122
|
static VALUE
|
2146
|
-
pgconn_consume_input(self)
|
2147
|
-
VALUE self;
|
2123
|
+
pgconn_consume_input(VALUE self)
|
2148
2124
|
{
|
2149
|
-
VALUE error;
|
2150
2125
|
PGconn *conn = pg_get_pgconn(self);
|
2151
2126
|
/* returns 0 on error */
|
2152
2127
|
if(PQconsumeInput(conn) == 0) {
|
2153
|
-
|
2154
|
-
|
2155
|
-
rb_exc_raise(error);
|
2128
|
+
pgconn_close_socket_io(self);
|
2129
|
+
pg_raise_conn_error( rb_eConnectionBad, self, "%s", PQerrorMessage(conn));
|
2156
2130
|
}
|
2131
|
+
|
2157
2132
|
return Qnil;
|
2158
2133
|
}
|
2159
2134
|
|
@@ -2162,38 +2137,20 @@ pgconn_consume_input(self)
|
|
2162
2137
|
* conn.is_busy() -> Boolean
|
2163
2138
|
*
|
2164
2139
|
* Returns +true+ if a command is busy, that is, if
|
2165
|
-
*
|
2140
|
+
* #get_result would block. Otherwise returns +false+.
|
2166
2141
|
*/
|
2167
2142
|
static VALUE
|
2168
|
-
pgconn_is_busy(self)
|
2169
|
-
VALUE self;
|
2143
|
+
pgconn_is_busy(VALUE self)
|
2170
2144
|
{
|
2171
2145
|
return gvl_PQisBusy(pg_get_pgconn(self)) ? Qtrue : Qfalse;
|
2172
2146
|
}
|
2173
2147
|
|
2174
|
-
/*
|
2175
|
-
* call-seq:
|
2176
|
-
* conn.setnonblocking(Boolean) -> nil
|
2177
|
-
*
|
2178
|
-
* Sets the nonblocking status of the connection.
|
2179
|
-
* In the blocking state, calls to #send_query
|
2180
|
-
* will block until the message is sent to the server,
|
2181
|
-
* but will not wait for the query results.
|
2182
|
-
* In the nonblocking state, calls to #send_query
|
2183
|
-
* will return an error if the socket is not ready for
|
2184
|
-
* writing.
|
2185
|
-
* Note: This function does not affect #exec, because
|
2186
|
-
* that function doesn't return until the server has
|
2187
|
-
* processed the query and returned the results.
|
2188
|
-
* Returns +nil+.
|
2189
|
-
*/
|
2190
2148
|
static VALUE
|
2191
|
-
|
2192
|
-
VALUE self, state;
|
2149
|
+
pgconn_sync_setnonblocking(VALUE self, VALUE state)
|
2193
2150
|
{
|
2194
2151
|
int arg;
|
2195
|
-
VALUE error;
|
2196
2152
|
PGconn *conn = pg_get_pgconn(self);
|
2153
|
+
rb_check_frozen(self);
|
2197
2154
|
if(state == Qtrue)
|
2198
2155
|
arg = 1;
|
2199
2156
|
else if (state == Qfalse)
|
@@ -2201,67 +2158,32 @@ pgconn_setnonblocking(self, state)
|
|
2201
2158
|
else
|
2202
2159
|
rb_raise(rb_eArgError, "Boolean value expected");
|
2203
2160
|
|
2204
|
-
if(PQsetnonblocking(conn, arg) == -1)
|
2205
|
-
|
2206
|
-
|
2207
|
-
rb_exc_raise(error);
|
2208
|
-
}
|
2161
|
+
if(PQsetnonblocking(conn, arg) == -1)
|
2162
|
+
pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(conn));
|
2163
|
+
|
2209
2164
|
return Qnil;
|
2210
2165
|
}
|
2211
2166
|
|
2212
2167
|
|
2213
|
-
/*
|
2214
|
-
* call-seq:
|
2215
|
-
* conn.isnonblocking() -> Boolean
|
2216
|
-
*
|
2217
|
-
* Returns +true+ if a command is busy, that is, if
|
2218
|
-
* PQgetResult would block. Otherwise returns +false+.
|
2219
|
-
*/
|
2220
2168
|
static VALUE
|
2221
|
-
|
2222
|
-
VALUE self;
|
2169
|
+
pgconn_sync_isnonblocking(VALUE self)
|
2223
2170
|
{
|
2224
2171
|
return PQisnonblocking(pg_get_pgconn(self)) ? Qtrue : Qfalse;
|
2225
2172
|
}
|
2226
2173
|
|
2227
|
-
/*
|
2228
|
-
* call-seq:
|
2229
|
-
* conn.flush() -> Boolean
|
2230
|
-
*
|
2231
|
-
* Attempts to flush any queued output data to the server.
|
2232
|
-
* Returns +true+ if data is successfully flushed, +false+
|
2233
|
-
* if not (can only return +false+ if connection is
|
2234
|
-
* nonblocking.
|
2235
|
-
* Raises PG::Error if some other failure occurred.
|
2236
|
-
*/
|
2237
2174
|
static VALUE
|
2238
|
-
|
2239
|
-
VALUE self;
|
2175
|
+
pgconn_sync_flush(VALUE self)
|
2240
2176
|
{
|
2241
2177
|
PGconn *conn = pg_get_pgconn(self);
|
2242
|
-
int ret;
|
2243
|
-
|
2244
|
-
|
2245
|
-
|
2246
|
-
error = rb_exc_new2(rb_ePGerror, PQerrorMessage(conn));
|
2247
|
-
rb_iv_set(error, "@connection", self);
|
2248
|
-
rb_exc_raise(error);
|
2249
|
-
}
|
2178
|
+
int ret = PQflush(conn);
|
2179
|
+
if(ret == -1)
|
2180
|
+
pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(conn));
|
2181
|
+
|
2250
2182
|
return (ret) ? Qfalse : Qtrue;
|
2251
2183
|
}
|
2252
2184
|
|
2253
|
-
/*
|
2254
|
-
* call-seq:
|
2255
|
-
* conn.cancel() -> String
|
2256
|
-
*
|
2257
|
-
* Requests cancellation of the command currently being
|
2258
|
-
* processed. (Only implemented in PostgreSQL >= 8.0)
|
2259
|
-
*
|
2260
|
-
* Returns +nil+ on success, or a string containing the
|
2261
|
-
* error message if a failure occurs.
|
2262
|
-
*/
|
2263
2185
|
static VALUE
|
2264
|
-
|
2186
|
+
pgconn_sync_cancel(VALUE self)
|
2265
2187
|
{
|
2266
2188
|
char errbuf[256];
|
2267
2189
|
PGcancel *cancel;
|
@@ -2270,9 +2192,9 @@ pgconn_cancel(VALUE self)
|
|
2270
2192
|
|
2271
2193
|
cancel = PQgetCancel(pg_get_pgconn(self));
|
2272
2194
|
if(cancel == NULL)
|
2273
|
-
|
2195
|
+
pg_raise_conn_error( rb_ePGerror, self, "Invalid connection!");
|
2274
2196
|
|
2275
|
-
ret = gvl_PQcancel(cancel, errbuf,
|
2197
|
+
ret = gvl_PQcancel(cancel, errbuf, sizeof(errbuf));
|
2276
2198
|
if(ret == 1)
|
2277
2199
|
retval = Qnil;
|
2278
2200
|
else
|
@@ -2293,7 +2215,7 @@ pgconn_cancel(VALUE self)
|
|
2293
2215
|
static VALUE
|
2294
2216
|
pgconn_notifies(VALUE self)
|
2295
2217
|
{
|
2296
|
-
|
2218
|
+
t_pg_connection *this = pg_get_connection_safe( self );
|
2297
2219
|
PGnotify *notification;
|
2298
2220
|
VALUE hash;
|
2299
2221
|
VALUE sym_relname, sym_be_pid, sym_extra;
|
@@ -2303,17 +2225,17 @@ pgconn_notifies(VALUE self)
|
|
2303
2225
|
sym_be_pid = ID2SYM(rb_intern("be_pid"));
|
2304
2226
|
sym_extra = ID2SYM(rb_intern("extra"));
|
2305
2227
|
|
2306
|
-
notification = gvl_PQnotifies(
|
2228
|
+
notification = gvl_PQnotifies(this->pgconn);
|
2307
2229
|
if (notification == NULL) {
|
2308
2230
|
return Qnil;
|
2309
2231
|
}
|
2310
2232
|
|
2311
2233
|
hash = rb_hash_new();
|
2312
|
-
relname =
|
2234
|
+
relname = rb_str_new2(notification->relname);
|
2313
2235
|
be_pid = INT2NUM(notification->be_pid);
|
2314
|
-
extra =
|
2315
|
-
PG_ENCODING_SET_NOCHECK( relname,
|
2316
|
-
PG_ENCODING_SET_NOCHECK( extra,
|
2236
|
+
extra = rb_str_new2(notification->extra);
|
2237
|
+
PG_ENCODING_SET_NOCHECK( relname, this->enc_idx );
|
2238
|
+
PG_ENCODING_SET_NOCHECK( extra, this->enc_idx );
|
2317
2239
|
|
2318
2240
|
rb_hash_aset(hash, sym_relname, relname);
|
2319
2241
|
rb_hash_aset(hash, sym_be_pid, be_pid);
|
@@ -2323,55 +2245,63 @@ pgconn_notifies(VALUE self)
|
|
2323
2245
|
return hash;
|
2324
2246
|
}
|
2325
2247
|
|
2326
|
-
|
2327
|
-
|
2328
|
-
/*
|
2329
|
-
*
|
2330
|
-
* 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.
|
2331
2252
|
*/
|
2332
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
|
+
|
2333
2264
|
int rb_w32_wait_events( HANDLE *events, int num, DWORD timeout );
|
2334
2265
|
|
2335
|
-
static
|
2336
|
-
|
2337
|
-
|
2338
|
-
|
2339
|
-
|
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
|
+
|
2340
2271
|
struct timeval aborttime={0,0}, currtime, waittime;
|
2341
2272
|
DWORD timeout_milisec = INFINITE;
|
2342
|
-
|
2343
|
-
WSAEVENT hEvent;
|
2273
|
+
HANDLE hEvent = WSACreateEvent();
|
2344
2274
|
|
2345
|
-
|
2346
|
-
|
2347
|
-
|
2348
|
-
hEvent = WSACreateEvent();
|
2275
|
+
long rb_events = NUM2UINT(events);
|
2276
|
+
long w32_events = 0;
|
2277
|
+
DWORD wait_ret;
|
2349
2278
|
|
2350
|
-
|
2351
|
-
if(
|
2352
|
-
|
2353
|
-
|
2354
|
-
}
|
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);
|
2355
2283
|
|
2356
|
-
if ( ptimeout ) {
|
2357
2284
|
gettimeofday(&currtime, NULL);
|
2358
|
-
timeradd(&currtime, ptimeout, &aborttime);
|
2285
|
+
timeradd(&currtime, &ptimeout, &aborttime);
|
2359
2286
|
}
|
2360
2287
|
|
2361
|
-
|
2362
|
-
|
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 ) {
|
2363
2294
|
WSACloseEvent( hEvent );
|
2364
2295
|
rb_raise( rb_eConnectionBad, "WSAEventSelect socket error: %d", WSAGetLastError() );
|
2365
2296
|
}
|
2366
2297
|
|
2367
|
-
if (
|
2298
|
+
if ( !NIL_P(timeout) ) {
|
2368
2299
|
gettimeofday(&currtime, NULL);
|
2369
2300
|
timersub(&aborttime, &currtime, &waittime);
|
2370
2301
|
timeout_milisec = (DWORD)( waittime.tv_sec * 1e3 + waittime.tv_usec / 1e3 );
|
2371
2302
|
}
|
2372
2303
|
|
2373
|
-
|
2374
|
-
if( !ptimeout || (waittime.tv_sec >= 0 && waittime.tv_usec >= 0) ){
|
2304
|
+
if( NIL_P(timeout) || (waittime.tv_sec >= 0 && waittime.tv_usec >= 0) ){
|
2375
2305
|
/* Wait for the socket to become readable before checking again */
|
2376
2306
|
wait_ret = rb_w32_wait_events( &hEvent, 1, timeout_milisec );
|
2377
2307
|
} else {
|
@@ -2380,9 +2310,11 @@ wait_socket_readable( PGconn *conn, struct timeval *ptimeout, void *(*is_readabl
|
|
2380
2310
|
|
2381
2311
|
if ( wait_ret == WAIT_TIMEOUT ) {
|
2382
2312
|
WSACloseEvent( hEvent );
|
2383
|
-
return
|
2313
|
+
return UINT2NUM(0);
|
2384
2314
|
} else if ( wait_ret == WAIT_OBJECT_0 ) {
|
2315
|
+
WSACloseEvent( hEvent );
|
2385
2316
|
/* The event we were waiting for. */
|
2317
|
+
return UINT2NUM(rb_events);
|
2386
2318
|
} else if ( wait_ret == WAIT_OBJECT_0 + 1) {
|
2387
2319
|
/* This indicates interruption from timer thread, GC, exception
|
2388
2320
|
* from other threads etc... */
|
@@ -2394,36 +2326,66 @@ wait_socket_readable( PGconn *conn, struct timeval *ptimeout, void *(*is_readabl
|
|
2394
2326
|
WSACloseEvent( hEvent );
|
2395
2327
|
rb_raise( rb_eConnectionBad, "Wait on socket abandoned (WaitForMultipleObjects)" );
|
2396
2328
|
}
|
2397
|
-
|
2398
|
-
/* Check for connection errors (PQisBusy is true on connection errors) */
|
2399
|
-
if ( PQconsumeInput(conn) == 0 ) {
|
2400
|
-
WSACloseEvent( hEvent );
|
2401
|
-
rb_raise( rb_eConnectionBad, "PQconsumeInput() %s", PQerrorMessage(conn) );
|
2402
|
-
}
|
2403
2329
|
}
|
2330
|
+
}
|
2404
2331
|
|
2405
|
-
|
2406
|
-
|
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);
|
2407
2345
|
}
|
2408
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
|
+
|
2409
2355
|
#else
|
2356
|
+
/* For compat with ruby < 3.0 */
|
2357
|
+
|
2358
|
+
typedef enum {
|
2359
|
+
PG_RUBY_IO_READABLE = RB_WAITFD_IN,
|
2360
|
+
PG_RUBY_IO_WRITABLE = RB_WAITFD_OUT,
|
2361
|
+
PG_RUBY_IO_PRIORITY = RB_WAITFD_PRI,
|
2362
|
+
} pg_rb_io_event_t;
|
2410
2363
|
|
2411
|
-
|
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
|
2412
2380
|
|
2413
2381
|
static void *
|
2414
|
-
wait_socket_readable(
|
2382
|
+
wait_socket_readable( VALUE self, struct timeval *ptimeout, void *(*is_readable)(PGconn *))
|
2415
2383
|
{
|
2416
|
-
|
2417
|
-
int ret;
|
2384
|
+
VALUE ret;
|
2418
2385
|
void *retval;
|
2419
2386
|
struct timeval aborttime={0,0}, currtime, waittime;
|
2420
|
-
|
2421
|
-
|
2422
|
-
rb_raise(rb_eConnectionBad, "PQsocket() can't get socket descriptor");
|
2423
|
-
|
2424
|
-
/* Check for connection errors (PQisBusy is true on connection errors) */
|
2425
|
-
if ( PQconsumeInput(conn) == 0 )
|
2426
|
-
rb_raise( rb_eConnectionBad, "PQconsumeInput() %s", PQerrorMessage(conn) );
|
2387
|
+
VALUE wait_timeout = Qnil;
|
2388
|
+
PGconn *conn = pg_get_pgconn(self);
|
2427
2389
|
|
2428
2390
|
if ( ptimeout ) {
|
2429
2391
|
gettimeofday(&currtime, NULL);
|
@@ -2434,36 +2396,81 @@ wait_socket_readable( PGconn *conn, struct timeval *ptimeout, void *(*is_readabl
|
|
2434
2396
|
if ( ptimeout ) {
|
2435
2397
|
gettimeofday(&currtime, NULL);
|
2436
2398
|
timersub(&aborttime, &currtime, &waittime);
|
2399
|
+
wait_timeout = DBL2NUM((double)(waittime.tv_sec) + (double)(waittime.tv_usec) / 1000000.0);
|
2437
2400
|
}
|
2438
2401
|
|
2439
2402
|
/* Is the given timeout valid? */
|
2440
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);
|
2441
2412
|
/* Wait for the socket to become readable before checking again */
|
2442
|
-
ret =
|
2413
|
+
ret = pg_rb_io_wait(socket_io, RB_INT2NUM(PG_RUBY_IO_READABLE), wait_timeout);
|
2443
2414
|
} else {
|
2444
|
-
ret =
|
2445
|
-
}
|
2446
|
-
|
2447
|
-
if ( ret < 0 ){
|
2448
|
-
rb_sys_fail( "rb_wait_for_single_fd()" );
|
2415
|
+
ret = Qfalse;
|
2449
2416
|
}
|
2450
2417
|
|
2451
2418
|
/* Return false if the select() timed out */
|
2452
|
-
if ( ret ==
|
2419
|
+
if ( ret == Qfalse ){
|
2453
2420
|
return NULL;
|
2454
2421
|
}
|
2455
2422
|
|
2456
2423
|
/* Check for connection errors (PQisBusy is true on connection errors) */
|
2457
2424
|
if ( PQconsumeInput(conn) == 0 ){
|
2458
|
-
|
2425
|
+
pgconn_close_socket_io(self);
|
2426
|
+
pg_raise_conn_error(rb_eConnectionBad, self, "PQconsumeInput() %s", PQerrorMessage(conn));
|
2459
2427
|
}
|
2460
2428
|
}
|
2461
2429
|
|
2462
2430
|
return retval;
|
2463
2431
|
}
|
2464
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
|
+
}
|
2465
2466
|
|
2466
|
-
|
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
|
+
}
|
2467
2474
|
|
2468
2475
|
static void *
|
2469
2476
|
notify_readable(PGconn *conn)
|
@@ -2486,7 +2493,7 @@ notify_readable(PGconn *conn)
|
|
2486
2493
|
static VALUE
|
2487
2494
|
pgconn_wait_for_notify(int argc, VALUE *argv, VALUE self)
|
2488
2495
|
{
|
2489
|
-
|
2496
|
+
t_pg_connection *this = pg_get_connection_safe( self );
|
2490
2497
|
PGnotify *pnotification;
|
2491
2498
|
struct timeval timeout;
|
2492
2499
|
struct timeval *ptimeout = NULL;
|
@@ -2502,17 +2509,17 @@ pgconn_wait_for_notify(int argc, VALUE *argv, VALUE self)
|
|
2502
2509
|
ptimeout = &timeout;
|
2503
2510
|
}
|
2504
2511
|
|
2505
|
-
pnotification = (PGnotify*) wait_socket_readable(
|
2512
|
+
pnotification = (PGnotify*) wait_socket_readable( self, ptimeout, notify_readable);
|
2506
2513
|
|
2507
2514
|
/* Return nil if the select timed out */
|
2508
2515
|
if ( !pnotification ) return Qnil;
|
2509
2516
|
|
2510
|
-
relname =
|
2511
|
-
PG_ENCODING_SET_NOCHECK( relname,
|
2517
|
+
relname = rb_str_new2( pnotification->relname );
|
2518
|
+
PG_ENCODING_SET_NOCHECK( relname, this->enc_idx );
|
2512
2519
|
be_pid = INT2NUM( pnotification->be_pid );
|
2513
2520
|
if ( *pnotification->extra ) {
|
2514
|
-
extra =
|
2515
|
-
PG_ENCODING_SET_NOCHECK( extra,
|
2521
|
+
extra = rb_str_new2( pnotification->extra );
|
2522
|
+
PG_ENCODING_SET_NOCHECK( extra, this->enc_idx );
|
2516
2523
|
}
|
2517
2524
|
PQfreemem( pnotification );
|
2518
2525
|
|
@@ -2523,28 +2530,8 @@ pgconn_wait_for_notify(int argc, VALUE *argv, VALUE self)
|
|
2523
2530
|
}
|
2524
2531
|
|
2525
2532
|
|
2526
|
-
/*
|
2527
|
-
* call-seq:
|
2528
|
-
* conn.put_copy_data( buffer [, encoder] ) -> Boolean
|
2529
|
-
*
|
2530
|
-
* Transmits _buffer_ as copy data to the server.
|
2531
|
-
* Returns true if the data was sent, false if it was
|
2532
|
-
* not sent (false is only possible if the connection
|
2533
|
-
* is in nonblocking mode, and this command would block).
|
2534
|
-
*
|
2535
|
-
* _encoder_ can be a PG::Coder derivation (typically PG::TextEncoder::CopyRow).
|
2536
|
-
* This encodes the data fields given as _buffer_ from an Array of Strings to
|
2537
|
-
* PostgreSQL's COPY text format inclusive proper escaping. Optionally
|
2538
|
-
* the encoder can type cast the fields from various Ruby types in one step,
|
2539
|
-
* if PG::TextEncoder::CopyRow#type_map is set accordingly.
|
2540
|
-
*
|
2541
|
-
* Raises an exception if an error occurs.
|
2542
|
-
*
|
2543
|
-
* See also #copy_data.
|
2544
|
-
*
|
2545
|
-
*/
|
2546
2533
|
static VALUE
|
2547
|
-
|
2534
|
+
pgconn_sync_put_copy_data(int argc, VALUE *argv, VALUE self)
|
2548
2535
|
{
|
2549
2536
|
int ret;
|
2550
2537
|
int len;
|
@@ -2561,18 +2548,16 @@ pgconn_put_copy_data(int argc, VALUE *argv, VALUE self)
|
|
2561
2548
|
if( NIL_P(this->encoder_for_put_copy_data) ){
|
2562
2549
|
buffer = value;
|
2563
2550
|
} else {
|
2564
|
-
p_coder =
|
2551
|
+
p_coder = RTYPEDDATA_DATA( this->encoder_for_put_copy_data );
|
2565
2552
|
}
|
2566
|
-
} else if( rb_obj_is_kind_of(encoder, rb_cPG_Coder) ) {
|
2567
|
-
Data_Get_Struct( encoder, t_pg_coder, p_coder );
|
2568
2553
|
} else {
|
2569
|
-
|
2570
|
-
|
2554
|
+
/* Check argument type and use argument encoder */
|
2555
|
+
TypedData_Get_Struct(encoder, t_pg_coder, &pg_coder_type, p_coder);
|
2571
2556
|
}
|
2572
2557
|
|
2573
2558
|
if( p_coder ){
|
2574
2559
|
t_pg_coder_enc_func enc_func;
|
2575
|
-
int enc_idx =
|
2560
|
+
int enc_idx = this->enc_idx;
|
2576
2561
|
|
2577
2562
|
enc_func = pg_coder_enc_func( p_coder );
|
2578
2563
|
len = enc_func( p_coder, value, NULL, &intermediate, enc_idx);
|
@@ -2590,78 +2575,39 @@ pgconn_put_copy_data(int argc, VALUE *argv, VALUE self)
|
|
2590
2575
|
Check_Type(buffer, T_STRING);
|
2591
2576
|
|
2592
2577
|
ret = gvl_PQputCopyData(this->pgconn, RSTRING_PTR(buffer), RSTRING_LENINT(buffer));
|
2593
|
-
if(ret == -1)
|
2594
|
-
|
2595
|
-
|
2596
|
-
rb_exc_raise(error);
|
2597
|
-
}
|
2578
|
+
if(ret == -1)
|
2579
|
+
pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(this->pgconn));
|
2580
|
+
|
2598
2581
|
RB_GC_GUARD(intermediate);
|
2599
2582
|
RB_GC_GUARD(buffer);
|
2600
2583
|
|
2601
2584
|
return (ret) ? Qtrue : Qfalse;
|
2602
2585
|
}
|
2603
2586
|
|
2604
|
-
/*
|
2605
|
-
* call-seq:
|
2606
|
-
* conn.put_copy_end( [ error_message ] ) -> Boolean
|
2607
|
-
*
|
2608
|
-
* Sends end-of-data indication to the server.
|
2609
|
-
*
|
2610
|
-
* _error_message_ is an optional parameter, and if set,
|
2611
|
-
* forces the COPY command to fail with the string
|
2612
|
-
* _error_message_.
|
2613
|
-
*
|
2614
|
-
* Returns true if the end-of-data was sent, false if it was
|
2615
|
-
* not sent (false is only possible if the connection
|
2616
|
-
* is in nonblocking mode, and this command would block).
|
2617
|
-
*/
|
2618
2587
|
static VALUE
|
2619
|
-
|
2588
|
+
pgconn_sync_put_copy_end(int argc, VALUE *argv, VALUE self)
|
2620
2589
|
{
|
2621
2590
|
VALUE str;
|
2622
|
-
VALUE error;
|
2623
2591
|
int ret;
|
2624
2592
|
const char *error_message = NULL;
|
2625
|
-
|
2593
|
+
t_pg_connection *this = pg_get_connection_safe( self );
|
2626
2594
|
|
2627
2595
|
if (rb_scan_args(argc, argv, "01", &str) == 0)
|
2628
2596
|
error_message = NULL;
|
2629
2597
|
else
|
2630
|
-
error_message = pg_cstr_enc(str,
|
2598
|
+
error_message = pg_cstr_enc(str, this->enc_idx);
|
2599
|
+
|
2600
|
+
ret = gvl_PQputCopyEnd(this->pgconn, error_message);
|
2601
|
+
if(ret == -1)
|
2602
|
+
pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(this->pgconn));
|
2631
2603
|
|
2632
|
-
ret = gvl_PQputCopyEnd(conn, error_message);
|
2633
|
-
if(ret == -1) {
|
2634
|
-
error = rb_exc_new2(rb_ePGerror, PQerrorMessage(conn));
|
2635
|
-
rb_iv_set(error, "@connection", self);
|
2636
|
-
rb_exc_raise(error);
|
2637
|
-
}
|
2638
2604
|
return (ret) ? Qtrue : Qfalse;
|
2639
2605
|
}
|
2640
2606
|
|
2641
|
-
/*
|
2642
|
-
* call-seq:
|
2643
|
-
* conn.get_copy_data( [ async = false [, decoder = nil ]] ) -> Object
|
2644
|
-
*
|
2645
|
-
* Return one row of data, +nil+
|
2646
|
-
* if the copy is done, or +false+ if the call would
|
2647
|
-
* block (only possible if _async_ is true).
|
2648
|
-
*
|
2649
|
-
* If _decoder_ is not set or +nil+, data is returned as binary string.
|
2650
|
-
*
|
2651
|
-
* If _decoder_ is set to a PG::Coder derivation, the return type depends on this decoder.
|
2652
|
-
* PG::TextDecoder::CopyRow decodes the received data fields from one row of PostgreSQL's
|
2653
|
-
* COPY text format to an Array of Strings.
|
2654
|
-
* Optionally the decoder can type cast the single fields to various Ruby types in one step,
|
2655
|
-
* if PG::TextDecoder::CopyRow#type_map is set accordingly.
|
2656
|
-
*
|
2657
|
-
* See also #copy_data.
|
2658
|
-
*
|
2659
|
-
*/
|
2660
2607
|
static VALUE
|
2661
|
-
|
2608
|
+
pgconn_sync_get_copy_data(int argc, VALUE *argv, VALUE self )
|
2662
2609
|
{
|
2663
2610
|
VALUE async_in;
|
2664
|
-
VALUE error;
|
2665
2611
|
VALUE result;
|
2666
2612
|
int ret;
|
2667
2613
|
char *buffer;
|
@@ -2673,20 +2619,16 @@ pgconn_get_copy_data(int argc, VALUE *argv, VALUE self )
|
|
2673
2619
|
|
2674
2620
|
if( NIL_P(decoder) ){
|
2675
2621
|
if( !NIL_P(this->decoder_for_get_copy_data) ){
|
2676
|
-
p_coder =
|
2622
|
+
p_coder = RTYPEDDATA_DATA( this->decoder_for_get_copy_data );
|
2677
2623
|
}
|
2678
|
-
} else if( rb_obj_is_kind_of(decoder, rb_cPG_Coder) ) {
|
2679
|
-
Data_Get_Struct( decoder, t_pg_coder, p_coder );
|
2680
2624
|
} else {
|
2681
|
-
|
2682
|
-
|
2625
|
+
/* Check argument type and use argument decoder */
|
2626
|
+
TypedData_Get_Struct(decoder, t_pg_coder, &pg_coder_type, p_coder);
|
2683
2627
|
}
|
2684
2628
|
|
2685
2629
|
ret = gvl_PQgetCopyData(this->pgconn, &buffer, RTEST(async_in));
|
2686
|
-
if(ret == -2)
|
2687
|
-
|
2688
|
-
rb_iv_set(error, "@connection", self);
|
2689
|
-
rb_exc_raise(error);
|
2630
|
+
if(ret == -2){ /* error */
|
2631
|
+
pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(this->pgconn));
|
2690
2632
|
}
|
2691
2633
|
if(ret == -1) { /* No data left */
|
2692
2634
|
return Qnil;
|
@@ -2697,9 +2639,9 @@ pgconn_get_copy_data(int argc, VALUE *argv, VALUE self )
|
|
2697
2639
|
|
2698
2640
|
if( p_coder ){
|
2699
2641
|
t_pg_coder_dec_func dec_func = pg_coder_dec_func( p_coder, p_coder->format );
|
2700
|
-
result = dec_func( p_coder, buffer, ret, 0, 0,
|
2642
|
+
result = dec_func( p_coder, buffer, ret, 0, 0, this->enc_idx );
|
2701
2643
|
} else {
|
2702
|
-
result =
|
2644
|
+
result = rb_str_new(buffer, ret);
|
2703
2645
|
}
|
2704
2646
|
|
2705
2647
|
PQfreemem(buffer);
|
@@ -2712,9 +2654,16 @@ pgconn_get_copy_data(int argc, VALUE *argv, VALUE self )
|
|
2712
2654
|
*
|
2713
2655
|
* Sets connection's verbosity to _verbosity_ and returns
|
2714
2656
|
* the previous setting. Available settings are:
|
2657
|
+
*
|
2715
2658
|
* * PQERRORS_TERSE
|
2716
2659
|
* * PQERRORS_DEFAULT
|
2717
2660
|
* * PQERRORS_VERBOSE
|
2661
|
+
* * PQERRORS_SQLSTATE
|
2662
|
+
*
|
2663
|
+
* Changing the verbosity does not affect the messages available from already-existing PG::Result objects, only subsequently-created ones.
|
2664
|
+
* (But see PG::Result#verbose_error_message if you want to print a previous error with a different verbosity.)
|
2665
|
+
*
|
2666
|
+
* See also corresponding {libpq function}[https://www.postgresql.org/docs/current/libpq-control.html#LIBPQ-PQSETERRORVERBOSITY].
|
2718
2667
|
*/
|
2719
2668
|
static VALUE
|
2720
2669
|
pgconn_set_error_verbosity(VALUE self, VALUE in_verbosity)
|
@@ -2724,6 +2673,37 @@ pgconn_set_error_verbosity(VALUE self, VALUE in_verbosity)
|
|
2724
2673
|
return INT2FIX(PQsetErrorVerbosity(conn, verbosity));
|
2725
2674
|
}
|
2726
2675
|
|
2676
|
+
#ifdef HAVE_PQRESULTVERBOSEERRORMESSAGE
|
2677
|
+
/*
|
2678
|
+
* call-seq:
|
2679
|
+
* conn.set_error_context_visibility( context_visibility ) -> Integer
|
2680
|
+
*
|
2681
|
+
* Sets connection's context display mode to _context_visibility_ and returns
|
2682
|
+
* the previous setting. Available settings are:
|
2683
|
+
* * PQSHOW_CONTEXT_NEVER
|
2684
|
+
* * PQSHOW_CONTEXT_ERRORS
|
2685
|
+
* * PQSHOW_CONTEXT_ALWAYS
|
2686
|
+
*
|
2687
|
+
* This mode controls whether the CONTEXT field is included in messages (unless the verbosity setting is TERSE, in which case CONTEXT is never shown).
|
2688
|
+
* The NEVER mode never includes CONTEXT, while ALWAYS always includes it if available.
|
2689
|
+
* In ERRORS mode (the default), CONTEXT fields are included only for error messages, not for notices and warnings.
|
2690
|
+
*
|
2691
|
+
* Changing this mode does not affect the messages available from already-existing PG::Result objects, only subsequently-created ones.
|
2692
|
+
* (But see PG::Result#verbose_error_message if you want to print a previous error with a different display mode.)
|
2693
|
+
*
|
2694
|
+
* See also corresponding {libpq function}[https://www.postgresql.org/docs/current/libpq-control.html#LIBPQ-PQSETERRORCONTEXTVISIBILITY].
|
2695
|
+
*
|
2696
|
+
* Available since PostgreSQL-9.6
|
2697
|
+
*/
|
2698
|
+
static VALUE
|
2699
|
+
pgconn_set_error_context_visibility(VALUE self, VALUE in_context_visibility)
|
2700
|
+
{
|
2701
|
+
PGconn *conn = pg_get_pgconn(self);
|
2702
|
+
PGContextVisibility context_visibility = NUM2INT(in_context_visibility);
|
2703
|
+
return INT2FIX(PQsetErrorContextVisibility(conn, context_visibility));
|
2704
|
+
}
|
2705
|
+
#endif
|
2706
|
+
|
2727
2707
|
/*
|
2728
2708
|
* call-seq:
|
2729
2709
|
* conn.trace( stream ) -> nil
|
@@ -2742,7 +2722,8 @@ pgconn_trace(VALUE self, VALUE stream)
|
|
2742
2722
|
VALUE new_file;
|
2743
2723
|
t_pg_connection *this = pg_get_connection_safe( self );
|
2744
2724
|
|
2745
|
-
|
2725
|
+
rb_check_frozen(self);
|
2726
|
+
if(!rb_respond_to(stream,rb_intern("fileno")))
|
2746
2727
|
rb_raise(rb_eArgError, "stream does not respond to method: fileno");
|
2747
2728
|
|
2748
2729
|
fileno = rb_funcall(stream, rb_intern("fileno"), 0);
|
@@ -2763,7 +2744,7 @@ pgconn_trace(VALUE self, VALUE stream)
|
|
2763
2744
|
rb_raise(rb_eArgError, "stream is not writable");
|
2764
2745
|
|
2765
2746
|
new_file = rb_funcall(rb_cIO, rb_intern("new"), 1, INT2NUM(new_fd));
|
2766
|
-
this->trace_stream
|
2747
|
+
RB_OBJ_WRITE(self, &this->trace_stream, new_file);
|
2767
2748
|
|
2768
2749
|
PQtrace(this->pgconn, new_fp);
|
2769
2750
|
return Qnil;
|
@@ -2782,7 +2763,7 @@ pgconn_untrace(VALUE self)
|
|
2782
2763
|
|
2783
2764
|
PQuntrace(this->pgconn);
|
2784
2765
|
rb_funcall(this->trace_stream, rb_intern("close"), 0);
|
2785
|
-
this->trace_stream
|
2766
|
+
RB_OBJ_WRITE(self, &this->trace_stream, Qnil);
|
2786
2767
|
return Qnil;
|
2787
2768
|
}
|
2788
2769
|
|
@@ -2841,13 +2822,14 @@ pgconn_set_notice_receiver(VALUE self)
|
|
2841
2822
|
VALUE proc, old_proc;
|
2842
2823
|
t_pg_connection *this = pg_get_connection_safe( self );
|
2843
2824
|
|
2825
|
+
rb_check_frozen(self);
|
2844
2826
|
/* If default_notice_receiver is unset, assume that the current
|
2845
2827
|
* notice receiver is the default, and save it to a global variable.
|
2846
2828
|
* This should not be a problem because the default receiver is
|
2847
2829
|
* always the same, so won't vary among connections.
|
2848
2830
|
*/
|
2849
|
-
if(default_notice_receiver == NULL)
|
2850
|
-
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);
|
2851
2833
|
|
2852
2834
|
old_proc = this->notice_receiver;
|
2853
2835
|
if( rb_block_given_p() ) {
|
@@ -2856,10 +2838,10 @@ pgconn_set_notice_receiver(VALUE self)
|
|
2856
2838
|
} else {
|
2857
2839
|
/* if no block is given, set back to default */
|
2858
2840
|
proc = Qnil;
|
2859
|
-
PQsetNoticeReceiver(this->pgconn, default_notice_receiver, NULL);
|
2841
|
+
PQsetNoticeReceiver(this->pgconn, this->default_notice_receiver, NULL);
|
2860
2842
|
}
|
2861
2843
|
|
2862
|
-
this->notice_receiver
|
2844
|
+
RB_OBJ_WRITE(self, &this->notice_receiver, proc);
|
2863
2845
|
return old_proc;
|
2864
2846
|
}
|
2865
2847
|
|
@@ -2874,10 +2856,10 @@ notice_processor_proxy(void *arg, const char *message)
|
|
2874
2856
|
VALUE self = (VALUE)arg;
|
2875
2857
|
t_pg_connection *this = pg_get_connection( self );
|
2876
2858
|
|
2877
|
-
if (this->
|
2878
|
-
VALUE message_str =
|
2879
|
-
PG_ENCODING_SET_NOCHECK( message_str,
|
2880
|
-
rb_funcall(this->
|
2859
|
+
if (this->notice_processor != Qnil) {
|
2860
|
+
VALUE message_str = rb_str_new2(message);
|
2861
|
+
PG_ENCODING_SET_NOCHECK( message_str, this->enc_idx );
|
2862
|
+
rb_funcall(this->notice_processor, rb_intern("call"), 1, message_str);
|
2881
2863
|
}
|
2882
2864
|
return;
|
2883
2865
|
}
|
@@ -2886,7 +2868,7 @@ notice_processor_proxy(void *arg, const char *message)
|
|
2886
2868
|
* call-seq:
|
2887
2869
|
* conn.set_notice_processor {|message| ... } -> Proc
|
2888
2870
|
*
|
2889
|
-
* See #set_notice_receiver for the
|
2871
|
+
* See #set_notice_receiver for the description of what this and the
|
2890
2872
|
* notice_processor methods do.
|
2891
2873
|
*
|
2892
2874
|
* This function takes a new block to act as the notice processor and returns
|
@@ -2901,25 +2883,26 @@ pgconn_set_notice_processor(VALUE self)
|
|
2901
2883
|
VALUE proc, old_proc;
|
2902
2884
|
t_pg_connection *this = pg_get_connection_safe( self );
|
2903
2885
|
|
2886
|
+
rb_check_frozen(self);
|
2904
2887
|
/* If default_notice_processor is unset, assume that the current
|
2905
2888
|
* notice processor is the default, and save it to a global variable.
|
2906
2889
|
* This should not be a problem because the default processor is
|
2907
2890
|
* always the same, so won't vary among connections.
|
2908
2891
|
*/
|
2909
|
-
if(default_notice_processor == NULL)
|
2910
|
-
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);
|
2911
2894
|
|
2912
|
-
old_proc = this->
|
2895
|
+
old_proc = this->notice_processor;
|
2913
2896
|
if( rb_block_given_p() ) {
|
2914
2897
|
proc = rb_block_proc();
|
2915
2898
|
PQsetNoticeProcessor(this->pgconn, gvl_notice_processor_proxy, (void *)self);
|
2916
2899
|
} else {
|
2917
2900
|
/* if no block is given, set back to default */
|
2918
2901
|
proc = Qnil;
|
2919
|
-
PQsetNoticeProcessor(this->pgconn, default_notice_processor, NULL);
|
2902
|
+
PQsetNoticeProcessor(this->pgconn, this->default_notice_processor, NULL);
|
2920
2903
|
}
|
2921
2904
|
|
2922
|
-
this->
|
2905
|
+
RB_OBJ_WRITE(self, &this->notice_processor, proc);
|
2923
2906
|
return old_proc;
|
2924
2907
|
}
|
2925
2908
|
|
@@ -2934,74 +2917,34 @@ static VALUE
|
|
2934
2917
|
pgconn_get_client_encoding(VALUE self)
|
2935
2918
|
{
|
2936
2919
|
char *encoding = (char *)pg_encoding_to_char(PQclientEncoding(pg_get_pgconn(self)));
|
2937
|
-
return
|
2920
|
+
return rb_str_new2(encoding);
|
2938
2921
|
}
|
2939
2922
|
|
2940
2923
|
|
2941
2924
|
/*
|
2942
2925
|
* call-seq:
|
2943
|
-
* conn.
|
2926
|
+
* conn.sync_set_client_encoding( encoding )
|
2944
2927
|
*
|
2945
|
-
*
|
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.
|
2946
2931
|
*/
|
2947
2932
|
static VALUE
|
2948
|
-
|
2933
|
+
pgconn_sync_set_client_encoding(VALUE self, VALUE str)
|
2949
2934
|
{
|
2950
2935
|
PGconn *conn = pg_get_pgconn( self );
|
2951
2936
|
|
2937
|
+
rb_check_frozen(self);
|
2952
2938
|
Check_Type(str, T_STRING);
|
2953
2939
|
|
2954
|
-
if ( (gvl_PQsetClientEncoding(conn, StringValueCStr(str))) == -1 )
|
2955
|
-
|
2956
|
-
|
2940
|
+
if ( (gvl_PQsetClientEncoding(conn, StringValueCStr(str))) == -1 )
|
2941
|
+
pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(conn));
|
2942
|
+
|
2957
2943
|
pgconn_set_internal_encoding_index( self );
|
2958
2944
|
|
2959
2945
|
return Qnil;
|
2960
2946
|
}
|
2961
2947
|
|
2962
|
-
/*
|
2963
|
-
* call-seq:
|
2964
|
-
* conn.transaction { |conn| ... } -> result of the block
|
2965
|
-
*
|
2966
|
-
* Executes a +BEGIN+ at the start of the block,
|
2967
|
-
* and a +COMMIT+ at the end of the block, or
|
2968
|
-
* +ROLLBACK+ if any exception occurs.
|
2969
|
-
*/
|
2970
|
-
static VALUE
|
2971
|
-
pgconn_transaction(VALUE self)
|
2972
|
-
{
|
2973
|
-
PGconn *conn = pg_get_pgconn(self);
|
2974
|
-
PGresult *result;
|
2975
|
-
VALUE rb_pgresult;
|
2976
|
-
VALUE block_result = Qnil;
|
2977
|
-
int status;
|
2978
|
-
|
2979
|
-
if (rb_block_given_p()) {
|
2980
|
-
result = gvl_PQexec(conn, "BEGIN");
|
2981
|
-
rb_pgresult = pg_new_result(result, self);
|
2982
|
-
pg_result_check(rb_pgresult);
|
2983
|
-
block_result = rb_protect(rb_yield, self, &status);
|
2984
|
-
if(status == 0) {
|
2985
|
-
result = gvl_PQexec(conn, "COMMIT");
|
2986
|
-
rb_pgresult = pg_new_result(result, self);
|
2987
|
-
pg_result_check(rb_pgresult);
|
2988
|
-
}
|
2989
|
-
else {
|
2990
|
-
/* exception occurred, ROLLBACK and re-raise */
|
2991
|
-
result = gvl_PQexec(conn, "ROLLBACK");
|
2992
|
-
rb_pgresult = pg_new_result(result, self);
|
2993
|
-
pg_result_check(rb_pgresult);
|
2994
|
-
rb_jump_tag(status);
|
2995
|
-
}
|
2996
|
-
|
2997
|
-
}
|
2998
|
-
else {
|
2999
|
-
/* no block supplied? */
|
3000
|
-
rb_raise(rb_eArgError, "Must supply block for PG::Connection#transaction");
|
3001
|
-
}
|
3002
|
-
return block_result;
|
3003
|
-
}
|
3004
|
-
|
3005
2948
|
|
3006
2949
|
/*
|
3007
2950
|
* call-seq:
|
@@ -3046,14 +2989,12 @@ pgconn_s_quote_ident(VALUE self, VALUE str_or_array)
|
|
3046
2989
|
int enc_idx;
|
3047
2990
|
|
3048
2991
|
if( rb_obj_is_kind_of(self, rb_cPGconn) ){
|
3049
|
-
enc_idx =
|
2992
|
+
enc_idx = pg_get_connection(self)->enc_idx;
|
3050
2993
|
}else{
|
3051
2994
|
enc_idx = RB_TYPE_P(str_or_array, T_STRING) ? ENCODING_GET( str_or_array ) : rb_ascii8bit_encindex();
|
3052
2995
|
}
|
3053
2996
|
pg_text_enc_identifier(NULL, str_or_array, NULL, &ret, enc_idx);
|
3054
2997
|
|
3055
|
-
OBJ_INFECT(ret, str_or_array);
|
3056
|
-
|
3057
2998
|
return ret;
|
3058
2999
|
}
|
3059
3000
|
|
@@ -3078,10 +3019,8 @@ get_result_readable(PGconn *conn)
|
|
3078
3019
|
* If +true+ is returned, +conn.is_busy+ will return +false+
|
3079
3020
|
* and +conn.get_result+ will not block.
|
3080
3021
|
*/
|
3081
|
-
|
3022
|
+
VALUE
|
3082
3023
|
pgconn_block( int argc, VALUE *argv, VALUE self ) {
|
3083
|
-
PGconn *conn = pg_get_pgconn( self );
|
3084
|
-
|
3085
3024
|
struct timeval timeout;
|
3086
3025
|
struct timeval *ptimeout = NULL;
|
3087
3026
|
VALUE timeout_in;
|
@@ -3095,7 +3034,7 @@ pgconn_block( int argc, VALUE *argv, VALUE self ) {
|
|
3095
3034
|
ptimeout = &timeout;
|
3096
3035
|
}
|
3097
3036
|
|
3098
|
-
ret = wait_socket_readable(
|
3037
|
+
ret = wait_socket_readable( self, ptimeout, get_result_readable);
|
3099
3038
|
|
3100
3039
|
if( !ret )
|
3101
3040
|
return Qfalse;
|
@@ -3106,20 +3045,14 @@ pgconn_block( int argc, VALUE *argv, VALUE self ) {
|
|
3106
3045
|
|
3107
3046
|
/*
|
3108
3047
|
* call-seq:
|
3109
|
-
* conn.
|
3110
|
-
*
|
3111
|
-
* This function retrieves all available results
|
3112
|
-
* on the current connection (from previously issued
|
3113
|
-
* asynchronous commands like +send_query()+) and
|
3114
|
-
* returns the last non-NULL result, or +nil+ if no
|
3115
|
-
* results are available.
|
3048
|
+
* conn.sync_get_last_result( ) -> PG::Result
|
3116
3049
|
*
|
3117
|
-
* This function is
|
3118
|
-
*
|
3119
|
-
*
|
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.
|
3120
3053
|
*/
|
3121
3054
|
static VALUE
|
3122
|
-
|
3055
|
+
pgconn_sync_get_last_result(VALUE self)
|
3123
3056
|
{
|
3124
3057
|
PGconn *conn = pg_get_pgconn(self);
|
3125
3058
|
VALUE rb_pgresult = Qnil;
|
@@ -3134,7 +3067,7 @@ pgconn_get_last_result(VALUE self)
|
|
3134
3067
|
prev = cur;
|
3135
3068
|
|
3136
3069
|
status = PQresultStatus(cur);
|
3137
|
-
if (status == PGRES_COPY_OUT || status == PGRES_COPY_IN)
|
3070
|
+
if (status == PGRES_COPY_OUT || status == PGRES_COPY_IN || status == PGRES_COPY_BOTH)
|
3138
3071
|
break;
|
3139
3072
|
}
|
3140
3073
|
|
@@ -3148,49 +3081,174 @@ pgconn_get_last_result(VALUE self)
|
|
3148
3081
|
|
3149
3082
|
/*
|
3150
3083
|
* call-seq:
|
3151
|
-
* conn.
|
3084
|
+
* conn.get_last_result( ) -> PG::Result
|
3152
3085
|
*
|
3153
|
-
*
|
3154
|
-
*
|
3155
|
-
*
|
3086
|
+
* This function retrieves all available results
|
3087
|
+
* on the current connection (from previously issued
|
3088
|
+
* asynchronous commands like +send_query()+) and
|
3089
|
+
* returns the last non-NULL result, or +nil+ if no
|
3090
|
+
* results are available.
|
3091
|
+
*
|
3092
|
+
* If the last result contains a bad result_status, an
|
3093
|
+
* appropriate exception is raised.
|
3094
|
+
*
|
3095
|
+
* This function is similar to #get_result
|
3096
|
+
* except that it is designed to get one and only
|
3097
|
+
* one result and that it checks the result state.
|
3156
3098
|
*/
|
3157
3099
|
static VALUE
|
3158
|
-
|
3100
|
+
pgconn_async_get_last_result(VALUE self)
|
3159
3101
|
{
|
3160
3102
|
PGconn *conn = pg_get_pgconn(self);
|
3103
|
+
VALUE rb_pgresult = Qnil;
|
3104
|
+
PGresult *cur, *prev;
|
3161
3105
|
|
3162
|
-
|
3163
|
-
|
3164
|
-
int status
|
3165
|
-
PQclear(cur);
|
3166
|
-
if (status == PGRES_COPY_IN){
|
3167
|
-
gvl_PQputCopyEnd(conn, "COPY terminated by new PQexec");
|
3168
|
-
}
|
3169
|
-
if (status == PGRES_COPY_OUT){
|
3170
|
-
char *buffer = NULL;
|
3171
|
-
while( gvl_PQgetCopyData(conn, &buffer, 0) > 0)
|
3172
|
-
PQfreemem(buffer);
|
3173
|
-
}
|
3174
|
-
}
|
3106
|
+
cur = prev = NULL;
|
3107
|
+
for(;;) {
|
3108
|
+
int status;
|
3175
3109
|
|
3176
|
-
|
3110
|
+
/* wait for input (without blocking) before reading each result */
|
3111
|
+
wait_socket_readable(self, NULL, get_result_readable);
|
3112
|
+
|
3113
|
+
cur = gvl_PQgetResult(conn);
|
3114
|
+
if (cur == NULL)
|
3115
|
+
break;
|
3116
|
+
|
3117
|
+
if (prev) PQclear(prev);
|
3118
|
+
prev = cur;
|
3119
|
+
|
3120
|
+
status = PQresultStatus(cur);
|
3121
|
+
if (status == PGRES_COPY_OUT || status == PGRES_COPY_IN || status == PGRES_COPY_BOTH)
|
3122
|
+
break;
|
3123
|
+
}
|
3124
|
+
|
3125
|
+
if (prev) {
|
3126
|
+
rb_pgresult = pg_new_result( prev, self );
|
3127
|
+
pg_result_check(rb_pgresult);
|
3128
|
+
}
|
3129
|
+
|
3130
|
+
return rb_pgresult;
|
3177
3131
|
}
|
3178
3132
|
|
3179
3133
|
/*
|
3180
3134
|
* call-seq:
|
3181
|
-
* conn.
|
3182
|
-
* conn.async_exec(sql) {|pg_result| block }
|
3135
|
+
* conn.discard_results()
|
3183
3136
|
*
|
3184
|
-
*
|
3185
|
-
*
|
3186
|
-
*
|
3137
|
+
* Silently discard any prior query result that application didn't eat.
|
3138
|
+
* This is internally used prior to Connection#exec and sibling methods.
|
3139
|
+
* It doesn't raise an exception on connection errors, but returns +false+ instead.
|
3187
3140
|
*
|
3188
|
-
*
|
3189
|
-
*
|
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
|
3190
3145
|
*
|
3191
|
-
|
3192
|
-
|
3193
|
-
|
3146
|
+
*/
|
3147
|
+
static VALUE
|
3148
|
+
pgconn_discard_results(VALUE self)
|
3149
|
+
{
|
3150
|
+
PGconn *conn = pg_get_pgconn(self);
|
3151
|
+
VALUE socket_io;
|
3152
|
+
|
3153
|
+
switch( PQtransactionStatus(conn) ) {
|
3154
|
+
case PQTRANS_IDLE:
|
3155
|
+
case PQTRANS_INTRANS:
|
3156
|
+
case PQTRANS_INERROR:
|
3157
|
+
return Qnil;
|
3158
|
+
default:;
|
3159
|
+
}
|
3160
|
+
|
3161
|
+
socket_io = pgconn_socket_io(self);
|
3162
|
+
|
3163
|
+
for(;;) {
|
3164
|
+
PGresult *cur;
|
3165
|
+
int status;
|
3166
|
+
|
3167
|
+
/* pgconn_block() raises an exception in case of errors.
|
3168
|
+
* To avoid this call pg_rb_io_wait() and PQconsumeInput() without rb_raise().
|
3169
|
+
*/
|
3170
|
+
while( gvl_PQisBusy(conn) ){
|
3171
|
+
int events;
|
3172
|
+
|
3173
|
+
switch( PQflush(conn) ) {
|
3174
|
+
case 1:
|
3175
|
+
events = RB_NUM2INT(pg_rb_io_wait(socket_io, RB_INT2NUM(PG_RUBY_IO_READABLE | PG_RUBY_IO_WRITABLE), Qnil));
|
3176
|
+
if (events & PG_RUBY_IO_READABLE){
|
3177
|
+
if ( PQconsumeInput(conn) == 0 ) goto error;
|
3178
|
+
}
|
3179
|
+
break;
|
3180
|
+
case 0:
|
3181
|
+
pg_rb_io_wait(socket_io, RB_INT2NUM(PG_RUBY_IO_READABLE), Qnil);
|
3182
|
+
if ( PQconsumeInput(conn) == 0 ) goto error;
|
3183
|
+
break;
|
3184
|
+
default:
|
3185
|
+
goto error;
|
3186
|
+
}
|
3187
|
+
}
|
3188
|
+
|
3189
|
+
cur = gvl_PQgetResult(conn);
|
3190
|
+
if( cur == NULL) break;
|
3191
|
+
|
3192
|
+
status = PQresultStatus(cur);
|
3193
|
+
PQclear(cur);
|
3194
|
+
if (status == PGRES_COPY_IN){
|
3195
|
+
while( gvl_PQputCopyEnd(conn, "COPY terminated by new query or discard_results") == 0 ){
|
3196
|
+
pgconn_async_flush(self);
|
3197
|
+
}
|
3198
|
+
}
|
3199
|
+
if (status == PGRES_COPY_OUT){
|
3200
|
+
for(;;) {
|
3201
|
+
char *buffer = NULL;
|
3202
|
+
int st = gvl_PQgetCopyData(conn, &buffer, 1);
|
3203
|
+
if( st == 0 ) {
|
3204
|
+
/* would block -> wait for readable data */
|
3205
|
+
pg_rb_io_wait(socket_io, RB_INT2NUM(PG_RUBY_IO_READABLE), Qnil);
|
3206
|
+
if ( PQconsumeInput(conn) == 0 ) goto error;
|
3207
|
+
} else if( st > 0 ) {
|
3208
|
+
/* some data retrieved -> discard it */
|
3209
|
+
PQfreemem(buffer);
|
3210
|
+
} else {
|
3211
|
+
/* no more data */
|
3212
|
+
break;
|
3213
|
+
}
|
3214
|
+
}
|
3215
|
+
}
|
3216
|
+
}
|
3217
|
+
|
3218
|
+
return Qtrue;
|
3219
|
+
|
3220
|
+
error:
|
3221
|
+
pgconn_close_socket_io(self);
|
3222
|
+
return Qfalse;
|
3223
|
+
}
|
3224
|
+
|
3225
|
+
/*
|
3226
|
+
* call-seq:
|
3227
|
+
* conn.exec(sql) -> PG::Result
|
3228
|
+
* conn.exec(sql) {|pg_result| block }
|
3229
|
+
*
|
3230
|
+
* Sends SQL query request specified by _sql_ to PostgreSQL.
|
3231
|
+
* On success, it returns a PG::Result instance with all result rows and columns.
|
3232
|
+
* On failure, it raises a PG::Error.
|
3233
|
+
*
|
3234
|
+
* For backward compatibility, if you pass more than one parameter to this method,
|
3235
|
+
* it will call #exec_params for you. New code should explicitly use #exec_params if
|
3236
|
+
* argument placeholders are used.
|
3237
|
+
*
|
3238
|
+
* If the optional code block is given, it will be passed <i>result</i> as an argument,
|
3239
|
+
* and the PG::Result object will automatically be cleared when the block terminates.
|
3240
|
+
* In this instance, <code>conn.exec</code> returns the value of the block.
|
3241
|
+
*
|
3242
|
+
* #exec is an alias for #async_exec which is almost identical to #sync_exec .
|
3243
|
+
* #sync_exec is implemented on the simpler synchronous command processing API of libpq, whereas
|
3244
|
+
* #async_exec is implemented on the asynchronous API and on ruby's IO mechanisms.
|
3245
|
+
* Only #async_exec is compatible to <tt>Fiber.scheduler</tt> based asynchronous IO processing introduced in ruby-3.0.
|
3246
|
+
* Both methods ensure that other threads can process while waiting for the server to
|
3247
|
+
* complete the request, but #sync_exec blocks all signals to be processed until the query is finished.
|
3248
|
+
* This is most notably visible by a delayed reaction to Control+C.
|
3249
|
+
* It's not recommended to use explicit sync or async variants but #exec instead, unless you have a good reason to do so.
|
3250
|
+
*
|
3251
|
+
* See also corresponding {libpq function}[https://www.postgresql.org/docs/current/libpq-exec.html#LIBPQ-PQEXEC].
|
3194
3252
|
*/
|
3195
3253
|
static VALUE
|
3196
3254
|
pgconn_async_exec(int argc, VALUE *argv, VALUE self)
|
@@ -3199,8 +3257,7 @@ pgconn_async_exec(int argc, VALUE *argv, VALUE self)
|
|
3199
3257
|
|
3200
3258
|
pgconn_discard_results( self );
|
3201
3259
|
pgconn_send_query( argc, argv, self );
|
3202
|
-
|
3203
|
-
rb_pgresult = pgconn_get_last_result( self );
|
3260
|
+
rb_pgresult = pgconn_async_get_last_result( self );
|
3204
3261
|
|
3205
3262
|
if ( rb_block_given_p() ) {
|
3206
3263
|
return rb_ensure( rb_yield, rb_pgresult, pg_result_clear, rb_pgresult );
|
@@ -3211,11 +3268,53 @@ pgconn_async_exec(int argc, VALUE *argv, VALUE self)
|
|
3211
3268
|
|
3212
3269
|
/*
|
3213
3270
|
* call-seq:
|
3214
|
-
* conn.
|
3215
|
-
* conn.
|
3271
|
+
* conn.exec_params(sql, params [, result_format [, type_map ]] ) -> nil
|
3272
|
+
* conn.exec_params(sql, params [, result_format [, type_map ]] ) {|pg_result| block }
|
3216
3273
|
*
|
3217
|
-
*
|
3218
|
-
*
|
3274
|
+
* Sends SQL query request specified by +sql+ to PostgreSQL using placeholders
|
3275
|
+
* for parameters.
|
3276
|
+
*
|
3277
|
+
* Returns a PG::Result instance on success. On failure, it raises a PG::Error.
|
3278
|
+
*
|
3279
|
+
* +params+ is an array of the bind parameters for the SQL query.
|
3280
|
+
* Each element of the +params+ array may be either:
|
3281
|
+
* a hash of the form:
|
3282
|
+
* {:value => String (value of bind parameter)
|
3283
|
+
* :type => Integer (oid of type of bind parameter)
|
3284
|
+
* :format => Integer (0 for text, 1 for binary)
|
3285
|
+
* }
|
3286
|
+
* or, it may be a String. If it is a string, that is equivalent to the hash:
|
3287
|
+
* { :value => <string value>, :type => 0, :format => 0 }
|
3288
|
+
*
|
3289
|
+
* PostgreSQL bind parameters are represented as $1, $2, $3, etc.,
|
3290
|
+
* inside the SQL query. The 0th element of the +params+ array is bound
|
3291
|
+
* to $1, the 1st element is bound to $2, etc. +nil+ is treated as +NULL+.
|
3292
|
+
*
|
3293
|
+
* If the types are not specified, they will be inferred by PostgreSQL.
|
3294
|
+
* Instead of specifying type oids, it's recommended to simply add
|
3295
|
+
* explicit casts in the query to ensure that the right type is used.
|
3296
|
+
*
|
3297
|
+
* For example: "SELECT $1::int"
|
3298
|
+
*
|
3299
|
+
* The optional +result_format+ should be 0 for text results, 1
|
3300
|
+
* for binary.
|
3301
|
+
*
|
3302
|
+
* +type_map+ can be a PG::TypeMap derivation (such as PG::BasicTypeMapForQueries).
|
3303
|
+
* This will type cast the params from various Ruby types before transmission
|
3304
|
+
* based on the encoders defined by the type map. When a type encoder is used
|
3305
|
+
* the format and oid of a given bind parameter are retrieved from the encoder
|
3306
|
+
* instead out of the hash form described above.
|
3307
|
+
*
|
3308
|
+
* If the optional code block is given, it will be passed <i>result</i> as an argument,
|
3309
|
+
* and the PG::Result object will automatically be cleared when the block terminates.
|
3310
|
+
* In this instance, <code>conn.exec</code> returns the value of the block.
|
3311
|
+
*
|
3312
|
+
* The primary advantage of #exec_params over #exec is that parameter values can be separated from the command string, thus avoiding the need for tedious and error-prone quoting and escaping.
|
3313
|
+
* Unlike #exec, #exec_params allows at most one SQL command in the given string.
|
3314
|
+
* (There can be semicolons in it, but not more than one nonempty command.)
|
3315
|
+
* This is a limitation of the underlying protocol, but has some usefulness as an extra defense against SQL-injection attacks.
|
3316
|
+
*
|
3317
|
+
* See also corresponding {libpq function}[https://www.postgresql.org/docs/current/libpq-exec.html#LIBPQ-PQEXECPARAMS].
|
3219
3318
|
*/
|
3220
3319
|
static VALUE
|
3221
3320
|
pgconn_async_exec_params(int argc, VALUE *argv, VALUE self)
|
@@ -3230,8 +3329,7 @@ pgconn_async_exec_params(int argc, VALUE *argv, VALUE self)
|
|
3230
3329
|
} else {
|
3231
3330
|
pgconn_send_query_params( argc, argv, self );
|
3232
3331
|
}
|
3233
|
-
|
3234
|
-
rb_pgresult = pgconn_get_last_result( self );
|
3332
|
+
rb_pgresult = pgconn_async_get_last_result( self );
|
3235
3333
|
|
3236
3334
|
if ( rb_block_given_p() ) {
|
3237
3335
|
return rb_ensure( rb_yield, rb_pgresult, pg_result_clear, rb_pgresult );
|
@@ -3242,10 +3340,25 @@ pgconn_async_exec_params(int argc, VALUE *argv, VALUE self)
|
|
3242
3340
|
|
3243
3341
|
/*
|
3244
3342
|
* call-seq:
|
3245
|
-
* conn.
|
3343
|
+
* conn.prepare(stmt_name, sql [, param_types ] ) -> PG::Result
|
3246
3344
|
*
|
3247
|
-
*
|
3248
|
-
*
|
3345
|
+
* Prepares statement _sql_ with name _name_ to be executed later.
|
3346
|
+
* Returns a PG::Result instance on success.
|
3347
|
+
* On failure, it raises a PG::Error.
|
3348
|
+
*
|
3349
|
+
* +param_types+ is an optional parameter to specify the Oids of the
|
3350
|
+
* types of the parameters.
|
3351
|
+
*
|
3352
|
+
* If the types are not specified, they will be inferred by PostgreSQL.
|
3353
|
+
* Instead of specifying type oids, it's recommended to simply add
|
3354
|
+
* explicit casts in the query to ensure that the right type is used.
|
3355
|
+
*
|
3356
|
+
* For example: "SELECT $1::int"
|
3357
|
+
*
|
3358
|
+
* PostgreSQL bind parameters are represented as $1, $2, $3, etc.,
|
3359
|
+
* inside the SQL query.
|
3360
|
+
*
|
3361
|
+
* See also corresponding {libpq function}[https://www.postgresql.org/docs/current/libpq-exec.html#LIBPQ-PQPREPARE].
|
3249
3362
|
*/
|
3250
3363
|
static VALUE
|
3251
3364
|
pgconn_async_prepare(int argc, VALUE *argv, VALUE self)
|
@@ -3254,8 +3367,7 @@ pgconn_async_prepare(int argc, VALUE *argv, VALUE self)
|
|
3254
3367
|
|
3255
3368
|
pgconn_discard_results( self );
|
3256
3369
|
pgconn_send_prepare( argc, argv, self );
|
3257
|
-
|
3258
|
-
rb_pgresult = pgconn_get_last_result( self );
|
3370
|
+
rb_pgresult = pgconn_async_get_last_result( self );
|
3259
3371
|
|
3260
3372
|
if ( rb_block_given_p() ) {
|
3261
3373
|
return rb_ensure( rb_yield, rb_pgresult, pg_result_clear, rb_pgresult );
|
@@ -3266,11 +3378,40 @@ pgconn_async_prepare(int argc, VALUE *argv, VALUE self)
|
|
3266
3378
|
|
3267
3379
|
/*
|
3268
3380
|
* call-seq:
|
3269
|
-
* conn.
|
3270
|
-
* conn.
|
3381
|
+
* conn.exec_prepared(statement_name [, params, result_format[, type_map]] ) -> PG::Result
|
3382
|
+
* conn.exec_prepared(statement_name [, params, result_format[, type_map]] ) {|pg_result| block }
|
3271
3383
|
*
|
3272
|
-
*
|
3273
|
-
*
|
3384
|
+
* Execute prepared named statement specified by _statement_name_.
|
3385
|
+
* Returns a PG::Result instance on success.
|
3386
|
+
* On failure, it raises a PG::Error.
|
3387
|
+
*
|
3388
|
+
* +params+ is an array of the optional bind parameters for the
|
3389
|
+
* SQL query. Each element of the +params+ array may be either:
|
3390
|
+
* a hash of the form:
|
3391
|
+
* {:value => String (value of bind parameter)
|
3392
|
+
* :format => Integer (0 for text, 1 for binary)
|
3393
|
+
* }
|
3394
|
+
* or, it may be a String. If it is a string, that is equivalent to the hash:
|
3395
|
+
* { :value => <string value>, :format => 0 }
|
3396
|
+
*
|
3397
|
+
* PostgreSQL bind parameters are represented as $1, $2, $3, etc.,
|
3398
|
+
* inside the SQL query. The 0th element of the +params+ array is bound
|
3399
|
+
* to $1, the 1st element is bound to $2, etc. +nil+ is treated as +NULL+.
|
3400
|
+
*
|
3401
|
+
* The optional +result_format+ should be 0 for text results, 1
|
3402
|
+
* for binary.
|
3403
|
+
*
|
3404
|
+
* +type_map+ can be a PG::TypeMap derivation (such as PG::BasicTypeMapForQueries).
|
3405
|
+
* This will type cast the params from various Ruby types before transmission
|
3406
|
+
* based on the encoders defined by the type map. When a type encoder is used
|
3407
|
+
* the format and oid of a given bind parameter are retrieved from the encoder
|
3408
|
+
* instead out of the hash form described above.
|
3409
|
+
*
|
3410
|
+
* If the optional code block is given, it will be passed <i>result</i> as an argument,
|
3411
|
+
* and the PG::Result object will automatically be cleared when the block terminates.
|
3412
|
+
* In this instance, <code>conn.exec_prepared</code> returns the value of the block.
|
3413
|
+
*
|
3414
|
+
* See also corresponding {libpq function}[https://www.postgresql.org/docs/current/libpq-exec.html#LIBPQ-PQEXECPREPARED].
|
3274
3415
|
*/
|
3275
3416
|
static VALUE
|
3276
3417
|
pgconn_async_exec_prepared(int argc, VALUE *argv, VALUE self)
|
@@ -3279,8 +3420,7 @@ pgconn_async_exec_prepared(int argc, VALUE *argv, VALUE self)
|
|
3279
3420
|
|
3280
3421
|
pgconn_discard_results( self );
|
3281
3422
|
pgconn_send_query_prepared( argc, argv, self );
|
3282
|
-
|
3283
|
-
rb_pgresult = pgconn_get_last_result( self );
|
3423
|
+
rb_pgresult = pgconn_async_get_last_result( self );
|
3284
3424
|
|
3285
3425
|
if ( rb_block_given_p() ) {
|
3286
3426
|
return rb_ensure( rb_yield, rb_pgresult, pg_result_clear, rb_pgresult );
|
@@ -3291,10 +3431,11 @@ pgconn_async_exec_prepared(int argc, VALUE *argv, VALUE self)
|
|
3291
3431
|
|
3292
3432
|
/*
|
3293
3433
|
* call-seq:
|
3294
|
-
* conn.
|
3434
|
+
* conn.describe_portal( portal_name ) -> PG::Result
|
3295
3435
|
*
|
3296
|
-
*
|
3297
|
-
*
|
3436
|
+
* Retrieve information about the portal _portal_name_.
|
3437
|
+
*
|
3438
|
+
* See also corresponding {libpq function}[https://www.postgresql.org/docs/current/libpq-exec.html#LIBPQ-PQDESCRIBEPORTAL].
|
3298
3439
|
*/
|
3299
3440
|
static VALUE
|
3300
3441
|
pgconn_async_describe_portal(VALUE self, VALUE portal)
|
@@ -3303,8 +3444,7 @@ pgconn_async_describe_portal(VALUE self, VALUE portal)
|
|
3303
3444
|
|
3304
3445
|
pgconn_discard_results( self );
|
3305
3446
|
pgconn_send_describe_portal( self, portal );
|
3306
|
-
|
3307
|
-
rb_pgresult = pgconn_get_last_result( self );
|
3447
|
+
rb_pgresult = pgconn_async_get_last_result( self );
|
3308
3448
|
|
3309
3449
|
if ( rb_block_given_p() ) {
|
3310
3450
|
return rb_ensure( rb_yield, rb_pgresult, pg_result_clear, rb_pgresult );
|
@@ -3315,10 +3455,11 @@ pgconn_async_describe_portal(VALUE self, VALUE portal)
|
|
3315
3455
|
|
3316
3456
|
/*
|
3317
3457
|
* call-seq:
|
3318
|
-
* conn.
|
3458
|
+
* conn.describe_prepared( statement_name ) -> PG::Result
|
3319
3459
|
*
|
3320
|
-
*
|
3321
|
-
*
|
3460
|
+
* Retrieve information about the prepared statement _statement_name_.
|
3461
|
+
*
|
3462
|
+
* See also corresponding {libpq function}[https://www.postgresql.org/docs/current/libpq-exec.html#LIBPQ-PQDESCRIBEPREPARED].
|
3322
3463
|
*/
|
3323
3464
|
static VALUE
|
3324
3465
|
pgconn_async_describe_prepared(VALUE self, VALUE stmt_name)
|
@@ -3327,8 +3468,7 @@ pgconn_async_describe_prepared(VALUE self, VALUE stmt_name)
|
|
3327
3468
|
|
3328
3469
|
pgconn_discard_results( self );
|
3329
3470
|
pgconn_send_describe_prepared( self, stmt_name );
|
3330
|
-
|
3331
|
-
rb_pgresult = pgconn_get_last_result( self );
|
3471
|
+
rb_pgresult = pgconn_async_get_last_result( self );
|
3332
3472
|
|
3333
3473
|
if ( rb_block_given_p() ) {
|
3334
3474
|
return rb_ensure( rb_yield, rb_pgresult, pg_result_clear, rb_pgresult );
|
@@ -3342,7 +3482,7 @@ pgconn_async_describe_prepared(VALUE self, VALUE stmt_name)
|
|
3342
3482
|
* call-seq:
|
3343
3483
|
* conn.ssl_in_use? -> Boolean
|
3344
3484
|
*
|
3345
|
-
* Returns +true+ if the connection uses SSL, +false+ if not.
|
3485
|
+
* Returns +true+ if the connection uses SSL/TLS, +false+ if not.
|
3346
3486
|
*
|
3347
3487
|
* Available since PostgreSQL-9.5
|
3348
3488
|
*/
|
@@ -3376,7 +3516,7 @@ pgconn_ssl_in_use(VALUE self)
|
|
3376
3516
|
* If SSL compression is in use, returns the name of the compression algorithm, or "on" if compression is used but the algorithm is not known. If compression is not in use, returns "off".
|
3377
3517
|
*
|
3378
3518
|
*
|
3379
|
-
* See also #ssl_attribute_names and
|
3519
|
+
* See also #ssl_attribute_names and the {corresponding libpq function}[https://www.postgresql.org/docs/current/libpq-status.html#LIBPQ-PQSSLATTRIBUTE].
|
3380
3520
|
*
|
3381
3521
|
* Available since PostgreSQL-9.5
|
3382
3522
|
*/
|
@@ -3416,10 +3556,134 @@ pgconn_ssl_attribute_names(VALUE self)
|
|
3416
3556
|
#endif
|
3417
3557
|
|
3418
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
|
+
|
3419
3675
|
/**************************************************************************
|
3420
3676
|
* LARGE OBJECT SUPPORT
|
3421
3677
|
**************************************************************************/
|
3422
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
|
+
|
3423
3687
|
/*
|
3424
3688
|
* call-seq:
|
3425
3689
|
* conn.lo_creat( [mode] ) -> Integer
|
@@ -3440,9 +3704,12 @@ pgconn_locreat(int argc, VALUE *argv, VALUE self)
|
|
3440
3704
|
else
|
3441
3705
|
mode = NUM2INT(nmode);
|
3442
3706
|
|
3443
|
-
|
3707
|
+
BLOCKING_BEGIN(conn)
|
3708
|
+
lo_oid = lo_creat(conn, mode);
|
3709
|
+
BLOCKING_END(conn)
|
3710
|
+
|
3444
3711
|
if (lo_oid == 0)
|
3445
|
-
|
3712
|
+
pg_raise_conn_error( rb_ePGerror, self, "lo_creat failed");
|
3446
3713
|
|
3447
3714
|
return UINT2NUM(lo_oid);
|
3448
3715
|
}
|
@@ -3463,7 +3730,7 @@ pgconn_locreate(VALUE self, VALUE in_lo_oid)
|
|
3463
3730
|
|
3464
3731
|
ret = lo_create(conn, lo_oid);
|
3465
3732
|
if (ret == InvalidOid)
|
3466
|
-
|
3733
|
+
pg_raise_conn_error( rb_ePGerror, self, "lo_create failed");
|
3467
3734
|
|
3468
3735
|
return UINT2NUM(ret);
|
3469
3736
|
}
|
@@ -3485,9 +3752,12 @@ pgconn_loimport(VALUE self, VALUE filename)
|
|
3485
3752
|
|
3486
3753
|
Check_Type(filename, T_STRING);
|
3487
3754
|
|
3488
|
-
|
3755
|
+
BLOCKING_BEGIN(conn)
|
3756
|
+
lo_oid = lo_import(conn, StringValueCStr(filename));
|
3757
|
+
BLOCKING_END(conn)
|
3758
|
+
|
3489
3759
|
if (lo_oid == 0) {
|
3490
|
-
|
3760
|
+
pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(conn));
|
3491
3761
|
}
|
3492
3762
|
return UINT2NUM(lo_oid);
|
3493
3763
|
}
|
@@ -3503,12 +3773,17 @@ pgconn_loexport(VALUE self, VALUE lo_oid, VALUE filename)
|
|
3503
3773
|
{
|
3504
3774
|
PGconn *conn = pg_get_pgconn(self);
|
3505
3775
|
Oid oid;
|
3776
|
+
int ret;
|
3506
3777
|
Check_Type(filename, T_STRING);
|
3507
3778
|
|
3508
3779
|
oid = NUM2UINT(lo_oid);
|
3509
3780
|
|
3510
|
-
|
3511
|
-
|
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));
|
3512
3787
|
}
|
3513
3788
|
return Qnil;
|
3514
3789
|
}
|
@@ -3538,8 +3813,12 @@ pgconn_loopen(int argc, VALUE *argv, VALUE self)
|
|
3538
3813
|
else
|
3539
3814
|
mode = NUM2INT(nmode);
|
3540
3815
|
|
3541
|
-
|
3542
|
-
|
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));
|
3543
3822
|
}
|
3544
3823
|
return INT2FIX(fd);
|
3545
3824
|
}
|
@@ -3561,11 +3840,15 @@ pgconn_lowrite(VALUE self, VALUE in_lo_desc, VALUE buffer)
|
|
3561
3840
|
Check_Type(buffer, T_STRING);
|
3562
3841
|
|
3563
3842
|
if( RSTRING_LEN(buffer) < 0) {
|
3564
|
-
|
3843
|
+
pg_raise_conn_error( rb_ePGerror, self, "write buffer zero string");
|
3565
3844
|
}
|
3566
|
-
|
3567
|
-
|
3568
|
-
|
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));
|
3569
3852
|
}
|
3570
3853
|
|
3571
3854
|
return INT2FIX(n);
|
@@ -3588,23 +3871,24 @@ pgconn_loread(VALUE self, VALUE in_lo_desc, VALUE in_len)
|
|
3588
3871
|
VALUE str;
|
3589
3872
|
char *buffer;
|
3590
3873
|
|
3591
|
-
|
3592
|
-
|
3593
|
-
rb_raise(rb_eNoMemError, "ALLOC failed!");
|
3874
|
+
if (len < 0)
|
3875
|
+
pg_raise_conn_error( rb_ePGerror, self, "negative length %d given", len);
|
3594
3876
|
|
3595
|
-
|
3596
|
-
|
3597
|
-
|
3877
|
+
buffer = ALLOC_N(char, len);
|
3878
|
+
|
3879
|
+
BLOCKING_BEGIN(conn)
|
3880
|
+
ret = lo_read(conn, lo_desc, buffer, len);
|
3881
|
+
BLOCKING_END(conn)
|
3598
3882
|
|
3599
|
-
if(
|
3600
|
-
|
3883
|
+
if(ret < 0)
|
3884
|
+
pg_raise_conn_error( rb_ePGerror, self, "lo_read failed");
|
3601
3885
|
|
3602
3886
|
if(ret == 0) {
|
3603
3887
|
xfree(buffer);
|
3604
3888
|
return Qnil;
|
3605
3889
|
}
|
3606
3890
|
|
3607
|
-
str =
|
3891
|
+
str = rb_str_new(buffer, ret);
|
3608
3892
|
xfree(buffer);
|
3609
3893
|
|
3610
3894
|
return str;
|
@@ -3626,8 +3910,12 @@ pgconn_lolseek(VALUE self, VALUE in_lo_desc, VALUE offset, VALUE whence)
|
|
3626
3910
|
int lo_desc = NUM2INT(in_lo_desc);
|
3627
3911
|
int ret;
|
3628
3912
|
|
3629
|
-
|
3630
|
-
|
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");
|
3631
3919
|
}
|
3632
3920
|
|
3633
3921
|
return INT2FIX(ret);
|
@@ -3646,8 +3934,12 @@ pgconn_lotell(VALUE self, VALUE in_lo_desc)
|
|
3646
3934
|
PGconn *conn = pg_get_pgconn(self);
|
3647
3935
|
int lo_desc = NUM2INT(in_lo_desc);
|
3648
3936
|
|
3649
|
-
|
3650
|
-
|
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");
|
3651
3943
|
|
3652
3944
|
return INT2FIX(position);
|
3653
3945
|
}
|
@@ -3664,9 +3956,14 @@ pgconn_lotruncate(VALUE self, VALUE in_lo_desc, VALUE in_len)
|
|
3664
3956
|
PGconn *conn = pg_get_pgconn(self);
|
3665
3957
|
int lo_desc = NUM2INT(in_lo_desc);
|
3666
3958
|
size_t len = NUM2INT(in_len);
|
3959
|
+
int ret;
|
3667
3960
|
|
3668
|
-
|
3669
|
-
|
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");
|
3670
3967
|
|
3671
3968
|
return Qnil;
|
3672
3969
|
}
|
@@ -3682,9 +3979,14 @@ pgconn_loclose(VALUE self, VALUE in_lo_desc)
|
|
3682
3979
|
{
|
3683
3980
|
PGconn *conn = pg_get_pgconn(self);
|
3684
3981
|
int lo_desc = NUM2INT(in_lo_desc);
|
3982
|
+
int ret;
|
3685
3983
|
|
3686
|
-
|
3687
|
-
|
3984
|
+
BLOCKING_BEGIN(conn)
|
3985
|
+
ret = lo_close(conn,lo_desc);
|
3986
|
+
BLOCKING_END(conn)
|
3987
|
+
|
3988
|
+
if(ret < 0)
|
3989
|
+
pg_raise_conn_error( rb_ePGerror, self, "lo_close failed");
|
3688
3990
|
|
3689
3991
|
return Qnil;
|
3690
3992
|
}
|
@@ -3700,20 +4002,28 @@ pgconn_lounlink(VALUE self, VALUE in_oid)
|
|
3700
4002
|
{
|
3701
4003
|
PGconn *conn = pg_get_pgconn(self);
|
3702
4004
|
Oid oid = NUM2UINT(in_oid);
|
4005
|
+
int ret;
|
4006
|
+
|
4007
|
+
BLOCKING_BEGIN(conn)
|
4008
|
+
ret = lo_unlink(conn,oid);
|
4009
|
+
BLOCKING_END(conn)
|
3703
4010
|
|
3704
|
-
if(
|
3705
|
-
|
4011
|
+
if(ret < 0)
|
4012
|
+
pg_raise_conn_error( rb_ePGerror, self, "lo_unlink failed");
|
3706
4013
|
|
3707
4014
|
return Qnil;
|
3708
4015
|
}
|
3709
4016
|
|
3710
4017
|
|
3711
|
-
void
|
4018
|
+
static void
|
3712
4019
|
pgconn_set_internal_encoding_index( VALUE self )
|
3713
4020
|
{
|
3714
|
-
|
3715
|
-
|
3716
|
-
|
4021
|
+
int enc_idx;
|
4022
|
+
t_pg_connection *this = pg_get_connection_safe( self );
|
4023
|
+
rb_encoding *enc = pg_conn_enc_get( this->pgconn );
|
4024
|
+
enc_idx = rb_enc_to_index(enc);
|
4025
|
+
if( enc_idx >= (1<<(PG_ENC_IDX_BITS-1)) ) rb_raise(rb_eArgError, "unsupported encoding index %d", enc_idx);
|
4026
|
+
this->enc_idx = enc_idx;
|
3717
4027
|
}
|
3718
4028
|
|
3719
4029
|
/*
|
@@ -3756,13 +4066,13 @@ static VALUE pgconn_external_encoding(VALUE self);
|
|
3756
4066
|
static VALUE
|
3757
4067
|
pgconn_internal_encoding_set(VALUE self, VALUE enc)
|
3758
4068
|
{
|
3759
|
-
|
4069
|
+
rb_check_frozen(self);
|
3760
4070
|
if (NIL_P(enc)) {
|
3761
|
-
|
4071
|
+
pgconn_sync_set_client_encoding( self, rb_usascii_str_new_cstr("SQL_ASCII") );
|
3762
4072
|
return enc;
|
3763
4073
|
}
|
3764
4074
|
else if ( TYPE(enc) == T_STRING && strcasecmp("JOHAB", StringValueCStr(enc)) == 0 ) {
|
3765
|
-
|
4075
|
+
pgconn_sync_set_client_encoding(self, rb_usascii_str_new_cstr("JOHAB"));
|
3766
4076
|
return enc;
|
3767
4077
|
}
|
3768
4078
|
else {
|
@@ -3777,11 +4087,6 @@ pgconn_internal_encoding_set(VALUE self, VALUE enc)
|
|
3777
4087
|
pgconn_set_internal_encoding_index( self );
|
3778
4088
|
return enc;
|
3779
4089
|
}
|
3780
|
-
|
3781
|
-
enc_inspect = rb_inspect(enc);
|
3782
|
-
rb_raise( rb_ePGerror, "unknown encoding: %s", StringValueCStr(enc_inspect) );
|
3783
|
-
|
3784
|
-
return Qnil;
|
3785
4090
|
}
|
3786
4091
|
|
3787
4092
|
|
@@ -3800,42 +4105,56 @@ pgconn_external_encoding(VALUE self)
|
|
3800
4105
|
rb_encoding *enc = NULL;
|
3801
4106
|
const char *pg_encname = NULL;
|
3802
4107
|
|
3803
|
-
/* Use cached value if found */
|
3804
|
-
if ( RTEST(this->external_encoding) ) return this->external_encoding;
|
3805
|
-
|
3806
4108
|
pg_encname = PQparameterStatus( this->pgconn, "server_encoding" );
|
3807
4109
|
enc = pg_get_pg_encname_as_rb_encoding( pg_encname );
|
3808
|
-
|
3809
|
-
|
3810
|
-
return this->external_encoding;
|
4110
|
+
return rb_enc_from_encoding( enc );
|
3811
4111
|
}
|
3812
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
|
+
}
|
3813
4134
|
|
3814
4135
|
static VALUE
|
3815
4136
|
pgconn_set_client_encoding_async1( VALUE args )
|
3816
4137
|
{
|
3817
4138
|
VALUE self = ((VALUE*)args)[0];
|
3818
4139
|
VALUE encname = ((VALUE*)args)[1];
|
3819
|
-
|
3820
|
-
VALUE query = rb_funcall(query_format, rb_intern("%"), 1, encname);
|
3821
|
-
|
3822
|
-
pgconn_async_exec(1, &query, self);
|
4140
|
+
pgconn_async_set_client_encoding(self, encname);
|
3823
4141
|
return 0;
|
3824
4142
|
}
|
3825
4143
|
|
3826
4144
|
|
3827
4145
|
static VALUE
|
3828
|
-
pgconn_set_client_encoding_async2( VALUE arg )
|
4146
|
+
pgconn_set_client_encoding_async2( VALUE arg, VALUE ex )
|
3829
4147
|
{
|
3830
4148
|
UNUSED(arg);
|
4149
|
+
UNUSED(ex);
|
3831
4150
|
return 1;
|
3832
4151
|
}
|
3833
4152
|
|
3834
4153
|
|
3835
4154
|
static VALUE
|
3836
|
-
pgconn_set_client_encoding_async( VALUE self,
|
4155
|
+
pgconn_set_client_encoding_async( VALUE self, VALUE encname )
|
3837
4156
|
{
|
3838
|
-
VALUE args[] = { self,
|
4157
|
+
VALUE args[] = { self, encname };
|
3839
4158
|
return rb_rescue(pgconn_set_client_encoding_async1, (VALUE)&args, pgconn_set_client_encoding_async2, Qnil);
|
3840
4159
|
}
|
3841
4160
|
|
@@ -3855,12 +4174,12 @@ pgconn_set_default_encoding( VALUE self )
|
|
3855
4174
|
rb_encoding *enc;
|
3856
4175
|
const char *encname;
|
3857
4176
|
|
4177
|
+
rb_check_frozen(self);
|
3858
4178
|
if (( enc = rb_default_internal_encoding() )) {
|
3859
4179
|
encname = pg_get_rb_encoding_as_pg_encoding( enc );
|
3860
|
-
if ( pgconn_set_client_encoding_async(self, encname) != 0 )
|
4180
|
+
if ( pgconn_set_client_encoding_async(self, rb_str_new_cstr(encname)) != 0 )
|
3861
4181
|
rb_warning( "Failed to set the default_internal encoding to %s: '%s'",
|
3862
4182
|
encname, PQerrorMessage(conn) );
|
3863
|
-
pgconn_set_internal_encoding_index( self );
|
3864
4183
|
return rb_enc_from_encoding( enc );
|
3865
4184
|
} else {
|
3866
4185
|
pgconn_set_internal_encoding_index( self );
|
@@ -3882,13 +4201,14 @@ static VALUE
|
|
3882
4201
|
pgconn_type_map_for_queries_set(VALUE self, VALUE typemap)
|
3883
4202
|
{
|
3884
4203
|
t_pg_connection *this = pg_get_connection( self );
|
4204
|
+
t_typemap *tm;
|
4205
|
+
UNUSED(tm);
|
3885
4206
|
|
3886
|
-
|
3887
|
-
|
3888
|
-
|
3889
|
-
|
3890
|
-
|
3891
|
-
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);
|
3892
4212
|
|
3893
4213
|
return typemap;
|
3894
4214
|
}
|
@@ -3922,13 +4242,12 @@ static VALUE
|
|
3922
4242
|
pgconn_type_map_for_results_set(VALUE self, VALUE typemap)
|
3923
4243
|
{
|
3924
4244
|
t_pg_connection *this = pg_get_connection( self );
|
4245
|
+
t_typemap *tm;
|
4246
|
+
UNUSED(tm);
|
3925
4247
|
|
3926
|
-
|
3927
|
-
|
3928
|
-
|
3929
|
-
}
|
3930
|
-
Check_Type(typemap, T_DATA);
|
3931
|
-
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);
|
3932
4251
|
|
3933
4252
|
return typemap;
|
3934
4253
|
}
|
@@ -3962,20 +4281,20 @@ pgconn_type_map_for_results_get(VALUE self)
|
|
3962
4281
|
*
|
3963
4282
|
*/
|
3964
4283
|
static VALUE
|
3965
|
-
pgconn_encoder_for_put_copy_data_set(VALUE self, VALUE
|
4284
|
+
pgconn_encoder_for_put_copy_data_set(VALUE self, VALUE encoder)
|
3966
4285
|
{
|
3967
4286
|
t_pg_connection *this = pg_get_connection( self );
|
3968
4287
|
|
3969
|
-
|
3970
|
-
|
3971
|
-
|
3972
|
-
|
3973
|
-
|
3974
|
-
|
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);
|
3975
4294
|
}
|
3976
|
-
this->encoder_for_put_copy_data
|
4295
|
+
RB_OBJ_WRITE(self, &this->encoder_for_put_copy_data, encoder);
|
3977
4296
|
|
3978
|
-
return
|
4297
|
+
return encoder;
|
3979
4298
|
}
|
3980
4299
|
|
3981
4300
|
/*
|
@@ -4011,20 +4330,20 @@ pgconn_encoder_for_put_copy_data_get(VALUE self)
|
|
4011
4330
|
*
|
4012
4331
|
*/
|
4013
4332
|
static VALUE
|
4014
|
-
pgconn_decoder_for_get_copy_data_set(VALUE self, VALUE
|
4333
|
+
pgconn_decoder_for_get_copy_data_set(VALUE self, VALUE decoder)
|
4015
4334
|
{
|
4016
4335
|
t_pg_connection *this = pg_get_connection( self );
|
4017
4336
|
|
4018
|
-
|
4019
|
-
|
4020
|
-
|
4021
|
-
|
4022
|
-
|
4023
|
-
|
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);
|
4024
4343
|
}
|
4025
|
-
this->decoder_for_get_copy_data
|
4344
|
+
RB_OBJ_WRITE(self, &this->decoder_for_get_copy_data, decoder);
|
4026
4345
|
|
4027
|
-
return
|
4346
|
+
return decoder;
|
4028
4347
|
}
|
4029
4348
|
|
4030
4349
|
/*
|
@@ -4049,16 +4368,55 @@ pgconn_decoder_for_get_copy_data_get(VALUE self)
|
|
4049
4368
|
|
4050
4369
|
/*
|
4051
4370
|
* call-seq:
|
4052
|
-
*
|
4371
|
+
* conn.field_name_type = Symbol
|
4372
|
+
*
|
4373
|
+
* Set default type of field names of results retrieved by this connection.
|
4374
|
+
* It can be set to one of:
|
4375
|
+
* * +:string+ to use String based field names
|
4376
|
+
* * +:symbol+ to use Symbol based field names
|
4377
|
+
*
|
4378
|
+
* The default is +:string+ .
|
4379
|
+
*
|
4380
|
+
* Settings the type of field names affects only future results.
|
4381
|
+
*
|
4382
|
+
* See further description at PG::Result#field_name_type=
|
4053
4383
|
*
|
4054
|
-
* This method is for testing only and will probably be removed in the future.
|
4055
4384
|
*/
|
4056
4385
|
static VALUE
|
4057
|
-
|
4386
|
+
pgconn_field_name_type_set(VALUE self, VALUE sym)
|
4058
4387
|
{
|
4059
4388
|
t_pg_connection *this = pg_get_connection( self );
|
4060
|
-
|
4061
|
-
|
4389
|
+
|
4390
|
+
rb_check_frozen(self);
|
4391
|
+
this->flags &= ~PG_RESULT_FIELD_NAMES_MASK;
|
4392
|
+
if( sym == sym_symbol ) this->flags |= PG_RESULT_FIELD_NAMES_SYMBOL;
|
4393
|
+
else if ( sym == sym_static_symbol ) this->flags |= PG_RESULT_FIELD_NAMES_STATIC_SYMBOL;
|
4394
|
+
else if ( sym == sym_string );
|
4395
|
+
else rb_raise(rb_eArgError, "invalid argument %+"PRIsVALUE, sym);
|
4396
|
+
|
4397
|
+
return sym;
|
4398
|
+
}
|
4399
|
+
|
4400
|
+
/*
|
4401
|
+
* call-seq:
|
4402
|
+
* conn.field_name_type -> Symbol
|
4403
|
+
*
|
4404
|
+
* Get type of field names.
|
4405
|
+
*
|
4406
|
+
* See description at #field_name_type=
|
4407
|
+
*/
|
4408
|
+
static VALUE
|
4409
|
+
pgconn_field_name_type_get(VALUE self)
|
4410
|
+
{
|
4411
|
+
t_pg_connection *this = pg_get_connection( self );
|
4412
|
+
|
4413
|
+
if( this->flags & PG_RESULT_FIELD_NAMES_SYMBOL ){
|
4414
|
+
return sym_symbol;
|
4415
|
+
} else if( this->flags & PG_RESULT_FIELD_NAMES_STATIC_SYMBOL ){
|
4416
|
+
return sym_static_symbol;
|
4417
|
+
} else {
|
4418
|
+
return sym_string;
|
4419
|
+
}
|
4062
4420
|
}
|
4063
4421
|
|
4064
4422
|
|
@@ -4066,23 +4424,25 @@ pgconn_guess_result_memsize_set(VALUE self, VALUE enable)
|
|
4066
4424
|
* Document-class: PG::Connection
|
4067
4425
|
*/
|
4068
4426
|
void
|
4069
|
-
init_pg_connection()
|
4427
|
+
init_pg_connection(void)
|
4070
4428
|
{
|
4071
4429
|
s_id_encode = rb_intern("encode");
|
4430
|
+
s_id_autoclose_set = rb_intern("autoclose=");
|
4072
4431
|
sym_type = ID2SYM(rb_intern("type"));
|
4073
4432
|
sym_format = ID2SYM(rb_intern("format"));
|
4074
4433
|
sym_value = ID2SYM(rb_intern("value"));
|
4434
|
+
sym_string = ID2SYM(rb_intern("string"));
|
4435
|
+
sym_symbol = ID2SYM(rb_intern("symbol"));
|
4436
|
+
sym_static_symbol = ID2SYM(rb_intern("static_symbol"));
|
4075
4437
|
|
4076
4438
|
rb_cPGconn = rb_define_class_under( rb_mPG, "Connection", rb_cObject );
|
4439
|
+
/* Help rdoc to known the Constants module */
|
4440
|
+
/* rb_mPGconstants = rb_define_module_under( rb_mPG, "Constants" ); */
|
4077
4441
|
rb_include_module(rb_cPGconn, rb_mPGconstants);
|
4078
4442
|
|
4079
4443
|
/****** PG::Connection CLASS METHODS ******/
|
4080
4444
|
rb_define_alloc_func( rb_cPGconn, pgconn_s_allocate );
|
4081
4445
|
|
4082
|
-
SINGLETON_ALIAS(rb_cPGconn, "connect", "new");
|
4083
|
-
SINGLETON_ALIAS(rb_cPGconn, "open", "new");
|
4084
|
-
SINGLETON_ALIAS(rb_cPGconn, "setdb", "new");
|
4085
|
-
SINGLETON_ALIAS(rb_cPGconn, "setdblogin", "new");
|
4086
4446
|
rb_define_singleton_method(rb_cPGconn, "escape_string", pgconn_s_escape, 1);
|
4087
4447
|
SINGLETON_ALIAS(rb_cPGconn, "escape", "escape_string");
|
4088
4448
|
rb_define_singleton_method(rb_cPGconn, "escape_bytea", pgconn_s_escape_bytea, 1);
|
@@ -4091,14 +4451,15 @@ init_pg_connection()
|
|
4091
4451
|
rb_define_singleton_method(rb_cPGconn, "quote_ident", pgconn_s_quote_ident, 1);
|
4092
4452
|
rb_define_singleton_method(rb_cPGconn, "connect_start", pgconn_s_connect_start, -1);
|
4093
4453
|
rb_define_singleton_method(rb_cPGconn, "conndefaults", pgconn_s_conndefaults, 0);
|
4094
|
-
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);
|
4095
4457
|
|
4096
4458
|
/****** PG::Connection INSTANCE METHODS: Connection Control ******/
|
4097
|
-
rb_define_method(rb_cPGconn, "initialize", pgconn_init, -1);
|
4098
4459
|
rb_define_method(rb_cPGconn, "connect_poll", pgconn_connect_poll, 0);
|
4099
4460
|
rb_define_method(rb_cPGconn, "finish", pgconn_finish, 0);
|
4100
4461
|
rb_define_method(rb_cPGconn, "finished?", pgconn_finished_p, 0);
|
4101
|
-
rb_define_method(rb_cPGconn, "
|
4462
|
+
rb_define_method(rb_cPGconn, "sync_reset", pgconn_sync_reset, 0);
|
4102
4463
|
rb_define_method(rb_cPGconn, "reset_start", pgconn_reset_start, 0);
|
4103
4464
|
rb_define_method(rb_cPGconn, "reset_poll", pgconn_reset_poll, 0);
|
4104
4465
|
rb_define_alias(rb_cPGconn, "close", "finish");
|
@@ -4108,11 +4469,12 @@ init_pg_connection()
|
|
4108
4469
|
rb_define_method(rb_cPGconn, "user", pgconn_user, 0);
|
4109
4470
|
rb_define_method(rb_cPGconn, "pass", pgconn_pass, 0);
|
4110
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
|
4111
4475
|
rb_define_method(rb_cPGconn, "port", pgconn_port, 0);
|
4112
4476
|
rb_define_method(rb_cPGconn, "tty", pgconn_tty, 0);
|
4113
|
-
#ifdef HAVE_PQCONNINFO
|
4114
4477
|
rb_define_method(rb_cPGconn, "conninfo", pgconn_conninfo, 0);
|
4115
|
-
#endif
|
4116
4478
|
rb_define_method(rb_cPGconn, "options", pgconn_options, 0);
|
4117
4479
|
rb_define_method(rb_cPGconn, "status", pgconn_status, 0);
|
4118
4480
|
rb_define_method(rb_cPGconn, "transaction_status", pgconn_transaction_status, 0);
|
@@ -4123,17 +4485,34 @@ init_pg_connection()
|
|
4123
4485
|
rb_define_method(rb_cPGconn, "socket", pgconn_socket, 0);
|
4124
4486
|
rb_define_method(rb_cPGconn, "socket_io", pgconn_socket_io, 0);
|
4125
4487
|
rb_define_method(rb_cPGconn, "backend_pid", pgconn_backend_pid, 0);
|
4488
|
+
rb_define_method(rb_cPGconn, "backend_key", pgconn_backend_key, 0);
|
4126
4489
|
rb_define_method(rb_cPGconn, "connection_needs_password", pgconn_connection_needs_password, 0);
|
4127
4490
|
rb_define_method(rb_cPGconn, "connection_used_password", pgconn_connection_used_password, 0);
|
4128
4491
|
/* rb_define_method(rb_cPGconn, "getssl", pgconn_getssl, 0); */
|
4129
4492
|
|
4130
4493
|
/****** PG::Connection INSTANCE METHODS: Command Execution ******/
|
4131
|
-
rb_define_method(rb_cPGconn, "sync_exec",
|
4132
|
-
rb_define_method(rb_cPGconn, "sync_exec_params",
|
4133
|
-
rb_define_method(rb_cPGconn, "sync_prepare",
|
4134
|
-
rb_define_method(rb_cPGconn, "sync_exec_prepared",
|
4135
|
-
rb_define_method(rb_cPGconn, "sync_describe_prepared",
|
4136
|
-
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);
|
4500
|
+
|
4501
|
+
rb_define_method(rb_cPGconn, "exec", pgconn_async_exec, -1);
|
4502
|
+
rb_define_method(rb_cPGconn, "exec_params", pgconn_async_exec_params, -1);
|
4503
|
+
rb_define_method(rb_cPGconn, "prepare", pgconn_async_prepare, -1);
|
4504
|
+
rb_define_method(rb_cPGconn, "exec_prepared", pgconn_async_exec_prepared, -1);
|
4505
|
+
rb_define_method(rb_cPGconn, "describe_prepared", pgconn_async_describe_prepared, 1);
|
4506
|
+
rb_define_method(rb_cPGconn, "describe_portal", pgconn_async_describe_portal, 1);
|
4507
|
+
|
4508
|
+
rb_define_alias(rb_cPGconn, "async_exec", "exec");
|
4509
|
+
rb_define_alias(rb_cPGconn, "async_query", "async_exec");
|
4510
|
+
rb_define_alias(rb_cPGconn, "async_exec_params", "exec_params");
|
4511
|
+
rb_define_alias(rb_cPGconn, "async_prepare", "prepare");
|
4512
|
+
rb_define_alias(rb_cPGconn, "async_exec_prepared", "exec_prepared");
|
4513
|
+
rb_define_alias(rb_cPGconn, "async_describe_prepared", "describe_prepared");
|
4514
|
+
rb_define_alias(rb_cPGconn, "async_describe_portal", "describe_portal");
|
4515
|
+
|
4137
4516
|
rb_define_method(rb_cPGconn, "make_empty_pgresult", pgconn_make_empty_pgresult, 1);
|
4138
4517
|
rb_define_method(rb_cPGconn, "escape_string", pgconn_s_escape, 1);
|
4139
4518
|
rb_define_alias(rb_cPGconn, "escape", "escape_string");
|
@@ -4146,42 +4525,38 @@ init_pg_connection()
|
|
4146
4525
|
/****** PG::Connection INSTANCE METHODS: Asynchronous Command Processing ******/
|
4147
4526
|
rb_define_method(rb_cPGconn, "send_query", pgconn_send_query, -1);
|
4148
4527
|
rb_define_method(rb_cPGconn, "send_query_params", pgconn_send_query_params, -1);
|
4149
|
-
rb_define_method(rb_cPGconn, "async_exec", pgconn_async_exec, -1);
|
4150
|
-
rb_define_method(rb_cPGconn, "async_exec_params", pgconn_async_exec_params, -1);
|
4151
|
-
rb_define_alias(rb_cPGconn, "async_query", "async_exec");
|
4152
4528
|
rb_define_method(rb_cPGconn, "send_prepare", pgconn_send_prepare, -1);
|
4153
|
-
rb_define_method(rb_cPGconn, "async_prepare", pgconn_async_prepare, -1);
|
4154
4529
|
rb_define_method(rb_cPGconn, "send_query_prepared", pgconn_send_query_prepared, -1);
|
4155
|
-
rb_define_method(rb_cPGconn, "async_exec_prepared", pgconn_async_exec_prepared, -1);
|
4156
4530
|
rb_define_method(rb_cPGconn, "send_describe_prepared", pgconn_send_describe_prepared, 1);
|
4157
|
-
rb_define_method(rb_cPGconn, "async_describe_prepared", pgconn_async_describe_prepared, 1);
|
4158
4531
|
rb_define_method(rb_cPGconn, "send_describe_portal", pgconn_send_describe_portal, 1);
|
4159
|
-
rb_define_method(rb_cPGconn, "
|
4160
|
-
rb_define_method(rb_cPGconn, "get_result", pgconn_get_result, 0);
|
4532
|
+
rb_define_method(rb_cPGconn, "sync_get_result", pgconn_sync_get_result, 0);
|
4161
4533
|
rb_define_method(rb_cPGconn, "consume_input", pgconn_consume_input, 0);
|
4162
4534
|
rb_define_method(rb_cPGconn, "is_busy", pgconn_is_busy, 0);
|
4163
|
-
rb_define_method(rb_cPGconn, "
|
4164
|
-
rb_define_method(rb_cPGconn, "
|
4165
|
-
|
4166
|
-
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");
|
4167
4540
|
rb_define_method(rb_cPGconn, "discard_results", pgconn_discard_results, 0);
|
4168
4541
|
|
4169
4542
|
/****** PG::Connection INSTANCE METHODS: Cancelling Queries in Progress ******/
|
4170
|
-
rb_define_method(rb_cPGconn, "
|
4543
|
+
rb_define_method(rb_cPGconn, "sync_cancel", pgconn_sync_cancel, 0);
|
4171
4544
|
|
4172
4545
|
/****** PG::Connection INSTANCE METHODS: NOTIFY ******/
|
4173
4546
|
rb_define_method(rb_cPGconn, "notifies", pgconn_notifies, 0);
|
4174
4547
|
|
4175
4548
|
/****** PG::Connection INSTANCE METHODS: COPY ******/
|
4176
|
-
rb_define_method(rb_cPGconn, "
|
4177
|
-
rb_define_method(rb_cPGconn, "
|
4178
|
-
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);
|
4179
4552
|
|
4180
4553
|
/****** PG::Connection INSTANCE METHODS: Control Functions ******/
|
4181
4554
|
rb_define_method(rb_cPGconn, "set_error_verbosity", pgconn_set_error_verbosity, 1);
|
4555
|
+
#ifdef HAVE_PQRESULTVERBOSEERRORMESSAGE
|
4556
|
+
rb_define_method(rb_cPGconn, "set_error_context_visibility", pgconn_set_error_context_visibility, 1 );
|
4557
|
+
#endif
|
4182
4558
|
rb_define_method(rb_cPGconn, "trace", pgconn_trace, 1);
|
4183
4559
|
rb_define_method(rb_cPGconn, "untrace", pgconn_untrace, 0);
|
4184
|
-
rb_define_method(rb_cPGconn, "guess_result_memsize=", pgconn_guess_result_memsize_set, 1);
|
4185
4560
|
|
4186
4561
|
/****** PG::Connection INSTANCE METHODS: Notice Processing ******/
|
4187
4562
|
rb_define_method(rb_cPGconn, "set_notice_receiver", pgconn_set_notice_receiver, 0);
|
@@ -4189,16 +4564,20 @@ init_pg_connection()
|
|
4189
4564
|
|
4190
4565
|
/****** PG::Connection INSTANCE METHODS: Other ******/
|
4191
4566
|
rb_define_method(rb_cPGconn, "get_client_encoding", pgconn_get_client_encoding, 0);
|
4192
|
-
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");
|
4193
4570
|
rb_define_alias(rb_cPGconn, "client_encoding=", "set_client_encoding");
|
4194
|
-
rb_define_method(rb_cPGconn, "transaction", pgconn_transaction, 0);
|
4195
4571
|
rb_define_method(rb_cPGconn, "block", pgconn_block, -1);
|
4572
|
+
rb_define_private_method(rb_cPGconn, "flush_data=", pgconn_flush_data_set, 1);
|
4196
4573
|
rb_define_method(rb_cPGconn, "wait_for_notify", pgconn_wait_for_notify, -1);
|
4197
4574
|
rb_define_alias(rb_cPGconn, "notifies_wait", "wait_for_notify");
|
4198
4575
|
rb_define_method(rb_cPGconn, "quote_ident", pgconn_s_quote_ident, 1);
|
4199
|
-
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");
|
4200
4579
|
#ifdef HAVE_PQENCRYPTPASSWORDCONN
|
4201
|
-
rb_define_method(rb_cPGconn, "
|
4580
|
+
rb_define_method(rb_cPGconn, "sync_encrypt_password", pgconn_sync_encrypt_password, -1);
|
4202
4581
|
#endif
|
4203
4582
|
|
4204
4583
|
#ifdef HAVE_PQSSLATTRIBUTE
|
@@ -4207,6 +4586,14 @@ init_pg_connection()
|
|
4207
4586
|
rb_define_method(rb_cPGconn, "ssl_attribute_names", pgconn_ssl_attribute_names, 0);
|
4208
4587
|
#endif
|
4209
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
|
+
|
4210
4597
|
/****** PG::Connection INSTANCE METHODS: Large Object Support ******/
|
4211
4598
|
rb_define_method(rb_cPGconn, "lo_creat", pgconn_locreat, -1);
|
4212
4599
|
rb_define_alias(rb_cPGconn, "locreat", "lo_creat");
|
@@ -4248,5 +4635,7 @@ init_pg_connection()
|
|
4248
4635
|
rb_define_method(rb_cPGconn, "encoder_for_put_copy_data", pgconn_encoder_for_put_copy_data_get, 0);
|
4249
4636
|
rb_define_method(rb_cPGconn, "decoder_for_get_copy_data=", pgconn_decoder_for_get_copy_data_set, 1);
|
4250
4637
|
rb_define_method(rb_cPGconn, "decoder_for_get_copy_data", pgconn_decoder_for_get_copy_data_get, 0);
|
4251
|
-
}
|
4252
4638
|
|
4639
|
+
rb_define_method(rb_cPGconn, "field_name_type=", pgconn_field_name_type_set, 1 );
|
4640
|
+
rb_define_method(rb_cPGconn, "field_name_type", pgconn_field_name_type_get, 0 );
|
4641
|
+
}
|