pg 1.0.0 → 1.5.4
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 +141 -0
- data/.gitignore +22 -0
- data/.hgsigs +34 -0
- data/.hgtags +41 -0
- data/.irbrc +23 -0
- data/.pryrc +23 -0
- data/.tm_properties +21 -0
- data/.travis.yml +49 -0
- data/Gemfile +14 -0
- data/History.md +884 -0
- data/Manifest.txt +8 -3
- data/README-Windows.rdoc +4 -4
- data/README.ja.md +300 -0
- data/README.md +286 -0
- data/Rakefile +38 -138
- data/Rakefile.cross +63 -63
- data/certs/ged.pem +24 -0
- data/certs/larskanis-2022.pem +26 -0
- data/certs/larskanis-2023.pem +24 -0
- data/ext/errorcodes.def +80 -0
- data/ext/errorcodes.rb +1 -1
- data/ext/errorcodes.txt +22 -2
- data/ext/extconf.rb +106 -25
- data/ext/gvl_wrappers.c +4 -0
- data/ext/gvl_wrappers.h +23 -0
- data/ext/pg.c +213 -155
- data/ext/pg.h +89 -23
- data/ext/pg_binary_decoder.c +162 -16
- data/ext/pg_binary_encoder.c +238 -13
- data/ext/pg_coder.c +159 -35
- data/ext/pg_connection.c +1557 -972
- data/ext/pg_copy_coder.c +364 -38
- data/ext/pg_errors.c +1 -1
- data/ext/pg_record_coder.c +522 -0
- data/ext/pg_result.c +708 -215
- data/ext/pg_text_decoder.c +627 -43
- data/ext/pg_text_encoder.c +206 -62
- data/ext/pg_tuple.c +572 -0
- data/ext/pg_type_map.c +45 -11
- data/ext/pg_type_map_all_strings.c +21 -7
- data/ext/pg_type_map_by_class.c +59 -27
- data/ext/pg_type_map_by_column.c +80 -37
- data/ext/pg_type_map_by_mri_type.c +49 -20
- data/ext/pg_type_map_by_oid.c +62 -29
- data/ext/pg_type_map_in_ruby.c +56 -22
- data/ext/{util.c → pg_util.c} +12 -12
- data/ext/{util.h → pg_util.h} +2 -2
- data/lib/pg/basic_type_map_based_on_result.rb +67 -0
- data/lib/pg/basic_type_map_for_queries.rb +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 +36 -13
- data/lib/pg/connection.rb +749 -70
- data/lib/pg/exceptions.rb +16 -2
- data/lib/pg/result.rb +14 -2
- 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/tuple.rb +30 -0
- data/lib/pg/type_map_by_column.rb +3 -2
- data/lib/pg/version.rb +4 -0
- data/lib/pg.rb +96 -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 +936 -0
- data/translation/po/ja.po +1036 -0
- data/translation/po4a.cfg +12 -0
- data.tar.gz.sig +0 -0
- metadata +147 -219
- metadata.gz.sig +0 -0
- data/ChangeLog +0 -6595
- data/History.rdoc +0 -422
- data/README.ja.rdoc +0 -14
- data/README.rdoc +0 -167
- data/lib/pg/basic_type_mapping.rb +0 -426
- data/lib/pg/constants.rb +0 -11
- data/lib/pg/text_decoder.rb +0 -51
- data/lib/pg/text_encoder.rb +0 -35
- data/spec/data/expected_trace.out +0 -26
- data/spec/data/random_binary_data +0 -0
- data/spec/helpers.rb +0 -348
- data/spec/pg/basic_type_mapping_spec.rb +0 -305
- data/spec/pg/connection_spec.rb +0 -1719
- data/spec/pg/result_spec.rb +0 -456
- data/spec/pg/type_map_by_class_spec.rb +0 -138
- data/spec/pg/type_map_by_column_spec.rb +0 -222
- data/spec/pg/type_map_by_mri_type_spec.rb +0 -136
- data/spec/pg/type_map_by_oid_spec.rb +0 -149
- data/spec/pg/type_map_in_ruby_spec.rb +0 -164
- data/spec/pg/type_map_spec.rb +0 -22
- data/spec/pg/type_spec.rb +0 -777
- data/spec/pg_spec.rb +0 -50
data/ext/pg_connection.c
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
/*
|
2
2
|
* pg_connection.c - PG::Connection class extension
|
3
|
-
* $Id
|
3
|
+
* $Id$
|
4
4
|
*
|
5
5
|
*/
|
6
6
|
|
@@ -12,19 +12,41 @@
|
|
12
12
|
|
13
13
|
VALUE rb_cPGconn;
|
14
14
|
static ID s_id_encode;
|
15
|
+
static ID s_id_autoclose_set;
|
15
16
|
static VALUE sym_type, sym_format, sym_value;
|
16
|
-
|
17
|
-
static PQnoticeReceiver default_notice_receiver = NULL;
|
18
|
-
static PQnoticeProcessor default_notice_processor = NULL;
|
17
|
+
static VALUE sym_symbol, sym_string, sym_static_symbol;
|
19
18
|
|
20
19
|
static VALUE pgconn_finish( VALUE );
|
21
20
|
static VALUE pgconn_set_default_encoding( VALUE self );
|
22
|
-
|
21
|
+
static VALUE pgconn_wait_for_flush( VALUE self );
|
22
|
+
static void pgconn_set_internal_encoding_index( VALUE );
|
23
|
+
static const rb_data_type_t pg_connection_type;
|
24
|
+
static VALUE pgconn_async_flush(VALUE self);
|
23
25
|
|
24
26
|
/*
|
25
27
|
* Global functions
|
26
28
|
*/
|
27
29
|
|
30
|
+
/*
|
31
|
+
* Convenience function to raise connection errors
|
32
|
+
*/
|
33
|
+
#ifdef __GNUC__
|
34
|
+
__attribute__((format(printf, 3, 4)))
|
35
|
+
#endif
|
36
|
+
static void
|
37
|
+
pg_raise_conn_error( VALUE klass, VALUE self, const char *format, ...)
|
38
|
+
{
|
39
|
+
VALUE msg, error;
|
40
|
+
va_list ap;
|
41
|
+
|
42
|
+
va_start(ap, format);
|
43
|
+
msg = rb_vsprintf(format, ap);
|
44
|
+
va_end(ap);
|
45
|
+
error = rb_exc_new_str(klass, msg);
|
46
|
+
rb_iv_set(error, "@connection", self);
|
47
|
+
rb_exc_raise(error);
|
48
|
+
}
|
49
|
+
|
28
50
|
/*
|
29
51
|
* Fetch the PG::Connection object data pointer.
|
30
52
|
*/
|
@@ -32,7 +54,7 @@ t_pg_connection *
|
|
32
54
|
pg_get_connection( VALUE self )
|
33
55
|
{
|
34
56
|
t_pg_connection *this;
|
35
|
-
|
57
|
+
TypedData_Get_Struct( self, t_pg_connection, &pg_connection_type, this);
|
36
58
|
|
37
59
|
return this;
|
38
60
|
}
|
@@ -45,10 +67,10 @@ static t_pg_connection *
|
|
45
67
|
pg_get_connection_safe( VALUE self )
|
46
68
|
{
|
47
69
|
t_pg_connection *this;
|
48
|
-
|
70
|
+
TypedData_Get_Struct( self, t_pg_connection, &pg_connection_type, this);
|
49
71
|
|
50
72
|
if ( !this->pgconn )
|
51
|
-
|
73
|
+
pg_raise_conn_error( rb_eConnectionBad, self, "connection is closed");
|
52
74
|
|
53
75
|
return this;
|
54
76
|
}
|
@@ -64,10 +86,11 @@ PGconn *
|
|
64
86
|
pg_get_pgconn( VALUE self )
|
65
87
|
{
|
66
88
|
t_pg_connection *this;
|
67
|
-
|
89
|
+
TypedData_Get_Struct( self, t_pg_connection, &pg_connection_type, this);
|
68
90
|
|
69
|
-
if ( !this->pgconn )
|
70
|
-
|
91
|
+
if ( !this->pgconn ){
|
92
|
+
pg_raise_conn_error( rb_eConnectionBad, self, "connection is closed");
|
93
|
+
}
|
71
94
|
|
72
95
|
return this->pgconn;
|
73
96
|
}
|
@@ -85,15 +108,13 @@ pgconn_close_socket_io( VALUE self )
|
|
85
108
|
|
86
109
|
if ( RTEST(socket_io) ) {
|
87
110
|
#if defined(_WIN32)
|
88
|
-
|
89
|
-
|
90
|
-
rb_raise(rb_eConnectionBad, "Could not unwrap win32 socket handle");
|
91
|
-
}
|
111
|
+
if( rb_w32_unwrap_io_handle(this->ruby_sd) )
|
112
|
+
pg_raise_conn_error( rb_eConnectionBad, self, "Could not unwrap win32 socket handle");
|
92
113
|
#endif
|
93
114
|
rb_funcall( socket_io, rb_intern("close"), 0 );
|
94
115
|
}
|
95
116
|
|
96
|
-
this->socket_io
|
117
|
+
RB_OBJ_WRITE(self, &this->socket_io, Qnil);
|
97
118
|
}
|
98
119
|
|
99
120
|
|
@@ -145,17 +166,31 @@ static const char *pg_cstr_enc(VALUE str, int enc_idx){
|
|
145
166
|
* GC Mark function
|
146
167
|
*/
|
147
168
|
static void
|
148
|
-
pgconn_gc_mark(
|
169
|
+
pgconn_gc_mark( void *_this )
|
170
|
+
{
|
171
|
+
t_pg_connection *this = (t_pg_connection *)_this;
|
172
|
+
rb_gc_mark_movable( this->socket_io );
|
173
|
+
rb_gc_mark_movable( this->notice_receiver );
|
174
|
+
rb_gc_mark_movable( this->notice_processor );
|
175
|
+
rb_gc_mark_movable( this->type_map_for_queries );
|
176
|
+
rb_gc_mark_movable( this->type_map_for_results );
|
177
|
+
rb_gc_mark_movable( this->trace_stream );
|
178
|
+
rb_gc_mark_movable( this->encoder_for_put_copy_data );
|
179
|
+
rb_gc_mark_movable( this->decoder_for_get_copy_data );
|
180
|
+
}
|
181
|
+
|
182
|
+
static void
|
183
|
+
pgconn_gc_compact( void *_this )
|
149
184
|
{
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
185
|
+
t_pg_connection *this = (t_pg_connection *)_this;
|
186
|
+
pg_gc_location( this->socket_io );
|
187
|
+
pg_gc_location( this->notice_receiver );
|
188
|
+
pg_gc_location( this->notice_processor );
|
189
|
+
pg_gc_location( this->type_map_for_queries );
|
190
|
+
pg_gc_location( this->type_map_for_results );
|
191
|
+
pg_gc_location( this->trace_stream );
|
192
|
+
pg_gc_location( this->encoder_for_put_copy_data );
|
193
|
+
pg_gc_location( this->decoder_for_get_copy_data );
|
159
194
|
}
|
160
195
|
|
161
196
|
|
@@ -163,14 +198,45 @@ pgconn_gc_mark( t_pg_connection *this )
|
|
163
198
|
* GC Free function
|
164
199
|
*/
|
165
200
|
static void
|
166
|
-
pgconn_gc_free(
|
201
|
+
pgconn_gc_free( void *_this )
|
167
202
|
{
|
203
|
+
t_pg_connection *this = (t_pg_connection *)_this;
|
204
|
+
#if defined(_WIN32)
|
205
|
+
if ( RTEST(this->socket_io) ) {
|
206
|
+
if( rb_w32_unwrap_io_handle(this->ruby_sd) ){
|
207
|
+
rb_warn("pg: Could not unwrap win32 socket handle by garbage collector");
|
208
|
+
}
|
209
|
+
}
|
210
|
+
#endif
|
168
211
|
if (this->pgconn != NULL)
|
169
212
|
PQfinish( this->pgconn );
|
170
213
|
|
171
214
|
xfree(this);
|
172
215
|
}
|
173
216
|
|
217
|
+
/*
|
218
|
+
* Object Size function
|
219
|
+
*/
|
220
|
+
static size_t
|
221
|
+
pgconn_memsize( const void *_this )
|
222
|
+
{
|
223
|
+
const t_pg_connection *this = (const t_pg_connection *)_this;
|
224
|
+
return sizeof(*this);
|
225
|
+
}
|
226
|
+
|
227
|
+
static const rb_data_type_t pg_connection_type = {
|
228
|
+
"PG::Connection",
|
229
|
+
{
|
230
|
+
pgconn_gc_mark,
|
231
|
+
pgconn_gc_free,
|
232
|
+
pgconn_memsize,
|
233
|
+
pg_compact_callback(pgconn_gc_compact),
|
234
|
+
},
|
235
|
+
0,
|
236
|
+
0,
|
237
|
+
RUBY_TYPED_WB_PROTECTED,
|
238
|
+
};
|
239
|
+
|
174
240
|
|
175
241
|
/**************************************************************************
|
176
242
|
* Class Methods
|
@@ -186,99 +252,38 @@ static VALUE
|
|
186
252
|
pgconn_s_allocate( VALUE klass )
|
187
253
|
{
|
188
254
|
t_pg_connection *this;
|
189
|
-
VALUE self =
|
255
|
+
VALUE self = TypedData_Make_Struct( klass, t_pg_connection, &pg_connection_type, this );
|
190
256
|
|
191
257
|
this->pgconn = NULL;
|
192
|
-
this->socket_io
|
193
|
-
this->notice_receiver
|
194
|
-
this->notice_processor
|
195
|
-
this->type_map_for_queries
|
196
|
-
this->type_map_for_results
|
197
|
-
this->encoder_for_put_copy_data
|
198
|
-
this->decoder_for_get_copy_data
|
199
|
-
this->trace_stream
|
200
|
-
|
258
|
+
RB_OBJ_WRITE(self, &this->socket_io, Qnil);
|
259
|
+
RB_OBJ_WRITE(self, &this->notice_receiver, Qnil);
|
260
|
+
RB_OBJ_WRITE(self, &this->notice_processor, Qnil);
|
261
|
+
RB_OBJ_WRITE(self, &this->type_map_for_queries, pg_typemap_all_strings);
|
262
|
+
RB_OBJ_WRITE(self, &this->type_map_for_results, pg_typemap_all_strings);
|
263
|
+
RB_OBJ_WRITE(self, &this->encoder_for_put_copy_data, Qnil);
|
264
|
+
RB_OBJ_WRITE(self, &this->decoder_for_get_copy_data, Qnil);
|
265
|
+
RB_OBJ_WRITE(self, &this->trace_stream, Qnil);
|
266
|
+
rb_ivar_set(self, rb_intern("@calls_to_put_copy_data"), INT2FIX(0));
|
201
267
|
|
202
268
|
return self;
|
203
269
|
}
|
204
270
|
|
205
|
-
|
206
|
-
/*
|
207
|
-
* Document-method: new
|
208
|
-
*
|
209
|
-
* call-seq:
|
210
|
-
* PG::Connection.new -> conn
|
211
|
-
* PG::Connection.new(connection_hash) -> conn
|
212
|
-
* PG::Connection.new(connection_string) -> conn
|
213
|
-
* PG::Connection.new(host, port, options, tty, dbname, user, password) -> conn
|
214
|
-
*
|
215
|
-
* Create a connection to the specified server.
|
216
|
-
*
|
217
|
-
* [+host+]
|
218
|
-
* server hostname
|
219
|
-
* [+hostaddr+]
|
220
|
-
* server address (avoids hostname lookup, overrides +host+)
|
221
|
-
* [+port+]
|
222
|
-
* server port number
|
223
|
-
* [+dbname+]
|
224
|
-
* connecting database name
|
225
|
-
* [+user+]
|
226
|
-
* login user name
|
227
|
-
* [+password+]
|
228
|
-
* login password
|
229
|
-
* [+connect_timeout+]
|
230
|
-
* maximum time to wait for connection to succeed
|
231
|
-
* [+options+]
|
232
|
-
* backend options
|
233
|
-
* [+tty+]
|
234
|
-
* (ignored in newer versions of PostgreSQL)
|
235
|
-
* [+sslmode+]
|
236
|
-
* (disable|allow|prefer|require)
|
237
|
-
* [+krbsrvname+]
|
238
|
-
* kerberos service name
|
239
|
-
* [+gsslib+]
|
240
|
-
* GSS library to use for GSSAPI authentication
|
241
|
-
* [+service+]
|
242
|
-
* service name to use for additional parameters
|
243
|
-
*
|
244
|
-
* Examples:
|
245
|
-
*
|
246
|
-
* # Connect using all defaults
|
247
|
-
* PG::Connection.new
|
248
|
-
*
|
249
|
-
* # As a Hash
|
250
|
-
* PG::Connection.new( :dbname => 'test', :port => 5432 )
|
251
|
-
*
|
252
|
-
* # As a String
|
253
|
-
* PG::Connection.new( "dbname=test port=5432" )
|
254
|
-
*
|
255
|
-
* # As an Array
|
256
|
-
* PG::Connection.new( nil, 5432, nil, nil, 'test', nil, nil )
|
257
|
-
*
|
258
|
-
* If the Ruby default internal encoding is set (i.e., Encoding.default_internal != nil), the
|
259
|
-
* connection will have its +client_encoding+ set accordingly.
|
260
|
-
*
|
261
|
-
* Raises a PG::Error if the connection fails.
|
262
|
-
*/
|
263
271
|
static VALUE
|
264
|
-
|
272
|
+
pgconn_s_sync_connect(int argc, VALUE *argv, VALUE klass)
|
265
273
|
{
|
266
274
|
t_pg_connection *this;
|
267
275
|
VALUE conninfo;
|
268
|
-
VALUE
|
276
|
+
VALUE self = pgconn_s_allocate( klass );
|
269
277
|
|
270
278
|
this = pg_get_connection( self );
|
271
279
|
conninfo = rb_funcall2( rb_cPGconn, rb_intern("parse_connect_args"), argc, argv );
|
272
280
|
this->pgconn = gvl_PQconnectdb(StringValueCStr(conninfo));
|
273
281
|
|
274
282
|
if(this->pgconn == NULL)
|
275
|
-
rb_raise(rb_ePGerror, "PQconnectdb() unable to allocate structure");
|
283
|
+
rb_raise(rb_ePGerror, "PQconnectdb() unable to allocate PGconn structure");
|
276
284
|
|
277
|
-
if (PQstatus(this->pgconn) == CONNECTION_BAD)
|
278
|
-
|
279
|
-
rb_iv_set(error, "@connection", self);
|
280
|
-
rb_exc_raise(error);
|
281
|
-
}
|
285
|
+
if (PQstatus(this->pgconn) == CONNECTION_BAD)
|
286
|
+
pg_raise_conn_error( rb_eConnectionBad, self, "%s", PQerrorMessage(this->pgconn));
|
282
287
|
|
283
288
|
pgconn_set_default_encoding( self );
|
284
289
|
|
@@ -294,14 +299,16 @@ pgconn_init(int argc, VALUE *argv, VALUE self)
|
|
294
299
|
* PG::Connection.connect_start(connection_string) -> conn
|
295
300
|
* PG::Connection.connect_start(host, port, options, tty, dbname, login, password) -> conn
|
296
301
|
*
|
297
|
-
* This is an asynchronous version of PG::Connection.
|
302
|
+
* This is an asynchronous version of PG::Connection.new.
|
298
303
|
*
|
299
304
|
* Use #connect_poll to poll the status of the connection.
|
300
305
|
*
|
301
306
|
* NOTE: this does *not* set the connection's +client_encoding+ for you if
|
302
|
-
* Encoding.default_internal is set. To set it after the connection is established,
|
307
|
+
* +Encoding.default_internal+ is set. To set it after the connection is established,
|
303
308
|
* call #internal_encoding=. You can also set it automatically by setting
|
304
|
-
* 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].
|
305
312
|
*
|
306
313
|
*/
|
307
314
|
static VALUE
|
@@ -309,7 +316,6 @@ pgconn_s_connect_start( int argc, VALUE *argv, VALUE klass )
|
|
309
316
|
{
|
310
317
|
VALUE rb_conn;
|
311
318
|
VALUE conninfo;
|
312
|
-
VALUE error;
|
313
319
|
t_pg_connection *this;
|
314
320
|
|
315
321
|
/*
|
@@ -322,13 +328,10 @@ pgconn_s_connect_start( int argc, VALUE *argv, VALUE klass )
|
|
322
328
|
this->pgconn = gvl_PQconnectStart( StringValueCStr(conninfo) );
|
323
329
|
|
324
330
|
if( this->pgconn == NULL )
|
325
|
-
rb_raise(rb_ePGerror, "PQconnectStart() unable to allocate structure");
|
331
|
+
rb_raise(rb_ePGerror, "PQconnectStart() unable to allocate PGconn structure");
|
326
332
|
|
327
|
-
if ( PQstatus(this->pgconn) == CONNECTION_BAD )
|
328
|
-
|
329
|
-
rb_iv_set(error, "@connection", rb_conn);
|
330
|
-
rb_exc_raise(error);
|
331
|
-
}
|
333
|
+
if ( PQstatus(this->pgconn) == CONNECTION_BAD )
|
334
|
+
pg_raise_conn_error( rb_eConnectionBad, rb_conn, "%s", PQerrorMessage(this->pgconn));
|
332
335
|
|
333
336
|
if ( rb_block_given_p() ) {
|
334
337
|
return rb_ensure( rb_yield, rb_conn, pgconn_finish, rb_conn );
|
@@ -336,34 +339,14 @@ pgconn_s_connect_start( int argc, VALUE *argv, VALUE klass )
|
|
336
339
|
return rb_conn;
|
337
340
|
}
|
338
341
|
|
339
|
-
/*
|
340
|
-
* call-seq:
|
341
|
-
* PG::Connection.ping(connection_hash) -> Integer
|
342
|
-
* PG::Connection.ping(connection_string) -> Integer
|
343
|
-
* PG::Connection.ping(host, port, options, tty, dbname, login, password) -> Integer
|
344
|
-
*
|
345
|
-
* Check server status.
|
346
|
-
*
|
347
|
-
* Returns one of:
|
348
|
-
* [+PQPING_OK+]
|
349
|
-
* server is accepting connections
|
350
|
-
* [+PQPING_REJECT+]
|
351
|
-
* server is alive but rejecting connections
|
352
|
-
* [+PQPING_NO_RESPONSE+]
|
353
|
-
* could not establish connection
|
354
|
-
* [+PQPING_NO_ATTEMPT+]
|
355
|
-
* connection not attempted (bad params)
|
356
|
-
*
|
357
|
-
* Available since PostgreSQL-9.1
|
358
|
-
*/
|
359
342
|
static VALUE
|
360
|
-
|
343
|
+
pgconn_s_sync_ping( int argc, VALUE *argv, VALUE klass )
|
361
344
|
{
|
362
345
|
PGPing ping;
|
363
346
|
VALUE conninfo;
|
364
347
|
|
365
348
|
conninfo = rb_funcall2( klass, rb_intern("parse_connect_args"), argc, argv );
|
366
|
-
ping =
|
349
|
+
ping = gvl_PQping( StringValueCStr(conninfo) );
|
367
350
|
|
368
351
|
return INT2FIX((int)ping);
|
369
352
|
}
|
@@ -404,31 +387,40 @@ pgconn_s_conndefaults(VALUE self)
|
|
404
387
|
return array;
|
405
388
|
}
|
406
389
|
|
407
|
-
|
408
|
-
#ifdef HAVE_PQENCRYPTPASSWORDCONN
|
409
390
|
/*
|
410
|
-
*
|
411
|
-
* conn.encrypt_password( password, username, algorithm=nil ) -> String
|
412
|
-
*
|
413
|
-
* This function is intended to be used by client applications that wish to send commands like <tt>ALTER USER joe PASSWORD 'pwd'</tt>.
|
414
|
-
* It is good practice not to send the original cleartext password in such a command, because it might be exposed in command logs, activity displays, and so on.
|
415
|
-
* Instead, use this function to convert the password to encrypted form before it is sent.
|
416
|
-
*
|
417
|
-
* The +password+ and +username+ arguments are the cleartext password, and the SQL name of the user it is for.
|
418
|
-
* +algorithm+ specifies the encryption algorithm to use to encrypt the password.
|
419
|
-
* Currently supported algorithms are +md5+ and +scram-sha-256+ (+on+ and +off+ are also accepted as aliases for +md5+, for compatibility with older server versions).
|
420
|
-
* Note that support for +scram-sha-256+ was introduced in PostgreSQL version 10, and will not work correctly with older server versions.
|
421
|
-
* If algorithm is omitted or +nil+, this function will query the server for the current value of the +password_encryption+ setting.
|
422
|
-
* That can block, and will fail if the current transaction is aborted, or if the connection is busy executing another query.
|
423
|
-
* If you wish to use the default algorithm for the server but want to avoid blocking, query +password_encryption+ yourself before calling #encrypt_password, and pass that value as the algorithm.
|
391
|
+
* Document-method: PG::Connection.conninfo_parse
|
424
392
|
*
|
425
|
-
*
|
426
|
-
*
|
393
|
+
* call-seq:
|
394
|
+
* PG::Connection.conninfo_parse(conninfo_string) -> Array
|
427
395
|
*
|
428
|
-
*
|
396
|
+
* Returns parsed connection options from the provided connection string as an array of hashes.
|
397
|
+
* Each hash has the same keys as PG::Connection.conndefaults() .
|
398
|
+
* The values from the +conninfo_string+ are stored in the +:val+ key.
|
429
399
|
*/
|
430
400
|
static VALUE
|
431
|
-
|
401
|
+
pgconn_s_conninfo_parse(VALUE self, VALUE conninfo)
|
402
|
+
{
|
403
|
+
VALUE array;
|
404
|
+
char *errmsg = NULL;
|
405
|
+
PQconninfoOption *options = PQconninfoParse(StringValueCStr(conninfo), &errmsg);
|
406
|
+
if(errmsg){
|
407
|
+
VALUE error = rb_str_new_cstr(errmsg);
|
408
|
+
PQfreemem(errmsg);
|
409
|
+
rb_raise(rb_ePGerror, "%"PRIsVALUE, error);
|
410
|
+
}
|
411
|
+
array = pgconn_make_conninfo_array( options );
|
412
|
+
|
413
|
+
PQconninfoFree(options);
|
414
|
+
|
415
|
+
UNUSED( self );
|
416
|
+
|
417
|
+
return array;
|
418
|
+
}
|
419
|
+
|
420
|
+
|
421
|
+
#ifdef HAVE_PQENCRYPTPASSWORDCONN
|
422
|
+
static VALUE
|
423
|
+
pgconn_sync_encrypt_password(int argc, VALUE *argv, VALUE self)
|
432
424
|
{
|
433
425
|
char *encrypted = NULL;
|
434
426
|
VALUE rval = Qnil;
|
@@ -444,12 +436,8 @@ pgconn_encrypt_password(int argc, VALUE *argv, VALUE self)
|
|
444
436
|
if ( encrypted ) {
|
445
437
|
rval = rb_str_new2( encrypted );
|
446
438
|
PQfreemem( encrypted );
|
447
|
-
|
448
|
-
OBJ_INFECT( rval, password );
|
449
|
-
OBJ_INFECT( rval, username );
|
450
|
-
OBJ_INFECT( rval, algorithm );
|
451
439
|
} else {
|
452
|
-
|
440
|
+
pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(conn));
|
453
441
|
}
|
454
442
|
|
455
443
|
return rval;
|
@@ -480,9 +468,6 @@ pgconn_s_encrypt_password(VALUE self, VALUE password, VALUE username)
|
|
480
468
|
rval = rb_str_new2( encrypted );
|
481
469
|
PQfreemem( encrypted );
|
482
470
|
|
483
|
-
OBJ_INFECT( rval, password );
|
484
|
-
OBJ_INFECT( rval, username );
|
485
|
-
|
486
471
|
return rval;
|
487
472
|
}
|
488
473
|
|
@@ -506,17 +491,18 @@ pgconn_s_encrypt_password(VALUE self, VALUE password, VALUE username)
|
|
506
491
|
* the asynchronous connection is ready
|
507
492
|
*
|
508
493
|
* Example:
|
509
|
-
*
|
510
|
-
*
|
494
|
+
* require "io/wait"
|
495
|
+
*
|
496
|
+
* conn = PG::Connection.connect_start(dbname: 'mydatabase')
|
511
497
|
* status = conn.connect_poll
|
512
498
|
* while(status != PG::PGRES_POLLING_OK) do
|
513
499
|
* # do some work while waiting for the connection to complete
|
514
500
|
* if(status == PG::PGRES_POLLING_READING)
|
515
|
-
*
|
501
|
+
* unless conn.socket_io.wait_readable(10.0)
|
516
502
|
* raise "Asynchronous connection timed out!"
|
517
503
|
* end
|
518
504
|
* elsif(status == PG::PGRES_POLLING_WRITING)
|
519
|
-
*
|
505
|
+
* unless conn.socket_io.wait_writable(10.0)
|
520
506
|
* raise "Asynchronous connection timed out!"
|
521
507
|
* end
|
522
508
|
* end
|
@@ -530,6 +516,9 @@ pgconn_connect_poll(VALUE self)
|
|
530
516
|
{
|
531
517
|
PostgresPollingStatusType status;
|
532
518
|
status = gvl_PQconnectPoll(pg_get_pgconn(self));
|
519
|
+
|
520
|
+
pgconn_close_socket_io(self);
|
521
|
+
|
533
522
|
return INT2FIX((int)status);
|
534
523
|
}
|
535
524
|
|
@@ -566,15 +555,8 @@ pgconn_finished_p( VALUE self )
|
|
566
555
|
}
|
567
556
|
|
568
557
|
|
569
|
-
/*
|
570
|
-
* call-seq:
|
571
|
-
* conn.reset()
|
572
|
-
*
|
573
|
-
* Resets the backend connection. This method closes the
|
574
|
-
* backend connection and tries to re-connect.
|
575
|
-
*/
|
576
558
|
static VALUE
|
577
|
-
|
559
|
+
pgconn_sync_reset( VALUE self )
|
578
560
|
{
|
579
561
|
pgconn_close_socket_io( self );
|
580
562
|
gvl_PQreset( pg_get_pgconn(self) );
|
@@ -596,7 +578,7 @@ pgconn_reset_start(VALUE self)
|
|
596
578
|
{
|
597
579
|
pgconn_close_socket_io( self );
|
598
580
|
if(gvl_PQresetStart(pg_get_pgconn(self)) == 0)
|
599
|
-
|
581
|
+
pg_raise_conn_error( rb_eUnableToSend, self, "reset has failed");
|
600
582
|
return Qnil;
|
601
583
|
}
|
602
584
|
|
@@ -613,6 +595,9 @@ pgconn_reset_poll(VALUE self)
|
|
613
595
|
{
|
614
596
|
PostgresPollingStatusType status;
|
615
597
|
status = gvl_PQresetPoll(pg_get_pgconn(self));
|
598
|
+
|
599
|
+
pgconn_close_socket_io(self);
|
600
|
+
|
616
601
|
return INT2FIX((int)status);
|
617
602
|
}
|
618
603
|
|
@@ -628,7 +613,7 @@ pgconn_db(VALUE self)
|
|
628
613
|
{
|
629
614
|
char *db = PQdb(pg_get_pgconn(self));
|
630
615
|
if (!db) return Qnil;
|
631
|
-
return
|
616
|
+
return rb_str_new2(db);
|
632
617
|
}
|
633
618
|
|
634
619
|
/*
|
@@ -642,7 +627,7 @@ pgconn_user(VALUE self)
|
|
642
627
|
{
|
643
628
|
char *user = PQuser(pg_get_pgconn(self));
|
644
629
|
if (!user) return Qnil;
|
645
|
-
return
|
630
|
+
return rb_str_new2(user);
|
646
631
|
}
|
647
632
|
|
648
633
|
/*
|
@@ -656,22 +641,53 @@ pgconn_pass(VALUE self)
|
|
656
641
|
{
|
657
642
|
char *user = PQpass(pg_get_pgconn(self));
|
658
643
|
if (!user) return Qnil;
|
659
|
-
return
|
644
|
+
return rb_str_new2(user);
|
660
645
|
}
|
661
646
|
|
662
647
|
/*
|
663
648
|
* call-seq:
|
664
649
|
* conn.host()
|
665
650
|
*
|
666
|
-
* 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 .
|
667
663
|
*/
|
668
664
|
static VALUE
|
669
665
|
pgconn_host(VALUE self)
|
670
666
|
{
|
671
667
|
char *host = PQhost(pg_get_pgconn(self));
|
672
668
|
if (!host) return Qnil;
|
673
|
-
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);
|
674
689
|
}
|
690
|
+
#endif
|
675
691
|
|
676
692
|
/*
|
677
693
|
* call-seq:
|
@@ -683,21 +699,22 @@ static VALUE
|
|
683
699
|
pgconn_port(VALUE self)
|
684
700
|
{
|
685
701
|
char* port = PQport(pg_get_pgconn(self));
|
686
|
-
|
702
|
+
if (!port || port[0] == '\0')
|
703
|
+
return INT2NUM(DEF_PGPORT);
|
704
|
+
else
|
705
|
+
return INT2NUM(atoi(port));
|
687
706
|
}
|
688
707
|
|
689
708
|
/*
|
690
709
|
* call-seq:
|
691
710
|
* conn.tty()
|
692
711
|
*
|
693
|
-
*
|
712
|
+
* Obsolete function.
|
694
713
|
*/
|
695
714
|
static VALUE
|
696
715
|
pgconn_tty(VALUE self)
|
697
716
|
{
|
698
|
-
|
699
|
-
if (!tty) return Qnil;
|
700
|
-
return rb_tainted_str_new2(tty);
|
717
|
+
return rb_str_new2("");
|
701
718
|
}
|
702
719
|
|
703
720
|
/*
|
@@ -711,11 +728,10 @@ pgconn_options(VALUE self)
|
|
711
728
|
{
|
712
729
|
char *options = PQoptions(pg_get_pgconn(self));
|
713
730
|
if (!options) return Qnil;
|
714
|
-
return
|
731
|
+
return rb_str_new2(options);
|
715
732
|
}
|
716
733
|
|
717
734
|
|
718
|
-
#ifdef HAVE_PQCONNINFO
|
719
735
|
/*
|
720
736
|
* call-seq:
|
721
737
|
* conn.conninfo -> hash
|
@@ -735,14 +751,24 @@ pgconn_conninfo( VALUE self )
|
|
735
751
|
|
736
752
|
return array;
|
737
753
|
}
|
738
|
-
#endif
|
739
754
|
|
740
755
|
|
741
756
|
/*
|
742
757
|
* call-seq:
|
743
758
|
* conn.status()
|
744
759
|
*
|
745
|
-
* 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
|
746
772
|
*/
|
747
773
|
static VALUE
|
748
774
|
pgconn_status(VALUE self)
|
@@ -792,7 +818,7 @@ pgconn_parameter_status(VALUE self, VALUE param_name)
|
|
792
818
|
if(ret == NULL)
|
793
819
|
return Qnil;
|
794
820
|
else
|
795
|
-
return
|
821
|
+
return rb_str_new2(ret);
|
796
822
|
}
|
797
823
|
|
798
824
|
/*
|
@@ -830,14 +856,17 @@ pgconn_server_version(VALUE self)
|
|
830
856
|
* call-seq:
|
831
857
|
* conn.error_message -> String
|
832
858
|
*
|
833
|
-
* 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.
|
834
863
|
*/
|
835
864
|
static VALUE
|
836
865
|
pgconn_error_message(VALUE self)
|
837
866
|
{
|
838
867
|
char *error = PQerrorMessage(pg_get_pgconn(self));
|
839
868
|
if (!error) return Qnil;
|
840
|
-
return
|
869
|
+
return rb_str_new2(error);
|
841
870
|
}
|
842
871
|
|
843
872
|
/*
|
@@ -861,8 +890,11 @@ static VALUE
|
|
861
890
|
pgconn_socket(VALUE self)
|
862
891
|
{
|
863
892
|
int sd;
|
893
|
+
pg_deprecated(4, ("conn.socket is deprecated and should be replaced by conn.socket_io"));
|
894
|
+
|
864
895
|
if( (sd = PQsocket(pg_get_pgconn(self))) < 0)
|
865
|
-
|
896
|
+
pg_raise_conn_error( rb_eConnectionBad, self, "PQsocket() can't get socket descriptor");
|
897
|
+
|
866
898
|
return INT2NUM(sd);
|
867
899
|
}
|
868
900
|
|
@@ -870,41 +902,47 @@ pgconn_socket(VALUE self)
|
|
870
902
|
* call-seq:
|
871
903
|
* conn.socket_io() -> IO
|
872
904
|
*
|
873
|
-
* Fetch
|
874
|
-
* This object can be used for IO.select to wait for events while running
|
875
|
-
*
|
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>.
|
876
908
|
*
|
877
|
-
*
|
878
|
-
*
|
879
|
-
*
|
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.
|
880
914
|
*/
|
881
915
|
static VALUE
|
882
916
|
pgconn_socket_io(VALUE self)
|
883
917
|
{
|
884
918
|
int sd;
|
885
919
|
int ruby_sd;
|
886
|
-
ID id_autoclose = rb_intern("autoclose=");
|
887
920
|
t_pg_connection *this = pg_get_connection_safe( self );
|
921
|
+
VALUE cSocket;
|
888
922
|
VALUE socket_io = this->socket_io;
|
889
923
|
|
890
924
|
if ( !RTEST(socket_io) ) {
|
891
|
-
if( (sd = PQsocket(this->pgconn)) < 0)
|
892
|
-
|
925
|
+
if( (sd = PQsocket(this->pgconn)) < 0){
|
926
|
+
pg_raise_conn_error( rb_eConnectionBad, self, "PQsocket() can't get socket descriptor");
|
927
|
+
}
|
893
928
|
|
894
929
|
#ifdef _WIN32
|
895
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
|
+
|
934
|
+
this->ruby_sd = ruby_sd;
|
896
935
|
#else
|
897
936
|
ruby_sd = sd;
|
898
937
|
#endif
|
899
938
|
|
900
|
-
|
939
|
+
cSocket = rb_const_get(rb_cObject, rb_intern("BasicSocket"));
|
940
|
+
socket_io = rb_funcall( cSocket, rb_intern("for_fd"), 1, INT2NUM(ruby_sd));
|
901
941
|
|
902
|
-
/* Disable autoclose feature
|
903
|
-
|
904
|
-
rb_funcall( socket_io, id_autoclose, 1, Qfalse );
|
905
|
-
}
|
942
|
+
/* Disable autoclose feature */
|
943
|
+
rb_funcall( socket_io, s_id_autoclose_set, 1, Qfalse );
|
906
944
|
|
907
|
-
this->socket_io
|
945
|
+
RB_OBJ_WRITE(self, &this->socket_io, socket_io);
|
908
946
|
}
|
909
947
|
|
910
948
|
return socket_io;
|
@@ -924,6 +962,51 @@ pgconn_backend_pid(VALUE self)
|
|
924
962
|
return INT2NUM(PQbackendPID(pg_get_pgconn(self)));
|
925
963
|
}
|
926
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
|
+
|
927
1010
|
/*
|
928
1011
|
* call-seq:
|
929
1012
|
* conn.connection_needs_password() -> Boolean
|
@@ -954,44 +1037,35 @@ pgconn_connection_used_password(VALUE self)
|
|
954
1037
|
/* :TODO: get_ssl */
|
955
1038
|
|
956
1039
|
|
957
|
-
static VALUE
|
1040
|
+
static VALUE pgconn_sync_exec_params( int, VALUE *, VALUE );
|
958
1041
|
|
959
1042
|
/*
|
960
1043
|
* call-seq:
|
961
|
-
* conn.
|
962
|
-
* conn.
|
963
|
-
*
|
964
|
-
* Sends SQL query request specified by _sql_ to PostgreSQL.
|
965
|
-
* Returns a PG::Result instance on success.
|
966
|
-
* On failure, it raises a PG::Error.
|
1044
|
+
* conn.sync_exec(sql) -> PG::Result
|
1045
|
+
* conn.sync_exec(sql) {|pg_result| block }
|
967
1046
|
*
|
968
|
-
*
|
969
|
-
*
|
970
|
-
* 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.
|
971
1049
|
*
|
972
|
-
*
|
973
|
-
*
|
974
|
-
* 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:
|
975
1052
|
*
|
976
|
-
* #
|
977
|
-
*
|
978
|
-
*
|
979
|
-
* the query is finished. This is most notably visible by a delayed reaction to Control+C.
|
980
|
-
* Both methods ensure that other threads can process while waiting for the server to
|
981
|
-
* complete the request.
|
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.
|
982
1056
|
*/
|
983
1057
|
static VALUE
|
984
|
-
|
1058
|
+
pgconn_sync_exec(int argc, VALUE *argv, VALUE self)
|
985
1059
|
{
|
986
|
-
|
1060
|
+
t_pg_connection *this = pg_get_connection_safe( self );
|
987
1061
|
PGresult *result = NULL;
|
988
1062
|
VALUE rb_pgresult;
|
989
1063
|
|
990
|
-
/* If called with no parameters, use PQexec */
|
991
|
-
if ( argc == 1 ) {
|
1064
|
+
/* If called with no or nil parameters, use PQexec for compatibility */
|
1065
|
+
if ( argc == 1 || (argc >= 2 && argc <= 4 && NIL_P(argv[1]) )) {
|
992
1066
|
VALUE query_str = argv[0];
|
993
1067
|
|
994
|
-
result = gvl_PQexec(
|
1068
|
+
result = gvl_PQexec(this->pgconn, pg_cstr_enc(query_str, this->enc_idx));
|
995
1069
|
rb_pgresult = pg_new_result(result, self);
|
996
1070
|
pg_result_check(rb_pgresult);
|
997
1071
|
if (rb_block_given_p()) {
|
@@ -999,11 +1073,10 @@ pgconn_exec(int argc, VALUE *argv, VALUE self)
|
|
999
1073
|
}
|
1000
1074
|
return rb_pgresult;
|
1001
1075
|
}
|
1076
|
+
pg_deprecated(0, ("forwarding exec to exec_params is deprecated"));
|
1002
1077
|
|
1003
1078
|
/* Otherwise, just call #exec_params instead for backward-compatibility */
|
1004
|
-
|
1005
|
-
return pgconn_exec_params( argc, argv, self );
|
1006
|
-
}
|
1079
|
+
return pgconn_sync_exec_params( argc, argv, self );
|
1007
1080
|
|
1008
1081
|
}
|
1009
1082
|
|
@@ -1035,7 +1108,7 @@ struct query_params_data {
|
|
1035
1108
|
* Filled by alloc_query_params()
|
1036
1109
|
*/
|
1037
1110
|
|
1038
|
-
/* Wraps the pointer of allocated memory, if function parameters
|
1111
|
+
/* Wraps the pointer of allocated memory, if function parameters don't
|
1039
1112
|
* fit in the memory_pool below.
|
1040
1113
|
*/
|
1041
1114
|
VALUE heap_pool;
|
@@ -1053,7 +1126,7 @@ struct query_params_data {
|
|
1053
1126
|
Oid *types;
|
1054
1127
|
|
1055
1128
|
/* This array takes the string values for the timeframe of the query,
|
1056
|
-
* if param value
|
1129
|
+
* if param value conversion is required
|
1057
1130
|
*/
|
1058
1131
|
VALUE gc_array;
|
1059
1132
|
|
@@ -1067,8 +1140,9 @@ struct query_params_data {
|
|
1067
1140
|
};
|
1068
1141
|
|
1069
1142
|
static void
|
1070
|
-
free_typecast_heap_chain(
|
1143
|
+
free_typecast_heap_chain(void *_chain_entry)
|
1071
1144
|
{
|
1145
|
+
struct linked_typecast_data *chain_entry = (struct linked_typecast_data *)_chain_entry;
|
1072
1146
|
while(chain_entry){
|
1073
1147
|
struct linked_typecast_data *next = chain_entry->next;
|
1074
1148
|
xfree(chain_entry);
|
@@ -1076,6 +1150,18 @@ free_typecast_heap_chain(struct linked_typecast_data *chain_entry)
|
|
1076
1150
|
}
|
1077
1151
|
}
|
1078
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
|
+
|
1079
1165
|
static char *
|
1080
1166
|
alloc_typecast_buf( VALUE *typecast_heap_chain, int len )
|
1081
1167
|
{
|
@@ -1086,17 +1172,28 @@ alloc_typecast_buf( VALUE *typecast_heap_chain, int len )
|
|
1086
1172
|
/* Did we already wrap a memory chain per T_DATA object? */
|
1087
1173
|
if( NIL_P( *typecast_heap_chain ) ){
|
1088
1174
|
/* Leave free'ing of the buffer chain to the GC, when paramsData has left the stack */
|
1089
|
-
*typecast_heap_chain =
|
1175
|
+
*typecast_heap_chain = TypedData_Wrap_Struct( rb_cObject, &pg_typecast_buffer_type, allocated );
|
1090
1176
|
allocated->next = NULL;
|
1091
1177
|
} else {
|
1092
1178
|
/* Append to the chain */
|
1093
|
-
allocated->next =
|
1094
|
-
|
1179
|
+
allocated->next = RTYPEDDATA_DATA( *typecast_heap_chain );
|
1180
|
+
RTYPEDDATA_DATA( *typecast_heap_chain ) = allocated;
|
1095
1181
|
}
|
1096
1182
|
|
1097
1183
|
return &allocated->data[0];
|
1098
1184
|
}
|
1099
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
|
+
};
|
1100
1197
|
|
1101
1198
|
static int
|
1102
1199
|
alloc_query_params(struct query_params_data *paramsData)
|
@@ -1111,7 +1208,7 @@ alloc_query_params(struct query_params_data *paramsData)
|
|
1111
1208
|
|
1112
1209
|
Check_Type(paramsData->params, T_ARRAY);
|
1113
1210
|
|
1114
|
-
p_typemap =
|
1211
|
+
p_typemap = RTYPEDDATA_DATA( paramsData->typemap );
|
1115
1212
|
p_typemap->funcs.fit_to_query( paramsData->typemap, paramsData->params );
|
1116
1213
|
|
1117
1214
|
paramsData->heap_pool = Qnil;
|
@@ -1130,7 +1227,7 @@ alloc_query_params(struct query_params_data *paramsData)
|
|
1130
1227
|
/* Allocate one combined memory pool for all possible function parameters */
|
1131
1228
|
memory_pool = (char*)xmalloc( required_pool_size );
|
1132
1229
|
/* Leave free'ing of the buffer to the GC, when paramsData has left the stack */
|
1133
|
-
paramsData->heap_pool =
|
1230
|
+
paramsData->heap_pool = TypedData_Wrap_Struct( rb_cObject, &pg_query_heap_pool_type, memory_pool );
|
1134
1231
|
required_pool_size = 0;
|
1135
1232
|
}else{
|
1136
1233
|
/* Use stack memory for function parameters */
|
@@ -1243,85 +1340,52 @@ pgconn_query_assign_typemap( VALUE self, struct query_params_data *paramsData )
|
|
1243
1340
|
/* Use default typemap for queries. It's type is checked when assigned. */
|
1244
1341
|
paramsData->typemap = pg_get_connection(self)->type_map_for_queries;
|
1245
1342
|
}else{
|
1343
|
+
t_typemap *tm;
|
1344
|
+
UNUSED(tm);
|
1345
|
+
|
1246
1346
|
/* Check type of method param */
|
1247
|
-
|
1248
|
-
rb_raise( rb_eTypeError, "wrong argument type %s (expected kind of PG::TypeMap)",
|
1249
|
-
rb_obj_classname( paramsData->typemap ) );
|
1250
|
-
}
|
1251
|
-
Check_Type( paramsData->typemap, T_DATA );
|
1347
|
+
TypedData_Get_Struct(paramsData->typemap, t_typemap, &pg_typemap_type, tm);
|
1252
1348
|
}
|
1253
1349
|
}
|
1254
1350
|
|
1255
1351
|
/*
|
1256
1352
|
* call-seq:
|
1257
|
-
* conn.
|
1258
|
-
* conn.
|
1259
|
-
*
|
1260
|
-
* Sends SQL query request specified by +sql+ to PostgreSQL using placeholders
|
1261
|
-
* for parameters.
|
1262
|
-
*
|
1263
|
-
* Returns a PG::Result instance on success. On failure, it raises a PG::Error.
|
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 }
|
1264
1355
|
*
|
1265
|
-
*
|
1266
|
-
*
|
1267
|
-
*
|
1268
|
-
* {:value => String (value of bind parameter)
|
1269
|
-
* :type => Integer (oid of type of bind parameter)
|
1270
|
-
* :format => Integer (0 for text, 1 for binary)
|
1271
|
-
* }
|
1272
|
-
* or, it may be a String. If it is a string, that is equivalent to the hash:
|
1273
|
-
* { :value => <string value>, :type => 0, :format => 0 }
|
1274
|
-
*
|
1275
|
-
* PostgreSQL bind parameters are represented as $1, $1, $2, etc.,
|
1276
|
-
* inside the SQL query. The 0th element of the +params+ array is bound
|
1277
|
-
* to $1, the 1st element is bound to $2, etc. +nil+ is treated as +NULL+.
|
1278
|
-
*
|
1279
|
-
* If the types are not specified, they will be inferred by PostgreSQL.
|
1280
|
-
* Instead of specifying type oids, it's recommended to simply add
|
1281
|
-
* explicit casts in the query to ensure that the right type is used.
|
1282
|
-
*
|
1283
|
-
* For example: "SELECT $1::int"
|
1284
|
-
*
|
1285
|
-
* The optional +result_format+ should be 0 for text results, 1
|
1286
|
-
* for binary.
|
1287
|
-
*
|
1288
|
-
* type_map can be a PG::TypeMap derivation (such as PG::BasicTypeMapForQueries).
|
1289
|
-
* This will type cast the params from various Ruby types before transmission
|
1290
|
-
* based on the encoders defined by the type map. When a type encoder is used
|
1291
|
-
* the format and oid of a given bind parameter are retrieved from the encoder
|
1292
|
-
* instead out of the hash form described above.
|
1293
|
-
*
|
1294
|
-
* If the optional code block is given, it will be passed <i>result</i> as an argument,
|
1295
|
-
* and the PG::Result object will automatically be cleared when the block terminates.
|
1296
|
-
* 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.
|
1297
1359
|
*/
|
1298
1360
|
static VALUE
|
1299
|
-
|
1361
|
+
pgconn_sync_exec_params( int argc, VALUE *argv, VALUE self )
|
1300
1362
|
{
|
1301
|
-
|
1363
|
+
t_pg_connection *this = pg_get_connection_safe( self );
|
1302
1364
|
PGresult *result = NULL;
|
1303
1365
|
VALUE rb_pgresult;
|
1304
1366
|
VALUE command, in_res_fmt;
|
1305
1367
|
int nParams;
|
1306
1368
|
int resultFormat;
|
1307
|
-
struct query_params_data paramsData = {
|
1369
|
+
struct query_params_data paramsData = { this->enc_idx };
|
1308
1370
|
|
1371
|
+
/* For compatibility we accept 1 to 4 parameters */
|
1309
1372
|
rb_scan_args(argc, argv, "13", &command, ¶msData.params, &in_res_fmt, ¶msData.typemap);
|
1310
1373
|
paramsData.with_types = 1;
|
1311
1374
|
|
1312
1375
|
/*
|
1313
|
-
*
|
1314
|
-
*
|
1376
|
+
* For backward compatibility no or +nil+ for the second parameter
|
1377
|
+
* is passed to #exec
|
1315
1378
|
*/
|
1316
1379
|
if ( NIL_P(paramsData.params) ) {
|
1317
|
-
|
1380
|
+
pg_deprecated(1, ("forwarding exec_params to exec is deprecated"));
|
1381
|
+
return pgconn_sync_exec( 1, argv, self );
|
1318
1382
|
}
|
1319
1383
|
pgconn_query_assign_typemap( self, ¶msData );
|
1320
1384
|
|
1321
1385
|
resultFormat = NIL_P(in_res_fmt) ? 0 : NUM2INT(in_res_fmt);
|
1322
1386
|
nParams = alloc_query_params( ¶msData );
|
1323
1387
|
|
1324
|
-
result = gvl_PQexecParams(
|
1388
|
+
result = gvl_PQexecParams(this->pgconn, pg_cstr_enc(command, paramsData.enc_idx), nParams, paramsData.types,
|
1325
1389
|
(const char * const *)paramsData.values, paramsData.lengths, paramsData.formats, resultFormat);
|
1326
1390
|
|
1327
1391
|
free_query_params( ¶msData );
|
@@ -1338,28 +1402,16 @@ pgconn_exec_params( int argc, VALUE *argv, VALUE self )
|
|
1338
1402
|
|
1339
1403
|
/*
|
1340
1404
|
* call-seq:
|
1341
|
-
* conn.
|
1342
|
-
*
|
1343
|
-
* Prepares statement _sql_ with name _name_ to be executed later.
|
1344
|
-
* Returns a PG::Result instance on success.
|
1345
|
-
* On failure, it raises a PG::Error.
|
1346
|
-
*
|
1347
|
-
* +param_types+ is an optional parameter to specify the Oids of the
|
1348
|
-
* types of the parameters.
|
1405
|
+
* conn.sync_prepare(stmt_name, sql [, param_types ] ) -> PG::Result
|
1349
1406
|
*
|
1350
|
-
*
|
1351
|
-
*
|
1352
|
-
* explicit
|
1353
|
-
*
|
1354
|
-
* For example: "SELECT $1::int"
|
1355
|
-
*
|
1356
|
-
* PostgreSQL bind parameters are represented as $1, $1, $2, etc.,
|
1357
|
-
* inside the SQL query.
|
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.
|
1358
1410
|
*/
|
1359
1411
|
static VALUE
|
1360
|
-
|
1412
|
+
pgconn_sync_prepare(int argc, VALUE *argv, VALUE self)
|
1361
1413
|
{
|
1362
|
-
|
1414
|
+
t_pg_connection *this = pg_get_connection_safe( self );
|
1363
1415
|
PGresult *result = NULL;
|
1364
1416
|
VALUE rb_pgresult;
|
1365
1417
|
VALUE name, command, in_paramtypes;
|
@@ -1369,7 +1421,7 @@ pgconn_prepare(int argc, VALUE *argv, VALUE self)
|
|
1369
1421
|
Oid *paramTypes = NULL;
|
1370
1422
|
const char *name_cstr;
|
1371
1423
|
const char *command_cstr;
|
1372
|
-
int enc_idx =
|
1424
|
+
int enc_idx = this->enc_idx;
|
1373
1425
|
|
1374
1426
|
rb_scan_args(argc, argv, "21", &name, &command, &in_paramtypes);
|
1375
1427
|
name_cstr = pg_cstr_enc(name, enc_idx);
|
@@ -1387,7 +1439,7 @@ pgconn_prepare(int argc, VALUE *argv, VALUE self)
|
|
1387
1439
|
paramTypes[i] = NUM2UINT(param);
|
1388
1440
|
}
|
1389
1441
|
}
|
1390
|
-
result = gvl_PQprepare(
|
1442
|
+
result = gvl_PQprepare(this->pgconn, name_cstr, command_cstr, nParams, paramTypes);
|
1391
1443
|
|
1392
1444
|
xfree(paramTypes);
|
1393
1445
|
|
@@ -1398,49 +1450,23 @@ pgconn_prepare(int argc, VALUE *argv, VALUE self)
|
|
1398
1450
|
|
1399
1451
|
/*
|
1400
1452
|
* call-seq:
|
1401
|
-
* conn.
|
1402
|
-
* conn.
|
1403
|
-
*
|
1404
|
-
* Execute prepared named statement specified by _statement_name_.
|
1405
|
-
* Returns a PG::Result instance on success.
|
1406
|
-
* On failure, it raises a PG::Error.
|
1407
|
-
*
|
1408
|
-
* +params+ is an array of the optional bind parameters for the
|
1409
|
-
* SQL query. Each element of the +params+ array may be either:
|
1410
|
-
* a hash of the form:
|
1411
|
-
* {:value => String (value of bind parameter)
|
1412
|
-
* :format => Integer (0 for text, 1 for binary)
|
1413
|
-
* }
|
1414
|
-
* or, it may be a String. If it is a string, that is equivalent to the hash:
|
1415
|
-
* { :value => <string value>, :format => 0 }
|
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 }
|
1416
1455
|
*
|
1417
|
-
*
|
1418
|
-
*
|
1419
|
-
* to
|
1420
|
-
*
|
1421
|
-
* The optional +result_format+ should be 0 for text results, 1
|
1422
|
-
* for binary.
|
1423
|
-
*
|
1424
|
-
* type_map can be a PG::TypeMap derivation (such as PG::BasicTypeMapForQueries).
|
1425
|
-
* This will type cast the params from various Ruby types before transmission
|
1426
|
-
* based on the encoders defined by the type map. When a type encoder is used
|
1427
|
-
* the format and oid of a given bind parameter are retrieved from the encoder
|
1428
|
-
* instead out of the hash form described above.
|
1429
|
-
*
|
1430
|
-
* If the optional code block is given, it will be passed <i>result</i> as an argument,
|
1431
|
-
* and the PG::Result object will automatically be cleared when the block terminates.
|
1432
|
-
* In this instance, <code>conn.exec_prepared</code> returns the value of the block.
|
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.
|
1433
1459
|
*/
|
1434
1460
|
static VALUE
|
1435
|
-
|
1461
|
+
pgconn_sync_exec_prepared(int argc, VALUE *argv, VALUE self)
|
1436
1462
|
{
|
1437
|
-
|
1463
|
+
t_pg_connection *this = pg_get_connection_safe( self );
|
1438
1464
|
PGresult *result = NULL;
|
1439
1465
|
VALUE rb_pgresult;
|
1440
1466
|
VALUE name, in_res_fmt;
|
1441
1467
|
int nParams;
|
1442
1468
|
int resultFormat;
|
1443
|
-
struct query_params_data paramsData = {
|
1469
|
+
struct query_params_data paramsData = { this->enc_idx };
|
1444
1470
|
|
1445
1471
|
rb_scan_args(argc, argv, "13", &name, ¶msData.params, &in_res_fmt, ¶msData.typemap);
|
1446
1472
|
paramsData.with_types = 0;
|
@@ -1453,7 +1479,7 @@ pgconn_exec_prepared(int argc, VALUE *argv, VALUE self)
|
|
1453
1479
|
resultFormat = NIL_P(in_res_fmt) ? 0 : NUM2INT(in_res_fmt);
|
1454
1480
|
nParams = alloc_query_params( ¶msData );
|
1455
1481
|
|
1456
|
-
result = gvl_PQexecPrepared(
|
1482
|
+
result = gvl_PQexecPrepared(this->pgconn, pg_cstr_enc(name, paramsData.enc_idx), nParams,
|
1457
1483
|
(const char * const *)paramsData.values, paramsData.lengths, paramsData.formats,
|
1458
1484
|
resultFormat);
|
1459
1485
|
|
@@ -1470,25 +1496,26 @@ pgconn_exec_prepared(int argc, VALUE *argv, VALUE self)
|
|
1470
1496
|
|
1471
1497
|
/*
|
1472
1498
|
* call-seq:
|
1473
|
-
* conn.
|
1499
|
+
* conn.sync_describe_prepared( statement_name ) -> PG::Result
|
1474
1500
|
*
|
1475
|
-
*
|
1476
|
-
*
|
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.
|
1477
1504
|
*/
|
1478
1505
|
static VALUE
|
1479
|
-
|
1506
|
+
pgconn_sync_describe_prepared(VALUE self, VALUE stmt_name)
|
1480
1507
|
{
|
1481
1508
|
PGresult *result;
|
1482
1509
|
VALUE rb_pgresult;
|
1483
|
-
|
1510
|
+
t_pg_connection *this = pg_get_connection_safe( self );
|
1484
1511
|
const char *stmt;
|
1485
1512
|
if(NIL_P(stmt_name)) {
|
1486
1513
|
stmt = NULL;
|
1487
1514
|
}
|
1488
1515
|
else {
|
1489
|
-
stmt = pg_cstr_enc(stmt_name,
|
1516
|
+
stmt = pg_cstr_enc(stmt_name, this->enc_idx);
|
1490
1517
|
}
|
1491
|
-
result = gvl_PQdescribePrepared(
|
1518
|
+
result = gvl_PQdescribePrepared(this->pgconn, stmt);
|
1492
1519
|
rb_pgresult = pg_new_result(result, self);
|
1493
1520
|
pg_result_check(rb_pgresult);
|
1494
1521
|
return rb_pgresult;
|
@@ -1497,25 +1524,26 @@ pgconn_describe_prepared(VALUE self, VALUE stmt_name)
|
|
1497
1524
|
|
1498
1525
|
/*
|
1499
1526
|
* call-seq:
|
1500
|
-
* conn.
|
1527
|
+
* conn.sync_describe_portal( portal_name ) -> PG::Result
|
1501
1528
|
*
|
1502
|
-
*
|
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.
|
1503
1532
|
*/
|
1504
1533
|
static VALUE
|
1505
|
-
|
1506
|
-
VALUE self, stmt_name;
|
1534
|
+
pgconn_sync_describe_portal(VALUE self, VALUE stmt_name)
|
1507
1535
|
{
|
1508
1536
|
PGresult *result;
|
1509
1537
|
VALUE rb_pgresult;
|
1510
|
-
|
1538
|
+
t_pg_connection *this = pg_get_connection_safe( self );
|
1511
1539
|
const char *stmt;
|
1512
1540
|
if(NIL_P(stmt_name)) {
|
1513
1541
|
stmt = NULL;
|
1514
1542
|
}
|
1515
1543
|
else {
|
1516
|
-
stmt = pg_cstr_enc(stmt_name,
|
1544
|
+
stmt = pg_cstr_enc(stmt_name, this->enc_idx);
|
1517
1545
|
}
|
1518
|
-
result = gvl_PQdescribePortal(
|
1546
|
+
result = gvl_PQdescribePortal(this->pgconn, stmt);
|
1519
1547
|
rb_pgresult = pg_new_result(result, self);
|
1520
1548
|
pg_result_check(rb_pgresult);
|
1521
1549
|
return rb_pgresult;
|
@@ -1537,6 +1565,9 @@ pgconn_describe_portal(self, stmt_name)
|
|
1537
1565
|
* * +PGRES_NONFATAL_ERROR+
|
1538
1566
|
* * +PGRES_FATAL_ERROR+
|
1539
1567
|
* * +PGRES_COPY_BOTH+
|
1568
|
+
* * +PGRES_SINGLE_TUPLE+
|
1569
|
+
* * +PGRES_PIPELINE_SYNC+
|
1570
|
+
* * +PGRES_PIPELINE_ABORTED+
|
1540
1571
|
*/
|
1541
1572
|
static VALUE
|
1542
1573
|
pgconn_make_empty_pgresult(VALUE self, VALUE status)
|
@@ -1562,13 +1593,15 @@ pgconn_make_empty_pgresult(VALUE self, VALUE status)
|
|
1562
1593
|
* Consider using exec_params, which avoids the need for passing values
|
1563
1594
|
* inside of SQL commands.
|
1564
1595
|
*
|
1565
|
-
*
|
1596
|
+
* Character encoding of escaped string will be equal to client encoding of connection.
|
1566
1597
|
*
|
1567
1598
|
* NOTE: This class version of this method can only be used safely in client
|
1568
1599
|
* programs that use a single PostgreSQL connection at a time (in this case it can
|
1569
1600
|
* find out what it needs to know "behind the scenes"). It might give the wrong
|
1570
1601
|
* results if used in programs that use multiple database connections; use the
|
1571
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.
|
1572
1605
|
*/
|
1573
1606
|
static VALUE
|
1574
1607
|
pgconn_s_escape(VALUE self, VALUE string)
|
@@ -1579,8 +1612,8 @@ pgconn_s_escape(VALUE self, VALUE string)
|
|
1579
1612
|
int enc_idx;
|
1580
1613
|
int singleton = !rb_obj_is_kind_of(self, rb_cPGconn);
|
1581
1614
|
|
1582
|
-
|
1583
|
-
enc_idx =
|
1615
|
+
StringValueCStr(string);
|
1616
|
+
enc_idx = singleton ? ENCODING_GET(string) : pg_get_connection(self)->enc_idx;
|
1584
1617
|
if( ENCODING_GET(string) != enc_idx ){
|
1585
1618
|
string = rb_str_export_to_enc(string, rb_enc_from_index(enc_idx));
|
1586
1619
|
}
|
@@ -1590,14 +1623,13 @@ pgconn_s_escape(VALUE self, VALUE string)
|
|
1590
1623
|
if( !singleton ) {
|
1591
1624
|
size = PQescapeStringConn(pg_get_pgconn(self), RSTRING_PTR(result),
|
1592
1625
|
RSTRING_PTR(string), RSTRING_LEN(string), &error);
|
1593
|
-
if(error)
|
1594
|
-
|
1595
|
-
|
1626
|
+
if(error)
|
1627
|
+
pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(pg_get_pgconn(self)));
|
1628
|
+
|
1596
1629
|
} else {
|
1597
1630
|
size = PQescapeString(RSTRING_PTR(result), RSTRING_PTR(string), RSTRING_LEN(string));
|
1598
1631
|
}
|
1599
1632
|
rb_str_set_len(result, size);
|
1600
|
-
OBJ_INFECT(result, string);
|
1601
1633
|
|
1602
1634
|
return result;
|
1603
1635
|
}
|
@@ -1643,7 +1675,6 @@ pgconn_s_escape_bytea(VALUE self, VALUE str)
|
|
1643
1675
|
}
|
1644
1676
|
|
1645
1677
|
ret = rb_str_new((char*)to, to_len - 1);
|
1646
|
-
OBJ_INFECT(ret, str);
|
1647
1678
|
PQfreemem(to);
|
1648
1679
|
return ret;
|
1649
1680
|
}
|
@@ -1673,7 +1704,6 @@ pgconn_s_unescape_bytea(VALUE self, VALUE str)
|
|
1673
1704
|
to = PQunescapeBytea(from, &to_len);
|
1674
1705
|
|
1675
1706
|
ret = rb_str_new((char*)to, to_len);
|
1676
|
-
OBJ_INFECT(ret, str);
|
1677
1707
|
PQfreemem(to);
|
1678
1708
|
return ret;
|
1679
1709
|
}
|
@@ -1684,33 +1714,27 @@ pgconn_s_unescape_bytea(VALUE self, VALUE str)
|
|
1684
1714
|
*
|
1685
1715
|
* Escape an arbitrary String +str+ as a literal.
|
1686
1716
|
*
|
1687
|
-
*
|
1717
|
+
* See also PG::TextEncoder::QuotedLiteral for a type cast integrated version of this function.
|
1688
1718
|
*/
|
1689
1719
|
static VALUE
|
1690
1720
|
pgconn_escape_literal(VALUE self, VALUE string)
|
1691
1721
|
{
|
1692
|
-
|
1722
|
+
t_pg_connection *this = pg_get_connection_safe( self );
|
1693
1723
|
char *escaped = NULL;
|
1694
|
-
VALUE error;
|
1695
1724
|
VALUE result = Qnil;
|
1696
|
-
int enc_idx =
|
1725
|
+
int enc_idx = this->enc_idx;
|
1697
1726
|
|
1698
|
-
|
1727
|
+
StringValueCStr(string);
|
1699
1728
|
if( ENCODING_GET(string) != enc_idx ){
|
1700
1729
|
string = rb_str_export_to_enc(string, rb_enc_from_index(enc_idx));
|
1701
1730
|
}
|
1702
1731
|
|
1703
|
-
escaped = PQescapeLiteral(
|
1732
|
+
escaped = PQescapeLiteral(this->pgconn, RSTRING_PTR(string), RSTRING_LEN(string));
|
1704
1733
|
if (escaped == NULL)
|
1705
|
-
|
1706
|
-
|
1707
|
-
rb_iv_set(error, "@connection", self);
|
1708
|
-
rb_exc_raise(error);
|
1709
|
-
return Qnil;
|
1710
|
-
}
|
1734
|
+
pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(this->pgconn));
|
1735
|
+
|
1711
1736
|
result = rb_str_new2(escaped);
|
1712
1737
|
PQfreemem(escaped);
|
1713
|
-
OBJ_INFECT(result, string);
|
1714
1738
|
PG_ENCODING_SET_NOCHECK(result, enc_idx);
|
1715
1739
|
|
1716
1740
|
return result;
|
@@ -1725,34 +1749,26 @@ pgconn_escape_literal(VALUE self, VALUE string)
|
|
1725
1749
|
* This method does the same as #quote_ident with a String argument,
|
1726
1750
|
* but it doesn't support an Array argument and it makes use of libpq
|
1727
1751
|
* to process the string.
|
1728
|
-
*
|
1729
|
-
* Available since PostgreSQL-9.0
|
1730
1752
|
*/
|
1731
1753
|
static VALUE
|
1732
1754
|
pgconn_escape_identifier(VALUE self, VALUE string)
|
1733
1755
|
{
|
1734
|
-
|
1756
|
+
t_pg_connection *this = pg_get_connection_safe( self );
|
1735
1757
|
char *escaped = NULL;
|
1736
|
-
VALUE error;
|
1737
1758
|
VALUE result = Qnil;
|
1738
|
-
int enc_idx =
|
1759
|
+
int enc_idx = this->enc_idx;
|
1739
1760
|
|
1740
|
-
|
1761
|
+
StringValueCStr(string);
|
1741
1762
|
if( ENCODING_GET(string) != enc_idx ){
|
1742
1763
|
string = rb_str_export_to_enc(string, rb_enc_from_index(enc_idx));
|
1743
1764
|
}
|
1744
1765
|
|
1745
|
-
escaped = PQescapeIdentifier(
|
1766
|
+
escaped = PQescapeIdentifier(this->pgconn, RSTRING_PTR(string), RSTRING_LEN(string));
|
1746
1767
|
if (escaped == NULL)
|
1747
|
-
|
1748
|
-
|
1749
|
-
rb_iv_set(error, "@connection", self);
|
1750
|
-
rb_exc_raise(error);
|
1751
|
-
return Qnil;
|
1752
|
-
}
|
1768
|
+
pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(this->pgconn));
|
1769
|
+
|
1753
1770
|
result = rb_str_new2(escaped);
|
1754
1771
|
PQfreemem(escaped);
|
1755
|
-
OBJ_INFECT(result, string);
|
1756
1772
|
PG_ENCODING_SET_NOCHECK(result, enc_idx);
|
1757
1773
|
|
1758
1774
|
return result;
|
@@ -1793,34 +1809,65 @@ pgconn_escape_identifier(VALUE self, VALUE string)
|
|
1793
1809
|
* # do something with the received row
|
1794
1810
|
* end
|
1795
1811
|
* end
|
1796
|
-
*
|
1797
|
-
* Available since PostgreSQL-9.2
|
1798
1812
|
*/
|
1799
1813
|
static VALUE
|
1800
1814
|
pgconn_set_single_row_mode(VALUE self)
|
1801
1815
|
{
|
1802
1816
|
PGconn *conn = pg_get_pgconn(self);
|
1803
|
-
VALUE error;
|
1804
1817
|
|
1818
|
+
rb_check_frozen(self);
|
1805
1819
|
if( PQsetSingleRowMode(conn) == 0 )
|
1806
|
-
|
1807
|
-
error = rb_exc_new2(rb_ePGerror, PQerrorMessage(conn));
|
1808
|
-
rb_iv_set(error, "@connection", self);
|
1809
|
-
rb_exc_raise(error);
|
1810
|
-
}
|
1820
|
+
pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(conn));
|
1811
1821
|
|
1812
1822
|
return self;
|
1813
1823
|
}
|
1814
1824
|
|
1825
|
+
static VALUE pgconn_send_query_params(int argc, VALUE *argv, VALUE self);
|
1826
|
+
|
1827
|
+
/*
|
1828
|
+
* call-seq:
|
1829
|
+
* conn.send_query(sql) -> nil
|
1830
|
+
*
|
1831
|
+
* Sends SQL query request specified by _sql_ to PostgreSQL for
|
1832
|
+
* asynchronous processing, and immediately returns.
|
1833
|
+
* On failure, it raises a PG::Error.
|
1834
|
+
*
|
1835
|
+
* For backward compatibility, if you pass more than one parameter to this method,
|
1836
|
+
* it will call #send_query_params for you. New code should explicitly use #send_query_params if
|
1837
|
+
* argument placeholders are used.
|
1838
|
+
*
|
1839
|
+
*/
|
1840
|
+
static VALUE
|
1841
|
+
pgconn_send_query(int argc, VALUE *argv, VALUE self)
|
1842
|
+
{
|
1843
|
+
t_pg_connection *this = pg_get_connection_safe( self );
|
1844
|
+
|
1845
|
+
/* If called with no or nil parameters, use PQexec for compatibility */
|
1846
|
+
if ( argc == 1 || (argc >= 2 && argc <= 4 && NIL_P(argv[1]) )) {
|
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 );
|
1851
|
+
return Qnil;
|
1852
|
+
}
|
1853
|
+
|
1854
|
+
pg_deprecated(2, ("forwarding async_exec to async_exec_params and send_query to send_query_params is deprecated"));
|
1855
|
+
|
1856
|
+
/* If called with parameters, and optionally result_format,
|
1857
|
+
* use PQsendQueryParams
|
1858
|
+
*/
|
1859
|
+
return pgconn_send_query_params( argc, argv, self);
|
1860
|
+
}
|
1861
|
+
|
1815
1862
|
/*
|
1816
1863
|
* call-seq:
|
1817
|
-
* conn.
|
1864
|
+
* conn.send_query_params(sql, params [, result_format [, type_map ]] ) -> nil
|
1818
1865
|
*
|
1819
1866
|
* Sends SQL query request specified by _sql_ to PostgreSQL for
|
1820
1867
|
* asynchronous processing, and immediately returns.
|
1821
1868
|
* On failure, it raises a PG::Error.
|
1822
1869
|
*
|
1823
|
-
* +params+ is an
|
1870
|
+
* +params+ is an array of the bind parameters for the SQL query.
|
1824
1871
|
* Each element of the +params+ array may be either:
|
1825
1872
|
* a hash of the form:
|
1826
1873
|
* {:value => String (value of bind parameter)
|
@@ -1830,7 +1877,7 @@ pgconn_set_single_row_mode(VALUE self)
|
|
1830
1877
|
* or, it may be a String. If it is a string, that is equivalent to the hash:
|
1831
1878
|
* { :value => <string value>, :type => 0, :format => 0 }
|
1832
1879
|
*
|
1833
|
-
* PostgreSQL bind parameters are represented as $1, $
|
1880
|
+
* PostgreSQL bind parameters are represented as $1, $2, $3, etc.,
|
1834
1881
|
* inside the SQL query. The 0th element of the +params+ array is bound
|
1835
1882
|
* to $1, the 1st element is bound to $2, etc. +nil+ is treated as +NULL+.
|
1836
1883
|
*
|
@@ -1843,7 +1890,7 @@ pgconn_set_single_row_mode(VALUE self)
|
|
1843
1890
|
* The optional +result_format+ should be 0 for text results, 1
|
1844
1891
|
* for binary.
|
1845
1892
|
*
|
1846
|
-
* 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).
|
1847
1894
|
* This will type cast the params from various Ruby types before transmission
|
1848
1895
|
* based on the encoders defined by the type map. When a type encoder is used
|
1849
1896
|
* the format and oid of a given bind parameter are retrieved from the encoder
|
@@ -1851,47 +1898,31 @@ pgconn_set_single_row_mode(VALUE self)
|
|
1851
1898
|
*
|
1852
1899
|
*/
|
1853
1900
|
static VALUE
|
1854
|
-
|
1901
|
+
pgconn_send_query_params(int argc, VALUE *argv, VALUE self)
|
1855
1902
|
{
|
1856
|
-
|
1903
|
+
t_pg_connection *this = pg_get_connection_safe( self );
|
1857
1904
|
int result;
|
1858
1905
|
VALUE command, in_res_fmt;
|
1859
|
-
VALUE error;
|
1860
1906
|
int nParams;
|
1861
1907
|
int resultFormat;
|
1862
|
-
struct query_params_data paramsData = {
|
1908
|
+
struct query_params_data paramsData = { this->enc_idx };
|
1863
1909
|
|
1864
|
-
rb_scan_args(argc, argv, "
|
1910
|
+
rb_scan_args(argc, argv, "22", &command, ¶msData.params, &in_res_fmt, ¶msData.typemap);
|
1865
1911
|
paramsData.with_types = 1;
|
1866
1912
|
|
1867
|
-
/* If called with no parameters, use PQsendQuery */
|
1868
|
-
if(NIL_P(paramsData.params)) {
|
1869
|
-
if(gvl_PQsendQuery(conn, pg_cstr_enc(command, paramsData.enc_idx)) == 0) {
|
1870
|
-
error = rb_exc_new2(rb_eUnableToSend, PQerrorMessage(conn));
|
1871
|
-
rb_iv_set(error, "@connection", self);
|
1872
|
-
rb_exc_raise(error);
|
1873
|
-
}
|
1874
|
-
return Qnil;
|
1875
|
-
}
|
1876
|
-
|
1877
|
-
/* If called with parameters, and optionally result_format,
|
1878
|
-
* use PQsendQueryParams
|
1879
|
-
*/
|
1880
|
-
|
1881
1913
|
pgconn_query_assign_typemap( self, ¶msData );
|
1882
1914
|
resultFormat = NIL_P(in_res_fmt) ? 0 : NUM2INT(in_res_fmt);
|
1883
1915
|
nParams = alloc_query_params( ¶msData );
|
1884
1916
|
|
1885
|
-
result = gvl_PQsendQueryParams(
|
1917
|
+
result = gvl_PQsendQueryParams(this->pgconn, pg_cstr_enc(command, paramsData.enc_idx), nParams, paramsData.types,
|
1886
1918
|
(const char * const *)paramsData.values, paramsData.lengths, paramsData.formats, resultFormat);
|
1887
1919
|
|
1888
1920
|
free_query_params( ¶msData );
|
1889
1921
|
|
1890
|
-
if(result == 0)
|
1891
|
-
|
1892
|
-
|
1893
|
-
|
1894
|
-
}
|
1922
|
+
if(result == 0)
|
1923
|
+
pg_raise_conn_error( rb_eUnableToSend, self, "%s", PQerrorMessage(this->pgconn));
|
1924
|
+
|
1925
|
+
pgconn_wait_for_flush( self );
|
1895
1926
|
return Qnil;
|
1896
1927
|
}
|
1897
1928
|
|
@@ -1912,23 +1943,22 @@ pgconn_send_query(int argc, VALUE *argv, VALUE self)
|
|
1912
1943
|
*
|
1913
1944
|
* For example: "SELECT $1::int"
|
1914
1945
|
*
|
1915
|
-
* PostgreSQL bind parameters are represented as $1, $
|
1946
|
+
* PostgreSQL bind parameters are represented as $1, $2, $3, etc.,
|
1916
1947
|
* inside the SQL query.
|
1917
1948
|
*/
|
1918
1949
|
static VALUE
|
1919
1950
|
pgconn_send_prepare(int argc, VALUE *argv, VALUE self)
|
1920
1951
|
{
|
1921
|
-
|
1952
|
+
t_pg_connection *this = pg_get_connection_safe( self );
|
1922
1953
|
int result;
|
1923
1954
|
VALUE name, command, in_paramtypes;
|
1924
1955
|
VALUE param;
|
1925
|
-
VALUE error;
|
1926
1956
|
int i = 0;
|
1927
1957
|
int nParams = 0;
|
1928
1958
|
Oid *paramTypes = NULL;
|
1929
1959
|
const char *name_cstr;
|
1930
1960
|
const char *command_cstr;
|
1931
|
-
int enc_idx =
|
1961
|
+
int enc_idx = this->enc_idx;
|
1932
1962
|
|
1933
1963
|
rb_scan_args(argc, argv, "21", &name, &command, &in_paramtypes);
|
1934
1964
|
name_cstr = pg_cstr_enc(name, enc_idx);
|
@@ -1946,15 +1976,14 @@ pgconn_send_prepare(int argc, VALUE *argv, VALUE self)
|
|
1946
1976
|
paramTypes[i] = NUM2UINT(param);
|
1947
1977
|
}
|
1948
1978
|
}
|
1949
|
-
result = gvl_PQsendPrepare(
|
1979
|
+
result = gvl_PQsendPrepare(this->pgconn, name_cstr, command_cstr, nParams, paramTypes);
|
1950
1980
|
|
1951
1981
|
xfree(paramTypes);
|
1952
1982
|
|
1953
1983
|
if(result == 0) {
|
1954
|
-
|
1955
|
-
rb_iv_set(error, "@connection", self);
|
1956
|
-
rb_exc_raise(error);
|
1984
|
+
pg_raise_conn_error( rb_eUnableToSend, self, "%s", PQerrorMessage(this->pgconn));
|
1957
1985
|
}
|
1986
|
+
pgconn_wait_for_flush( self );
|
1958
1987
|
return Qnil;
|
1959
1988
|
}
|
1960
1989
|
|
@@ -1976,14 +2005,14 @@ pgconn_send_prepare(int argc, VALUE *argv, VALUE self)
|
|
1976
2005
|
* or, it may be a String. If it is a string, that is equivalent to the hash:
|
1977
2006
|
* { :value => <string value>, :format => 0 }
|
1978
2007
|
*
|
1979
|
-
* PostgreSQL bind parameters are represented as $1, $
|
2008
|
+
* PostgreSQL bind parameters are represented as $1, $2, $3, etc.,
|
1980
2009
|
* inside the SQL query. The 0th element of the +params+ array is bound
|
1981
2010
|
* to $1, the 1st element is bound to $2, etc. +nil+ is treated as +NULL+.
|
1982
2011
|
*
|
1983
2012
|
* The optional +result_format+ should be 0 for text results, 1
|
1984
2013
|
* for binary.
|
1985
2014
|
*
|
1986
|
-
* 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).
|
1987
2016
|
* This will type cast the params from various Ruby types before transmission
|
1988
2017
|
* based on the encoders defined by the type map. When a type encoder is used
|
1989
2018
|
* the format and oid of a given bind parameter are retrieved from the encoder
|
@@ -1993,37 +2022,34 @@ pgconn_send_prepare(int argc, VALUE *argv, VALUE self)
|
|
1993
2022
|
static VALUE
|
1994
2023
|
pgconn_send_query_prepared(int argc, VALUE *argv, VALUE self)
|
1995
2024
|
{
|
1996
|
-
|
2025
|
+
t_pg_connection *this = pg_get_connection_safe( self );
|
1997
2026
|
int result;
|
1998
2027
|
VALUE name, in_res_fmt;
|
1999
|
-
VALUE error;
|
2000
2028
|
int nParams;
|
2001
2029
|
int resultFormat;
|
2002
|
-
struct query_params_data paramsData = {
|
2030
|
+
struct query_params_data paramsData = { this->enc_idx };
|
2003
2031
|
|
2004
2032
|
rb_scan_args(argc, argv, "13", &name, ¶msData.params, &in_res_fmt, ¶msData.typemap);
|
2005
2033
|
paramsData.with_types = 0;
|
2006
2034
|
|
2007
2035
|
if(NIL_P(paramsData.params)) {
|
2008
2036
|
paramsData.params = rb_ary_new2(0);
|
2009
|
-
resultFormat = 0;
|
2010
2037
|
}
|
2011
2038
|
pgconn_query_assign_typemap( self, ¶msData );
|
2012
2039
|
|
2013
2040
|
resultFormat = NIL_P(in_res_fmt) ? 0 : NUM2INT(in_res_fmt);
|
2014
2041
|
nParams = alloc_query_params( ¶msData );
|
2015
2042
|
|
2016
|
-
result = gvl_PQsendQueryPrepared(
|
2043
|
+
result = gvl_PQsendQueryPrepared(this->pgconn, pg_cstr_enc(name, paramsData.enc_idx), nParams,
|
2017
2044
|
(const char * const *)paramsData.values, paramsData.lengths, paramsData.formats,
|
2018
2045
|
resultFormat);
|
2019
2046
|
|
2020
2047
|
free_query_params( ¶msData );
|
2021
2048
|
|
2022
|
-
if(result == 0)
|
2023
|
-
|
2024
|
-
|
2025
|
-
|
2026
|
-
}
|
2049
|
+
if(result == 0)
|
2050
|
+
pg_raise_conn_error( rb_eUnableToSend, self, "%s", PQerrorMessage(this->pgconn));
|
2051
|
+
|
2052
|
+
pgconn_wait_for_flush( self );
|
2027
2053
|
return Qnil;
|
2028
2054
|
}
|
2029
2055
|
|
@@ -2037,14 +2063,12 @@ pgconn_send_query_prepared(int argc, VALUE *argv, VALUE self)
|
|
2037
2063
|
static VALUE
|
2038
2064
|
pgconn_send_describe_prepared(VALUE self, VALUE stmt_name)
|
2039
2065
|
{
|
2040
|
-
|
2041
|
-
PGconn *conn = pg_get_pgconn(self);
|
2066
|
+
t_pg_connection *this = pg_get_connection_safe( self );
|
2042
2067
|
/* returns 0 on failure */
|
2043
|
-
if(gvl_PQsendDescribePrepared(
|
2044
|
-
|
2045
|
-
|
2046
|
-
|
2047
|
-
}
|
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 );
|
2048
2072
|
return Qnil;
|
2049
2073
|
}
|
2050
2074
|
|
@@ -2059,36 +2083,18 @@ pgconn_send_describe_prepared(VALUE self, VALUE stmt_name)
|
|
2059
2083
|
static VALUE
|
2060
2084
|
pgconn_send_describe_portal(VALUE self, VALUE portal)
|
2061
2085
|
{
|
2062
|
-
|
2063
|
-
PGconn *conn = pg_get_pgconn(self);
|
2086
|
+
t_pg_connection *this = pg_get_connection_safe( self );
|
2064
2087
|
/* returns 0 on failure */
|
2065
|
-
if(gvl_PQsendDescribePortal(
|
2066
|
-
|
2067
|
-
|
2068
|
-
|
2069
|
-
}
|
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 );
|
2070
2092
|
return Qnil;
|
2071
2093
|
}
|
2072
2094
|
|
2073
2095
|
|
2074
|
-
/*
|
2075
|
-
* call-seq:
|
2076
|
-
* conn.get_result() -> PG::Result
|
2077
|
-
* conn.get_result() {|pg_result| block }
|
2078
|
-
*
|
2079
|
-
* Blocks waiting for the next result from a call to
|
2080
|
-
* #send_query (or another asynchronous command), and returns
|
2081
|
-
* it. Returns +nil+ if no more results are available.
|
2082
|
-
*
|
2083
|
-
* Note: call this function repeatedly until it returns +nil+, or else
|
2084
|
-
* you will not be able to issue further commands.
|
2085
|
-
*
|
2086
|
-
* If the optional code block is given, it will be passed <i>result</i> as an argument,
|
2087
|
-
* and the PG::Result object will automatically be cleared when the block terminates.
|
2088
|
-
* In this instance, <code>conn.exec</code> returns the value of the block.
|
2089
|
-
*/
|
2090
2096
|
static VALUE
|
2091
|
-
|
2097
|
+
pgconn_sync_get_result(VALUE self)
|
2092
2098
|
{
|
2093
2099
|
PGconn *conn = pg_get_pgconn(self);
|
2094
2100
|
PGresult *result;
|
@@ -2114,17 +2120,15 @@ pgconn_get_result(VALUE self)
|
|
2114
2120
|
* or *notifies* to see if the state has changed.
|
2115
2121
|
*/
|
2116
2122
|
static VALUE
|
2117
|
-
pgconn_consume_input(self)
|
2118
|
-
VALUE self;
|
2123
|
+
pgconn_consume_input(VALUE self)
|
2119
2124
|
{
|
2120
|
-
VALUE error;
|
2121
2125
|
PGconn *conn = pg_get_pgconn(self);
|
2122
2126
|
/* returns 0 on error */
|
2123
2127
|
if(PQconsumeInput(conn) == 0) {
|
2124
|
-
|
2125
|
-
|
2126
|
-
rb_exc_raise(error);
|
2128
|
+
pgconn_close_socket_io(self);
|
2129
|
+
pg_raise_conn_error( rb_eConnectionBad, self, "%s", PQerrorMessage(conn));
|
2127
2130
|
}
|
2131
|
+
|
2128
2132
|
return Qnil;
|
2129
2133
|
}
|
2130
2134
|
|
@@ -2133,38 +2137,20 @@ pgconn_consume_input(self)
|
|
2133
2137
|
* conn.is_busy() -> Boolean
|
2134
2138
|
*
|
2135
2139
|
* Returns +true+ if a command is busy, that is, if
|
2136
|
-
*
|
2140
|
+
* #get_result would block. Otherwise returns +false+.
|
2137
2141
|
*/
|
2138
2142
|
static VALUE
|
2139
|
-
pgconn_is_busy(self)
|
2140
|
-
VALUE self;
|
2143
|
+
pgconn_is_busy(VALUE self)
|
2141
2144
|
{
|
2142
2145
|
return gvl_PQisBusy(pg_get_pgconn(self)) ? Qtrue : Qfalse;
|
2143
2146
|
}
|
2144
2147
|
|
2145
|
-
/*
|
2146
|
-
* call-seq:
|
2147
|
-
* conn.setnonblocking(Boolean) -> nil
|
2148
|
-
*
|
2149
|
-
* Sets the nonblocking status of the connection.
|
2150
|
-
* In the blocking state, calls to #send_query
|
2151
|
-
* will block until the message is sent to the server,
|
2152
|
-
* but will not wait for the query results.
|
2153
|
-
* In the nonblocking state, calls to #send_query
|
2154
|
-
* will return an error if the socket is not ready for
|
2155
|
-
* writing.
|
2156
|
-
* Note: This function does not affect #exec, because
|
2157
|
-
* that function doesn't return until the server has
|
2158
|
-
* processed the query and returned the results.
|
2159
|
-
* Returns +nil+.
|
2160
|
-
*/
|
2161
2148
|
static VALUE
|
2162
|
-
|
2163
|
-
VALUE self, state;
|
2149
|
+
pgconn_sync_setnonblocking(VALUE self, VALUE state)
|
2164
2150
|
{
|
2165
2151
|
int arg;
|
2166
|
-
VALUE error;
|
2167
2152
|
PGconn *conn = pg_get_pgconn(self);
|
2153
|
+
rb_check_frozen(self);
|
2168
2154
|
if(state == Qtrue)
|
2169
2155
|
arg = 1;
|
2170
2156
|
else if (state == Qfalse)
|
@@ -2172,67 +2158,32 @@ pgconn_setnonblocking(self, state)
|
|
2172
2158
|
else
|
2173
2159
|
rb_raise(rb_eArgError, "Boolean value expected");
|
2174
2160
|
|
2175
|
-
if(PQsetnonblocking(conn, arg) == -1)
|
2176
|
-
|
2177
|
-
|
2178
|
-
rb_exc_raise(error);
|
2179
|
-
}
|
2161
|
+
if(PQsetnonblocking(conn, arg) == -1)
|
2162
|
+
pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(conn));
|
2163
|
+
|
2180
2164
|
return Qnil;
|
2181
2165
|
}
|
2182
2166
|
|
2183
2167
|
|
2184
|
-
/*
|
2185
|
-
* call-seq:
|
2186
|
-
* conn.isnonblocking() -> Boolean
|
2187
|
-
*
|
2188
|
-
* Returns +true+ if a command is busy, that is, if
|
2189
|
-
* PQgetResult would block. Otherwise returns +false+.
|
2190
|
-
*/
|
2191
2168
|
static VALUE
|
2192
|
-
|
2193
|
-
VALUE self;
|
2169
|
+
pgconn_sync_isnonblocking(VALUE self)
|
2194
2170
|
{
|
2195
2171
|
return PQisnonblocking(pg_get_pgconn(self)) ? Qtrue : Qfalse;
|
2196
2172
|
}
|
2197
2173
|
|
2198
|
-
/*
|
2199
|
-
* call-seq:
|
2200
|
-
* conn.flush() -> Boolean
|
2201
|
-
*
|
2202
|
-
* Attempts to flush any queued output data to the server.
|
2203
|
-
* Returns +true+ if data is successfully flushed, +false+
|
2204
|
-
* if not (can only return +false+ if connection is
|
2205
|
-
* nonblocking.
|
2206
|
-
* Raises PG::Error if some other failure occurred.
|
2207
|
-
*/
|
2208
2174
|
static VALUE
|
2209
|
-
|
2210
|
-
VALUE self;
|
2175
|
+
pgconn_sync_flush(VALUE self)
|
2211
2176
|
{
|
2212
2177
|
PGconn *conn = pg_get_pgconn(self);
|
2213
|
-
int ret;
|
2214
|
-
|
2215
|
-
|
2216
|
-
|
2217
|
-
error = rb_exc_new2(rb_ePGerror, PQerrorMessage(conn));
|
2218
|
-
rb_iv_set(error, "@connection", self);
|
2219
|
-
rb_exc_raise(error);
|
2220
|
-
}
|
2178
|
+
int ret = PQflush(conn);
|
2179
|
+
if(ret == -1)
|
2180
|
+
pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(conn));
|
2181
|
+
|
2221
2182
|
return (ret) ? Qfalse : Qtrue;
|
2222
2183
|
}
|
2223
2184
|
|
2224
|
-
/*
|
2225
|
-
* call-seq:
|
2226
|
-
* conn.cancel() -> String
|
2227
|
-
*
|
2228
|
-
* Requests cancellation of the command currently being
|
2229
|
-
* processed. (Only implemented in PostgreSQL >= 8.0)
|
2230
|
-
*
|
2231
|
-
* Returns +nil+ on success, or a string containing the
|
2232
|
-
* error message if a failure occurs.
|
2233
|
-
*/
|
2234
2185
|
static VALUE
|
2235
|
-
|
2186
|
+
pgconn_sync_cancel(VALUE self)
|
2236
2187
|
{
|
2237
2188
|
char errbuf[256];
|
2238
2189
|
PGcancel *cancel;
|
@@ -2241,9 +2192,9 @@ pgconn_cancel(VALUE self)
|
|
2241
2192
|
|
2242
2193
|
cancel = PQgetCancel(pg_get_pgconn(self));
|
2243
2194
|
if(cancel == NULL)
|
2244
|
-
|
2195
|
+
pg_raise_conn_error( rb_ePGerror, self, "Invalid connection!");
|
2245
2196
|
|
2246
|
-
ret = gvl_PQcancel(cancel, errbuf,
|
2197
|
+
ret = gvl_PQcancel(cancel, errbuf, sizeof(errbuf));
|
2247
2198
|
if(ret == 1)
|
2248
2199
|
retval = Qnil;
|
2249
2200
|
else
|
@@ -2264,7 +2215,7 @@ pgconn_cancel(VALUE self)
|
|
2264
2215
|
static VALUE
|
2265
2216
|
pgconn_notifies(VALUE self)
|
2266
2217
|
{
|
2267
|
-
|
2218
|
+
t_pg_connection *this = pg_get_connection_safe( self );
|
2268
2219
|
PGnotify *notification;
|
2269
2220
|
VALUE hash;
|
2270
2221
|
VALUE sym_relname, sym_be_pid, sym_extra;
|
@@ -2274,17 +2225,17 @@ pgconn_notifies(VALUE self)
|
|
2274
2225
|
sym_be_pid = ID2SYM(rb_intern("be_pid"));
|
2275
2226
|
sym_extra = ID2SYM(rb_intern("extra"));
|
2276
2227
|
|
2277
|
-
notification = gvl_PQnotifies(
|
2228
|
+
notification = gvl_PQnotifies(this->pgconn);
|
2278
2229
|
if (notification == NULL) {
|
2279
2230
|
return Qnil;
|
2280
2231
|
}
|
2281
2232
|
|
2282
2233
|
hash = rb_hash_new();
|
2283
|
-
relname =
|
2234
|
+
relname = rb_str_new2(notification->relname);
|
2284
2235
|
be_pid = INT2NUM(notification->be_pid);
|
2285
|
-
extra =
|
2286
|
-
PG_ENCODING_SET_NOCHECK( relname,
|
2287
|
-
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 );
|
2288
2239
|
|
2289
2240
|
rb_hash_aset(hash, sym_relname, relname);
|
2290
2241
|
rb_hash_aset(hash, sym_be_pid, be_pid);
|
@@ -2294,59 +2245,63 @@ pgconn_notifies(VALUE self)
|
|
2294
2245
|
return hash;
|
2295
2246
|
}
|
2296
2247
|
|
2297
|
-
|
2298
|
-
|
2299
|
-
/*
|
2300
|
-
*
|
2301
|
-
* instead of rb_thread_select().
|
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.
|
2302
2252
|
*/
|
2303
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
|
+
|
2304
2264
|
int rb_w32_wait_events( HANDLE *events, int num, DWORD timeout );
|
2305
2265
|
|
2306
|
-
|
2307
|
-
|
2308
|
-
*
|
2266
|
+
static VALUE
|
2267
|
+
pg_rb_thread_io_wait(VALUE io, VALUE events, VALUE timeout) {
|
2268
|
+
rb_io_t *fptr;
|
2269
|
+
struct timeval ptimeout;
|
2309
2270
|
|
2310
|
-
static void *
|
2311
|
-
wait_socket_readable( PGconn *conn, struct timeval *ptimeout, void *(*is_readable)(PGconn *) )
|
2312
|
-
{
|
2313
|
-
int sd = PQsocket( conn );
|
2314
|
-
void *retval;
|
2315
2271
|
struct timeval aborttime={0,0}, currtime, waittime;
|
2316
2272
|
DWORD timeout_milisec = INFINITE;
|
2317
|
-
|
2318
|
-
WSAEVENT hEvent;
|
2273
|
+
HANDLE hEvent = WSACreateEvent();
|
2319
2274
|
|
2320
|
-
|
2321
|
-
|
2322
|
-
|
2323
|
-
hEvent = WSACreateEvent();
|
2275
|
+
long rb_events = NUM2UINT(events);
|
2276
|
+
long w32_events = 0;
|
2277
|
+
DWORD wait_ret;
|
2324
2278
|
|
2325
|
-
|
2326
|
-
if(
|
2327
|
-
|
2328
|
-
|
2329
|
-
}
|
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);
|
2330
2283
|
|
2331
|
-
if ( ptimeout ) {
|
2332
2284
|
gettimeofday(&currtime, NULL);
|
2333
|
-
timeradd(&currtime, ptimeout, &aborttime);
|
2285
|
+
timeradd(&currtime, &ptimeout, &aborttime);
|
2334
2286
|
}
|
2335
2287
|
|
2336
|
-
|
2337
|
-
|
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 ) {
|
2338
2294
|
WSACloseEvent( hEvent );
|
2339
2295
|
rb_raise( rb_eConnectionBad, "WSAEventSelect socket error: %d", WSAGetLastError() );
|
2340
2296
|
}
|
2341
2297
|
|
2342
|
-
if (
|
2298
|
+
if ( !NIL_P(timeout) ) {
|
2343
2299
|
gettimeofday(&currtime, NULL);
|
2344
2300
|
timersub(&aborttime, &currtime, &waittime);
|
2345
2301
|
timeout_milisec = (DWORD)( waittime.tv_sec * 1e3 + waittime.tv_usec / 1e3 );
|
2346
2302
|
}
|
2347
2303
|
|
2348
|
-
|
2349
|
-
if( !ptimeout || (waittime.tv_sec >= 0 && waittime.tv_usec >= 0) ){
|
2304
|
+
if( NIL_P(timeout) || (waittime.tv_sec >= 0 && waittime.tv_usec >= 0) ){
|
2350
2305
|
/* Wait for the socket to become readable before checking again */
|
2351
2306
|
wait_ret = rb_w32_wait_events( &hEvent, 1, timeout_milisec );
|
2352
2307
|
} else {
|
@@ -2355,9 +2310,11 @@ wait_socket_readable( PGconn *conn, struct timeval *ptimeout, void *(*is_readabl
|
|
2355
2310
|
|
2356
2311
|
if ( wait_ret == WAIT_TIMEOUT ) {
|
2357
2312
|
WSACloseEvent( hEvent );
|
2358
|
-
return
|
2313
|
+
return UINT2NUM(0);
|
2359
2314
|
} else if ( wait_ret == WAIT_OBJECT_0 ) {
|
2315
|
+
WSACloseEvent( hEvent );
|
2360
2316
|
/* The event we were waiting for. */
|
2317
|
+
return UINT2NUM(rb_events);
|
2361
2318
|
} else if ( wait_ret == WAIT_OBJECT_0 + 1) {
|
2362
2319
|
/* This indicates interruption from timer thread, GC, exception
|
2363
2320
|
* from other threads etc... */
|
@@ -2369,39 +2326,66 @@ wait_socket_readable( PGconn *conn, struct timeval *ptimeout, void *(*is_readabl
|
|
2369
2326
|
WSACloseEvent( hEvent );
|
2370
2327
|
rb_raise( rb_eConnectionBad, "Wait on socket abandoned (WaitForMultipleObjects)" );
|
2371
2328
|
}
|
2372
|
-
|
2373
|
-
/* Check for connection errors (PQisBusy is true on connection errors) */
|
2374
|
-
if ( PQconsumeInput(conn) == 0 ) {
|
2375
|
-
WSACloseEvent( hEvent );
|
2376
|
-
rb_raise( rb_eConnectionBad, "PQconsumeInput() %s", PQerrorMessage(conn) );
|
2377
|
-
}
|
2378
2329
|
}
|
2330
|
+
}
|
2379
2331
|
|
2380
|
-
|
2381
|
-
|
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);
|
2382
2345
|
}
|
2383
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
|
+
|
2384
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;
|
2385
2363
|
|
2386
|
-
|
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
|
2387
2380
|
|
2388
2381
|
static void *
|
2389
|
-
wait_socket_readable(
|
2382
|
+
wait_socket_readable( VALUE self, struct timeval *ptimeout, void *(*is_readable)(PGconn *))
|
2390
2383
|
{
|
2391
|
-
|
2392
|
-
int ret;
|
2384
|
+
VALUE ret;
|
2393
2385
|
void *retval;
|
2394
|
-
rb_fdset_t sd_rset;
|
2395
2386
|
struct timeval aborttime={0,0}, currtime, waittime;
|
2396
|
-
|
2397
|
-
|
2398
|
-
rb_raise(rb_eConnectionBad, "PQsocket() can't get socket descriptor");
|
2399
|
-
|
2400
|
-
/* Check for connection errors (PQisBusy is true on connection errors) */
|
2401
|
-
if ( PQconsumeInput(conn) == 0 )
|
2402
|
-
rb_raise( rb_eConnectionBad, "PQconsumeInput() %s", PQerrorMessage(conn) );
|
2403
|
-
|
2404
|
-
rb_fd_init( &sd_rset );
|
2387
|
+
VALUE wait_timeout = Qnil;
|
2388
|
+
PGconn *conn = pg_get_pgconn(self);
|
2405
2389
|
|
2406
2390
|
if ( ptimeout ) {
|
2407
2391
|
gettimeofday(&currtime, NULL);
|
@@ -2409,46 +2393,84 @@ wait_socket_readable( PGconn *conn, struct timeval *ptimeout, void *(*is_readabl
|
|
2409
2393
|
}
|
2410
2394
|
|
2411
2395
|
while ( !(retval=is_readable(conn)) ) {
|
2412
|
-
rb_fd_zero( &sd_rset );
|
2413
|
-
rb_fd_set( sd, &sd_rset );
|
2414
|
-
|
2415
2396
|
if ( ptimeout ) {
|
2416
2397
|
gettimeofday(&currtime, NULL);
|
2417
2398
|
timersub(&aborttime, &currtime, &waittime);
|
2399
|
+
wait_timeout = DBL2NUM((double)(waittime.tv_sec) + (double)(waittime.tv_usec) / 1000000.0);
|
2418
2400
|
}
|
2419
2401
|
|
2420
2402
|
/* Is the given timeout valid? */
|
2421
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);
|
2422
2412
|
/* Wait for the socket to become readable before checking again */
|
2423
|
-
ret =
|
2413
|
+
ret = pg_rb_io_wait(socket_io, RB_INT2NUM(PG_RUBY_IO_READABLE), wait_timeout);
|
2424
2414
|
} else {
|
2425
|
-
ret =
|
2426
|
-
}
|
2427
|
-
|
2428
|
-
if ( ret < 0 ){
|
2429
|
-
rb_fd_term( &sd_rset );
|
2430
|
-
rb_sys_fail( "rb_thread_select()" );
|
2415
|
+
ret = Qfalse;
|
2431
2416
|
}
|
2432
2417
|
|
2433
2418
|
/* Return false if the select() timed out */
|
2434
|
-
if ( ret ==
|
2435
|
-
rb_fd_term( &sd_rset );
|
2419
|
+
if ( ret == Qfalse ){
|
2436
2420
|
return NULL;
|
2437
2421
|
}
|
2438
2422
|
|
2439
2423
|
/* Check for connection errors (PQisBusy is true on connection errors) */
|
2440
2424
|
if ( PQconsumeInput(conn) == 0 ){
|
2441
|
-
|
2442
|
-
|
2425
|
+
pgconn_close_socket_io(self);
|
2426
|
+
pg_raise_conn_error(rb_eConnectionBad, self, "PQconsumeInput() %s", PQerrorMessage(conn));
|
2443
2427
|
}
|
2444
2428
|
}
|
2445
2429
|
|
2446
|
-
rb_fd_term( &sd_rset );
|
2447
2430
|
return retval;
|
2448
2431
|
}
|
2449
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
|
+
}
|
2450
2458
|
|
2451
|
-
|
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
|
+
}
|
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
|
+
}
|
2452
2474
|
|
2453
2475
|
static void *
|
2454
2476
|
notify_readable(PGconn *conn)
|
@@ -2458,27 +2480,20 @@ notify_readable(PGconn *conn)
|
|
2458
2480
|
|
2459
2481
|
/*
|
2460
2482
|
* call-seq:
|
2461
|
-
* conn.wait_for_notify( [ timeout ] ) -> String
|
2462
|
-
* conn.wait_for_notify( [ timeout ] ) { |event, pid| block }
|
2463
|
-
* conn.wait_for_notify( [ timeout ] ) { |event, pid, payload| block } # PostgreSQL 9.0
|
2483
|
+
* conn.wait_for_notify( [ timeout ] ) { |event, pid, payload| block } -> String
|
2464
2484
|
*
|
2465
2485
|
* Blocks while waiting for notification(s), or until the optional
|
2466
2486
|
* _timeout_ is reached, whichever comes first. _timeout_ is
|
2467
2487
|
* measured in seconds and can be fractional.
|
2468
2488
|
*
|
2469
|
-
* Returns +nil+ if _timeout_ is reached, the name of the NOTIFY
|
2470
|
-
*
|
2471
|
-
*
|
2472
|
-
*
|
2473
|
-
* Under PostgreSQL 9.0 and later, if the notification is sent with
|
2474
|
-
* the optional +payload+ string, it will be given to the block as the
|
2475
|
-
* third argument.
|
2476
|
-
*
|
2489
|
+
* Returns +nil+ if _timeout_ is reached, the name of the NOTIFY event otherwise.
|
2490
|
+
* If used in block form, passes the name of the NOTIFY +event+, the generating
|
2491
|
+
* +pid+ and the optional +payload+ string into the block.
|
2477
2492
|
*/
|
2478
2493
|
static VALUE
|
2479
2494
|
pgconn_wait_for_notify(int argc, VALUE *argv, VALUE self)
|
2480
2495
|
{
|
2481
|
-
|
2496
|
+
t_pg_connection *this = pg_get_connection_safe( self );
|
2482
2497
|
PGnotify *pnotification;
|
2483
2498
|
struct timeval timeout;
|
2484
2499
|
struct timeval *ptimeout = NULL;
|
@@ -2494,17 +2509,17 @@ pgconn_wait_for_notify(int argc, VALUE *argv, VALUE self)
|
|
2494
2509
|
ptimeout = &timeout;
|
2495
2510
|
}
|
2496
2511
|
|
2497
|
-
pnotification = (PGnotify*) wait_socket_readable(
|
2512
|
+
pnotification = (PGnotify*) wait_socket_readable( self, ptimeout, notify_readable);
|
2498
2513
|
|
2499
2514
|
/* Return nil if the select timed out */
|
2500
2515
|
if ( !pnotification ) return Qnil;
|
2501
2516
|
|
2502
|
-
relname =
|
2503
|
-
PG_ENCODING_SET_NOCHECK( relname,
|
2517
|
+
relname = rb_str_new2( pnotification->relname );
|
2518
|
+
PG_ENCODING_SET_NOCHECK( relname, this->enc_idx );
|
2504
2519
|
be_pid = INT2NUM( pnotification->be_pid );
|
2505
2520
|
if ( *pnotification->extra ) {
|
2506
|
-
extra =
|
2507
|
-
PG_ENCODING_SET_NOCHECK( extra,
|
2521
|
+
extra = rb_str_new2( pnotification->extra );
|
2522
|
+
PG_ENCODING_SET_NOCHECK( extra, this->enc_idx );
|
2508
2523
|
}
|
2509
2524
|
PQfreemem( pnotification );
|
2510
2525
|
|
@@ -2515,28 +2530,8 @@ pgconn_wait_for_notify(int argc, VALUE *argv, VALUE self)
|
|
2515
2530
|
}
|
2516
2531
|
|
2517
2532
|
|
2518
|
-
/*
|
2519
|
-
* call-seq:
|
2520
|
-
* conn.put_copy_data( buffer [, encoder] ) -> Boolean
|
2521
|
-
*
|
2522
|
-
* Transmits _buffer_ as copy data to the server.
|
2523
|
-
* Returns true if the data was sent, false if it was
|
2524
|
-
* not sent (false is only possible if the connection
|
2525
|
-
* is in nonblocking mode, and this command would block).
|
2526
|
-
*
|
2527
|
-
* _encoder_ can be a PG::Coder derivation (typically PG::TextEncoder::CopyRow).
|
2528
|
-
* This encodes the data fields given as _buffer_ from an Array of Strings to
|
2529
|
-
* PostgreSQL's COPY text format inclusive proper escaping. Optionally
|
2530
|
-
* the encoder can type cast the fields from various Ruby types in one step,
|
2531
|
-
* if PG::TextEncoder::CopyRow#type_map is set accordingly.
|
2532
|
-
*
|
2533
|
-
* Raises an exception if an error occurs.
|
2534
|
-
*
|
2535
|
-
* See also #copy_data.
|
2536
|
-
*
|
2537
|
-
*/
|
2538
2533
|
static VALUE
|
2539
|
-
|
2534
|
+
pgconn_sync_put_copy_data(int argc, VALUE *argv, VALUE self)
|
2540
2535
|
{
|
2541
2536
|
int ret;
|
2542
2537
|
int len;
|
@@ -2553,18 +2548,16 @@ pgconn_put_copy_data(int argc, VALUE *argv, VALUE self)
|
|
2553
2548
|
if( NIL_P(this->encoder_for_put_copy_data) ){
|
2554
2549
|
buffer = value;
|
2555
2550
|
} else {
|
2556
|
-
p_coder =
|
2551
|
+
p_coder = RTYPEDDATA_DATA( this->encoder_for_put_copy_data );
|
2557
2552
|
}
|
2558
|
-
} else if( rb_obj_is_kind_of(encoder, rb_cPG_Coder) ) {
|
2559
|
-
Data_Get_Struct( encoder, t_pg_coder, p_coder );
|
2560
2553
|
} else {
|
2561
|
-
|
2562
|
-
|
2554
|
+
/* Check argument type and use argument encoder */
|
2555
|
+
TypedData_Get_Struct(encoder, t_pg_coder, &pg_coder_type, p_coder);
|
2563
2556
|
}
|
2564
2557
|
|
2565
2558
|
if( p_coder ){
|
2566
2559
|
t_pg_coder_enc_func enc_func;
|
2567
|
-
int enc_idx =
|
2560
|
+
int enc_idx = this->enc_idx;
|
2568
2561
|
|
2569
2562
|
enc_func = pg_coder_enc_func( p_coder );
|
2570
2563
|
len = enc_func( p_coder, value, NULL, &intermediate, enc_idx);
|
@@ -2582,76 +2575,39 @@ pgconn_put_copy_data(int argc, VALUE *argv, VALUE self)
|
|
2582
2575
|
Check_Type(buffer, T_STRING);
|
2583
2576
|
|
2584
2577
|
ret = gvl_PQputCopyData(this->pgconn, RSTRING_PTR(buffer), RSTRING_LENINT(buffer));
|
2585
|
-
if(ret == -1)
|
2586
|
-
|
2587
|
-
|
2588
|
-
rb_exc_raise(error);
|
2589
|
-
}
|
2578
|
+
if(ret == -1)
|
2579
|
+
pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(this->pgconn));
|
2580
|
+
|
2590
2581
|
RB_GC_GUARD(intermediate);
|
2591
2582
|
RB_GC_GUARD(buffer);
|
2592
2583
|
|
2593
2584
|
return (ret) ? Qtrue : Qfalse;
|
2594
2585
|
}
|
2595
2586
|
|
2596
|
-
/*
|
2597
|
-
* call-seq:
|
2598
|
-
* conn.put_copy_end( [ error_message ] ) -> Boolean
|
2599
|
-
*
|
2600
|
-
* Sends end-of-data indication to the server.
|
2601
|
-
*
|
2602
|
-
* _error_message_ is an optional parameter, and if set,
|
2603
|
-
* forces the COPY command to fail with the string
|
2604
|
-
* _error_message_.
|
2605
|
-
*
|
2606
|
-
* Returns true if the end-of-data was sent, false if it was
|
2607
|
-
* not sent (false is only possible if the connection
|
2608
|
-
* is in nonblocking mode, and this command would block).
|
2609
|
-
*/
|
2610
2587
|
static VALUE
|
2611
|
-
|
2588
|
+
pgconn_sync_put_copy_end(int argc, VALUE *argv, VALUE self)
|
2612
2589
|
{
|
2613
2590
|
VALUE str;
|
2614
|
-
VALUE error;
|
2615
2591
|
int ret;
|
2616
2592
|
const char *error_message = NULL;
|
2617
|
-
|
2593
|
+
t_pg_connection *this = pg_get_connection_safe( self );
|
2618
2594
|
|
2619
2595
|
if (rb_scan_args(argc, argv, "01", &str) == 0)
|
2620
2596
|
error_message = NULL;
|
2621
2597
|
else
|
2622
|
-
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));
|
2623
2603
|
|
2624
|
-
ret = gvl_PQputCopyEnd(conn, error_message);
|
2625
|
-
if(ret == -1) {
|
2626
|
-
error = rb_exc_new2(rb_ePGerror, PQerrorMessage(conn));
|
2627
|
-
rb_iv_set(error, "@connection", self);
|
2628
|
-
rb_exc_raise(error);
|
2629
|
-
}
|
2630
2604
|
return (ret) ? Qtrue : Qfalse;
|
2631
2605
|
}
|
2632
2606
|
|
2633
|
-
/*
|
2634
|
-
* call-seq:
|
2635
|
-
* conn.get_copy_data( [ async = false [, decoder = nil ]] ) -> String
|
2636
|
-
*
|
2637
|
-
* Return a string containing one row of data, +nil+
|
2638
|
-
* if the copy is done, or +false+ if the call would
|
2639
|
-
* block (only possible if _async_ is true).
|
2640
|
-
*
|
2641
|
-
* _decoder_ can be a PG::Coder derivation (typically PG::TextDecoder::CopyRow).
|
2642
|
-
* This decodes the received data fields from PostgreSQL's COPY text format to an
|
2643
|
-
* Array of Strings. Optionally
|
2644
|
-
* the decoder can type cast the fields to various Ruby types in one step,
|
2645
|
-
* if PG::TextDecoder::CopyRow#type_map is set accordingly.
|
2646
|
-
*
|
2647
|
-
* See also #copy_data.
|
2648
|
-
*
|
2649
|
-
*/
|
2650
2607
|
static VALUE
|
2651
|
-
|
2608
|
+
pgconn_sync_get_copy_data(int argc, VALUE *argv, VALUE self )
|
2652
2609
|
{
|
2653
2610
|
VALUE async_in;
|
2654
|
-
VALUE error;
|
2655
2611
|
VALUE result;
|
2656
2612
|
int ret;
|
2657
2613
|
char *buffer;
|
@@ -2663,20 +2619,16 @@ pgconn_get_copy_data(int argc, VALUE *argv, VALUE self )
|
|
2663
2619
|
|
2664
2620
|
if( NIL_P(decoder) ){
|
2665
2621
|
if( !NIL_P(this->decoder_for_get_copy_data) ){
|
2666
|
-
p_coder =
|
2622
|
+
p_coder = RTYPEDDATA_DATA( this->decoder_for_get_copy_data );
|
2667
2623
|
}
|
2668
|
-
} else if( rb_obj_is_kind_of(decoder, rb_cPG_Coder) ) {
|
2669
|
-
Data_Get_Struct( decoder, t_pg_coder, p_coder );
|
2670
2624
|
} else {
|
2671
|
-
|
2672
|
-
|
2625
|
+
/* Check argument type and use argument decoder */
|
2626
|
+
TypedData_Get_Struct(decoder, t_pg_coder, &pg_coder_type, p_coder);
|
2673
2627
|
}
|
2674
2628
|
|
2675
2629
|
ret = gvl_PQgetCopyData(this->pgconn, &buffer, RTEST(async_in));
|
2676
|
-
if(ret == -2)
|
2677
|
-
|
2678
|
-
rb_iv_set(error, "@connection", self);
|
2679
|
-
rb_exc_raise(error);
|
2630
|
+
if(ret == -2){ /* error */
|
2631
|
+
pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(this->pgconn));
|
2680
2632
|
}
|
2681
2633
|
if(ret == -1) { /* No data left */
|
2682
2634
|
return Qnil;
|
@@ -2687,9 +2639,9 @@ pgconn_get_copy_data(int argc, VALUE *argv, VALUE self )
|
|
2687
2639
|
|
2688
2640
|
if( p_coder ){
|
2689
2641
|
t_pg_coder_dec_func dec_func = pg_coder_dec_func( p_coder, p_coder->format );
|
2690
|
-
result = dec_func( p_coder, buffer, ret, 0, 0,
|
2642
|
+
result = dec_func( p_coder, buffer, ret, 0, 0, this->enc_idx );
|
2691
2643
|
} else {
|
2692
|
-
result =
|
2644
|
+
result = rb_str_new(buffer, ret);
|
2693
2645
|
}
|
2694
2646
|
|
2695
2647
|
PQfreemem(buffer);
|
@@ -2702,9 +2654,16 @@ pgconn_get_copy_data(int argc, VALUE *argv, VALUE self )
|
|
2702
2654
|
*
|
2703
2655
|
* Sets connection's verbosity to _verbosity_ and returns
|
2704
2656
|
* the previous setting. Available settings are:
|
2657
|
+
*
|
2705
2658
|
* * PQERRORS_TERSE
|
2706
2659
|
* * PQERRORS_DEFAULT
|
2707
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].
|
2708
2667
|
*/
|
2709
2668
|
static VALUE
|
2710
2669
|
pgconn_set_error_verbosity(VALUE self, VALUE in_verbosity)
|
@@ -2714,6 +2673,37 @@ pgconn_set_error_verbosity(VALUE self, VALUE in_verbosity)
|
|
2714
2673
|
return INT2FIX(PQsetErrorVerbosity(conn, verbosity));
|
2715
2674
|
}
|
2716
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
|
+
|
2717
2707
|
/*
|
2718
2708
|
* call-seq:
|
2719
2709
|
* conn.trace( stream ) -> nil
|
@@ -2732,7 +2722,8 @@ pgconn_trace(VALUE self, VALUE stream)
|
|
2732
2722
|
VALUE new_file;
|
2733
2723
|
t_pg_connection *this = pg_get_connection_safe( self );
|
2734
2724
|
|
2735
|
-
|
2725
|
+
rb_check_frozen(self);
|
2726
|
+
if(!rb_respond_to(stream,rb_intern("fileno")))
|
2736
2727
|
rb_raise(rb_eArgError, "stream does not respond to method: fileno");
|
2737
2728
|
|
2738
2729
|
fileno = rb_funcall(stream, rb_intern("fileno"), 0);
|
@@ -2753,7 +2744,7 @@ pgconn_trace(VALUE self, VALUE stream)
|
|
2753
2744
|
rb_raise(rb_eArgError, "stream is not writable");
|
2754
2745
|
|
2755
2746
|
new_file = rb_funcall(rb_cIO, rb_intern("new"), 1, INT2NUM(new_fd));
|
2756
|
-
this->trace_stream
|
2747
|
+
RB_OBJ_WRITE(self, &this->trace_stream, new_file);
|
2757
2748
|
|
2758
2749
|
PQtrace(this->pgconn, new_fp);
|
2759
2750
|
return Qnil;
|
@@ -2772,7 +2763,7 @@ pgconn_untrace(VALUE self)
|
|
2772
2763
|
|
2773
2764
|
PQuntrace(this->pgconn);
|
2774
2765
|
rb_funcall(this->trace_stream, rb_intern("close"), 0);
|
2775
|
-
this->trace_stream
|
2766
|
+
RB_OBJ_WRITE(self, &this->trace_stream, Qnil);
|
2776
2767
|
return Qnil;
|
2777
2768
|
}
|
2778
2769
|
|
@@ -2831,13 +2822,14 @@ pgconn_set_notice_receiver(VALUE self)
|
|
2831
2822
|
VALUE proc, old_proc;
|
2832
2823
|
t_pg_connection *this = pg_get_connection_safe( self );
|
2833
2824
|
|
2825
|
+
rb_check_frozen(self);
|
2834
2826
|
/* If default_notice_receiver is unset, assume that the current
|
2835
2827
|
* notice receiver is the default, and save it to a global variable.
|
2836
2828
|
* This should not be a problem because the default receiver is
|
2837
2829
|
* always the same, so won't vary among connections.
|
2838
2830
|
*/
|
2839
|
-
if(default_notice_receiver == NULL)
|
2840
|
-
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);
|
2841
2833
|
|
2842
2834
|
old_proc = this->notice_receiver;
|
2843
2835
|
if( rb_block_given_p() ) {
|
@@ -2846,10 +2838,10 @@ pgconn_set_notice_receiver(VALUE self)
|
|
2846
2838
|
} else {
|
2847
2839
|
/* if no block is given, set back to default */
|
2848
2840
|
proc = Qnil;
|
2849
|
-
PQsetNoticeReceiver(this->pgconn, default_notice_receiver, NULL);
|
2841
|
+
PQsetNoticeReceiver(this->pgconn, this->default_notice_receiver, NULL);
|
2850
2842
|
}
|
2851
2843
|
|
2852
|
-
this->notice_receiver
|
2844
|
+
RB_OBJ_WRITE(self, &this->notice_receiver, proc);
|
2853
2845
|
return old_proc;
|
2854
2846
|
}
|
2855
2847
|
|
@@ -2864,10 +2856,10 @@ notice_processor_proxy(void *arg, const char *message)
|
|
2864
2856
|
VALUE self = (VALUE)arg;
|
2865
2857
|
t_pg_connection *this = pg_get_connection( self );
|
2866
2858
|
|
2867
|
-
if (this->
|
2868
|
-
VALUE message_str =
|
2869
|
-
PG_ENCODING_SET_NOCHECK( message_str,
|
2870
|
-
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);
|
2871
2863
|
}
|
2872
2864
|
return;
|
2873
2865
|
}
|
@@ -2876,7 +2868,7 @@ notice_processor_proxy(void *arg, const char *message)
|
|
2876
2868
|
* call-seq:
|
2877
2869
|
* conn.set_notice_processor {|message| ... } -> Proc
|
2878
2870
|
*
|
2879
|
-
* See #set_notice_receiver for the
|
2871
|
+
* See #set_notice_receiver for the description of what this and the
|
2880
2872
|
* notice_processor methods do.
|
2881
2873
|
*
|
2882
2874
|
* This function takes a new block to act as the notice processor and returns
|
@@ -2891,25 +2883,26 @@ pgconn_set_notice_processor(VALUE self)
|
|
2891
2883
|
VALUE proc, old_proc;
|
2892
2884
|
t_pg_connection *this = pg_get_connection_safe( self );
|
2893
2885
|
|
2886
|
+
rb_check_frozen(self);
|
2894
2887
|
/* If default_notice_processor is unset, assume that the current
|
2895
2888
|
* notice processor is the default, and save it to a global variable.
|
2896
2889
|
* This should not be a problem because the default processor is
|
2897
2890
|
* always the same, so won't vary among connections.
|
2898
2891
|
*/
|
2899
|
-
if(default_notice_processor == NULL)
|
2900
|
-
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);
|
2901
2894
|
|
2902
|
-
old_proc = this->
|
2895
|
+
old_proc = this->notice_processor;
|
2903
2896
|
if( rb_block_given_p() ) {
|
2904
2897
|
proc = rb_block_proc();
|
2905
2898
|
PQsetNoticeProcessor(this->pgconn, gvl_notice_processor_proxy, (void *)self);
|
2906
2899
|
} else {
|
2907
2900
|
/* if no block is given, set back to default */
|
2908
2901
|
proc = Qnil;
|
2909
|
-
PQsetNoticeProcessor(this->pgconn, default_notice_processor, NULL);
|
2902
|
+
PQsetNoticeProcessor(this->pgconn, this->default_notice_processor, NULL);
|
2910
2903
|
}
|
2911
2904
|
|
2912
|
-
this->
|
2905
|
+
RB_OBJ_WRITE(self, &this->notice_processor, proc);
|
2913
2906
|
return old_proc;
|
2914
2907
|
}
|
2915
2908
|
|
@@ -2924,81 +2917,41 @@ static VALUE
|
|
2924
2917
|
pgconn_get_client_encoding(VALUE self)
|
2925
2918
|
{
|
2926
2919
|
char *encoding = (char *)pg_encoding_to_char(PQclientEncoding(pg_get_pgconn(self)));
|
2927
|
-
return
|
2920
|
+
return rb_str_new2(encoding);
|
2928
2921
|
}
|
2929
2922
|
|
2930
2923
|
|
2931
2924
|
/*
|
2932
2925
|
* call-seq:
|
2933
|
-
* conn.
|
2926
|
+
* conn.sync_set_client_encoding( encoding )
|
2934
2927
|
*
|
2935
|
-
*
|
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.
|
2936
2931
|
*/
|
2937
2932
|
static VALUE
|
2938
|
-
|
2933
|
+
pgconn_sync_set_client_encoding(VALUE self, VALUE str)
|
2939
2934
|
{
|
2940
2935
|
PGconn *conn = pg_get_pgconn( self );
|
2941
2936
|
|
2937
|
+
rb_check_frozen(self);
|
2942
2938
|
Check_Type(str, T_STRING);
|
2943
2939
|
|
2944
|
-
if ( (gvl_PQsetClientEncoding(conn, StringValueCStr(str))) == -1 )
|
2945
|
-
|
2946
|
-
|
2940
|
+
if ( (gvl_PQsetClientEncoding(conn, StringValueCStr(str))) == -1 )
|
2941
|
+
pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(conn));
|
2942
|
+
|
2947
2943
|
pgconn_set_internal_encoding_index( self );
|
2948
2944
|
|
2949
2945
|
return Qnil;
|
2950
2946
|
}
|
2951
2947
|
|
2948
|
+
|
2952
2949
|
/*
|
2953
2950
|
* call-seq:
|
2954
|
-
* conn.
|
2955
|
-
*
|
2956
|
-
*
|
2957
|
-
*
|
2958
|
-
* +ROLLBACK+ if any exception occurs.
|
2959
|
-
*/
|
2960
|
-
static VALUE
|
2961
|
-
pgconn_transaction(VALUE self)
|
2962
|
-
{
|
2963
|
-
PGconn *conn = pg_get_pgconn(self);
|
2964
|
-
PGresult *result;
|
2965
|
-
VALUE rb_pgresult;
|
2966
|
-
VALUE block_result = Qnil;
|
2967
|
-
int status;
|
2968
|
-
|
2969
|
-
if (rb_block_given_p()) {
|
2970
|
-
result = gvl_PQexec(conn, "BEGIN");
|
2971
|
-
rb_pgresult = pg_new_result(result, self);
|
2972
|
-
pg_result_check(rb_pgresult);
|
2973
|
-
block_result = rb_protect(rb_yield, self, &status);
|
2974
|
-
if(status == 0) {
|
2975
|
-
result = gvl_PQexec(conn, "COMMIT");
|
2976
|
-
rb_pgresult = pg_new_result(result, self);
|
2977
|
-
pg_result_check(rb_pgresult);
|
2978
|
-
}
|
2979
|
-
else {
|
2980
|
-
/* exception occurred, ROLLBACK and re-raise */
|
2981
|
-
result = gvl_PQexec(conn, "ROLLBACK");
|
2982
|
-
rb_pgresult = pg_new_result(result, self);
|
2983
|
-
pg_result_check(rb_pgresult);
|
2984
|
-
rb_jump_tag(status);
|
2985
|
-
}
|
2986
|
-
|
2987
|
-
}
|
2988
|
-
else {
|
2989
|
-
/* no block supplied? */
|
2990
|
-
rb_raise(rb_eArgError, "Must supply block for PG::Connection#transaction");
|
2991
|
-
}
|
2992
|
-
return block_result;
|
2993
|
-
}
|
2994
|
-
|
2995
|
-
|
2996
|
-
/*
|
2997
|
-
* call-seq:
|
2998
|
-
* conn.quote_ident( str ) -> String
|
2999
|
-
* conn.quote_ident( array ) -> String
|
3000
|
-
* PG::Connection.quote_ident( str ) -> String
|
3001
|
-
* PG::Connection.quote_ident( array ) -> String
|
2951
|
+
* conn.quote_ident( str ) -> String
|
2952
|
+
* conn.quote_ident( array ) -> String
|
2953
|
+
* PG::Connection.quote_ident( str ) -> String
|
2954
|
+
* PG::Connection.quote_ident( array ) -> String
|
3002
2955
|
*
|
3003
2956
|
* Returns a string that is safe for inclusion in a SQL query as an
|
3004
2957
|
* identifier. Note: this is not a quote function for values, but for
|
@@ -3036,14 +2989,12 @@ pgconn_s_quote_ident(VALUE self, VALUE str_or_array)
|
|
3036
2989
|
int enc_idx;
|
3037
2990
|
|
3038
2991
|
if( rb_obj_is_kind_of(self, rb_cPGconn) ){
|
3039
|
-
enc_idx =
|
2992
|
+
enc_idx = pg_get_connection(self)->enc_idx;
|
3040
2993
|
}else{
|
3041
2994
|
enc_idx = RB_TYPE_P(str_or_array, T_STRING) ? ENCODING_GET( str_or_array ) : rb_ascii8bit_encindex();
|
3042
2995
|
}
|
3043
2996
|
pg_text_enc_identifier(NULL, str_or_array, NULL, &ret, enc_idx);
|
3044
2997
|
|
3045
|
-
OBJ_INFECT(ret, str_or_array);
|
3046
|
-
|
3047
2998
|
return ret;
|
3048
2999
|
}
|
3049
3000
|
|
@@ -3068,14 +3019,8 @@ get_result_readable(PGconn *conn)
|
|
3068
3019
|
* If +true+ is returned, +conn.is_busy+ will return +false+
|
3069
3020
|
* and +conn.get_result+ will not block.
|
3070
3021
|
*/
|
3071
|
-
|
3022
|
+
VALUE
|
3072
3023
|
pgconn_block( int argc, VALUE *argv, VALUE self ) {
|
3073
|
-
PGconn *conn = pg_get_pgconn( self );
|
3074
|
-
|
3075
|
-
/* If WIN32 and Ruby 1.9 do not use rb_thread_select() which sometimes hangs
|
3076
|
-
* and does not wait (nor sleep) any time even if timeout is given.
|
3077
|
-
* Instead use the Winsock events and rb_w32_wait_events(). */
|
3078
|
-
|
3079
3024
|
struct timeval timeout;
|
3080
3025
|
struct timeval *ptimeout = NULL;
|
3081
3026
|
VALUE timeout_in;
|
@@ -3089,7 +3034,7 @@ pgconn_block( int argc, VALUE *argv, VALUE self ) {
|
|
3089
3034
|
ptimeout = &timeout;
|
3090
3035
|
}
|
3091
3036
|
|
3092
|
-
ret = wait_socket_readable(
|
3037
|
+
ret = wait_socket_readable( self, ptimeout, get_result_readable);
|
3093
3038
|
|
3094
3039
|
if( !ret )
|
3095
3040
|
return Qfalse;
|
@@ -3098,6 +3043,42 @@ pgconn_block( int argc, VALUE *argv, VALUE self ) {
|
|
3098
3043
|
}
|
3099
3044
|
|
3100
3045
|
|
3046
|
+
/*
|
3047
|
+
* call-seq:
|
3048
|
+
* conn.sync_get_last_result( ) -> PG::Result
|
3049
|
+
*
|
3050
|
+
* This function has the same behavior as #async_get_last_result, but is implemented using the synchronous command processing API of libpq.
|
3051
|
+
* See #async_exec for the differences between the two API variants.
|
3052
|
+
* It's not recommended to use explicit sync or async variants but #get_last_result instead, unless you have a good reason to do so.
|
3053
|
+
*/
|
3054
|
+
static VALUE
|
3055
|
+
pgconn_sync_get_last_result(VALUE self)
|
3056
|
+
{
|
3057
|
+
PGconn *conn = pg_get_pgconn(self);
|
3058
|
+
VALUE rb_pgresult = Qnil;
|
3059
|
+
PGresult *cur, *prev;
|
3060
|
+
|
3061
|
+
|
3062
|
+
cur = prev = NULL;
|
3063
|
+
while ((cur = gvl_PQgetResult(conn)) != NULL) {
|
3064
|
+
int status;
|
3065
|
+
|
3066
|
+
if (prev) PQclear(prev);
|
3067
|
+
prev = cur;
|
3068
|
+
|
3069
|
+
status = PQresultStatus(cur);
|
3070
|
+
if (status == PGRES_COPY_OUT || status == PGRES_COPY_IN || status == PGRES_COPY_BOTH)
|
3071
|
+
break;
|
3072
|
+
}
|
3073
|
+
|
3074
|
+
if (prev) {
|
3075
|
+
rb_pgresult = pg_new_result( prev, self );
|
3076
|
+
pg_result_check(rb_pgresult);
|
3077
|
+
}
|
3078
|
+
|
3079
|
+
return rb_pgresult;
|
3080
|
+
}
|
3081
|
+
|
3101
3082
|
/*
|
3102
3083
|
* call-seq:
|
3103
3084
|
* conn.get_last_result( ) -> PG::Result
|
@@ -3108,27 +3089,36 @@ pgconn_block( int argc, VALUE *argv, VALUE self ) {
|
|
3108
3089
|
* returns the last non-NULL result, or +nil+ if no
|
3109
3090
|
* results are available.
|
3110
3091
|
*
|
3092
|
+
* If the last result contains a bad result_status, an
|
3093
|
+
* appropriate exception is raised.
|
3094
|
+
*
|
3111
3095
|
* This function is similar to #get_result
|
3112
3096
|
* except that it is designed to get one and only
|
3113
|
-
* one result.
|
3097
|
+
* one result and that it checks the result state.
|
3114
3098
|
*/
|
3115
3099
|
static VALUE
|
3116
|
-
|
3100
|
+
pgconn_async_get_last_result(VALUE self)
|
3117
3101
|
{
|
3118
3102
|
PGconn *conn = pg_get_pgconn(self);
|
3119
3103
|
VALUE rb_pgresult = Qnil;
|
3120
3104
|
PGresult *cur, *prev;
|
3121
3105
|
|
3122
|
-
|
3123
3106
|
cur = prev = NULL;
|
3124
|
-
|
3107
|
+
for(;;) {
|
3125
3108
|
int status;
|
3126
3109
|
|
3110
|
+
/* wait for input (without blocking) before reading each result */
|
3111
|
+
wait_socket_readable(self, NULL, get_result_readable);
|
3112
|
+
|
3113
|
+
cur = gvl_PQgetResult(conn);
|
3114
|
+
if (cur == NULL)
|
3115
|
+
break;
|
3116
|
+
|
3127
3117
|
if (prev) PQclear(prev);
|
3128
3118
|
prev = cur;
|
3129
3119
|
|
3130
3120
|
status = PQresultStatus(cur);
|
3131
|
-
if (status == PGRES_COPY_OUT || status == PGRES_COPY_IN)
|
3121
|
+
if (status == PGRES_COPY_OUT || status == PGRES_COPY_IN || status == PGRES_COPY_BOTH)
|
3132
3122
|
break;
|
3133
3123
|
}
|
3134
3124
|
|
@@ -3142,25 +3132,343 @@ pgconn_get_last_result(VALUE self)
|
|
3142
3132
|
|
3143
3133
|
/*
|
3144
3134
|
* call-seq:
|
3145
|
-
* conn.
|
3146
|
-
*
|
3135
|
+
* conn.discard_results()
|
3136
|
+
*
|
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.
|
3140
|
+
*
|
3141
|
+
* Returns:
|
3142
|
+
* * +nil+ when the connection is already idle
|
3143
|
+
* * +true+ when some results have been discarded
|
3144
|
+
* * +false+ when a failure occured and the connection was closed
|
3145
|
+
*
|
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.
|
3147
3237
|
*
|
3148
|
-
*
|
3149
|
-
*
|
3150
|
-
*
|
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].
|
3151
3252
|
*/
|
3152
3253
|
static VALUE
|
3153
3254
|
pgconn_async_exec(int argc, VALUE *argv, VALUE self)
|
3154
3255
|
{
|
3155
3256
|
VALUE rb_pgresult = Qnil;
|
3156
3257
|
|
3157
|
-
|
3158
|
-
pgconn_block( 0, NULL, self ); /* wait for input (without blocking) before reading the last result */
|
3159
|
-
pgconn_get_last_result( self );
|
3160
|
-
|
3258
|
+
pgconn_discard_results( self );
|
3161
3259
|
pgconn_send_query( argc, argv, self );
|
3162
|
-
|
3163
|
-
|
3260
|
+
rb_pgresult = pgconn_async_get_last_result( self );
|
3261
|
+
|
3262
|
+
if ( rb_block_given_p() ) {
|
3263
|
+
return rb_ensure( rb_yield, rb_pgresult, pg_result_clear, rb_pgresult );
|
3264
|
+
}
|
3265
|
+
return rb_pgresult;
|
3266
|
+
}
|
3267
|
+
|
3268
|
+
|
3269
|
+
/*
|
3270
|
+
* call-seq:
|
3271
|
+
* conn.exec_params(sql, params [, result_format [, type_map ]] ) -> nil
|
3272
|
+
* conn.exec_params(sql, params [, result_format [, type_map ]] ) {|pg_result| block }
|
3273
|
+
*
|
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].
|
3318
|
+
*/
|
3319
|
+
static VALUE
|
3320
|
+
pgconn_async_exec_params(int argc, VALUE *argv, VALUE self)
|
3321
|
+
{
|
3322
|
+
VALUE rb_pgresult = Qnil;
|
3323
|
+
|
3324
|
+
pgconn_discard_results( self );
|
3325
|
+
/* If called with no or nil parameters, use PQsendQuery for compatibility */
|
3326
|
+
if ( argc == 1 || (argc >= 2 && argc <= 4 && NIL_P(argv[1]) )) {
|
3327
|
+
pg_deprecated(3, ("forwarding async_exec_params to async_exec is deprecated"));
|
3328
|
+
pgconn_send_query( argc, argv, self );
|
3329
|
+
} else {
|
3330
|
+
pgconn_send_query_params( argc, argv, self );
|
3331
|
+
}
|
3332
|
+
rb_pgresult = pgconn_async_get_last_result( self );
|
3333
|
+
|
3334
|
+
if ( rb_block_given_p() ) {
|
3335
|
+
return rb_ensure( rb_yield, rb_pgresult, pg_result_clear, rb_pgresult );
|
3336
|
+
}
|
3337
|
+
return rb_pgresult;
|
3338
|
+
}
|
3339
|
+
|
3340
|
+
|
3341
|
+
/*
|
3342
|
+
* call-seq:
|
3343
|
+
* conn.prepare(stmt_name, sql [, param_types ] ) -> PG::Result
|
3344
|
+
*
|
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].
|
3362
|
+
*/
|
3363
|
+
static VALUE
|
3364
|
+
pgconn_async_prepare(int argc, VALUE *argv, VALUE self)
|
3365
|
+
{
|
3366
|
+
VALUE rb_pgresult = Qnil;
|
3367
|
+
|
3368
|
+
pgconn_discard_results( self );
|
3369
|
+
pgconn_send_prepare( argc, argv, self );
|
3370
|
+
rb_pgresult = pgconn_async_get_last_result( self );
|
3371
|
+
|
3372
|
+
if ( rb_block_given_p() ) {
|
3373
|
+
return rb_ensure( rb_yield, rb_pgresult, pg_result_clear, rb_pgresult );
|
3374
|
+
}
|
3375
|
+
return rb_pgresult;
|
3376
|
+
}
|
3377
|
+
|
3378
|
+
|
3379
|
+
/*
|
3380
|
+
* call-seq:
|
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 }
|
3383
|
+
*
|
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].
|
3415
|
+
*/
|
3416
|
+
static VALUE
|
3417
|
+
pgconn_async_exec_prepared(int argc, VALUE *argv, VALUE self)
|
3418
|
+
{
|
3419
|
+
VALUE rb_pgresult = Qnil;
|
3420
|
+
|
3421
|
+
pgconn_discard_results( self );
|
3422
|
+
pgconn_send_query_prepared( argc, argv, self );
|
3423
|
+
rb_pgresult = pgconn_async_get_last_result( self );
|
3424
|
+
|
3425
|
+
if ( rb_block_given_p() ) {
|
3426
|
+
return rb_ensure( rb_yield, rb_pgresult, pg_result_clear, rb_pgresult );
|
3427
|
+
}
|
3428
|
+
return rb_pgresult;
|
3429
|
+
}
|
3430
|
+
|
3431
|
+
|
3432
|
+
/*
|
3433
|
+
* call-seq:
|
3434
|
+
* conn.describe_portal( portal_name ) -> PG::Result
|
3435
|
+
*
|
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].
|
3439
|
+
*/
|
3440
|
+
static VALUE
|
3441
|
+
pgconn_async_describe_portal(VALUE self, VALUE portal)
|
3442
|
+
{
|
3443
|
+
VALUE rb_pgresult = Qnil;
|
3444
|
+
|
3445
|
+
pgconn_discard_results( self );
|
3446
|
+
pgconn_send_describe_portal( self, portal );
|
3447
|
+
rb_pgresult = pgconn_async_get_last_result( self );
|
3448
|
+
|
3449
|
+
if ( rb_block_given_p() ) {
|
3450
|
+
return rb_ensure( rb_yield, rb_pgresult, pg_result_clear, rb_pgresult );
|
3451
|
+
}
|
3452
|
+
return rb_pgresult;
|
3453
|
+
}
|
3454
|
+
|
3455
|
+
|
3456
|
+
/*
|
3457
|
+
* call-seq:
|
3458
|
+
* conn.describe_prepared( statement_name ) -> PG::Result
|
3459
|
+
*
|
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].
|
3463
|
+
*/
|
3464
|
+
static VALUE
|
3465
|
+
pgconn_async_describe_prepared(VALUE self, VALUE stmt_name)
|
3466
|
+
{
|
3467
|
+
VALUE rb_pgresult = Qnil;
|
3468
|
+
|
3469
|
+
pgconn_discard_results( self );
|
3470
|
+
pgconn_send_describe_prepared( self, stmt_name );
|
3471
|
+
rb_pgresult = pgconn_async_get_last_result( self );
|
3164
3472
|
|
3165
3473
|
if ( rb_block_given_p() ) {
|
3166
3474
|
return rb_ensure( rb_yield, rb_pgresult, pg_result_clear, rb_pgresult );
|
@@ -3174,7 +3482,7 @@ pgconn_async_exec(int argc, VALUE *argv, VALUE self)
|
|
3174
3482
|
* call-seq:
|
3175
3483
|
* conn.ssl_in_use? -> Boolean
|
3176
3484
|
*
|
3177
|
-
* Returns +true+ if the connection uses SSL, +false+ if not.
|
3485
|
+
* Returns +true+ if the connection uses SSL/TLS, +false+ if not.
|
3178
3486
|
*
|
3179
3487
|
* Available since PostgreSQL-9.5
|
3180
3488
|
*/
|
@@ -3208,7 +3516,7 @@ pgconn_ssl_in_use(VALUE self)
|
|
3208
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".
|
3209
3517
|
*
|
3210
3518
|
*
|
3211
|
-
* 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].
|
3212
3520
|
*
|
3213
3521
|
* Available since PostgreSQL-9.5
|
3214
3522
|
*/
|
@@ -3248,10 +3556,134 @@ pgconn_ssl_attribute_names(VALUE self)
|
|
3248
3556
|
#endif
|
3249
3557
|
|
3250
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
|
+
|
3251
3675
|
/**************************************************************************
|
3252
3676
|
* LARGE OBJECT SUPPORT
|
3253
3677
|
**************************************************************************/
|
3254
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
|
+
|
3255
3687
|
/*
|
3256
3688
|
* call-seq:
|
3257
3689
|
* conn.lo_creat( [mode] ) -> Integer
|
@@ -3272,9 +3704,12 @@ pgconn_locreat(int argc, VALUE *argv, VALUE self)
|
|
3272
3704
|
else
|
3273
3705
|
mode = NUM2INT(nmode);
|
3274
3706
|
|
3275
|
-
|
3707
|
+
BLOCKING_BEGIN(conn)
|
3708
|
+
lo_oid = lo_creat(conn, mode);
|
3709
|
+
BLOCKING_END(conn)
|
3710
|
+
|
3276
3711
|
if (lo_oid == 0)
|
3277
|
-
|
3712
|
+
pg_raise_conn_error( rb_ePGerror, self, "lo_creat failed");
|
3278
3713
|
|
3279
3714
|
return UINT2NUM(lo_oid);
|
3280
3715
|
}
|
@@ -3295,7 +3730,7 @@ pgconn_locreate(VALUE self, VALUE in_lo_oid)
|
|
3295
3730
|
|
3296
3731
|
ret = lo_create(conn, lo_oid);
|
3297
3732
|
if (ret == InvalidOid)
|
3298
|
-
|
3733
|
+
pg_raise_conn_error( rb_ePGerror, self, "lo_create failed");
|
3299
3734
|
|
3300
3735
|
return UINT2NUM(ret);
|
3301
3736
|
}
|
@@ -3317,9 +3752,12 @@ pgconn_loimport(VALUE self, VALUE filename)
|
|
3317
3752
|
|
3318
3753
|
Check_Type(filename, T_STRING);
|
3319
3754
|
|
3320
|
-
|
3755
|
+
BLOCKING_BEGIN(conn)
|
3756
|
+
lo_oid = lo_import(conn, StringValueCStr(filename));
|
3757
|
+
BLOCKING_END(conn)
|
3758
|
+
|
3321
3759
|
if (lo_oid == 0) {
|
3322
|
-
|
3760
|
+
pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(conn));
|
3323
3761
|
}
|
3324
3762
|
return UINT2NUM(lo_oid);
|
3325
3763
|
}
|
@@ -3335,12 +3773,17 @@ pgconn_loexport(VALUE self, VALUE lo_oid, VALUE filename)
|
|
3335
3773
|
{
|
3336
3774
|
PGconn *conn = pg_get_pgconn(self);
|
3337
3775
|
Oid oid;
|
3776
|
+
int ret;
|
3338
3777
|
Check_Type(filename, T_STRING);
|
3339
3778
|
|
3340
3779
|
oid = NUM2UINT(lo_oid);
|
3341
3780
|
|
3342
|
-
|
3343
|
-
|
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));
|
3344
3787
|
}
|
3345
3788
|
return Qnil;
|
3346
3789
|
}
|
@@ -3370,8 +3813,12 @@ pgconn_loopen(int argc, VALUE *argv, VALUE self)
|
|
3370
3813
|
else
|
3371
3814
|
mode = NUM2INT(nmode);
|
3372
3815
|
|
3373
|
-
|
3374
|
-
|
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));
|
3375
3822
|
}
|
3376
3823
|
return INT2FIX(fd);
|
3377
3824
|
}
|
@@ -3393,11 +3840,15 @@ pgconn_lowrite(VALUE self, VALUE in_lo_desc, VALUE buffer)
|
|
3393
3840
|
Check_Type(buffer, T_STRING);
|
3394
3841
|
|
3395
3842
|
if( RSTRING_LEN(buffer) < 0) {
|
3396
|
-
|
3843
|
+
pg_raise_conn_error( rb_ePGerror, self, "write buffer zero string");
|
3397
3844
|
}
|
3398
|
-
|
3399
|
-
|
3400
|
-
|
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));
|
3401
3852
|
}
|
3402
3853
|
|
3403
3854
|
return INT2FIX(n);
|
@@ -3420,23 +3871,24 @@ pgconn_loread(VALUE self, VALUE in_lo_desc, VALUE in_len)
|
|
3420
3871
|
VALUE str;
|
3421
3872
|
char *buffer;
|
3422
3873
|
|
3423
|
-
|
3424
|
-
|
3425
|
-
rb_raise(rb_eNoMemError, "ALLOC failed!");
|
3874
|
+
if (len < 0)
|
3875
|
+
pg_raise_conn_error( rb_ePGerror, self, "negative length %d given", len);
|
3426
3876
|
|
3427
|
-
|
3428
|
-
rb_raise(rb_ePGerror,"nagative length %d given", len);
|
3429
|
-
}
|
3877
|
+
buffer = ALLOC_N(char, len);
|
3430
3878
|
|
3431
|
-
|
3432
|
-
|
3879
|
+
BLOCKING_BEGIN(conn)
|
3880
|
+
ret = lo_read(conn, lo_desc, buffer, len);
|
3881
|
+
BLOCKING_END(conn)
|
3882
|
+
|
3883
|
+
if(ret < 0)
|
3884
|
+
pg_raise_conn_error( rb_ePGerror, self, "lo_read failed");
|
3433
3885
|
|
3434
3886
|
if(ret == 0) {
|
3435
3887
|
xfree(buffer);
|
3436
3888
|
return Qnil;
|
3437
3889
|
}
|
3438
3890
|
|
3439
|
-
str =
|
3891
|
+
str = rb_str_new(buffer, ret);
|
3440
3892
|
xfree(buffer);
|
3441
3893
|
|
3442
3894
|
return str;
|
@@ -3458,8 +3910,12 @@ pgconn_lolseek(VALUE self, VALUE in_lo_desc, VALUE offset, VALUE whence)
|
|
3458
3910
|
int lo_desc = NUM2INT(in_lo_desc);
|
3459
3911
|
int ret;
|
3460
3912
|
|
3461
|
-
|
3462
|
-
|
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");
|
3463
3919
|
}
|
3464
3920
|
|
3465
3921
|
return INT2FIX(ret);
|
@@ -3478,8 +3934,12 @@ pgconn_lotell(VALUE self, VALUE in_lo_desc)
|
|
3478
3934
|
PGconn *conn = pg_get_pgconn(self);
|
3479
3935
|
int lo_desc = NUM2INT(in_lo_desc);
|
3480
3936
|
|
3481
|
-
|
3482
|
-
|
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");
|
3483
3943
|
|
3484
3944
|
return INT2FIX(position);
|
3485
3945
|
}
|
@@ -3496,9 +3956,14 @@ pgconn_lotruncate(VALUE self, VALUE in_lo_desc, VALUE in_len)
|
|
3496
3956
|
PGconn *conn = pg_get_pgconn(self);
|
3497
3957
|
int lo_desc = NUM2INT(in_lo_desc);
|
3498
3958
|
size_t len = NUM2INT(in_len);
|
3959
|
+
int ret;
|
3960
|
+
|
3961
|
+
BLOCKING_BEGIN(conn)
|
3962
|
+
ret = lo_truncate(conn,lo_desc,len);
|
3963
|
+
BLOCKING_END(conn)
|
3499
3964
|
|
3500
|
-
if(
|
3501
|
-
|
3965
|
+
if(ret < 0)
|
3966
|
+
pg_raise_conn_error( rb_ePGerror, self, "lo_truncate failed");
|
3502
3967
|
|
3503
3968
|
return Qnil;
|
3504
3969
|
}
|
@@ -3514,9 +3979,14 @@ pgconn_loclose(VALUE self, VALUE in_lo_desc)
|
|
3514
3979
|
{
|
3515
3980
|
PGconn *conn = pg_get_pgconn(self);
|
3516
3981
|
int lo_desc = NUM2INT(in_lo_desc);
|
3982
|
+
int ret;
|
3983
|
+
|
3984
|
+
BLOCKING_BEGIN(conn)
|
3985
|
+
ret = lo_close(conn,lo_desc);
|
3986
|
+
BLOCKING_END(conn)
|
3517
3987
|
|
3518
|
-
if(
|
3519
|
-
|
3988
|
+
if(ret < 0)
|
3989
|
+
pg_raise_conn_error( rb_ePGerror, self, "lo_close failed");
|
3520
3990
|
|
3521
3991
|
return Qnil;
|
3522
3992
|
}
|
@@ -3532,20 +4002,28 @@ pgconn_lounlink(VALUE self, VALUE in_oid)
|
|
3532
4002
|
{
|
3533
4003
|
PGconn *conn = pg_get_pgconn(self);
|
3534
4004
|
Oid oid = NUM2UINT(in_oid);
|
4005
|
+
int ret;
|
4006
|
+
|
4007
|
+
BLOCKING_BEGIN(conn)
|
4008
|
+
ret = lo_unlink(conn,oid);
|
4009
|
+
BLOCKING_END(conn)
|
3535
4010
|
|
3536
|
-
if(
|
3537
|
-
|
4011
|
+
if(ret < 0)
|
4012
|
+
pg_raise_conn_error( rb_ePGerror, self, "lo_unlink failed");
|
3538
4013
|
|
3539
4014
|
return Qnil;
|
3540
4015
|
}
|
3541
4016
|
|
3542
4017
|
|
3543
|
-
void
|
4018
|
+
static void
|
3544
4019
|
pgconn_set_internal_encoding_index( VALUE self )
|
3545
4020
|
{
|
3546
|
-
|
3547
|
-
|
3548
|
-
|
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;
|
3549
4027
|
}
|
3550
4028
|
|
3551
4029
|
/*
|
@@ -3588,13 +4066,13 @@ static VALUE pgconn_external_encoding(VALUE self);
|
|
3588
4066
|
static VALUE
|
3589
4067
|
pgconn_internal_encoding_set(VALUE self, VALUE enc)
|
3590
4068
|
{
|
3591
|
-
|
4069
|
+
rb_check_frozen(self);
|
3592
4070
|
if (NIL_P(enc)) {
|
3593
|
-
|
4071
|
+
pgconn_sync_set_client_encoding( self, rb_usascii_str_new_cstr("SQL_ASCII") );
|
3594
4072
|
return enc;
|
3595
4073
|
}
|
3596
4074
|
else if ( TYPE(enc) == T_STRING && strcasecmp("JOHAB", StringValueCStr(enc)) == 0 ) {
|
3597
|
-
|
4075
|
+
pgconn_sync_set_client_encoding(self, rb_usascii_str_new_cstr("JOHAB"));
|
3598
4076
|
return enc;
|
3599
4077
|
}
|
3600
4078
|
else {
|
@@ -3609,11 +4087,6 @@ pgconn_internal_encoding_set(VALUE self, VALUE enc)
|
|
3609
4087
|
pgconn_set_internal_encoding_index( self );
|
3610
4088
|
return enc;
|
3611
4089
|
}
|
3612
|
-
|
3613
|
-
enc_inspect = rb_inspect(enc);
|
3614
|
-
rb_raise( rb_ePGerror, "unknown encoding: %s", StringValueCStr(enc_inspect) );
|
3615
|
-
|
3616
|
-
return Qnil;
|
3617
4090
|
}
|
3618
4091
|
|
3619
4092
|
|
@@ -3632,42 +4105,56 @@ pgconn_external_encoding(VALUE self)
|
|
3632
4105
|
rb_encoding *enc = NULL;
|
3633
4106
|
const char *pg_encname = NULL;
|
3634
4107
|
|
3635
|
-
/* Use cached value if found */
|
3636
|
-
if ( RTEST(this->external_encoding) ) return this->external_encoding;
|
3637
|
-
|
3638
4108
|
pg_encname = PQparameterStatus( this->pgconn, "server_encoding" );
|
3639
4109
|
enc = pg_get_pg_encname_as_rb_encoding( pg_encname );
|
3640
|
-
|
3641
|
-
|
3642
|
-
return this->external_encoding;
|
4110
|
+
return rb_enc_from_encoding( enc );
|
3643
4111
|
}
|
3644
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
|
+
}
|
3645
4134
|
|
3646
4135
|
static VALUE
|
3647
4136
|
pgconn_set_client_encoding_async1( VALUE args )
|
3648
4137
|
{
|
3649
4138
|
VALUE self = ((VALUE*)args)[0];
|
3650
4139
|
VALUE encname = ((VALUE*)args)[1];
|
3651
|
-
|
3652
|
-
VALUE query = rb_funcall(query_format, rb_intern("%"), 1, encname);
|
3653
|
-
|
3654
|
-
pgconn_async_exec(1, &query, self);
|
4140
|
+
pgconn_async_set_client_encoding(self, encname);
|
3655
4141
|
return 0;
|
3656
4142
|
}
|
3657
4143
|
|
3658
4144
|
|
3659
4145
|
static VALUE
|
3660
|
-
pgconn_set_client_encoding_async2( VALUE arg )
|
4146
|
+
pgconn_set_client_encoding_async2( VALUE arg, VALUE ex )
|
3661
4147
|
{
|
3662
4148
|
UNUSED(arg);
|
4149
|
+
UNUSED(ex);
|
3663
4150
|
return 1;
|
3664
4151
|
}
|
3665
4152
|
|
3666
4153
|
|
3667
4154
|
static VALUE
|
3668
|
-
pgconn_set_client_encoding_async( VALUE self,
|
4155
|
+
pgconn_set_client_encoding_async( VALUE self, VALUE encname )
|
3669
4156
|
{
|
3670
|
-
VALUE args[] = { self,
|
4157
|
+
VALUE args[] = { self, encname };
|
3671
4158
|
return rb_rescue(pgconn_set_client_encoding_async1, (VALUE)&args, pgconn_set_client_encoding_async2, Qnil);
|
3672
4159
|
}
|
3673
4160
|
|
@@ -3684,16 +4171,23 @@ static VALUE
|
|
3684
4171
|
pgconn_set_default_encoding( VALUE self )
|
3685
4172
|
{
|
3686
4173
|
PGconn *conn = pg_get_pgconn( self );
|
3687
|
-
rb_encoding *
|
3688
|
-
|
3689
|
-
|
3690
|
-
if ((
|
3691
|
-
|
3692
|
-
|
3693
|
-
|
3694
|
-
|
4174
|
+
rb_encoding *rb_enc;
|
4175
|
+
|
4176
|
+
rb_check_frozen(self);
|
4177
|
+
if (( rb_enc = rb_default_internal_encoding() )) {
|
4178
|
+
rb_encoding * conn_encoding = pg_conn_enc_get( conn );
|
4179
|
+
|
4180
|
+
/* Don't set the server encoding, if it's unnecessary.
|
4181
|
+
* This is important for connection proxies, who disallow configuration settings.
|
4182
|
+
*/
|
4183
|
+
if ( conn_encoding != rb_enc ) {
|
4184
|
+
const char *encname = pg_get_rb_encoding_as_pg_encoding( rb_enc );
|
4185
|
+
if ( pgconn_set_client_encoding_async(self, rb_str_new_cstr(encname)) != 0 )
|
4186
|
+
rb_warning( "Failed to set the default_internal encoding to %s: '%s'",
|
4187
|
+
encname, PQerrorMessage(conn) );
|
4188
|
+
}
|
3695
4189
|
pgconn_set_internal_encoding_index( self );
|
3696
|
-
return rb_enc_from_encoding(
|
4190
|
+
return rb_enc_from_encoding( rb_enc );
|
3697
4191
|
} else {
|
3698
4192
|
pgconn_set_internal_encoding_index( self );
|
3699
4193
|
return Qnil;
|
@@ -3714,13 +4208,14 @@ static VALUE
|
|
3714
4208
|
pgconn_type_map_for_queries_set(VALUE self, VALUE typemap)
|
3715
4209
|
{
|
3716
4210
|
t_pg_connection *this = pg_get_connection( self );
|
4211
|
+
t_typemap *tm;
|
4212
|
+
UNUSED(tm);
|
3717
4213
|
|
3718
|
-
|
3719
|
-
|
3720
|
-
|
3721
|
-
|
3722
|
-
|
3723
|
-
this->type_map_for_queries = typemap;
|
4214
|
+
rb_check_frozen(self);
|
4215
|
+
/* Check type of method param */
|
4216
|
+
TypedData_Get_Struct(typemap, t_typemap, &pg_typemap_type, tm);
|
4217
|
+
|
4218
|
+
RB_OBJ_WRITE(self, &this->type_map_for_queries, typemap);
|
3724
4219
|
|
3725
4220
|
return typemap;
|
3726
4221
|
}
|
@@ -3754,13 +4249,12 @@ static VALUE
|
|
3754
4249
|
pgconn_type_map_for_results_set(VALUE self, VALUE typemap)
|
3755
4250
|
{
|
3756
4251
|
t_pg_connection *this = pg_get_connection( self );
|
4252
|
+
t_typemap *tm;
|
4253
|
+
UNUSED(tm);
|
3757
4254
|
|
3758
|
-
|
3759
|
-
|
3760
|
-
|
3761
|
-
}
|
3762
|
-
Check_Type(typemap, T_DATA);
|
3763
|
-
this->type_map_for_results = typemap;
|
4255
|
+
rb_check_frozen(self);
|
4256
|
+
TypedData_Get_Struct(typemap, t_typemap, &pg_typemap_type, tm);
|
4257
|
+
RB_OBJ_WRITE(self, &this->type_map_for_results, typemap);
|
3764
4258
|
|
3765
4259
|
return typemap;
|
3766
4260
|
}
|
@@ -3794,20 +4288,20 @@ pgconn_type_map_for_results_get(VALUE self)
|
|
3794
4288
|
*
|
3795
4289
|
*/
|
3796
4290
|
static VALUE
|
3797
|
-
pgconn_encoder_for_put_copy_data_set(VALUE self, VALUE
|
4291
|
+
pgconn_encoder_for_put_copy_data_set(VALUE self, VALUE encoder)
|
3798
4292
|
{
|
3799
4293
|
t_pg_connection *this = pg_get_connection( self );
|
3800
4294
|
|
3801
|
-
|
3802
|
-
|
3803
|
-
|
3804
|
-
|
3805
|
-
|
3806
|
-
|
4295
|
+
rb_check_frozen(self);
|
4296
|
+
if( encoder != Qnil ){
|
4297
|
+
t_pg_coder *co;
|
4298
|
+
UNUSED(co);
|
4299
|
+
/* Check argument type */
|
4300
|
+
TypedData_Get_Struct(encoder, t_pg_coder, &pg_coder_type, co);
|
3807
4301
|
}
|
3808
|
-
this->encoder_for_put_copy_data
|
4302
|
+
RB_OBJ_WRITE(self, &this->encoder_for_put_copy_data, encoder);
|
3809
4303
|
|
3810
|
-
return
|
4304
|
+
return encoder;
|
3811
4305
|
}
|
3812
4306
|
|
3813
4307
|
/*
|
@@ -3843,20 +4337,20 @@ pgconn_encoder_for_put_copy_data_get(VALUE self)
|
|
3843
4337
|
*
|
3844
4338
|
*/
|
3845
4339
|
static VALUE
|
3846
|
-
pgconn_decoder_for_get_copy_data_set(VALUE self, VALUE
|
4340
|
+
pgconn_decoder_for_get_copy_data_set(VALUE self, VALUE decoder)
|
3847
4341
|
{
|
3848
4342
|
t_pg_connection *this = pg_get_connection( self );
|
3849
4343
|
|
3850
|
-
|
3851
|
-
|
3852
|
-
|
3853
|
-
|
3854
|
-
|
3855
|
-
|
4344
|
+
rb_check_frozen(self);
|
4345
|
+
if( decoder != Qnil ){
|
4346
|
+
t_pg_coder *co;
|
4347
|
+
UNUSED(co);
|
4348
|
+
/* Check argument type */
|
4349
|
+
TypedData_Get_Struct(decoder, t_pg_coder, &pg_coder_type, co);
|
3856
4350
|
}
|
3857
|
-
this->decoder_for_get_copy_data
|
4351
|
+
RB_OBJ_WRITE(self, &this->decoder_for_get_copy_data, decoder);
|
3858
4352
|
|
3859
|
-
return
|
4353
|
+
return decoder;
|
3860
4354
|
}
|
3861
4355
|
|
3862
4356
|
/*
|
@@ -3879,28 +4373,83 @@ pgconn_decoder_for_get_copy_data_get(VALUE self)
|
|
3879
4373
|
return this->decoder_for_get_copy_data;
|
3880
4374
|
}
|
3881
4375
|
|
4376
|
+
/*
|
4377
|
+
* call-seq:
|
4378
|
+
* conn.field_name_type = Symbol
|
4379
|
+
*
|
4380
|
+
* Set default type of field names of results retrieved by this connection.
|
4381
|
+
* It can be set to one of:
|
4382
|
+
* * +:string+ to use String based field names
|
4383
|
+
* * +:symbol+ to use Symbol based field names
|
4384
|
+
*
|
4385
|
+
* The default is +:string+ .
|
4386
|
+
*
|
4387
|
+
* Settings the type of field names affects only future results.
|
4388
|
+
*
|
4389
|
+
* See further description at PG::Result#field_name_type=
|
4390
|
+
*
|
4391
|
+
*/
|
4392
|
+
static VALUE
|
4393
|
+
pgconn_field_name_type_set(VALUE self, VALUE sym)
|
4394
|
+
{
|
4395
|
+
t_pg_connection *this = pg_get_connection( self );
|
4396
|
+
|
4397
|
+
rb_check_frozen(self);
|
4398
|
+
this->flags &= ~PG_RESULT_FIELD_NAMES_MASK;
|
4399
|
+
if( sym == sym_symbol ) this->flags |= PG_RESULT_FIELD_NAMES_SYMBOL;
|
4400
|
+
else if ( sym == sym_static_symbol ) this->flags |= PG_RESULT_FIELD_NAMES_STATIC_SYMBOL;
|
4401
|
+
else if ( sym == sym_string );
|
4402
|
+
else rb_raise(rb_eArgError, "invalid argument %+"PRIsVALUE, sym);
|
4403
|
+
|
4404
|
+
return sym;
|
4405
|
+
}
|
4406
|
+
|
4407
|
+
/*
|
4408
|
+
* call-seq:
|
4409
|
+
* conn.field_name_type -> Symbol
|
4410
|
+
*
|
4411
|
+
* Get type of field names.
|
4412
|
+
*
|
4413
|
+
* See description at #field_name_type=
|
4414
|
+
*/
|
4415
|
+
static VALUE
|
4416
|
+
pgconn_field_name_type_get(VALUE self)
|
4417
|
+
{
|
4418
|
+
t_pg_connection *this = pg_get_connection( self );
|
4419
|
+
|
4420
|
+
if( this->flags & PG_RESULT_FIELD_NAMES_SYMBOL ){
|
4421
|
+
return sym_symbol;
|
4422
|
+
} else if( this->flags & PG_RESULT_FIELD_NAMES_STATIC_SYMBOL ){
|
4423
|
+
return sym_static_symbol;
|
4424
|
+
} else {
|
4425
|
+
return sym_string;
|
4426
|
+
}
|
4427
|
+
}
|
4428
|
+
|
3882
4429
|
|
3883
4430
|
/*
|
3884
4431
|
* Document-class: PG::Connection
|
3885
4432
|
*/
|
3886
4433
|
void
|
3887
|
-
init_pg_connection()
|
4434
|
+
init_pg_connection(void)
|
3888
4435
|
{
|
3889
4436
|
s_id_encode = rb_intern("encode");
|
4437
|
+
s_id_autoclose_set = rb_intern("autoclose=");
|
3890
4438
|
sym_type = ID2SYM(rb_intern("type"));
|
3891
4439
|
sym_format = ID2SYM(rb_intern("format"));
|
3892
4440
|
sym_value = ID2SYM(rb_intern("value"));
|
4441
|
+
sym_string = ID2SYM(rb_intern("string"));
|
4442
|
+
sym_symbol = ID2SYM(rb_intern("symbol"));
|
4443
|
+
sym_static_symbol = ID2SYM(rb_intern("static_symbol"));
|
3893
4444
|
|
3894
4445
|
rb_cPGconn = rb_define_class_under( rb_mPG, "Connection", rb_cObject );
|
4446
|
+
/* Help rdoc to known the Constants module */
|
4447
|
+
/* rb_mPGconstants = rb_define_module_under( rb_mPG, "Constants" ); */
|
3895
4448
|
rb_include_module(rb_cPGconn, rb_mPGconstants);
|
3896
4449
|
|
3897
4450
|
/****** PG::Connection CLASS METHODS ******/
|
3898
4451
|
rb_define_alloc_func( rb_cPGconn, pgconn_s_allocate );
|
3899
4452
|
|
3900
|
-
SINGLETON_ALIAS(rb_cPGconn, "connect", "new");
|
3901
|
-
SINGLETON_ALIAS(rb_cPGconn, "open", "new");
|
3902
|
-
SINGLETON_ALIAS(rb_cPGconn, "setdb", "new");
|
3903
|
-
SINGLETON_ALIAS(rb_cPGconn, "setdblogin", "new");
|
3904
4453
|
rb_define_singleton_method(rb_cPGconn, "escape_string", pgconn_s_escape, 1);
|
3905
4454
|
SINGLETON_ALIAS(rb_cPGconn, "escape", "escape_string");
|
3906
4455
|
rb_define_singleton_method(rb_cPGconn, "escape_bytea", pgconn_s_escape_bytea, 1);
|
@@ -3909,14 +4458,15 @@ init_pg_connection()
|
|
3909
4458
|
rb_define_singleton_method(rb_cPGconn, "quote_ident", pgconn_s_quote_ident, 1);
|
3910
4459
|
rb_define_singleton_method(rb_cPGconn, "connect_start", pgconn_s_connect_start, -1);
|
3911
4460
|
rb_define_singleton_method(rb_cPGconn, "conndefaults", pgconn_s_conndefaults, 0);
|
3912
|
-
rb_define_singleton_method(rb_cPGconn, "
|
4461
|
+
rb_define_singleton_method(rb_cPGconn, "conninfo_parse", pgconn_s_conninfo_parse, 1);
|
4462
|
+
rb_define_singleton_method(rb_cPGconn, "sync_ping", pgconn_s_sync_ping, -1);
|
4463
|
+
rb_define_singleton_method(rb_cPGconn, "sync_connect", pgconn_s_sync_connect, -1);
|
3913
4464
|
|
3914
4465
|
/****** PG::Connection INSTANCE METHODS: Connection Control ******/
|
3915
|
-
rb_define_method(rb_cPGconn, "initialize", pgconn_init, -1);
|
3916
4466
|
rb_define_method(rb_cPGconn, "connect_poll", pgconn_connect_poll, 0);
|
3917
4467
|
rb_define_method(rb_cPGconn, "finish", pgconn_finish, 0);
|
3918
4468
|
rb_define_method(rb_cPGconn, "finished?", pgconn_finished_p, 0);
|
3919
|
-
rb_define_method(rb_cPGconn, "
|
4469
|
+
rb_define_method(rb_cPGconn, "sync_reset", pgconn_sync_reset, 0);
|
3920
4470
|
rb_define_method(rb_cPGconn, "reset_start", pgconn_reset_start, 0);
|
3921
4471
|
rb_define_method(rb_cPGconn, "reset_poll", pgconn_reset_poll, 0);
|
3922
4472
|
rb_define_alias(rb_cPGconn, "close", "finish");
|
@@ -3926,11 +4476,12 @@ init_pg_connection()
|
|
3926
4476
|
rb_define_method(rb_cPGconn, "user", pgconn_user, 0);
|
3927
4477
|
rb_define_method(rb_cPGconn, "pass", pgconn_pass, 0);
|
3928
4478
|
rb_define_method(rb_cPGconn, "host", pgconn_host, 0);
|
4479
|
+
#if defined(HAVE_PQRESULTMEMORYSIZE)
|
4480
|
+
rb_define_method(rb_cPGconn, "hostaddr", pgconn_hostaddr, 0);
|
4481
|
+
#endif
|
3929
4482
|
rb_define_method(rb_cPGconn, "port", pgconn_port, 0);
|
3930
4483
|
rb_define_method(rb_cPGconn, "tty", pgconn_tty, 0);
|
3931
|
-
#ifdef HAVE_PQCONNINFO
|
3932
4484
|
rb_define_method(rb_cPGconn, "conninfo", pgconn_conninfo, 0);
|
3933
|
-
#endif
|
3934
4485
|
rb_define_method(rb_cPGconn, "options", pgconn_options, 0);
|
3935
4486
|
rb_define_method(rb_cPGconn, "status", pgconn_status, 0);
|
3936
4487
|
rb_define_method(rb_cPGconn, "transaction_status", pgconn_transaction_status, 0);
|
@@ -3941,18 +4492,34 @@ init_pg_connection()
|
|
3941
4492
|
rb_define_method(rb_cPGconn, "socket", pgconn_socket, 0);
|
3942
4493
|
rb_define_method(rb_cPGconn, "socket_io", pgconn_socket_io, 0);
|
3943
4494
|
rb_define_method(rb_cPGconn, "backend_pid", pgconn_backend_pid, 0);
|
4495
|
+
rb_define_method(rb_cPGconn, "backend_key", pgconn_backend_key, 0);
|
3944
4496
|
rb_define_method(rb_cPGconn, "connection_needs_password", pgconn_connection_needs_password, 0);
|
3945
4497
|
rb_define_method(rb_cPGconn, "connection_used_password", pgconn_connection_used_password, 0);
|
3946
4498
|
/* rb_define_method(rb_cPGconn, "getssl", pgconn_getssl, 0); */
|
3947
4499
|
|
3948
4500
|
/****** PG::Connection INSTANCE METHODS: Command Execution ******/
|
3949
|
-
rb_define_method(rb_cPGconn, "
|
3950
|
-
|
3951
|
-
rb_define_method(rb_cPGconn, "
|
3952
|
-
rb_define_method(rb_cPGconn, "
|
3953
|
-
rb_define_method(rb_cPGconn, "
|
3954
|
-
rb_define_method(rb_cPGconn, "
|
3955
|
-
|
4501
|
+
rb_define_method(rb_cPGconn, "sync_exec", pgconn_sync_exec, -1);
|
4502
|
+
rb_define_method(rb_cPGconn, "sync_exec_params", pgconn_sync_exec_params, -1);
|
4503
|
+
rb_define_method(rb_cPGconn, "sync_prepare", pgconn_sync_prepare, -1);
|
4504
|
+
rb_define_method(rb_cPGconn, "sync_exec_prepared", pgconn_sync_exec_prepared, -1);
|
4505
|
+
rb_define_method(rb_cPGconn, "sync_describe_prepared", pgconn_sync_describe_prepared, 1);
|
4506
|
+
rb_define_method(rb_cPGconn, "sync_describe_portal", pgconn_sync_describe_portal, 1);
|
4507
|
+
|
4508
|
+
rb_define_method(rb_cPGconn, "exec", pgconn_async_exec, -1);
|
4509
|
+
rb_define_method(rb_cPGconn, "exec_params", pgconn_async_exec_params, -1);
|
4510
|
+
rb_define_method(rb_cPGconn, "prepare", pgconn_async_prepare, -1);
|
4511
|
+
rb_define_method(rb_cPGconn, "exec_prepared", pgconn_async_exec_prepared, -1);
|
4512
|
+
rb_define_method(rb_cPGconn, "describe_prepared", pgconn_async_describe_prepared, 1);
|
4513
|
+
rb_define_method(rb_cPGconn, "describe_portal", pgconn_async_describe_portal, 1);
|
4514
|
+
|
4515
|
+
rb_define_alias(rb_cPGconn, "async_exec", "exec");
|
4516
|
+
rb_define_alias(rb_cPGconn, "async_query", "async_exec");
|
4517
|
+
rb_define_alias(rb_cPGconn, "async_exec_params", "exec_params");
|
4518
|
+
rb_define_alias(rb_cPGconn, "async_prepare", "prepare");
|
4519
|
+
rb_define_alias(rb_cPGconn, "async_exec_prepared", "exec_prepared");
|
4520
|
+
rb_define_alias(rb_cPGconn, "async_describe_prepared", "describe_prepared");
|
4521
|
+
rb_define_alias(rb_cPGconn, "async_describe_portal", "describe_portal");
|
4522
|
+
|
3956
4523
|
rb_define_method(rb_cPGconn, "make_empty_pgresult", pgconn_make_empty_pgresult, 1);
|
3957
4524
|
rb_define_method(rb_cPGconn, "escape_string", pgconn_s_escape, 1);
|
3958
4525
|
rb_define_alias(rb_cPGconn, "escape", "escape_string");
|
@@ -3964,31 +4531,37 @@ init_pg_connection()
|
|
3964
4531
|
|
3965
4532
|
/****** PG::Connection INSTANCE METHODS: Asynchronous Command Processing ******/
|
3966
4533
|
rb_define_method(rb_cPGconn, "send_query", pgconn_send_query, -1);
|
4534
|
+
rb_define_method(rb_cPGconn, "send_query_params", pgconn_send_query_params, -1);
|
3967
4535
|
rb_define_method(rb_cPGconn, "send_prepare", pgconn_send_prepare, -1);
|
3968
4536
|
rb_define_method(rb_cPGconn, "send_query_prepared", pgconn_send_query_prepared, -1);
|
3969
4537
|
rb_define_method(rb_cPGconn, "send_describe_prepared", pgconn_send_describe_prepared, 1);
|
3970
4538
|
rb_define_method(rb_cPGconn, "send_describe_portal", pgconn_send_describe_portal, 1);
|
3971
|
-
rb_define_method(rb_cPGconn, "
|
4539
|
+
rb_define_method(rb_cPGconn, "sync_get_result", pgconn_sync_get_result, 0);
|
3972
4540
|
rb_define_method(rb_cPGconn, "consume_input", pgconn_consume_input, 0);
|
3973
4541
|
rb_define_method(rb_cPGconn, "is_busy", pgconn_is_busy, 0);
|
3974
|
-
rb_define_method(rb_cPGconn, "
|
3975
|
-
rb_define_method(rb_cPGconn, "
|
3976
|
-
|
3977
|
-
rb_define_method(rb_cPGconn, "flush",
|
4542
|
+
rb_define_method(rb_cPGconn, "sync_setnonblocking", pgconn_sync_setnonblocking, 1);
|
4543
|
+
rb_define_method(rb_cPGconn, "sync_isnonblocking", pgconn_sync_isnonblocking, 0);
|
4544
|
+
rb_define_method(rb_cPGconn, "sync_flush", pgconn_sync_flush, 0);
|
4545
|
+
rb_define_method(rb_cPGconn, "flush", pgconn_async_flush, 0);
|
4546
|
+
rb_define_alias(rb_cPGconn, "async_flush", "flush");
|
4547
|
+
rb_define_method(rb_cPGconn, "discard_results", pgconn_discard_results, 0);
|
3978
4548
|
|
3979
4549
|
/****** PG::Connection INSTANCE METHODS: Cancelling Queries in Progress ******/
|
3980
|
-
rb_define_method(rb_cPGconn, "
|
4550
|
+
rb_define_method(rb_cPGconn, "sync_cancel", pgconn_sync_cancel, 0);
|
3981
4551
|
|
3982
4552
|
/****** PG::Connection INSTANCE METHODS: NOTIFY ******/
|
3983
4553
|
rb_define_method(rb_cPGconn, "notifies", pgconn_notifies, 0);
|
3984
4554
|
|
3985
4555
|
/****** PG::Connection INSTANCE METHODS: COPY ******/
|
3986
|
-
rb_define_method(rb_cPGconn, "
|
3987
|
-
rb_define_method(rb_cPGconn, "
|
3988
|
-
rb_define_method(rb_cPGconn, "
|
4556
|
+
rb_define_method(rb_cPGconn, "sync_put_copy_data", pgconn_sync_put_copy_data, -1);
|
4557
|
+
rb_define_method(rb_cPGconn, "sync_put_copy_end", pgconn_sync_put_copy_end, -1);
|
4558
|
+
rb_define_method(rb_cPGconn, "sync_get_copy_data", pgconn_sync_get_copy_data, -1);
|
3989
4559
|
|
3990
4560
|
/****** PG::Connection INSTANCE METHODS: Control Functions ******/
|
3991
4561
|
rb_define_method(rb_cPGconn, "set_error_verbosity", pgconn_set_error_verbosity, 1);
|
4562
|
+
#ifdef HAVE_PQRESULTVERBOSEERRORMESSAGE
|
4563
|
+
rb_define_method(rb_cPGconn, "set_error_context_visibility", pgconn_set_error_context_visibility, 1 );
|
4564
|
+
#endif
|
3992
4565
|
rb_define_method(rb_cPGconn, "trace", pgconn_trace, 1);
|
3993
4566
|
rb_define_method(rb_cPGconn, "untrace", pgconn_untrace, 0);
|
3994
4567
|
|
@@ -3998,18 +4571,20 @@ init_pg_connection()
|
|
3998
4571
|
|
3999
4572
|
/****** PG::Connection INSTANCE METHODS: Other ******/
|
4000
4573
|
rb_define_method(rb_cPGconn, "get_client_encoding", pgconn_get_client_encoding, 0);
|
4001
|
-
rb_define_method(rb_cPGconn, "
|
4574
|
+
rb_define_method(rb_cPGconn, "sync_set_client_encoding", pgconn_sync_set_client_encoding, 1);
|
4575
|
+
rb_define_method(rb_cPGconn, "set_client_encoding", pgconn_async_set_client_encoding, 1);
|
4576
|
+
rb_define_alias(rb_cPGconn, "async_set_client_encoding", "set_client_encoding");
|
4002
4577
|
rb_define_alias(rb_cPGconn, "client_encoding=", "set_client_encoding");
|
4003
|
-
rb_define_method(rb_cPGconn, "transaction", pgconn_transaction, 0);
|
4004
4578
|
rb_define_method(rb_cPGconn, "block", pgconn_block, -1);
|
4579
|
+
rb_define_private_method(rb_cPGconn, "flush_data=", pgconn_flush_data_set, 1);
|
4005
4580
|
rb_define_method(rb_cPGconn, "wait_for_notify", pgconn_wait_for_notify, -1);
|
4006
4581
|
rb_define_alias(rb_cPGconn, "notifies_wait", "wait_for_notify");
|
4007
4582
|
rb_define_method(rb_cPGconn, "quote_ident", pgconn_s_quote_ident, 1);
|
4008
|
-
rb_define_method(rb_cPGconn, "
|
4009
|
-
|
4010
|
-
|
4583
|
+
rb_define_method(rb_cPGconn, "sync_get_last_result", pgconn_sync_get_last_result, 0);
|
4584
|
+
rb_define_method(rb_cPGconn, "get_last_result", pgconn_async_get_last_result, 0);
|
4585
|
+
rb_define_alias(rb_cPGconn, "async_get_last_result", "get_last_result");
|
4011
4586
|
#ifdef HAVE_PQENCRYPTPASSWORDCONN
|
4012
|
-
rb_define_method(rb_cPGconn, "
|
4587
|
+
rb_define_method(rb_cPGconn, "sync_encrypt_password", pgconn_sync_encrypt_password, -1);
|
4013
4588
|
#endif
|
4014
4589
|
|
4015
4590
|
#ifdef HAVE_PQSSLATTRIBUTE
|
@@ -4018,6 +4593,14 @@ init_pg_connection()
|
|
4018
4593
|
rb_define_method(rb_cPGconn, "ssl_attribute_names", pgconn_ssl_attribute_names, 0);
|
4019
4594
|
#endif
|
4020
4595
|
|
4596
|
+
#ifdef HAVE_PQENTERPIPELINEMODE
|
4597
|
+
rb_define_method(rb_cPGconn, "pipeline_status", pgconn_pipeline_status, 0);
|
4598
|
+
rb_define_method(rb_cPGconn, "enter_pipeline_mode", pgconn_enter_pipeline_mode, 0);
|
4599
|
+
rb_define_method(rb_cPGconn, "exit_pipeline_mode", pgconn_exit_pipeline_mode, 0);
|
4600
|
+
rb_define_method(rb_cPGconn, "pipeline_sync", pgconn_pipeline_sync, 0);
|
4601
|
+
rb_define_method(rb_cPGconn, "send_flush_request", pgconn_send_flush_request, 0);
|
4602
|
+
#endif
|
4603
|
+
|
4021
4604
|
/****** PG::Connection INSTANCE METHODS: Large Object Support ******/
|
4022
4605
|
rb_define_method(rb_cPGconn, "lo_creat", pgconn_locreat, -1);
|
4023
4606
|
rb_define_alias(rb_cPGconn, "locreat", "lo_creat");
|
@@ -4059,5 +4642,7 @@ init_pg_connection()
|
|
4059
4642
|
rb_define_method(rb_cPGconn, "encoder_for_put_copy_data", pgconn_encoder_for_put_copy_data_get, 0);
|
4060
4643
|
rb_define_method(rb_cPGconn, "decoder_for_get_copy_data=", pgconn_decoder_for_get_copy_data_set, 1);
|
4061
4644
|
rb_define_method(rb_cPGconn, "decoder_for_get_copy_data", pgconn_decoder_for_get_copy_data_get, 0);
|
4062
|
-
}
|
4063
4645
|
|
4646
|
+
rb_define_method(rb_cPGconn, "field_name_type=", pgconn_field_name_type_set, 1 );
|
4647
|
+
rb_define_method(rb_cPGconn, "field_name_type", pgconn_field_name_type_get, 0 );
|
4648
|
+
}
|