pg 0.18.3 → 1.4.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- checksums.yaml.gz.sig +0 -0
- data/.appveyor.yml +36 -0
- data/.gems +6 -0
- data/.github/workflows/binary-gems.yml +86 -0
- data/.github/workflows/source-gem.yml +129 -0
- data/.gitignore +13 -0
- data/.hgsigs +34 -0
- data/.hgtags +41 -0
- data/.irbrc +23 -0
- data/.pryrc +23 -0
- data/.tm_properties +21 -0
- data/.travis.yml +49 -0
- data/BSDL +2 -2
- data/Gemfile +14 -0
- data/History.rdoc +448 -4
- data/Manifest.txt +8 -21
- data/README-Windows.rdoc +4 -4
- data/README.ja.rdoc +1 -2
- data/README.rdoc +69 -17
- data/Rakefile +33 -135
- data/Rakefile.cross +70 -69
- data/certs/ged.pem +24 -0
- data/certs/larskanis-2022.pem +26 -0
- data/ext/errorcodes.def +109 -0
- data/ext/errorcodes.rb +1 -1
- data/ext/errorcodes.txt +35 -2
- data/ext/extconf.rb +120 -54
- data/ext/gvl_wrappers.c +8 -0
- data/ext/gvl_wrappers.h +44 -33
- data/ext/pg.c +213 -171
- data/ext/pg.h +92 -98
- data/ext/pg_binary_decoder.c +84 -15
- data/ext/pg_binary_encoder.c +24 -21
- data/ext/pg_coder.c +175 -39
- data/ext/pg_connection.c +1730 -1135
- data/ext/pg_copy_coder.c +94 -27
- data/ext/pg_record_coder.c +521 -0
- data/ext/pg_result.c +640 -221
- data/ext/pg_text_decoder.c +608 -40
- data/ext/pg_text_encoder.c +253 -99
- data/ext/pg_tuple.c +569 -0
- data/ext/pg_type_map.c +61 -21
- data/ext/pg_type_map_all_strings.c +19 -5
- data/ext/pg_type_map_by_class.c +54 -24
- data/ext/pg_type_map_by_column.c +79 -40
- data/ext/pg_type_map_by_mri_type.c +48 -19
- data/ext/pg_type_map_by_oid.c +55 -25
- data/ext/pg_type_map_in_ruby.c +51 -20
- 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 +47 -0
- data/lib/pg/basic_type_map_for_queries.rb +193 -0
- data/lib/pg/basic_type_map_for_results.rb +81 -0
- data/lib/pg/basic_type_registry.rb +301 -0
- data/lib/pg/binary_decoder.rb +23 -0
- data/lib/pg/coder.rb +24 -3
- data/lib/pg/connection.rb +723 -65
- data/lib/pg/constants.rb +2 -1
- data/lib/pg/exceptions.rb +9 -2
- data/lib/pg/result.rb +24 -7
- data/lib/pg/text_decoder.rb +24 -22
- data/lib/pg/text_encoder.rb +40 -8
- 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 +61 -36
- data/misc/openssl-pg-segfault.rb +31 -0
- data/misc/postgres/History.txt +9 -0
- data/misc/postgres/Manifest.txt +5 -0
- data/misc/postgres/README.txt +21 -0
- data/misc/postgres/Rakefile +21 -0
- data/misc/postgres/lib/postgres.rb +16 -0
- data/misc/ruby-pg/History.txt +9 -0
- data/misc/ruby-pg/Manifest.txt +5 -0
- data/misc/ruby-pg/README.txt +21 -0
- data/misc/ruby-pg/Rakefile +21 -0
- data/misc/ruby-pg/lib/ruby/pg.rb +16 -0
- data/pg.gemspec +32 -0
- data/rakelib/task_extension.rb +46 -0
- data/sample/array_insert.rb +1 -1
- data/sample/async_api.rb +4 -8
- data/sample/async_copyto.rb +1 -1
- data/sample/async_mixed.rb +1 -1
- data/sample/check_conn.rb +1 -1
- data/sample/copydata.rb +71 -0
- data/sample/copyfrom.rb +1 -1
- data/sample/copyto.rb +1 -1
- data/sample/cursor.rb +1 -1
- data/sample/disk_usage_report.rb +6 -15
- data/sample/issue-119.rb +2 -2
- data/sample/losample.rb +1 -1
- data/sample/minimal-testcase.rb +2 -2
- data/sample/notify_wait.rb +1 -1
- data/sample/pg_statistics.rb +6 -15
- data/sample/replication_monitor.rb +9 -18
- data/sample/test_binary_values.rb +1 -1
- data/sample/wal_shipper.rb +2 -2
- data/sample/warehouse_partitions.rb +8 -17
- data.tar.gz.sig +0 -0
- metadata +80 -230
- metadata.gz.sig +0 -0
- data/ChangeLog +0 -5804
- data/lib/pg/basic_type_mapping.rb +0 -399
- data/spec/data/expected_trace.out +0 -26
- data/spec/data/random_binary_data +0 -0
- data/spec/helpers.rb +0 -355
- data/spec/pg/basic_type_mapping_spec.rb +0 -251
- data/spec/pg/connection_spec.rb +0 -1538
- data/spec/pg/result_spec.rb +0 -449
- 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 -690
- 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,30 +12,44 @@
|
|
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;
|
17
|
+
static VALUE sym_symbol, sym_string, sym_static_symbol;
|
16
18
|
|
17
19
|
static PQnoticeReceiver default_notice_receiver = NULL;
|
18
20
|
static PQnoticeProcessor default_notice_processor = NULL;
|
19
21
|
|
20
22
|
static VALUE pgconn_finish( VALUE );
|
21
|
-
#ifdef M17N_SUPPORTED
|
22
23
|
static VALUE pgconn_set_default_encoding( VALUE self );
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
#define rb_fdset_t fd_set
|
28
|
-
#define rb_fd_init(f)
|
29
|
-
#define rb_fd_zero(f) FD_ZERO(f)
|
30
|
-
#define rb_fd_set(n, f) FD_SET(n, f)
|
31
|
-
#define rb_fd_term(f)
|
32
|
-
#define rb_thread_fd_select rb_thread_select
|
33
|
-
#endif
|
24
|
+
static VALUE pgconn_wait_for_flush( VALUE self );
|
25
|
+
static void pgconn_set_internal_encoding_index( VALUE );
|
26
|
+
static const rb_data_type_t pg_connection_type;
|
27
|
+
static VALUE pgconn_async_flush(VALUE self);
|
34
28
|
|
35
29
|
/*
|
36
30
|
* Global functions
|
37
31
|
*/
|
38
32
|
|
33
|
+
/*
|
34
|
+
* Convenience function to raise connection errors
|
35
|
+
*/
|
36
|
+
#ifdef __GNUC__
|
37
|
+
__attribute__((format(printf, 3, 4)))
|
38
|
+
#endif
|
39
|
+
static void
|
40
|
+
pg_raise_conn_error( VALUE klass, VALUE self, const char *format, ...)
|
41
|
+
{
|
42
|
+
VALUE msg, error;
|
43
|
+
va_list ap;
|
44
|
+
|
45
|
+
va_start(ap, format);
|
46
|
+
msg = rb_vsprintf(format, ap);
|
47
|
+
va_end(ap);
|
48
|
+
error = rb_exc_new_str(klass, msg);
|
49
|
+
rb_iv_set(error, "@connection", self);
|
50
|
+
rb_exc_raise(error);
|
51
|
+
}
|
52
|
+
|
39
53
|
/*
|
40
54
|
* Fetch the PG::Connection object data pointer.
|
41
55
|
*/
|
@@ -43,7 +57,7 @@ t_pg_connection *
|
|
43
57
|
pg_get_connection( VALUE self )
|
44
58
|
{
|
45
59
|
t_pg_connection *this;
|
46
|
-
|
60
|
+
TypedData_Get_Struct( self, t_pg_connection, &pg_connection_type, this);
|
47
61
|
|
48
62
|
return this;
|
49
63
|
}
|
@@ -52,14 +66,14 @@ pg_get_connection( VALUE self )
|
|
52
66
|
* Fetch the PG::Connection object data pointer and check it's
|
53
67
|
* PGconn data pointer for sanity.
|
54
68
|
*/
|
55
|
-
t_pg_connection *
|
69
|
+
static t_pg_connection *
|
56
70
|
pg_get_connection_safe( VALUE self )
|
57
71
|
{
|
58
72
|
t_pg_connection *this;
|
59
|
-
|
73
|
+
TypedData_Get_Struct( self, t_pg_connection, &pg_connection_type, this);
|
60
74
|
|
61
75
|
if ( !this->pgconn )
|
62
|
-
|
76
|
+
pg_raise_conn_error( rb_eConnectionBad, self, "connection is closed");
|
63
77
|
|
64
78
|
return this;
|
65
79
|
}
|
@@ -75,10 +89,11 @@ PGconn *
|
|
75
89
|
pg_get_pgconn( VALUE self )
|
76
90
|
{
|
77
91
|
t_pg_connection *this;
|
78
|
-
|
92
|
+
TypedData_Get_Struct( self, t_pg_connection, &pg_connection_type, this);
|
79
93
|
|
80
|
-
if ( !this->pgconn )
|
81
|
-
|
94
|
+
if ( !this->pgconn ){
|
95
|
+
pg_raise_conn_error( rb_eConnectionBad, self, "connection is closed");
|
96
|
+
}
|
82
97
|
|
83
98
|
return this->pgconn;
|
84
99
|
}
|
@@ -88,18 +103,16 @@ pg_get_pgconn( VALUE self )
|
|
88
103
|
/*
|
89
104
|
* Close the associated socket IO object if there is one.
|
90
105
|
*/
|
91
|
-
void
|
106
|
+
static void
|
92
107
|
pgconn_close_socket_io( VALUE self )
|
93
108
|
{
|
94
109
|
t_pg_connection *this = pg_get_connection( self );
|
95
110
|
VALUE socket_io = this->socket_io;
|
96
111
|
|
97
112
|
if ( RTEST(socket_io) ) {
|
98
|
-
#if defined(_WIN32)
|
99
|
-
|
100
|
-
|
101
|
-
rb_raise(rb_eConnectionBad, "Could not unwrap win32 socket handle");
|
102
|
-
}
|
113
|
+
#if defined(_WIN32)
|
114
|
+
if( rb_w32_unwrap_io_handle(this->ruby_sd) )
|
115
|
+
pg_raise_conn_error( rb_eConnectionBad, self, "Could not unwrap win32 socket handle");
|
103
116
|
#endif
|
104
117
|
rb_funcall( socket_io, rb_intern("close"), 0 );
|
105
118
|
}
|
@@ -141,22 +154,46 @@ pgconn_make_conninfo_array( const PQconninfoOption *options )
|
|
141
154
|
return ary;
|
142
155
|
}
|
143
156
|
|
157
|
+
static const char *pg_cstr_enc(VALUE str, int enc_idx){
|
158
|
+
const char *ptr = StringValueCStr(str);
|
159
|
+
if( ENCODING_GET(str) == enc_idx ){
|
160
|
+
return ptr;
|
161
|
+
} else {
|
162
|
+
str = rb_str_export_to_enc(str, rb_enc_from_index(enc_idx));
|
163
|
+
return StringValueCStr(str);
|
164
|
+
}
|
165
|
+
}
|
166
|
+
|
144
167
|
|
145
168
|
/*
|
146
169
|
* GC Mark function
|
147
170
|
*/
|
148
171
|
static void
|
149
|
-
pgconn_gc_mark(
|
172
|
+
pgconn_gc_mark( void *_this )
|
173
|
+
{
|
174
|
+
t_pg_connection *this = (t_pg_connection *)_this;
|
175
|
+
rb_gc_mark_movable( this->socket_io );
|
176
|
+
rb_gc_mark_movable( this->notice_receiver );
|
177
|
+
rb_gc_mark_movable( this->notice_processor );
|
178
|
+
rb_gc_mark_movable( this->type_map_for_queries );
|
179
|
+
rb_gc_mark_movable( this->type_map_for_results );
|
180
|
+
rb_gc_mark_movable( this->trace_stream );
|
181
|
+
rb_gc_mark_movable( this->encoder_for_put_copy_data );
|
182
|
+
rb_gc_mark_movable( this->decoder_for_get_copy_data );
|
183
|
+
}
|
184
|
+
|
185
|
+
static void
|
186
|
+
pgconn_gc_compact( void *_this )
|
150
187
|
{
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
188
|
+
t_pg_connection *this = (t_pg_connection *)_this;
|
189
|
+
pg_gc_location( this->socket_io );
|
190
|
+
pg_gc_location( this->notice_receiver );
|
191
|
+
pg_gc_location( this->notice_processor );
|
192
|
+
pg_gc_location( this->type_map_for_queries );
|
193
|
+
pg_gc_location( this->type_map_for_results );
|
194
|
+
pg_gc_location( this->trace_stream );
|
195
|
+
pg_gc_location( this->encoder_for_put_copy_data );
|
196
|
+
pg_gc_location( this->decoder_for_get_copy_data );
|
160
197
|
}
|
161
198
|
|
162
199
|
|
@@ -164,14 +201,45 @@ pgconn_gc_mark( t_pg_connection *this )
|
|
164
201
|
* GC Free function
|
165
202
|
*/
|
166
203
|
static void
|
167
|
-
pgconn_gc_free(
|
204
|
+
pgconn_gc_free( void *_this )
|
168
205
|
{
|
206
|
+
t_pg_connection *this = (t_pg_connection *)_this;
|
207
|
+
#if defined(_WIN32)
|
208
|
+
if ( RTEST(this->socket_io) ) {
|
209
|
+
if( rb_w32_unwrap_io_handle(this->ruby_sd) ){
|
210
|
+
rb_warn("pg: Could not unwrap win32 socket handle by garbage collector");
|
211
|
+
}
|
212
|
+
}
|
213
|
+
#endif
|
169
214
|
if (this->pgconn != NULL)
|
170
215
|
PQfinish( this->pgconn );
|
171
216
|
|
172
217
|
xfree(this);
|
173
218
|
}
|
174
219
|
|
220
|
+
/*
|
221
|
+
* Object Size function
|
222
|
+
*/
|
223
|
+
static size_t
|
224
|
+
pgconn_memsize( const void *_this )
|
225
|
+
{
|
226
|
+
const t_pg_connection *this = (const t_pg_connection *)_this;
|
227
|
+
return sizeof(*this);
|
228
|
+
}
|
229
|
+
|
230
|
+
static const rb_data_type_t pg_connection_type = {
|
231
|
+
"PG::Connection",
|
232
|
+
{
|
233
|
+
pgconn_gc_mark,
|
234
|
+
pgconn_gc_free,
|
235
|
+
pgconn_memsize,
|
236
|
+
pg_compact_callback(pgconn_gc_compact),
|
237
|
+
},
|
238
|
+
0,
|
239
|
+
0,
|
240
|
+
0,
|
241
|
+
};
|
242
|
+
|
175
243
|
|
176
244
|
/**************************************************************************
|
177
245
|
* Class Methods
|
@@ -187,7 +255,7 @@ static VALUE
|
|
187
255
|
pgconn_s_allocate( VALUE klass )
|
188
256
|
{
|
189
257
|
t_pg_connection *this;
|
190
|
-
VALUE self =
|
258
|
+
VALUE self = TypedData_Make_Struct( klass, t_pg_connection, &pg_connection_type, this );
|
191
259
|
|
192
260
|
this->pgconn = NULL;
|
193
261
|
this->socket_io = Qnil;
|
@@ -198,92 +266,29 @@ pgconn_s_allocate( VALUE klass )
|
|
198
266
|
this->encoder_for_put_copy_data = Qnil;
|
199
267
|
this->decoder_for_get_copy_data = Qnil;
|
200
268
|
this->trace_stream = Qnil;
|
201
|
-
|
269
|
+
rb_ivar_set(self, rb_intern("@calls_to_put_copy_data"), INT2FIX(0));
|
202
270
|
|
203
271
|
return self;
|
204
272
|
}
|
205
273
|
|
206
|
-
|
207
|
-
/*
|
208
|
-
* Document-method: new
|
209
|
-
*
|
210
|
-
* call-seq:
|
211
|
-
* PG::Connection.new -> conn
|
212
|
-
* PG::Connection.new(connection_hash) -> conn
|
213
|
-
* PG::Connection.new(connection_string) -> conn
|
214
|
-
* PG::Connection.new(host, port, options, tty, dbname, user, password) -> conn
|
215
|
-
*
|
216
|
-
* Create a connection to the specified server.
|
217
|
-
*
|
218
|
-
* [+host+]
|
219
|
-
* server hostname
|
220
|
-
* [+hostaddr+]
|
221
|
-
* server address (avoids hostname lookup, overrides +host+)
|
222
|
-
* [+port+]
|
223
|
-
* server port number
|
224
|
-
* [+dbname+]
|
225
|
-
* connecting database name
|
226
|
-
* [+user+]
|
227
|
-
* login user name
|
228
|
-
* [+password+]
|
229
|
-
* login password
|
230
|
-
* [+connect_timeout+]
|
231
|
-
* maximum time to wait for connection to succeed
|
232
|
-
* [+options+]
|
233
|
-
* backend options
|
234
|
-
* [+tty+]
|
235
|
-
* (ignored in newer versions of PostgreSQL)
|
236
|
-
* [+sslmode+]
|
237
|
-
* (disable|allow|prefer|require)
|
238
|
-
* [+krbsrvname+]
|
239
|
-
* kerberos service name
|
240
|
-
* [+gsslib+]
|
241
|
-
* GSS library to use for GSSAPI authentication
|
242
|
-
* [+service+]
|
243
|
-
* service name to use for additional parameters
|
244
|
-
*
|
245
|
-
* Examples:
|
246
|
-
*
|
247
|
-
* # Connect using all defaults
|
248
|
-
* PG::Connection.new
|
249
|
-
*
|
250
|
-
* # As a Hash
|
251
|
-
* PG::Connection.new( :dbname => 'test', :port => 5432 )
|
252
|
-
*
|
253
|
-
* # As a String
|
254
|
-
* PG::Connection.new( "dbname=test port=5432" )
|
255
|
-
*
|
256
|
-
* # As an Array
|
257
|
-
* PG::Connection.new( nil, 5432, nil, nil, 'test', nil, nil )
|
258
|
-
*
|
259
|
-
* If the Ruby default internal encoding is set (i.e., Encoding.default_internal != nil), the
|
260
|
-
* connection will have its +client_encoding+ set accordingly.
|
261
|
-
*
|
262
|
-
* Raises a PG::Error if the connection fails.
|
263
|
-
*/
|
264
274
|
static VALUE
|
265
|
-
|
275
|
+
pgconn_s_sync_connect(int argc, VALUE *argv, VALUE klass)
|
266
276
|
{
|
267
277
|
t_pg_connection *this;
|
268
278
|
VALUE conninfo;
|
269
|
-
VALUE
|
279
|
+
VALUE self = pgconn_s_allocate( klass );
|
270
280
|
|
271
281
|
this = pg_get_connection( self );
|
272
282
|
conninfo = rb_funcall2( rb_cPGconn, rb_intern("parse_connect_args"), argc, argv );
|
273
283
|
this->pgconn = gvl_PQconnectdb(StringValueCStr(conninfo));
|
274
284
|
|
275
285
|
if(this->pgconn == NULL)
|
276
|
-
rb_raise(rb_ePGerror, "PQconnectdb() unable to allocate structure");
|
286
|
+
rb_raise(rb_ePGerror, "PQconnectdb() unable to allocate PGconn structure");
|
277
287
|
|
278
|
-
if (PQstatus(this->pgconn) == CONNECTION_BAD)
|
279
|
-
|
280
|
-
rb_iv_set(error, "@connection", self);
|
281
|
-
rb_exc_raise(error);
|
282
|
-
}
|
288
|
+
if (PQstatus(this->pgconn) == CONNECTION_BAD)
|
289
|
+
pg_raise_conn_error( rb_eConnectionBad, self, "%s", PQerrorMessage(this->pgconn));
|
283
290
|
|
284
|
-
#ifdef M17N_SUPPORTED
|
285
291
|
pgconn_set_default_encoding( self );
|
286
|
-
#endif
|
287
292
|
|
288
293
|
if (rb_block_given_p()) {
|
289
294
|
return rb_ensure(rb_yield, self, pgconn_finish, self);
|
@@ -297,14 +302,16 @@ pgconn_init(int argc, VALUE *argv, VALUE self)
|
|
297
302
|
* PG::Connection.connect_start(connection_string) -> conn
|
298
303
|
* PG::Connection.connect_start(host, port, options, tty, dbname, login, password) -> conn
|
299
304
|
*
|
300
|
-
* This is an asynchronous version of PG::Connection.
|
305
|
+
* This is an asynchronous version of PG::Connection.new.
|
301
306
|
*
|
302
307
|
* Use #connect_poll to poll the status of the connection.
|
303
308
|
*
|
304
309
|
* NOTE: this does *not* set the connection's +client_encoding+ for you if
|
305
|
-
* Encoding.default_internal is set. To set it after the connection is established,
|
310
|
+
* +Encoding.default_internal+ is set. To set it after the connection is established,
|
306
311
|
* call #internal_encoding=. You can also set it automatically by setting
|
307
|
-
* ENV['PGCLIENTENCODING']
|
312
|
+
* <code>ENV['PGCLIENTENCODING']</code>, or include the 'options' connection parameter.
|
313
|
+
*
|
314
|
+
* See also the 'sample' directory of this gem and the corresponding {libpq functions}[https://www.postgresql.org/docs/current/libpq-connect.html#LIBPQ-PQCONNECTSTARTPARAMS].
|
308
315
|
*
|
309
316
|
*/
|
310
317
|
static VALUE
|
@@ -312,7 +319,6 @@ pgconn_s_connect_start( int argc, VALUE *argv, VALUE klass )
|
|
312
319
|
{
|
313
320
|
VALUE rb_conn;
|
314
321
|
VALUE conninfo;
|
315
|
-
VALUE error;
|
316
322
|
t_pg_connection *this;
|
317
323
|
|
318
324
|
/*
|
@@ -325,13 +331,10 @@ pgconn_s_connect_start( int argc, VALUE *argv, VALUE klass )
|
|
325
331
|
this->pgconn = gvl_PQconnectStart( StringValueCStr(conninfo) );
|
326
332
|
|
327
333
|
if( this->pgconn == NULL )
|
328
|
-
rb_raise(rb_ePGerror, "PQconnectStart() unable to allocate structure");
|
334
|
+
rb_raise(rb_ePGerror, "PQconnectStart() unable to allocate PGconn structure");
|
329
335
|
|
330
|
-
if ( PQstatus(this->pgconn) == CONNECTION_BAD )
|
331
|
-
|
332
|
-
rb_iv_set(error, "@connection", rb_conn);
|
333
|
-
rb_exc_raise(error);
|
334
|
-
}
|
336
|
+
if ( PQstatus(this->pgconn) == CONNECTION_BAD )
|
337
|
+
pg_raise_conn_error( rb_eConnectionBad, rb_conn, "%s", PQerrorMessage(this->pgconn));
|
335
338
|
|
336
339
|
if ( rb_block_given_p() ) {
|
337
340
|
return rb_ensure( rb_yield, rb_conn, pgconn_finish, rb_conn );
|
@@ -339,41 +342,21 @@ pgconn_s_connect_start( int argc, VALUE *argv, VALUE klass )
|
|
339
342
|
return rb_conn;
|
340
343
|
}
|
341
344
|
|
342
|
-
#ifdef HAVE_PQPING
|
343
|
-
/*
|
344
|
-
* call-seq:
|
345
|
-
* PG::Connection.ping(connection_hash) -> Fixnum
|
346
|
-
* PG::Connection.ping(connection_string) -> Fixnum
|
347
|
-
* PG::Connection.ping(host, port, options, tty, dbname, login, password) -> Fixnum
|
348
|
-
*
|
349
|
-
* Check server status.
|
350
|
-
*
|
351
|
-
* Returns one of:
|
352
|
-
* [+PQPING_OK+]
|
353
|
-
* server is accepting connections
|
354
|
-
* [+PQPING_REJECT+]
|
355
|
-
* server is alive but rejecting connections
|
356
|
-
* [+PQPING_NO_RESPONSE+]
|
357
|
-
* could not establish connection
|
358
|
-
* [+PQPING_NO_ATTEMPT+]
|
359
|
-
* connection not attempted (bad params)
|
360
|
-
*/
|
361
345
|
static VALUE
|
362
|
-
|
346
|
+
pgconn_s_sync_ping( int argc, VALUE *argv, VALUE klass )
|
363
347
|
{
|
364
348
|
PGPing ping;
|
365
349
|
VALUE conninfo;
|
366
350
|
|
367
351
|
conninfo = rb_funcall2( klass, rb_intern("parse_connect_args"), argc, argv );
|
368
|
-
ping =
|
352
|
+
ping = gvl_PQping( StringValueCStr(conninfo) );
|
369
353
|
|
370
354
|
return INT2FIX((int)ping);
|
371
355
|
}
|
372
|
-
#endif
|
373
356
|
|
374
357
|
|
375
358
|
/*
|
376
|
-
* Document-method: conndefaults
|
359
|
+
* Document-method: PG::Connection.conndefaults
|
377
360
|
*
|
378
361
|
* call-seq:
|
379
362
|
* PG::Connection.conndefaults() -> Array
|
@@ -407,17 +390,71 @@ pgconn_s_conndefaults(VALUE self)
|
|
407
390
|
return array;
|
408
391
|
}
|
409
392
|
|
393
|
+
/*
|
394
|
+
* Document-method: PG::Connection.conninfo_parse
|
395
|
+
*
|
396
|
+
* call-seq:
|
397
|
+
* PG::Connection.conninfo_parse(conninfo_string) -> Array
|
398
|
+
*
|
399
|
+
* Returns parsed connection options from the provided connection string as an array of hashes.
|
400
|
+
* Each hash has the same keys as PG::Connection.conndefaults() .
|
401
|
+
* The values from the +conninfo_string+ are stored in the +:val+ key.
|
402
|
+
*/
|
403
|
+
static VALUE
|
404
|
+
pgconn_s_conninfo_parse(VALUE self, VALUE conninfo)
|
405
|
+
{
|
406
|
+
VALUE array;
|
407
|
+
char *errmsg = NULL;
|
408
|
+
PQconninfoOption *options = PQconninfoParse(StringValueCStr(conninfo), &errmsg);
|
409
|
+
if(errmsg){
|
410
|
+
VALUE error = rb_str_new_cstr(errmsg);
|
411
|
+
PQfreemem(errmsg);
|
412
|
+
rb_raise(rb_ePGerror, "%"PRIsVALUE, error);
|
413
|
+
}
|
414
|
+
array = pgconn_make_conninfo_array( options );
|
415
|
+
|
416
|
+
PQconninfoFree(options);
|
417
|
+
|
418
|
+
UNUSED( self );
|
419
|
+
|
420
|
+
return array;
|
421
|
+
}
|
422
|
+
|
423
|
+
|
424
|
+
#ifdef HAVE_PQENCRYPTPASSWORDCONN
|
425
|
+
static VALUE
|
426
|
+
pgconn_sync_encrypt_password(int argc, VALUE *argv, VALUE self)
|
427
|
+
{
|
428
|
+
char *encrypted = NULL;
|
429
|
+
VALUE rval = Qnil;
|
430
|
+
VALUE password, username, algorithm;
|
431
|
+
PGconn *conn = pg_get_pgconn(self);
|
432
|
+
|
433
|
+
rb_scan_args( argc, argv, "21", &password, &username, &algorithm );
|
434
|
+
|
435
|
+
Check_Type(password, T_STRING);
|
436
|
+
Check_Type(username, T_STRING);
|
437
|
+
|
438
|
+
encrypted = gvl_PQencryptPasswordConn(conn, StringValueCStr(password), StringValueCStr(username), RTEST(algorithm) ? StringValueCStr(algorithm) : NULL);
|
439
|
+
if ( encrypted ) {
|
440
|
+
rval = rb_str_new2( encrypted );
|
441
|
+
PQfreemem( encrypted );
|
442
|
+
} else {
|
443
|
+
pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(conn));
|
444
|
+
}
|
445
|
+
|
446
|
+
return rval;
|
447
|
+
}
|
448
|
+
#endif
|
449
|
+
|
410
450
|
|
411
451
|
/*
|
412
452
|
* call-seq:
|
413
453
|
* PG::Connection.encrypt_password( password, username ) -> String
|
414
454
|
*
|
415
|
-
* This
|
416
|
-
*
|
417
|
-
* The arguments are the cleartext password, and the SQL name
|
418
|
-
* of the user it is for.
|
455
|
+
* This is an older, deprecated version of #encrypt_password.
|
456
|
+
* The difference is that this function always uses +md5+ as the encryption algorithm.
|
419
457
|
*
|
420
|
-
* Return value is the encrypted password.
|
421
458
|
*/
|
422
459
|
static VALUE
|
423
460
|
pgconn_s_encrypt_password(VALUE self, VALUE password, VALUE username)
|
@@ -434,9 +471,6 @@ pgconn_s_encrypt_password(VALUE self, VALUE password, VALUE username)
|
|
434
471
|
rval = rb_str_new2( encrypted );
|
435
472
|
PQfreemem( encrypted );
|
436
473
|
|
437
|
-
OBJ_INFECT( rval, password );
|
438
|
-
OBJ_INFECT( rval, username );
|
439
|
-
|
440
474
|
return rval;
|
441
475
|
}
|
442
476
|
|
@@ -447,7 +481,7 @@ pgconn_s_encrypt_password(VALUE self, VALUE password, VALUE username)
|
|
447
481
|
|
448
482
|
/*
|
449
483
|
* call-seq:
|
450
|
-
* conn.connect_poll() ->
|
484
|
+
* conn.connect_poll() -> Integer
|
451
485
|
*
|
452
486
|
* Returns one of:
|
453
487
|
* [+PGRES_POLLING_READING+]
|
@@ -460,17 +494,18 @@ pgconn_s_encrypt_password(VALUE self, VALUE password, VALUE username)
|
|
460
494
|
* the asynchronous connection is ready
|
461
495
|
*
|
462
496
|
* Example:
|
463
|
-
*
|
464
|
-
*
|
497
|
+
* require "io/wait"
|
498
|
+
*
|
499
|
+
* conn = PG::Connection.connect_start(dbname: 'mydatabase')
|
465
500
|
* status = conn.connect_poll
|
466
501
|
* while(status != PG::PGRES_POLLING_OK) do
|
467
502
|
* # do some work while waiting for the connection to complete
|
468
503
|
* if(status == PG::PGRES_POLLING_READING)
|
469
|
-
*
|
504
|
+
* unless conn.socket_io.wait_readable(10.0)
|
470
505
|
* raise "Asynchronous connection timed out!"
|
471
506
|
* end
|
472
507
|
* elsif(status == PG::PGRES_POLLING_WRITING)
|
473
|
-
*
|
508
|
+
* unless conn.socket_io.wait_writable(10.0)
|
474
509
|
* raise "Asynchronous connection timed out!"
|
475
510
|
* end
|
476
511
|
* end
|
@@ -484,6 +519,9 @@ pgconn_connect_poll(VALUE self)
|
|
484
519
|
{
|
485
520
|
PostgresPollingStatusType status;
|
486
521
|
status = gvl_PQconnectPoll(pg_get_pgconn(self));
|
522
|
+
|
523
|
+
pgconn_close_socket_io(self);
|
524
|
+
|
487
525
|
return INT2FIX((int)status);
|
488
526
|
}
|
489
527
|
|
@@ -520,15 +558,8 @@ pgconn_finished_p( VALUE self )
|
|
520
558
|
}
|
521
559
|
|
522
560
|
|
523
|
-
/*
|
524
|
-
* call-seq:
|
525
|
-
* conn.reset()
|
526
|
-
*
|
527
|
-
* Resets the backend connection. This method closes the
|
528
|
-
* backend connection and tries to re-connect.
|
529
|
-
*/
|
530
561
|
static VALUE
|
531
|
-
|
562
|
+
pgconn_sync_reset( VALUE self )
|
532
563
|
{
|
533
564
|
pgconn_close_socket_io( self );
|
534
565
|
gvl_PQreset( pg_get_pgconn(self) );
|
@@ -550,13 +581,13 @@ pgconn_reset_start(VALUE self)
|
|
550
581
|
{
|
551
582
|
pgconn_close_socket_io( self );
|
552
583
|
if(gvl_PQresetStart(pg_get_pgconn(self)) == 0)
|
553
|
-
|
584
|
+
pg_raise_conn_error( rb_eUnableToSend, self, "reset has failed");
|
554
585
|
return Qnil;
|
555
586
|
}
|
556
587
|
|
557
588
|
/*
|
558
589
|
* call-seq:
|
559
|
-
* conn.reset_poll ->
|
590
|
+
* conn.reset_poll -> Integer
|
560
591
|
*
|
561
592
|
* Checks the status of a connection reset operation.
|
562
593
|
* See #connect_start and #connect_poll for
|
@@ -567,6 +598,9 @@ pgconn_reset_poll(VALUE self)
|
|
567
598
|
{
|
568
599
|
PostgresPollingStatusType status;
|
569
600
|
status = gvl_PQresetPoll(pg_get_pgconn(self));
|
601
|
+
|
602
|
+
pgconn_close_socket_io(self);
|
603
|
+
|
570
604
|
return INT2FIX((int)status);
|
571
605
|
}
|
572
606
|
|
@@ -582,7 +616,7 @@ pgconn_db(VALUE self)
|
|
582
616
|
{
|
583
617
|
char *db = PQdb(pg_get_pgconn(self));
|
584
618
|
if (!db) return Qnil;
|
585
|
-
return
|
619
|
+
return rb_str_new2(db);
|
586
620
|
}
|
587
621
|
|
588
622
|
/*
|
@@ -596,36 +630,67 @@ pgconn_user(VALUE self)
|
|
596
630
|
{
|
597
631
|
char *user = PQuser(pg_get_pgconn(self));
|
598
632
|
if (!user) return Qnil;
|
599
|
-
return
|
633
|
+
return rb_str_new2(user);
|
600
634
|
}
|
601
635
|
|
602
636
|
/*
|
603
637
|
* call-seq:
|
604
638
|
* conn.pass()
|
605
639
|
*
|
606
|
-
* Returns the authenticated
|
640
|
+
* Returns the authenticated password.
|
607
641
|
*/
|
608
642
|
static VALUE
|
609
643
|
pgconn_pass(VALUE self)
|
610
644
|
{
|
611
645
|
char *user = PQpass(pg_get_pgconn(self));
|
612
646
|
if (!user) return Qnil;
|
613
|
-
return
|
647
|
+
return rb_str_new2(user);
|
614
648
|
}
|
615
649
|
|
616
650
|
/*
|
617
651
|
* call-seq:
|
618
652
|
* conn.host()
|
619
653
|
*
|
620
|
-
* Returns the
|
654
|
+
* Returns the server host name of the active connection.
|
655
|
+
* This can be a host name, an IP address, or a directory path if the connection is via Unix socket.
|
656
|
+
* (The path case can be distinguished because it will always be an absolute path, beginning with +/+ .)
|
657
|
+
*
|
658
|
+
* If the connection parameters specified both host and hostaddr, then +host+ will return the host information.
|
659
|
+
* If only hostaddr was specified, then that is returned.
|
660
|
+
* If multiple hosts were specified in the connection parameters, +host+ returns the host actually connected to.
|
661
|
+
*
|
662
|
+
* If there is an error producing the host information (perhaps if the connection has not been fully established or there was an error), it returns an empty string.
|
663
|
+
*
|
664
|
+
* If multiple hosts were specified in the connection parameters, it is not possible to rely on the result of +host+ until the connection is established.
|
665
|
+
* The status of the connection can be checked using the function Connection#status .
|
621
666
|
*/
|
622
667
|
static VALUE
|
623
668
|
pgconn_host(VALUE self)
|
624
669
|
{
|
625
670
|
char *host = PQhost(pg_get_pgconn(self));
|
626
671
|
if (!host) return Qnil;
|
627
|
-
return
|
672
|
+
return rb_str_new2(host);
|
673
|
+
}
|
674
|
+
|
675
|
+
/* PQhostaddr() appeared in PostgreSQL-12 together with PQresultMemorySize() */
|
676
|
+
#if defined(HAVE_PQRESULTMEMORYSIZE)
|
677
|
+
/*
|
678
|
+
* call-seq:
|
679
|
+
* conn.hostaddr()
|
680
|
+
*
|
681
|
+
* Returns the server IP address of the active connection.
|
682
|
+
* This can be the address that a host name resolved to, or an IP address provided through the hostaddr parameter.
|
683
|
+
* If there is an error producing the host information (perhaps if the connection has not been fully established or there was an error), it returns an empty string.
|
684
|
+
*
|
685
|
+
*/
|
686
|
+
static VALUE
|
687
|
+
pgconn_hostaddr(VALUE self)
|
688
|
+
{
|
689
|
+
char *host = PQhostaddr(pg_get_pgconn(self));
|
690
|
+
if (!host) return Qnil;
|
691
|
+
return rb_str_new2(host);
|
628
692
|
}
|
693
|
+
#endif
|
629
694
|
|
630
695
|
/*
|
631
696
|
* call-seq:
|
@@ -637,21 +702,19 @@ static VALUE
|
|
637
702
|
pgconn_port(VALUE self)
|
638
703
|
{
|
639
704
|
char* port = PQport(pg_get_pgconn(self));
|
640
|
-
return INT2NUM(
|
705
|
+
return INT2NUM(atoi(port));
|
641
706
|
}
|
642
707
|
|
643
708
|
/*
|
644
709
|
* call-seq:
|
645
710
|
* conn.tty()
|
646
711
|
*
|
647
|
-
*
|
712
|
+
* Obsolete function.
|
648
713
|
*/
|
649
714
|
static VALUE
|
650
715
|
pgconn_tty(VALUE self)
|
651
716
|
{
|
652
|
-
|
653
|
-
if (!tty) return Qnil;
|
654
|
-
return rb_tainted_str_new2(tty);
|
717
|
+
return rb_str_new2("");
|
655
718
|
}
|
656
719
|
|
657
720
|
/*
|
@@ -665,17 +728,17 @@ pgconn_options(VALUE self)
|
|
665
728
|
{
|
666
729
|
char *options = PQoptions(pg_get_pgconn(self));
|
667
730
|
if (!options) return Qnil;
|
668
|
-
return
|
731
|
+
return rb_str_new2(options);
|
669
732
|
}
|
670
733
|
|
671
734
|
|
672
|
-
#ifdef HAVE_PQCONNINFO
|
673
735
|
/*
|
674
736
|
* call-seq:
|
675
737
|
* conn.conninfo -> hash
|
676
738
|
*
|
677
739
|
* Returns the connection options used by a live connection.
|
678
740
|
*
|
741
|
+
* Available since PostgreSQL-9.3
|
679
742
|
*/
|
680
743
|
static VALUE
|
681
744
|
pgconn_conninfo( VALUE self )
|
@@ -688,14 +751,20 @@ pgconn_conninfo( VALUE self )
|
|
688
751
|
|
689
752
|
return array;
|
690
753
|
}
|
691
|
-
#endif
|
692
754
|
|
693
755
|
|
694
756
|
/*
|
695
757
|
* call-seq:
|
696
758
|
* conn.status()
|
697
759
|
*
|
698
|
-
* Returns status of connection
|
760
|
+
* Returns the status of the connection, which is one:
|
761
|
+
* PG::Constants::CONNECTION_OK
|
762
|
+
* PG::Constants::CONNECTION_BAD
|
763
|
+
*
|
764
|
+
* ... and other constants of kind PG::Constants::CONNECTION_*
|
765
|
+
*
|
766
|
+
* Example:
|
767
|
+
* PG.constants.grep(/CONNECTION_/).find{|c| PG.const_get(c) == conn.status} # => :CONNECTION_OK
|
699
768
|
*/
|
700
769
|
static VALUE
|
701
770
|
pgconn_status(VALUE self)
|
@@ -745,7 +814,7 @@ pgconn_parameter_status(VALUE self, VALUE param_name)
|
|
745
814
|
if(ret == NULL)
|
746
815
|
return Qnil;
|
747
816
|
else
|
748
|
-
return
|
817
|
+
return rb_str_new2(ret);
|
749
818
|
}
|
750
819
|
|
751
820
|
/*
|
@@ -783,19 +852,24 @@ pgconn_server_version(VALUE self)
|
|
783
852
|
* call-seq:
|
784
853
|
* conn.error_message -> String
|
785
854
|
*
|
786
|
-
* Returns the error message
|
855
|
+
* Returns the error message most recently generated by an operation on the connection.
|
856
|
+
*
|
857
|
+
* Nearly all libpq functions will set a message for conn.error_message if they fail.
|
858
|
+
* Note that by libpq convention, a nonempty error_message result can consist of multiple lines, and will include a trailing newline.
|
787
859
|
*/
|
788
860
|
static VALUE
|
789
861
|
pgconn_error_message(VALUE self)
|
790
862
|
{
|
791
863
|
char *error = PQerrorMessage(pg_get_pgconn(self));
|
792
864
|
if (!error) return Qnil;
|
793
|
-
return
|
865
|
+
return rb_str_new2(error);
|
794
866
|
}
|
795
867
|
|
796
868
|
/*
|
797
869
|
* call-seq:
|
798
|
-
* conn.socket() ->
|
870
|
+
* conn.socket() -> Integer
|
871
|
+
*
|
872
|
+
* This method is deprecated. Please use the more portable method #socket_io .
|
799
873
|
*
|
800
874
|
* Returns the socket's file descriptor for this connection.
|
801
875
|
* <tt>IO.for_fd()</tt> can be used to build a proper IO object to the socket.
|
@@ -805,60 +879,64 @@ pgconn_error_message(VALUE self)
|
|
805
879
|
* creates an IO that's associated with the connection object itself,
|
806
880
|
* and so won't go out of scope until the connection does.
|
807
881
|
*
|
808
|
-
* *Note:* On Windows the file descriptor is not
|
882
|
+
* *Note:* On Windows the file descriptor is not usable,
|
809
883
|
* since it can not be used to build a Ruby IO object.
|
810
884
|
*/
|
811
885
|
static VALUE
|
812
886
|
pgconn_socket(VALUE self)
|
813
887
|
{
|
814
888
|
int sd;
|
889
|
+
pg_deprecated(4, ("conn.socket is deprecated and should be replaced by conn.socket_io"));
|
890
|
+
|
815
891
|
if( (sd = PQsocket(pg_get_pgconn(self))) < 0)
|
816
|
-
|
892
|
+
pg_raise_conn_error( rb_eConnectionBad, self, "PQsocket() can't get socket descriptor");
|
893
|
+
|
817
894
|
return INT2NUM(sd);
|
818
895
|
}
|
819
896
|
|
820
|
-
|
821
|
-
#if !defined(_WIN32) || defined(HAVE_RB_W32_WRAP_IO_HANDLE)
|
822
|
-
|
823
897
|
/*
|
824
898
|
* call-seq:
|
825
899
|
* conn.socket_io() -> IO
|
826
900
|
*
|
827
|
-
* Fetch
|
828
|
-
* This object can be used for IO.select to wait for events while running
|
829
|
-
*
|
901
|
+
* Fetch an IO object created from the Connection's underlying socket.
|
902
|
+
* This object can be used per <tt>socket_io.wait_readable</tt>, <tt>socket_io.wait_writable</tt> or for <tt>IO.select</tt> to wait for events while running asynchronous API calls.
|
903
|
+
* <tt>IO#wait_*able</tt> is is <tt>Fiber.scheduler</tt> compatible in contrast to <tt>IO.select</tt>.
|
830
904
|
*
|
831
|
-
*
|
832
|
-
*
|
833
|
-
* goes out of scope.
|
905
|
+
* The IO object can change while the connection is established, but is memorized afterwards.
|
906
|
+
* So be sure not to cache the IO object, but repeat calling <tt>conn.socket_io</tt> instead.
|
834
907
|
*
|
835
|
-
*
|
908
|
+
* Using this method also works on Windows in contrast to using #socket .
|
909
|
+
* It also avoids the problem of the underlying connection being closed by Ruby when an IO created using <tt>IO.for_fd(conn.socket)</tt> goes out of scope.
|
836
910
|
*/
|
837
911
|
static VALUE
|
838
912
|
pgconn_socket_io(VALUE self)
|
839
913
|
{
|
840
914
|
int sd;
|
841
915
|
int ruby_sd;
|
842
|
-
ID id_autoclose = rb_intern("autoclose=");
|
843
916
|
t_pg_connection *this = pg_get_connection_safe( self );
|
917
|
+
VALUE cSocket;
|
844
918
|
VALUE socket_io = this->socket_io;
|
845
919
|
|
846
920
|
if ( !RTEST(socket_io) ) {
|
847
|
-
if( (sd = PQsocket(this->pgconn)) < 0)
|
848
|
-
|
921
|
+
if( (sd = PQsocket(this->pgconn)) < 0){
|
922
|
+
pg_raise_conn_error( rb_eConnectionBad, self, "PQsocket() can't get socket descriptor");
|
923
|
+
}
|
849
924
|
|
850
925
|
#ifdef _WIN32
|
851
926
|
ruby_sd = rb_w32_wrap_io_handle((HANDLE)(intptr_t)sd, O_RDWR|O_BINARY|O_NOINHERIT);
|
927
|
+
if( ruby_sd == -1 )
|
928
|
+
pg_raise_conn_error( rb_eConnectionBad, self, "Could not wrap win32 socket handle");
|
929
|
+
|
930
|
+
this->ruby_sd = ruby_sd;
|
852
931
|
#else
|
853
932
|
ruby_sd = sd;
|
854
933
|
#endif
|
855
934
|
|
856
|
-
|
935
|
+
cSocket = rb_const_get(rb_cObject, rb_intern("BasicSocket"));
|
936
|
+
socket_io = rb_funcall( cSocket, rb_intern("for_fd"), 1, INT2NUM(ruby_sd));
|
857
937
|
|
858
|
-
/* Disable autoclose feature
|
859
|
-
|
860
|
-
rb_funcall( socket_io, id_autoclose, 1, Qfalse );
|
861
|
-
}
|
938
|
+
/* Disable autoclose feature */
|
939
|
+
rb_funcall( socket_io, s_id_autoclose_set, 1, Qfalse );
|
862
940
|
|
863
941
|
this->socket_io = socket_io;
|
864
942
|
}
|
@@ -866,11 +944,9 @@ pgconn_socket_io(VALUE self)
|
|
866
944
|
return socket_io;
|
867
945
|
}
|
868
946
|
|
869
|
-
#endif
|
870
|
-
|
871
947
|
/*
|
872
948
|
* call-seq:
|
873
|
-
* conn.backend_pid() ->
|
949
|
+
* conn.backend_pid() -> Integer
|
874
950
|
*
|
875
951
|
* Returns the process ID of the backend server
|
876
952
|
* process for this connection.
|
@@ -882,6 +958,51 @@ pgconn_backend_pid(VALUE self)
|
|
882
958
|
return INT2NUM(PQbackendPID(pg_get_pgconn(self)));
|
883
959
|
}
|
884
960
|
|
961
|
+
typedef struct
|
962
|
+
{
|
963
|
+
struct sockaddr_storage addr;
|
964
|
+
socklen_t salen;
|
965
|
+
} SockAddr;
|
966
|
+
|
967
|
+
/* Copy of struct pg_cancel from libpq-int.h
|
968
|
+
*
|
969
|
+
* See https://github.com/postgres/postgres/blame/master/src/interfaces/libpq/libpq-int.h#L577-L586
|
970
|
+
*/
|
971
|
+
struct pg_cancel
|
972
|
+
{
|
973
|
+
SockAddr raddr; /* Remote address */
|
974
|
+
int be_pid; /* PID of backend --- needed for cancels */
|
975
|
+
int be_key; /* key of backend --- needed for cancels */
|
976
|
+
};
|
977
|
+
|
978
|
+
/*
|
979
|
+
* call-seq:
|
980
|
+
* conn.backend_key() -> Integer
|
981
|
+
*
|
982
|
+
* Returns the key of the backend server process for this connection.
|
983
|
+
* This key can be used to cancel queries on the server.
|
984
|
+
*/
|
985
|
+
static VALUE
|
986
|
+
pgconn_backend_key(VALUE self)
|
987
|
+
{
|
988
|
+
int be_key;
|
989
|
+
struct pg_cancel *cancel;
|
990
|
+
PGconn *conn = pg_get_pgconn(self);
|
991
|
+
|
992
|
+
cancel = (struct pg_cancel*)PQgetCancel(conn);
|
993
|
+
if(cancel == NULL)
|
994
|
+
pg_raise_conn_error( rb_ePGerror, self, "Invalid connection!");
|
995
|
+
|
996
|
+
if( cancel->be_pid != PQbackendPID(conn) )
|
997
|
+
rb_raise(rb_ePGerror,"Unexpected binary struct layout - please file a bug report at ruby-pg!");
|
998
|
+
|
999
|
+
be_key = cancel->be_key;
|
1000
|
+
|
1001
|
+
PQfreeCancel(cancel);
|
1002
|
+
|
1003
|
+
return INT2NUM(be_key);
|
1004
|
+
}
|
1005
|
+
|
885
1006
|
/*
|
886
1007
|
* call-seq:
|
887
1008
|
* conn.connection_needs_password() -> Boolean
|
@@ -912,44 +1033,35 @@ pgconn_connection_used_password(VALUE self)
|
|
912
1033
|
/* :TODO: get_ssl */
|
913
1034
|
|
914
1035
|
|
915
|
-
static VALUE
|
1036
|
+
static VALUE pgconn_sync_exec_params( int, VALUE *, VALUE );
|
916
1037
|
|
917
1038
|
/*
|
918
1039
|
* call-seq:
|
919
|
-
* conn.
|
920
|
-
* conn.
|
921
|
-
*
|
922
|
-
* Sends SQL query request specified by _sql_ to PostgreSQL.
|
923
|
-
* Returns a PG::Result instance on success.
|
924
|
-
* On failure, it raises a PG::Error.
|
1040
|
+
* conn.sync_exec(sql) -> PG::Result
|
1041
|
+
* conn.sync_exec(sql) {|pg_result| block }
|
925
1042
|
*
|
926
|
-
*
|
927
|
-
*
|
928
|
-
* argument placeholders are used.
|
1043
|
+
* This function has the same behavior as #async_exec, but is implemented using the synchronous command processing API of libpq.
|
1044
|
+
* It's not recommended to use explicit sync or async variants but #exec instead, unless you have a good reason to do so.
|
929
1045
|
*
|
930
|
-
*
|
931
|
-
*
|
932
|
-
* In this instance, <code>conn.exec</code> returns the value of the block.
|
1046
|
+
* Both #sync_exec and #async_exec release the GVL while waiting for server response, so that concurrent threads will get executed.
|
1047
|
+
* However #async_exec has two advantages:
|
933
1048
|
*
|
934
|
-
* #
|
935
|
-
*
|
936
|
-
*
|
937
|
-
* the query is finished. This is most notably visible by a delayed reaction to Control+C.
|
938
|
-
* Both methods ensure that other threads can process while waiting for the server to
|
939
|
-
* complete the request.
|
1049
|
+
* 1. #async_exec can be aborted by signals (like Ctrl-C), while #exec blocks signal processing until the query is answered.
|
1050
|
+
* 2. Ruby VM gets notified about IO blocked operations and can pass them through <tt>Fiber.scheduler</tt>.
|
1051
|
+
* So only <tt>async_*</tt> methods are compatible to event based schedulers like the async gem.
|
940
1052
|
*/
|
941
1053
|
static VALUE
|
942
|
-
|
1054
|
+
pgconn_sync_exec(int argc, VALUE *argv, VALUE self)
|
943
1055
|
{
|
944
|
-
|
1056
|
+
t_pg_connection *this = pg_get_connection_safe( self );
|
945
1057
|
PGresult *result = NULL;
|
946
1058
|
VALUE rb_pgresult;
|
947
1059
|
|
948
|
-
/* If called with no parameters, use PQexec */
|
949
|
-
if ( argc == 1 ) {
|
950
|
-
|
1060
|
+
/* If called with no or nil parameters, use PQexec for compatibility */
|
1061
|
+
if ( argc == 1 || (argc >= 2 && argc <= 4 && NIL_P(argv[1]) )) {
|
1062
|
+
VALUE query_str = argv[0];
|
951
1063
|
|
952
|
-
result = gvl_PQexec(
|
1064
|
+
result = gvl_PQexec(this->pgconn, pg_cstr_enc(query_str, this->enc_idx));
|
953
1065
|
rb_pgresult = pg_new_result(result, self);
|
954
1066
|
pg_result_check(rb_pgresult);
|
955
1067
|
if (rb_block_given_p()) {
|
@@ -957,11 +1069,10 @@ pgconn_exec(int argc, VALUE *argv, VALUE self)
|
|
957
1069
|
}
|
958
1070
|
return rb_pgresult;
|
959
1071
|
}
|
1072
|
+
pg_deprecated(0, ("forwarding exec to exec_params is deprecated"));
|
960
1073
|
|
961
1074
|
/* Otherwise, just call #exec_params instead for backward-compatibility */
|
962
|
-
|
963
|
-
return pgconn_exec_params( argc, argv, self );
|
964
|
-
}
|
1075
|
+
return pgconn_sync_exec_params( argc, argv, self );
|
965
1076
|
|
966
1077
|
}
|
967
1078
|
|
@@ -978,6 +1089,10 @@ struct query_params_data {
|
|
978
1089
|
* Filled by caller
|
979
1090
|
*/
|
980
1091
|
|
1092
|
+
/* The character encoding index of the connection. Any strings
|
1093
|
+
* given as query parameters are converted to this encoding.
|
1094
|
+
*/
|
1095
|
+
int enc_idx;
|
981
1096
|
/* Is the query function to execute one with types array? */
|
982
1097
|
int with_types;
|
983
1098
|
/* Array of query params from user space */
|
@@ -989,7 +1104,7 @@ struct query_params_data {
|
|
989
1104
|
* Filled by alloc_query_params()
|
990
1105
|
*/
|
991
1106
|
|
992
|
-
/* Wraps the pointer of allocated memory, if function parameters
|
1107
|
+
/* Wraps the pointer of allocated memory, if function parameters don't
|
993
1108
|
* fit in the memory_pool below.
|
994
1109
|
*/
|
995
1110
|
VALUE heap_pool;
|
@@ -1007,7 +1122,7 @@ struct query_params_data {
|
|
1007
1122
|
Oid *types;
|
1008
1123
|
|
1009
1124
|
/* This array takes the string values for the timeframe of the query,
|
1010
|
-
* if param value
|
1125
|
+
* if param value conversion is required
|
1011
1126
|
*/
|
1012
1127
|
VALUE gc_array;
|
1013
1128
|
|
@@ -1021,8 +1136,9 @@ struct query_params_data {
|
|
1021
1136
|
};
|
1022
1137
|
|
1023
1138
|
static void
|
1024
|
-
free_typecast_heap_chain(
|
1139
|
+
free_typecast_heap_chain(void *_chain_entry)
|
1025
1140
|
{
|
1141
|
+
struct linked_typecast_data *chain_entry = (struct linked_typecast_data *)_chain_entry;
|
1026
1142
|
while(chain_entry){
|
1027
1143
|
struct linked_typecast_data *next = chain_entry->next;
|
1028
1144
|
xfree(chain_entry);
|
@@ -1030,6 +1146,18 @@ free_typecast_heap_chain(struct linked_typecast_data *chain_entry)
|
|
1030
1146
|
}
|
1031
1147
|
}
|
1032
1148
|
|
1149
|
+
static const rb_data_type_t pg_typecast_buffer_type = {
|
1150
|
+
"PG::Connection typecast buffer chain",
|
1151
|
+
{
|
1152
|
+
(RUBY_DATA_FUNC) NULL,
|
1153
|
+
free_typecast_heap_chain,
|
1154
|
+
(size_t (*)(const void *))NULL,
|
1155
|
+
},
|
1156
|
+
0,
|
1157
|
+
0,
|
1158
|
+
RUBY_TYPED_FREE_IMMEDIATELY,
|
1159
|
+
};
|
1160
|
+
|
1033
1161
|
static char *
|
1034
1162
|
alloc_typecast_buf( VALUE *typecast_heap_chain, int len )
|
1035
1163
|
{
|
@@ -1040,17 +1168,28 @@ alloc_typecast_buf( VALUE *typecast_heap_chain, int len )
|
|
1040
1168
|
/* Did we already wrap a memory chain per T_DATA object? */
|
1041
1169
|
if( NIL_P( *typecast_heap_chain ) ){
|
1042
1170
|
/* Leave free'ing of the buffer chain to the GC, when paramsData has left the stack */
|
1043
|
-
*typecast_heap_chain =
|
1171
|
+
*typecast_heap_chain = TypedData_Wrap_Struct( rb_cObject, &pg_typecast_buffer_type, allocated );
|
1044
1172
|
allocated->next = NULL;
|
1045
1173
|
} else {
|
1046
1174
|
/* Append to the chain */
|
1047
|
-
allocated->next =
|
1048
|
-
|
1175
|
+
allocated->next = RTYPEDDATA_DATA( *typecast_heap_chain );
|
1176
|
+
RTYPEDDATA_DATA( *typecast_heap_chain ) = allocated;
|
1049
1177
|
}
|
1050
1178
|
|
1051
1179
|
return &allocated->data[0];
|
1052
1180
|
}
|
1053
1181
|
|
1182
|
+
static const rb_data_type_t pg_query_heap_pool_type = {
|
1183
|
+
"PG::Connection query heap pool",
|
1184
|
+
{
|
1185
|
+
(RUBY_DATA_FUNC) NULL,
|
1186
|
+
RUBY_TYPED_DEFAULT_FREE,
|
1187
|
+
(size_t (*)(const void *))NULL,
|
1188
|
+
},
|
1189
|
+
0,
|
1190
|
+
0,
|
1191
|
+
RUBY_TYPED_FREE_IMMEDIATELY,
|
1192
|
+
};
|
1054
1193
|
|
1055
1194
|
static int
|
1056
1195
|
alloc_query_params(struct query_params_data *paramsData)
|
@@ -1065,7 +1204,7 @@ alloc_query_params(struct query_params_data *paramsData)
|
|
1065
1204
|
|
1066
1205
|
Check_Type(paramsData->params, T_ARRAY);
|
1067
1206
|
|
1068
|
-
p_typemap =
|
1207
|
+
p_typemap = RTYPEDDATA_DATA( paramsData->typemap );
|
1069
1208
|
p_typemap->funcs.fit_to_query( paramsData->typemap, paramsData->params );
|
1070
1209
|
|
1071
1210
|
paramsData->heap_pool = Qnil;
|
@@ -1084,7 +1223,7 @@ alloc_query_params(struct query_params_data *paramsData)
|
|
1084
1223
|
/* Allocate one combined memory pool for all possible function parameters */
|
1085
1224
|
memory_pool = (char*)xmalloc( required_pool_size );
|
1086
1225
|
/* Leave free'ing of the buffer to the GC, when paramsData has left the stack */
|
1087
|
-
paramsData->heap_pool =
|
1226
|
+
paramsData->heap_pool = TypedData_Wrap_Struct( rb_cObject, &pg_query_heap_pool_type, memory_pool );
|
1088
1227
|
required_pool_size = 0;
|
1089
1228
|
}else{
|
1090
1229
|
/* Use stack memory for function parameters */
|
@@ -1138,7 +1277,7 @@ alloc_query_params(struct query_params_data *paramsData)
|
|
1138
1277
|
VALUE intermediate;
|
1139
1278
|
|
1140
1279
|
/* 1st pass for retiving the required memory space */
|
1141
|
-
int len = enc_func(conv, param_value, NULL, &intermediate);
|
1280
|
+
int len = enc_func(conv, param_value, NULL, &intermediate, paramsData->enc_idx);
|
1142
1281
|
|
1143
1282
|
if( len == -1 ){
|
1144
1283
|
/* The intermediate value is a String that can be used directly. */
|
@@ -1162,7 +1301,7 @@ alloc_query_params(struct query_params_data *paramsData)
|
|
1162
1301
|
}
|
1163
1302
|
|
1164
1303
|
/* 2nd pass for writing the data to prepared buffer */
|
1165
|
-
len = enc_func(conv, param_value, typecast_buf, &intermediate);
|
1304
|
+
len = enc_func(conv, param_value, typecast_buf, &intermediate, paramsData->enc_idx);
|
1166
1305
|
paramsData->values[i] = typecast_buf;
|
1167
1306
|
if( paramsData->formats[i] == 0 ){
|
1168
1307
|
/* text format strings must be zero terminated and lengths are ignored */
|
@@ -1197,85 +1336,52 @@ pgconn_query_assign_typemap( VALUE self, struct query_params_data *paramsData )
|
|
1197
1336
|
/* Use default typemap for queries. It's type is checked when assigned. */
|
1198
1337
|
paramsData->typemap = pg_get_connection(self)->type_map_for_queries;
|
1199
1338
|
}else{
|
1339
|
+
t_typemap *tm;
|
1340
|
+
UNUSED(tm);
|
1341
|
+
|
1200
1342
|
/* Check type of method param */
|
1201
|
-
|
1202
|
-
rb_raise( rb_eTypeError, "wrong argument type %s (expected kind of PG::TypeMap)",
|
1203
|
-
rb_obj_classname( paramsData->typemap ) );
|
1204
|
-
}
|
1205
|
-
Check_Type( paramsData->typemap, T_DATA );
|
1343
|
+
TypedData_Get_Struct(paramsData->typemap, t_typemap, &pg_typemap_type, tm);
|
1206
1344
|
}
|
1207
1345
|
}
|
1208
1346
|
|
1209
1347
|
/*
|
1210
1348
|
* call-seq:
|
1211
|
-
* conn.
|
1212
|
-
* conn.
|
1213
|
-
*
|
1214
|
-
* Sends SQL query request specified by +sql+ to PostgreSQL using placeholders
|
1215
|
-
* for parameters.
|
1216
|
-
*
|
1217
|
-
* Returns a PG::Result instance on success. On failure, it raises a PG::Error.
|
1218
|
-
*
|
1219
|
-
* +params+ is an array of the bind parameters for the SQL query.
|
1220
|
-
* Each element of the +params+ array may be either:
|
1221
|
-
* a hash of the form:
|
1222
|
-
* {:value => String (value of bind parameter)
|
1223
|
-
* :type => Fixnum (oid of type of bind parameter)
|
1224
|
-
* :format => Fixnum (0 for text, 1 for binary)
|
1225
|
-
* }
|
1226
|
-
* or, it may be a String. If it is a string, that is equivalent to the hash:
|
1227
|
-
* { :value => <string value>, :type => 0, :format => 0 }
|
1228
|
-
*
|
1229
|
-
* PostgreSQL bind parameters are represented as $1, $1, $2, etc.,
|
1230
|
-
* inside the SQL query. The 0th element of the +params+ array is bound
|
1231
|
-
* to $1, the 1st element is bound to $2, etc. +nil+ is treated as +NULL+.
|
1232
|
-
*
|
1233
|
-
* If the types are not specified, they will be inferred by PostgreSQL.
|
1234
|
-
* Instead of specifying type oids, it's recommended to simply add
|
1235
|
-
* explicit casts in the query to ensure that the right type is used.
|
1236
|
-
*
|
1237
|
-
* For example: "SELECT $1::int"
|
1238
|
-
*
|
1239
|
-
* The optional +result_format+ should be 0 for text results, 1
|
1240
|
-
* for binary.
|
1241
|
-
*
|
1242
|
-
* type_map can be a PG::TypeMap derivation (such as PG::BasicTypeMapForQueries).
|
1243
|
-
* This will type cast the params form various Ruby types before transmission
|
1244
|
-
* based on the encoders defined by the type map. When a type encoder is used
|
1245
|
-
* the format and oid of a given bind parameter are retrieved from the encoder
|
1246
|
-
* instead out of the hash form described above.
|
1349
|
+
* conn.sync_exec_params(sql, params[, result_format[, type_map]] ) -> PG::Result
|
1350
|
+
* conn.sync_exec_params(sql, params[, result_format[, type_map]] ) {|pg_result| block }
|
1247
1351
|
*
|
1248
|
-
*
|
1249
|
-
*
|
1250
|
-
*
|
1352
|
+
* This function has the same behavior as #async_exec_params, but is implemented using the synchronous command processing API of libpq.
|
1353
|
+
* See #async_exec for the differences between the two API variants.
|
1354
|
+
* It's not recommended to use explicit sync or async variants but #exec_params instead, unless you have a good reason to do so.
|
1251
1355
|
*/
|
1252
1356
|
static VALUE
|
1253
|
-
|
1357
|
+
pgconn_sync_exec_params( int argc, VALUE *argv, VALUE self )
|
1254
1358
|
{
|
1255
|
-
|
1359
|
+
t_pg_connection *this = pg_get_connection_safe( self );
|
1256
1360
|
PGresult *result = NULL;
|
1257
1361
|
VALUE rb_pgresult;
|
1258
1362
|
VALUE command, in_res_fmt;
|
1259
1363
|
int nParams;
|
1260
1364
|
int resultFormat;
|
1261
|
-
struct query_params_data paramsData;
|
1365
|
+
struct query_params_data paramsData = { this->enc_idx };
|
1262
1366
|
|
1367
|
+
/* For compatibility we accept 1 to 4 parameters */
|
1263
1368
|
rb_scan_args(argc, argv, "13", &command, ¶msData.params, &in_res_fmt, ¶msData.typemap);
|
1264
1369
|
paramsData.with_types = 1;
|
1265
1370
|
|
1266
1371
|
/*
|
1267
|
-
*
|
1268
|
-
*
|
1372
|
+
* For backward compatibility no or +nil+ for the second parameter
|
1373
|
+
* is passed to #exec
|
1269
1374
|
*/
|
1270
1375
|
if ( NIL_P(paramsData.params) ) {
|
1271
|
-
|
1376
|
+
pg_deprecated(1, ("forwarding exec_params to exec is deprecated"));
|
1377
|
+
return pgconn_sync_exec( 1, argv, self );
|
1272
1378
|
}
|
1273
1379
|
pgconn_query_assign_typemap( self, ¶msData );
|
1274
1380
|
|
1275
1381
|
resultFormat = NIL_P(in_res_fmt) ? 0 : NUM2INT(in_res_fmt);
|
1276
1382
|
nParams = alloc_query_params( ¶msData );
|
1277
1383
|
|
1278
|
-
result = gvl_PQexecParams(
|
1384
|
+
result = gvl_PQexecParams(this->pgconn, pg_cstr_enc(command, paramsData.enc_idx), nParams, paramsData.types,
|
1279
1385
|
(const char * const *)paramsData.values, paramsData.lengths, paramsData.formats, resultFormat);
|
1280
1386
|
|
1281
1387
|
free_query_params( ¶msData );
|
@@ -1292,28 +1398,16 @@ pgconn_exec_params( int argc, VALUE *argv, VALUE self )
|
|
1292
1398
|
|
1293
1399
|
/*
|
1294
1400
|
* call-seq:
|
1295
|
-
* conn.
|
1296
|
-
*
|
1297
|
-
* Prepares statement _sql_ with name _name_ to be executed later.
|
1298
|
-
* Returns a PG::Result instance on success.
|
1299
|
-
* On failure, it raises a PG::Error.
|
1300
|
-
*
|
1301
|
-
* +param_types+ is an optional parameter to specify the Oids of the
|
1302
|
-
* types of the parameters.
|
1401
|
+
* conn.sync_prepare(stmt_name, sql [, param_types ] ) -> PG::Result
|
1303
1402
|
*
|
1304
|
-
*
|
1305
|
-
*
|
1306
|
-
* explicit
|
1307
|
-
*
|
1308
|
-
* For example: "SELECT $1::int"
|
1309
|
-
*
|
1310
|
-
* PostgreSQL bind parameters are represented as $1, $1, $2, etc.,
|
1311
|
-
* inside the SQL query.
|
1403
|
+
* This function has the same behavior as #async_prepare, but is implemented using the synchronous command processing API of libpq.
|
1404
|
+
* See #async_exec for the differences between the two API variants.
|
1405
|
+
* It's not recommended to use explicit sync or async variants but #prepare instead, unless you have a good reason to do so.
|
1312
1406
|
*/
|
1313
1407
|
static VALUE
|
1314
|
-
|
1408
|
+
pgconn_sync_prepare(int argc, VALUE *argv, VALUE self)
|
1315
1409
|
{
|
1316
|
-
|
1410
|
+
t_pg_connection *this = pg_get_connection_safe( self );
|
1317
1411
|
PGresult *result = NULL;
|
1318
1412
|
VALUE rb_pgresult;
|
1319
1413
|
VALUE name, command, in_paramtypes;
|
@@ -1321,10 +1415,13 @@ pgconn_prepare(int argc, VALUE *argv, VALUE self)
|
|
1321
1415
|
int i = 0;
|
1322
1416
|
int nParams = 0;
|
1323
1417
|
Oid *paramTypes = NULL;
|
1418
|
+
const char *name_cstr;
|
1419
|
+
const char *command_cstr;
|
1420
|
+
int enc_idx = this->enc_idx;
|
1324
1421
|
|
1325
1422
|
rb_scan_args(argc, argv, "21", &name, &command, &in_paramtypes);
|
1326
|
-
|
1327
|
-
|
1423
|
+
name_cstr = pg_cstr_enc(name, enc_idx);
|
1424
|
+
command_cstr = pg_cstr_enc(command, enc_idx);
|
1328
1425
|
|
1329
1426
|
if(! NIL_P(in_paramtypes)) {
|
1330
1427
|
Check_Type(in_paramtypes, T_ARRAY);
|
@@ -1338,8 +1435,7 @@ pgconn_prepare(int argc, VALUE *argv, VALUE self)
|
|
1338
1435
|
paramTypes[i] = NUM2UINT(param);
|
1339
1436
|
}
|
1340
1437
|
}
|
1341
|
-
result = gvl_PQprepare(
|
1342
|
-
nParams, paramTypes);
|
1438
|
+
result = gvl_PQprepare(this->pgconn, name_cstr, command_cstr, nParams, paramTypes);
|
1343
1439
|
|
1344
1440
|
xfree(paramTypes);
|
1345
1441
|
|
@@ -1350,53 +1446,26 @@ pgconn_prepare(int argc, VALUE *argv, VALUE self)
|
|
1350
1446
|
|
1351
1447
|
/*
|
1352
1448
|
* call-seq:
|
1353
|
-
* conn.
|
1354
|
-
* conn.
|
1355
|
-
*
|
1356
|
-
* Execute prepared named statement specified by _statement_name_.
|
1357
|
-
* Returns a PG::Result instance on success.
|
1358
|
-
* On failure, it raises a PG::Error.
|
1359
|
-
*
|
1360
|
-
* +params+ is an array of the optional bind parameters for the
|
1361
|
-
* SQL query. Each element of the +params+ array may be either:
|
1362
|
-
* a hash of the form:
|
1363
|
-
* {:value => String (value of bind parameter)
|
1364
|
-
* :format => Fixnum (0 for text, 1 for binary)
|
1365
|
-
* }
|
1366
|
-
* or, it may be a String. If it is a string, that is equivalent to the hash:
|
1367
|
-
* { :value => <string value>, :format => 0 }
|
1368
|
-
*
|
1369
|
-
* PostgreSQL bind parameters are represented as $1, $1, $2, etc.,
|
1370
|
-
* inside the SQL query. The 0th element of the +params+ array is bound
|
1371
|
-
* to $1, the 1st element is bound to $2, etc. +nil+ is treated as +NULL+.
|
1372
|
-
*
|
1373
|
-
* The optional +result_format+ should be 0 for text results, 1
|
1374
|
-
* for binary.
|
1449
|
+
* conn.sync_exec_prepared(statement_name [, params, result_format[, type_map]] ) -> PG::Result
|
1450
|
+
* conn.sync_exec_prepared(statement_name [, params, result_format[, type_map]] ) {|pg_result| block }
|
1375
1451
|
*
|
1376
|
-
*
|
1377
|
-
*
|
1378
|
-
*
|
1379
|
-
* the format and oid of a given bind parameter are retrieved from the encoder
|
1380
|
-
* instead out of the hash form described above.
|
1381
|
-
*
|
1382
|
-
* If the optional code block is given, it will be passed <i>result</i> as an argument,
|
1383
|
-
* and the PG::Result object will automatically be cleared when the block terminates.
|
1384
|
-
* In this instance, <code>conn.exec_prepared</code> returns the value of the block.
|
1452
|
+
* This function has the same behavior as #async_exec_prepared, but is implemented using the synchronous command processing API of libpq.
|
1453
|
+
* See #async_exec for the differences between the two API variants.
|
1454
|
+
* It's not recommended to use explicit sync or async variants but #exec_prepared instead, unless you have a good reason to do so.
|
1385
1455
|
*/
|
1386
1456
|
static VALUE
|
1387
|
-
|
1457
|
+
pgconn_sync_exec_prepared(int argc, VALUE *argv, VALUE self)
|
1388
1458
|
{
|
1389
|
-
|
1459
|
+
t_pg_connection *this = pg_get_connection_safe( self );
|
1390
1460
|
PGresult *result = NULL;
|
1391
1461
|
VALUE rb_pgresult;
|
1392
1462
|
VALUE name, in_res_fmt;
|
1393
1463
|
int nParams;
|
1394
1464
|
int resultFormat;
|
1395
|
-
struct query_params_data paramsData;
|
1465
|
+
struct query_params_data paramsData = { this->enc_idx };
|
1396
1466
|
|
1397
1467
|
rb_scan_args(argc, argv, "13", &name, ¶msData.params, &in_res_fmt, ¶msData.typemap);
|
1398
1468
|
paramsData.with_types = 0;
|
1399
|
-
Check_Type(name, T_STRING);
|
1400
1469
|
|
1401
1470
|
if(NIL_P(paramsData.params)) {
|
1402
1471
|
paramsData.params = rb_ary_new2(0);
|
@@ -1406,7 +1475,7 @@ pgconn_exec_prepared(int argc, VALUE *argv, VALUE self)
|
|
1406
1475
|
resultFormat = NIL_P(in_res_fmt) ? 0 : NUM2INT(in_res_fmt);
|
1407
1476
|
nParams = alloc_query_params( ¶msData );
|
1408
1477
|
|
1409
|
-
result = gvl_PQexecPrepared(
|
1478
|
+
result = gvl_PQexecPrepared(this->pgconn, pg_cstr_enc(name, paramsData.enc_idx), nParams,
|
1410
1479
|
(const char * const *)paramsData.values, paramsData.lengths, paramsData.formats,
|
1411
1480
|
resultFormat);
|
1412
1481
|
|
@@ -1423,26 +1492,26 @@ pgconn_exec_prepared(int argc, VALUE *argv, VALUE self)
|
|
1423
1492
|
|
1424
1493
|
/*
|
1425
1494
|
* call-seq:
|
1426
|
-
* conn.
|
1495
|
+
* conn.sync_describe_prepared( statement_name ) -> PG::Result
|
1427
1496
|
*
|
1428
|
-
*
|
1429
|
-
*
|
1497
|
+
* This function has the same behavior as #async_describe_prepared, but is implemented using the synchronous command processing API of libpq.
|
1498
|
+
* See #async_exec for the differences between the two API variants.
|
1499
|
+
* It's not recommended to use explicit sync or async variants but #describe_prepared instead, unless you have a good reason to do so.
|
1430
1500
|
*/
|
1431
1501
|
static VALUE
|
1432
|
-
|
1502
|
+
pgconn_sync_describe_prepared(VALUE self, VALUE stmt_name)
|
1433
1503
|
{
|
1434
1504
|
PGresult *result;
|
1435
1505
|
VALUE rb_pgresult;
|
1436
|
-
|
1437
|
-
char *stmt;
|
1438
|
-
if(stmt_name
|
1506
|
+
t_pg_connection *this = pg_get_connection_safe( self );
|
1507
|
+
const char *stmt;
|
1508
|
+
if(NIL_P(stmt_name)) {
|
1439
1509
|
stmt = NULL;
|
1440
1510
|
}
|
1441
1511
|
else {
|
1442
|
-
|
1443
|
-
stmt = StringValueCStr(stmt_name);
|
1512
|
+
stmt = pg_cstr_enc(stmt_name, this->enc_idx);
|
1444
1513
|
}
|
1445
|
-
result = gvl_PQdescribePrepared(
|
1514
|
+
result = gvl_PQdescribePrepared(this->pgconn, stmt);
|
1446
1515
|
rb_pgresult = pg_new_result(result, self);
|
1447
1516
|
pg_result_check(rb_pgresult);
|
1448
1517
|
return rb_pgresult;
|
@@ -1451,26 +1520,27 @@ pgconn_describe_prepared(VALUE self, VALUE stmt_name)
|
|
1451
1520
|
|
1452
1521
|
/*
|
1453
1522
|
* call-seq:
|
1454
|
-
* conn.
|
1523
|
+
* conn.sync_describe_portal( portal_name ) -> PG::Result
|
1455
1524
|
*
|
1456
|
-
*
|
1525
|
+
* This function has the same behavior as #async_describe_portal, but is implemented using the synchronous command processing API of libpq.
|
1526
|
+
* See #async_exec for the differences between the two API variants.
|
1527
|
+
* It's not recommended to use explicit sync or async variants but #describe_portal instead, unless you have a good reason to do so.
|
1457
1528
|
*/
|
1458
1529
|
static VALUE
|
1459
|
-
|
1530
|
+
pgconn_sync_describe_portal(self, stmt_name)
|
1460
1531
|
VALUE self, stmt_name;
|
1461
1532
|
{
|
1462
1533
|
PGresult *result;
|
1463
1534
|
VALUE rb_pgresult;
|
1464
|
-
|
1465
|
-
char *stmt;
|
1466
|
-
if(stmt_name
|
1535
|
+
t_pg_connection *this = pg_get_connection_safe( self );
|
1536
|
+
const char *stmt;
|
1537
|
+
if(NIL_P(stmt_name)) {
|
1467
1538
|
stmt = NULL;
|
1468
1539
|
}
|
1469
1540
|
else {
|
1470
|
-
|
1471
|
-
stmt = StringValueCStr(stmt_name);
|
1541
|
+
stmt = pg_cstr_enc(stmt_name, this->enc_idx);
|
1472
1542
|
}
|
1473
|
-
result = gvl_PQdescribePortal(
|
1543
|
+
result = gvl_PQdescribePortal(this->pgconn, stmt);
|
1474
1544
|
rb_pgresult = pg_new_result(result, self);
|
1475
1545
|
pg_result_check(rb_pgresult);
|
1476
1546
|
return rb_pgresult;
|
@@ -1492,6 +1562,9 @@ pgconn_describe_portal(self, stmt_name)
|
|
1492
1562
|
* * +PGRES_NONFATAL_ERROR+
|
1493
1563
|
* * +PGRES_FATAL_ERROR+
|
1494
1564
|
* * +PGRES_COPY_BOTH+
|
1565
|
+
* * +PGRES_SINGLE_TUPLE+
|
1566
|
+
* * +PGRES_PIPELINE_SYNC+
|
1567
|
+
* * +PGRES_PIPELINE_ABORTED+
|
1495
1568
|
*/
|
1496
1569
|
static VALUE
|
1497
1570
|
pgconn_make_empty_pgresult(VALUE self, VALUE status)
|
@@ -1510,10 +1583,6 @@ pgconn_make_empty_pgresult(VALUE self, VALUE status)
|
|
1510
1583
|
* call-seq:
|
1511
1584
|
* conn.escape_string( str ) -> String
|
1512
1585
|
*
|
1513
|
-
* Connection instance method for versions of 8.1 and higher of libpq
|
1514
|
-
* uses PQescapeStringConn, which is safer. Avoid calling as a class method,
|
1515
|
-
* the class method uses the deprecated PQescapeString() API function.
|
1516
|
-
*
|
1517
1586
|
* Returns a SQL-safe version of the String _str_.
|
1518
1587
|
* This is the preferred way to make strings safe for inclusion in
|
1519
1588
|
* SQL queries.
|
@@ -1521,33 +1590,43 @@ pgconn_make_empty_pgresult(VALUE self, VALUE status)
|
|
1521
1590
|
* Consider using exec_params, which avoids the need for passing values
|
1522
1591
|
* inside of SQL commands.
|
1523
1592
|
*
|
1524
|
-
*
|
1593
|
+
* Character encoding of escaped string will be equal to client encoding of connection.
|
1594
|
+
*
|
1595
|
+
* NOTE: This class version of this method can only be used safely in client
|
1596
|
+
* programs that use a single PostgreSQL connection at a time (in this case it can
|
1597
|
+
* find out what it needs to know "behind the scenes"). It might give the wrong
|
1598
|
+
* results if used in programs that use multiple database connections; use the
|
1599
|
+
* same method on the connection object in such cases.
|
1600
|
+
*
|
1601
|
+
* See also convenience functions #escape_literal and #escape_identifier which also add proper quotes around the string.
|
1525
1602
|
*/
|
1526
1603
|
static VALUE
|
1527
1604
|
pgconn_s_escape(VALUE self, VALUE string)
|
1528
1605
|
{
|
1529
|
-
char *escaped;
|
1530
1606
|
size_t size;
|
1531
1607
|
int error;
|
1532
1608
|
VALUE result;
|
1609
|
+
int enc_idx;
|
1610
|
+
int singleton = !rb_obj_is_kind_of(self, rb_cPGconn);
|
1533
1611
|
|
1534
|
-
|
1612
|
+
StringValueCStr(string);
|
1613
|
+
enc_idx = singleton ? ENCODING_GET(string) : pg_get_connection(self)->enc_idx;
|
1614
|
+
if( ENCODING_GET(string) != enc_idx ){
|
1615
|
+
string = rb_str_export_to_enc(string, rb_enc_from_index(enc_idx));
|
1616
|
+
}
|
1535
1617
|
|
1536
|
-
|
1537
|
-
|
1538
|
-
|
1618
|
+
result = rb_str_new(NULL, RSTRING_LEN(string) * 2 + 1);
|
1619
|
+
PG_ENCODING_SET_NOCHECK(result, enc_idx);
|
1620
|
+
if( !singleton ) {
|
1621
|
+
size = PQescapeStringConn(pg_get_pgconn(self), RSTRING_PTR(result),
|
1539
1622
|
RSTRING_PTR(string), RSTRING_LEN(string), &error);
|
1540
|
-
if(error)
|
1541
|
-
|
1542
|
-
|
1543
|
-
}
|
1623
|
+
if(error)
|
1624
|
+
pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(pg_get_pgconn(self)));
|
1625
|
+
|
1544
1626
|
} else {
|
1545
|
-
size = PQescapeString(
|
1627
|
+
size = PQescapeString(RSTRING_PTR(result), RSTRING_PTR(string), RSTRING_LEN(string));
|
1546
1628
|
}
|
1547
|
-
result
|
1548
|
-
xfree(escaped);
|
1549
|
-
OBJ_INFECT(result, string);
|
1550
|
-
PG_ENCODING_SET_NOCHECK(result, ENCODING_GET( rb_obj_is_kind_of(self, rb_cPGconn) ? self : string ));
|
1629
|
+
rb_str_set_len(result, size);
|
1551
1630
|
|
1552
1631
|
return result;
|
1553
1632
|
}
|
@@ -1556,13 +1635,6 @@ pgconn_s_escape(VALUE self, VALUE string)
|
|
1556
1635
|
* call-seq:
|
1557
1636
|
* conn.escape_bytea( string ) -> String
|
1558
1637
|
*
|
1559
|
-
* Connection instance method for versions of 8.1 and higher of libpq
|
1560
|
-
* uses PQescapeByteaConn, which is safer. Avoid calling as a class method,
|
1561
|
-
* the class method uses the deprecated PQescapeBytea() API function.
|
1562
|
-
*
|
1563
|
-
* Use the instance method version of this function, it is safer than the
|
1564
|
-
* class method.
|
1565
|
-
*
|
1566
1638
|
* Escapes binary data for use within an SQL command with the type +bytea+.
|
1567
1639
|
*
|
1568
1640
|
* Certain byte values must be escaped (but all byte values may be escaped)
|
@@ -1575,6 +1647,12 @@ pgconn_s_escape(VALUE self, VALUE string)
|
|
1575
1647
|
*
|
1576
1648
|
* Consider using exec_params, which avoids the need for passing values inside of
|
1577
1649
|
* SQL commands.
|
1650
|
+
*
|
1651
|
+
* NOTE: This class version of this method can only be used safely in client
|
1652
|
+
* programs that use a single PostgreSQL connection at a time (in this case it can
|
1653
|
+
* find out what it needs to know "behind the scenes"). It might give the wrong
|
1654
|
+
* results if used in programs that use multiple database connections; use the
|
1655
|
+
* same method on the connection object in such cases.
|
1578
1656
|
*/
|
1579
1657
|
static VALUE
|
1580
1658
|
pgconn_s_escape_bytea(VALUE self, VALUE str)
|
@@ -1594,7 +1672,6 @@ pgconn_s_escape_bytea(VALUE self, VALUE str)
|
|
1594
1672
|
}
|
1595
1673
|
|
1596
1674
|
ret = rb_str_new((char*)to, to_len - 1);
|
1597
|
-
OBJ_INFECT(ret, str);
|
1598
1675
|
PQfreemem(to);
|
1599
1676
|
return ret;
|
1600
1677
|
}
|
@@ -1624,83 +1701,76 @@ pgconn_s_unescape_bytea(VALUE self, VALUE str)
|
|
1624
1701
|
to = PQunescapeBytea(from, &to_len);
|
1625
1702
|
|
1626
1703
|
ret = rb_str_new((char*)to, to_len);
|
1627
|
-
OBJ_INFECT(ret, str);
|
1628
1704
|
PQfreemem(to);
|
1629
1705
|
return ret;
|
1630
1706
|
}
|
1631
1707
|
|
1632
|
-
#ifdef HAVE_PQESCAPELITERAL
|
1633
1708
|
/*
|
1634
1709
|
* call-seq:
|
1635
1710
|
* conn.escape_literal( str ) -> String
|
1636
1711
|
*
|
1637
1712
|
* Escape an arbitrary String +str+ as a literal.
|
1713
|
+
*
|
1714
|
+
* See also PG::TextEncoder::QuotedLiteral for a type cast integrated version of this function.
|
1638
1715
|
*/
|
1639
1716
|
static VALUE
|
1640
1717
|
pgconn_escape_literal(VALUE self, VALUE string)
|
1641
1718
|
{
|
1642
|
-
|
1719
|
+
t_pg_connection *this = pg_get_connection_safe( self );
|
1643
1720
|
char *escaped = NULL;
|
1644
|
-
VALUE error;
|
1645
1721
|
VALUE result = Qnil;
|
1722
|
+
int enc_idx = this->enc_idx;
|
1646
1723
|
|
1647
|
-
|
1724
|
+
StringValueCStr(string);
|
1725
|
+
if( ENCODING_GET(string) != enc_idx ){
|
1726
|
+
string = rb_str_export_to_enc(string, rb_enc_from_index(enc_idx));
|
1727
|
+
}
|
1648
1728
|
|
1649
|
-
escaped = PQescapeLiteral(
|
1729
|
+
escaped = PQescapeLiteral(this->pgconn, RSTRING_PTR(string), RSTRING_LEN(string));
|
1650
1730
|
if (escaped == NULL)
|
1651
|
-
|
1652
|
-
|
1653
|
-
rb_iv_set(error, "@connection", self);
|
1654
|
-
rb_exc_raise(error);
|
1655
|
-
return Qnil;
|
1656
|
-
}
|
1731
|
+
pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(this->pgconn));
|
1732
|
+
|
1657
1733
|
result = rb_str_new2(escaped);
|
1658
1734
|
PQfreemem(escaped);
|
1659
|
-
|
1660
|
-
PG_ENCODING_SET_NOCHECK(result, ENCODING_GET(self));
|
1735
|
+
PG_ENCODING_SET_NOCHECK(result, enc_idx);
|
1661
1736
|
|
1662
1737
|
return result;
|
1663
1738
|
}
|
1664
|
-
#endif
|
1665
1739
|
|
1666
|
-
#ifdef HAVE_PQESCAPEIDENTIFIER
|
1667
1740
|
/*
|
1668
1741
|
* call-seq:
|
1669
1742
|
* conn.escape_identifier( str ) -> String
|
1670
1743
|
*
|
1671
1744
|
* Escape an arbitrary String +str+ as an identifier.
|
1672
1745
|
*
|
1673
|
-
* This method does the same as #quote_ident
|
1674
|
-
*
|
1746
|
+
* This method does the same as #quote_ident with a String argument,
|
1747
|
+
* but it doesn't support an Array argument and it makes use of libpq
|
1748
|
+
* to process the string.
|
1675
1749
|
*/
|
1676
1750
|
static VALUE
|
1677
1751
|
pgconn_escape_identifier(VALUE self, VALUE string)
|
1678
1752
|
{
|
1679
|
-
|
1753
|
+
t_pg_connection *this = pg_get_connection_safe( self );
|
1680
1754
|
char *escaped = NULL;
|
1681
|
-
VALUE error;
|
1682
1755
|
VALUE result = Qnil;
|
1756
|
+
int enc_idx = this->enc_idx;
|
1683
1757
|
|
1684
|
-
|
1758
|
+
StringValueCStr(string);
|
1759
|
+
if( ENCODING_GET(string) != enc_idx ){
|
1760
|
+
string = rb_str_export_to_enc(string, rb_enc_from_index(enc_idx));
|
1761
|
+
}
|
1685
1762
|
|
1686
|
-
escaped = PQescapeIdentifier(
|
1763
|
+
escaped = PQescapeIdentifier(this->pgconn, RSTRING_PTR(string), RSTRING_LEN(string));
|
1687
1764
|
if (escaped == NULL)
|
1688
|
-
|
1689
|
-
|
1690
|
-
rb_iv_set(error, "@connection", self);
|
1691
|
-
rb_exc_raise(error);
|
1692
|
-
return Qnil;
|
1693
|
-
}
|
1765
|
+
pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(this->pgconn));
|
1766
|
+
|
1694
1767
|
result = rb_str_new2(escaped);
|
1695
1768
|
PQfreemem(escaped);
|
1696
|
-
|
1697
|
-
PG_ENCODING_SET_NOCHECK(result, ENCODING_GET(self));
|
1769
|
+
PG_ENCODING_SET_NOCHECK(result, enc_idx);
|
1698
1770
|
|
1699
1771
|
return result;
|
1700
1772
|
}
|
1701
|
-
#endif
|
1702
1773
|
|
1703
|
-
#ifdef HAVE_PQSETSINGLEROWMODE
|
1704
1774
|
/*
|
1705
1775
|
* call-seq:
|
1706
1776
|
* conn.set_single_row_mode -> self
|
@@ -1736,44 +1806,74 @@ pgconn_escape_identifier(VALUE self, VALUE string)
|
|
1736
1806
|
* # do something with the received row
|
1737
1807
|
* end
|
1738
1808
|
* end
|
1739
|
-
*
|
1740
1809
|
*/
|
1741
1810
|
static VALUE
|
1742
1811
|
pgconn_set_single_row_mode(VALUE self)
|
1743
1812
|
{
|
1744
1813
|
PGconn *conn = pg_get_pgconn(self);
|
1745
|
-
VALUE error;
|
1746
1814
|
|
1747
1815
|
if( PQsetSingleRowMode(conn) == 0 )
|
1748
|
-
|
1749
|
-
error = rb_exc_new2(rb_ePGerror, PQerrorMessage(conn));
|
1750
|
-
rb_iv_set(error, "@connection", self);
|
1751
|
-
rb_exc_raise(error);
|
1752
|
-
}
|
1816
|
+
pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(conn));
|
1753
1817
|
|
1754
1818
|
return self;
|
1755
1819
|
}
|
1756
|
-
|
1820
|
+
|
1821
|
+
static VALUE pgconn_send_query_params(int argc, VALUE *argv, VALUE self);
|
1822
|
+
|
1823
|
+
/*
|
1824
|
+
* call-seq:
|
1825
|
+
* conn.send_query(sql) -> nil
|
1826
|
+
*
|
1827
|
+
* Sends SQL query request specified by _sql_ to PostgreSQL for
|
1828
|
+
* asynchronous processing, and immediately returns.
|
1829
|
+
* On failure, it raises a PG::Error.
|
1830
|
+
*
|
1831
|
+
* For backward compatibility, if you pass more than one parameter to this method,
|
1832
|
+
* it will call #send_query_params for you. New code should explicitly use #send_query_params if
|
1833
|
+
* argument placeholders are used.
|
1834
|
+
*
|
1835
|
+
*/
|
1836
|
+
static VALUE
|
1837
|
+
pgconn_send_query(int argc, VALUE *argv, VALUE self)
|
1838
|
+
{
|
1839
|
+
t_pg_connection *this = pg_get_connection_safe( self );
|
1840
|
+
|
1841
|
+
/* If called with no or nil parameters, use PQexec for compatibility */
|
1842
|
+
if ( argc == 1 || (argc >= 2 && argc <= 4 && NIL_P(argv[1]) )) {
|
1843
|
+
if(gvl_PQsendQuery(this->pgconn, pg_cstr_enc(argv[0], this->enc_idx)) == 0)
|
1844
|
+
pg_raise_conn_error( rb_eUnableToSend, self, "%s", PQerrorMessage(this->pgconn));
|
1845
|
+
|
1846
|
+
pgconn_wait_for_flush( self );
|
1847
|
+
return Qnil;
|
1848
|
+
}
|
1849
|
+
|
1850
|
+
pg_deprecated(2, ("forwarding async_exec to async_exec_params and send_query to send_query_params is deprecated"));
|
1851
|
+
|
1852
|
+
/* If called with parameters, and optionally result_format,
|
1853
|
+
* use PQsendQueryParams
|
1854
|
+
*/
|
1855
|
+
return pgconn_send_query_params( argc, argv, self);
|
1856
|
+
}
|
1757
1857
|
|
1758
1858
|
/*
|
1759
1859
|
* call-seq:
|
1760
|
-
* conn.
|
1860
|
+
* conn.send_query_params(sql, params [, result_format [, type_map ]] ) -> nil
|
1761
1861
|
*
|
1762
1862
|
* Sends SQL query request specified by _sql_ to PostgreSQL for
|
1763
1863
|
* asynchronous processing, and immediately returns.
|
1764
1864
|
* On failure, it raises a PG::Error.
|
1765
1865
|
*
|
1766
|
-
* +params+ is an
|
1866
|
+
* +params+ is an array of the bind parameters for the SQL query.
|
1767
1867
|
* Each element of the +params+ array may be either:
|
1768
1868
|
* a hash of the form:
|
1769
1869
|
* {:value => String (value of bind parameter)
|
1770
|
-
* :type =>
|
1771
|
-
* :format =>
|
1870
|
+
* :type => Integer (oid of type of bind parameter)
|
1871
|
+
* :format => Integer (0 for text, 1 for binary)
|
1772
1872
|
* }
|
1773
1873
|
* or, it may be a String. If it is a string, that is equivalent to the hash:
|
1774
1874
|
* { :value => <string value>, :type => 0, :format => 0 }
|
1775
1875
|
*
|
1776
|
-
* PostgreSQL bind parameters are represented as $1, $
|
1876
|
+
* PostgreSQL bind parameters are represented as $1, $2, $3, etc.,
|
1777
1877
|
* inside the SQL query. The 0th element of the +params+ array is bound
|
1778
1878
|
* to $1, the 1st element is bound to $2, etc. +nil+ is treated as +NULL+.
|
1779
1879
|
*
|
@@ -1786,56 +1886,39 @@ pgconn_set_single_row_mode(VALUE self)
|
|
1786
1886
|
* The optional +result_format+ should be 0 for text results, 1
|
1787
1887
|
* for binary.
|
1788
1888
|
*
|
1789
|
-
* type_map can be a PG::TypeMap derivation (such as PG::BasicTypeMapForQueries).
|
1790
|
-
* This will type cast the params
|
1889
|
+
* +type_map+ can be a PG::TypeMap derivation (such as PG::BasicTypeMapForQueries).
|
1890
|
+
* This will type cast the params from various Ruby types before transmission
|
1791
1891
|
* based on the encoders defined by the type map. When a type encoder is used
|
1792
1892
|
* the format and oid of a given bind parameter are retrieved from the encoder
|
1793
1893
|
* instead out of the hash form described above.
|
1794
1894
|
*
|
1795
1895
|
*/
|
1796
1896
|
static VALUE
|
1797
|
-
|
1897
|
+
pgconn_send_query_params(int argc, VALUE *argv, VALUE self)
|
1798
1898
|
{
|
1799
|
-
|
1899
|
+
t_pg_connection *this = pg_get_connection_safe( self );
|
1800
1900
|
int result;
|
1801
1901
|
VALUE command, in_res_fmt;
|
1802
|
-
VALUE error;
|
1803
1902
|
int nParams;
|
1804
1903
|
int resultFormat;
|
1805
|
-
struct query_params_data paramsData;
|
1904
|
+
struct query_params_data paramsData = { this->enc_idx };
|
1806
1905
|
|
1807
|
-
rb_scan_args(argc, argv, "
|
1906
|
+
rb_scan_args(argc, argv, "22", &command, ¶msData.params, &in_res_fmt, ¶msData.typemap);
|
1808
1907
|
paramsData.with_types = 1;
|
1809
|
-
Check_Type(command, T_STRING);
|
1810
|
-
|
1811
|
-
/* If called with no parameters, use PQsendQuery */
|
1812
|
-
if(NIL_P(paramsData.params)) {
|
1813
|
-
if(gvl_PQsendQuery(conn,StringValueCStr(command)) == 0) {
|
1814
|
-
error = rb_exc_new2(rb_eUnableToSend, PQerrorMessage(conn));
|
1815
|
-
rb_iv_set(error, "@connection", self);
|
1816
|
-
rb_exc_raise(error);
|
1817
|
-
}
|
1818
|
-
return Qnil;
|
1819
|
-
}
|
1820
|
-
|
1821
|
-
/* If called with parameters, and optionally result_format,
|
1822
|
-
* use PQsendQueryParams
|
1823
|
-
*/
|
1824
1908
|
|
1825
1909
|
pgconn_query_assign_typemap( self, ¶msData );
|
1826
1910
|
resultFormat = NIL_P(in_res_fmt) ? 0 : NUM2INT(in_res_fmt);
|
1827
1911
|
nParams = alloc_query_params( ¶msData );
|
1828
1912
|
|
1829
|
-
result = gvl_PQsendQueryParams(
|
1913
|
+
result = gvl_PQsendQueryParams(this->pgconn, pg_cstr_enc(command, paramsData.enc_idx), nParams, paramsData.types,
|
1830
1914
|
(const char * const *)paramsData.values, paramsData.lengths, paramsData.formats, resultFormat);
|
1831
1915
|
|
1832
1916
|
free_query_params( ¶msData );
|
1833
1917
|
|
1834
|
-
if(result == 0)
|
1835
|
-
|
1836
|
-
|
1837
|
-
|
1838
|
-
}
|
1918
|
+
if(result == 0)
|
1919
|
+
pg_raise_conn_error( rb_eUnableToSend, self, "%s", PQerrorMessage(this->pgconn));
|
1920
|
+
|
1921
|
+
pgconn_wait_for_flush( self );
|
1839
1922
|
return Qnil;
|
1840
1923
|
}
|
1841
1924
|
|
@@ -1856,24 +1939,26 @@ pgconn_send_query(int argc, VALUE *argv, VALUE self)
|
|
1856
1939
|
*
|
1857
1940
|
* For example: "SELECT $1::int"
|
1858
1941
|
*
|
1859
|
-
* PostgreSQL bind parameters are represented as $1, $
|
1942
|
+
* PostgreSQL bind parameters are represented as $1, $2, $3, etc.,
|
1860
1943
|
* inside the SQL query.
|
1861
1944
|
*/
|
1862
1945
|
static VALUE
|
1863
1946
|
pgconn_send_prepare(int argc, VALUE *argv, VALUE self)
|
1864
1947
|
{
|
1865
|
-
|
1948
|
+
t_pg_connection *this = pg_get_connection_safe( self );
|
1866
1949
|
int result;
|
1867
1950
|
VALUE name, command, in_paramtypes;
|
1868
1951
|
VALUE param;
|
1869
|
-
VALUE error;
|
1870
1952
|
int i = 0;
|
1871
1953
|
int nParams = 0;
|
1872
1954
|
Oid *paramTypes = NULL;
|
1955
|
+
const char *name_cstr;
|
1956
|
+
const char *command_cstr;
|
1957
|
+
int enc_idx = this->enc_idx;
|
1873
1958
|
|
1874
1959
|
rb_scan_args(argc, argv, "21", &name, &command, &in_paramtypes);
|
1875
|
-
|
1876
|
-
|
1960
|
+
name_cstr = pg_cstr_enc(name, enc_idx);
|
1961
|
+
command_cstr = pg_cstr_enc(command, enc_idx);
|
1877
1962
|
|
1878
1963
|
if(! NIL_P(in_paramtypes)) {
|
1879
1964
|
Check_Type(in_paramtypes, T_ARRAY);
|
@@ -1887,16 +1972,14 @@ pgconn_send_prepare(int argc, VALUE *argv, VALUE self)
|
|
1887
1972
|
paramTypes[i] = NUM2UINT(param);
|
1888
1973
|
}
|
1889
1974
|
}
|
1890
|
-
result = gvl_PQsendPrepare(
|
1891
|
-
nParams, paramTypes);
|
1975
|
+
result = gvl_PQsendPrepare(this->pgconn, name_cstr, command_cstr, nParams, paramTypes);
|
1892
1976
|
|
1893
1977
|
xfree(paramTypes);
|
1894
1978
|
|
1895
1979
|
if(result == 0) {
|
1896
|
-
|
1897
|
-
rb_iv_set(error, "@connection", self);
|
1898
|
-
rb_exc_raise(error);
|
1980
|
+
pg_raise_conn_error( rb_eUnableToSend, self, "%s", PQerrorMessage(this->pgconn));
|
1899
1981
|
}
|
1982
|
+
pgconn_wait_for_flush( self );
|
1900
1983
|
return Qnil;
|
1901
1984
|
}
|
1902
1985
|
|
@@ -1913,20 +1996,20 @@ pgconn_send_prepare(int argc, VALUE *argv, VALUE self)
|
|
1913
1996
|
* SQL query. Each element of the +params+ array may be either:
|
1914
1997
|
* a hash of the form:
|
1915
1998
|
* {:value => String (value of bind parameter)
|
1916
|
-
* :format =>
|
1999
|
+
* :format => Integer (0 for text, 1 for binary)
|
1917
2000
|
* }
|
1918
2001
|
* or, it may be a String. If it is a string, that is equivalent to the hash:
|
1919
2002
|
* { :value => <string value>, :format => 0 }
|
1920
2003
|
*
|
1921
|
-
* PostgreSQL bind parameters are represented as $1, $
|
2004
|
+
* PostgreSQL bind parameters are represented as $1, $2, $3, etc.,
|
1922
2005
|
* inside the SQL query. The 0th element of the +params+ array is bound
|
1923
2006
|
* to $1, the 1st element is bound to $2, etc. +nil+ is treated as +NULL+.
|
1924
2007
|
*
|
1925
2008
|
* The optional +result_format+ should be 0 for text results, 1
|
1926
2009
|
* for binary.
|
1927
2010
|
*
|
1928
|
-
* type_map can be a PG::TypeMap derivation (such as PG::BasicTypeMapForQueries).
|
1929
|
-
* This will type cast the params
|
2011
|
+
* +type_map+ can be a PG::TypeMap derivation (such as PG::BasicTypeMapForQueries).
|
2012
|
+
* This will type cast the params from various Ruby types before transmission
|
1930
2013
|
* based on the encoders defined by the type map. When a type encoder is used
|
1931
2014
|
* the format and oid of a given bind parameter are retrieved from the encoder
|
1932
2015
|
* instead out of the hash form described above.
|
@@ -1935,38 +2018,34 @@ pgconn_send_prepare(int argc, VALUE *argv, VALUE self)
|
|
1935
2018
|
static VALUE
|
1936
2019
|
pgconn_send_query_prepared(int argc, VALUE *argv, VALUE self)
|
1937
2020
|
{
|
1938
|
-
|
2021
|
+
t_pg_connection *this = pg_get_connection_safe( self );
|
1939
2022
|
int result;
|
1940
2023
|
VALUE name, in_res_fmt;
|
1941
|
-
VALUE error;
|
1942
2024
|
int nParams;
|
1943
2025
|
int resultFormat;
|
1944
|
-
struct query_params_data paramsData;
|
2026
|
+
struct query_params_data paramsData = { this->enc_idx };
|
1945
2027
|
|
1946
2028
|
rb_scan_args(argc, argv, "13", &name, ¶msData.params, &in_res_fmt, ¶msData.typemap);
|
1947
2029
|
paramsData.with_types = 0;
|
1948
|
-
Check_Type(name, T_STRING);
|
1949
2030
|
|
1950
2031
|
if(NIL_P(paramsData.params)) {
|
1951
2032
|
paramsData.params = rb_ary_new2(0);
|
1952
|
-
resultFormat = 0;
|
1953
2033
|
}
|
1954
2034
|
pgconn_query_assign_typemap( self, ¶msData );
|
1955
2035
|
|
1956
2036
|
resultFormat = NIL_P(in_res_fmt) ? 0 : NUM2INT(in_res_fmt);
|
1957
2037
|
nParams = alloc_query_params( ¶msData );
|
1958
2038
|
|
1959
|
-
result = gvl_PQsendQueryPrepared(
|
2039
|
+
result = gvl_PQsendQueryPrepared(this->pgconn, pg_cstr_enc(name, paramsData.enc_idx), nParams,
|
1960
2040
|
(const char * const *)paramsData.values, paramsData.lengths, paramsData.formats,
|
1961
2041
|
resultFormat);
|
1962
2042
|
|
1963
2043
|
free_query_params( ¶msData );
|
1964
2044
|
|
1965
|
-
if(result == 0)
|
1966
|
-
|
1967
|
-
|
1968
|
-
|
1969
|
-
}
|
2045
|
+
if(result == 0)
|
2046
|
+
pg_raise_conn_error( rb_eUnableToSend, self, "%s", PQerrorMessage(this->pgconn));
|
2047
|
+
|
2048
|
+
pgconn_wait_for_flush( self );
|
1970
2049
|
return Qnil;
|
1971
2050
|
}
|
1972
2051
|
|
@@ -1980,14 +2059,12 @@ pgconn_send_query_prepared(int argc, VALUE *argv, VALUE self)
|
|
1980
2059
|
static VALUE
|
1981
2060
|
pgconn_send_describe_prepared(VALUE self, VALUE stmt_name)
|
1982
2061
|
{
|
1983
|
-
|
1984
|
-
PGconn *conn = pg_get_pgconn(self);
|
2062
|
+
t_pg_connection *this = pg_get_connection_safe( self );
|
1985
2063
|
/* returns 0 on failure */
|
1986
|
-
if(gvl_PQsendDescribePrepared(
|
1987
|
-
|
1988
|
-
|
1989
|
-
|
1990
|
-
}
|
2064
|
+
if(gvl_PQsendDescribePrepared(this->pgconn, pg_cstr_enc(stmt_name, this->enc_idx)) == 0)
|
2065
|
+
pg_raise_conn_error( rb_eUnableToSend, self, "%s", PQerrorMessage(this->pgconn));
|
2066
|
+
|
2067
|
+
pgconn_wait_for_flush( self );
|
1991
2068
|
return Qnil;
|
1992
2069
|
}
|
1993
2070
|
|
@@ -2002,36 +2079,18 @@ pgconn_send_describe_prepared(VALUE self, VALUE stmt_name)
|
|
2002
2079
|
static VALUE
|
2003
2080
|
pgconn_send_describe_portal(VALUE self, VALUE portal)
|
2004
2081
|
{
|
2005
|
-
|
2006
|
-
PGconn *conn = pg_get_pgconn(self);
|
2082
|
+
t_pg_connection *this = pg_get_connection_safe( self );
|
2007
2083
|
/* returns 0 on failure */
|
2008
|
-
if(gvl_PQsendDescribePortal(
|
2009
|
-
|
2010
|
-
|
2011
|
-
|
2012
|
-
}
|
2084
|
+
if(gvl_PQsendDescribePortal(this->pgconn, pg_cstr_enc(portal, this->enc_idx)) == 0)
|
2085
|
+
pg_raise_conn_error( rb_eUnableToSend, self, "%s", PQerrorMessage(this->pgconn));
|
2086
|
+
|
2087
|
+
pgconn_wait_for_flush( self );
|
2013
2088
|
return Qnil;
|
2014
2089
|
}
|
2015
2090
|
|
2016
2091
|
|
2017
|
-
/*
|
2018
|
-
* call-seq:
|
2019
|
-
* conn.get_result() -> PG::Result
|
2020
|
-
* conn.get_result() {|pg_result| block }
|
2021
|
-
*
|
2022
|
-
* Blocks waiting for the next result from a call to
|
2023
|
-
* #send_query (or another asynchronous command), and returns
|
2024
|
-
* it. Returns +nil+ if no more results are available.
|
2025
|
-
*
|
2026
|
-
* Note: call this function repeatedly until it returns +nil+, or else
|
2027
|
-
* you will not be able to issue further commands.
|
2028
|
-
*
|
2029
|
-
* If the optional code block is given, it will be passed <i>result</i> as an argument,
|
2030
|
-
* and the PG::Result object will automatically be cleared when the block terminates.
|
2031
|
-
* In this instance, <code>conn.exec</code> returns the value of the block.
|
2032
|
-
*/
|
2033
2092
|
static VALUE
|
2034
|
-
|
2093
|
+
pgconn_sync_get_result(VALUE self)
|
2035
2094
|
{
|
2036
2095
|
PGconn *conn = pg_get_pgconn(self);
|
2037
2096
|
PGresult *result;
|
@@ -2057,17 +2116,15 @@ pgconn_get_result(VALUE self)
|
|
2057
2116
|
* or *notifies* to see if the state has changed.
|
2058
2117
|
*/
|
2059
2118
|
static VALUE
|
2060
|
-
pgconn_consume_input(self)
|
2061
|
-
VALUE self;
|
2119
|
+
pgconn_consume_input(VALUE self)
|
2062
2120
|
{
|
2063
|
-
VALUE error;
|
2064
2121
|
PGconn *conn = pg_get_pgconn(self);
|
2065
2122
|
/* returns 0 on error */
|
2066
2123
|
if(PQconsumeInput(conn) == 0) {
|
2067
|
-
|
2068
|
-
|
2069
|
-
rb_exc_raise(error);
|
2124
|
+
pgconn_close_socket_io(self);
|
2125
|
+
pg_raise_conn_error( rb_eConnectionBad, self, "%s", PQerrorMessage(conn));
|
2070
2126
|
}
|
2127
|
+
|
2071
2128
|
return Qnil;
|
2072
2129
|
}
|
2073
2130
|
|
@@ -2076,37 +2133,18 @@ pgconn_consume_input(self)
|
|
2076
2133
|
* conn.is_busy() -> Boolean
|
2077
2134
|
*
|
2078
2135
|
* Returns +true+ if a command is busy, that is, if
|
2079
|
-
*
|
2136
|
+
* #get_result would block. Otherwise returns +false+.
|
2080
2137
|
*/
|
2081
2138
|
static VALUE
|
2082
|
-
pgconn_is_busy(self)
|
2083
|
-
VALUE self;
|
2139
|
+
pgconn_is_busy(VALUE self)
|
2084
2140
|
{
|
2085
2141
|
return gvl_PQisBusy(pg_get_pgconn(self)) ? Qtrue : Qfalse;
|
2086
2142
|
}
|
2087
2143
|
|
2088
|
-
/*
|
2089
|
-
* call-seq:
|
2090
|
-
* conn.setnonblocking(Boolean) -> nil
|
2091
|
-
*
|
2092
|
-
* Sets the nonblocking status of the connection.
|
2093
|
-
* In the blocking state, calls to #send_query
|
2094
|
-
* will block until the message is sent to the server,
|
2095
|
-
* but will not wait for the query results.
|
2096
|
-
* In the nonblocking state, calls to #send_query
|
2097
|
-
* will return an error if the socket is not ready for
|
2098
|
-
* writing.
|
2099
|
-
* Note: This function does not affect #exec, because
|
2100
|
-
* that function doesn't return until the server has
|
2101
|
-
* processed the query and returned the results.
|
2102
|
-
* Returns +nil+.
|
2103
|
-
*/
|
2104
2144
|
static VALUE
|
2105
|
-
|
2106
|
-
VALUE self, state;
|
2145
|
+
pgconn_sync_setnonblocking(VALUE self, VALUE state)
|
2107
2146
|
{
|
2108
2147
|
int arg;
|
2109
|
-
VALUE error;
|
2110
2148
|
PGconn *conn = pg_get_pgconn(self);
|
2111
2149
|
if(state == Qtrue)
|
2112
2150
|
arg = 1;
|
@@ -2115,69 +2153,33 @@ pgconn_setnonblocking(self, state)
|
|
2115
2153
|
else
|
2116
2154
|
rb_raise(rb_eArgError, "Boolean value expected");
|
2117
2155
|
|
2118
|
-
if(PQsetnonblocking(conn, arg) == -1)
|
2119
|
-
|
2120
|
-
|
2121
|
-
rb_exc_raise(error);
|
2122
|
-
}
|
2156
|
+
if(PQsetnonblocking(conn, arg) == -1)
|
2157
|
+
pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(conn));
|
2158
|
+
|
2123
2159
|
return Qnil;
|
2124
2160
|
}
|
2125
2161
|
|
2126
2162
|
|
2127
|
-
/*
|
2128
|
-
* call-seq:
|
2129
|
-
* conn.isnonblocking() -> Boolean
|
2130
|
-
*
|
2131
|
-
* Returns +true+ if a command is busy, that is, if
|
2132
|
-
* PQgetResult would block. Otherwise returns +false+.
|
2133
|
-
*/
|
2134
2163
|
static VALUE
|
2135
|
-
|
2136
|
-
VALUE self;
|
2164
|
+
pgconn_sync_isnonblocking(VALUE self)
|
2137
2165
|
{
|
2138
2166
|
return PQisnonblocking(pg_get_pgconn(self)) ? Qtrue : Qfalse;
|
2139
2167
|
}
|
2140
2168
|
|
2141
|
-
/*
|
2142
|
-
* call-seq:
|
2143
|
-
* conn.flush() -> Boolean
|
2144
|
-
*
|
2145
|
-
* Attempts to flush any queued output data to the server.
|
2146
|
-
* Returns +true+ if data is successfully flushed, +false+
|
2147
|
-
* if not (can only return +false+ if connection is
|
2148
|
-
* nonblocking.
|
2149
|
-
* Raises PG::Error if some other failure occurred.
|
2150
|
-
*/
|
2151
2169
|
static VALUE
|
2152
|
-
|
2153
|
-
VALUE self;
|
2170
|
+
pgconn_sync_flush(VALUE self)
|
2154
2171
|
{
|
2155
2172
|
PGconn *conn = pg_get_pgconn(self);
|
2156
|
-
int ret;
|
2157
|
-
|
2158
|
-
|
2159
|
-
|
2160
|
-
error = rb_exc_new2(rb_ePGerror, PQerrorMessage(conn));
|
2161
|
-
rb_iv_set(error, "@connection", self);
|
2162
|
-
rb_exc_raise(error);
|
2163
|
-
}
|
2173
|
+
int ret = PQflush(conn);
|
2174
|
+
if(ret == -1)
|
2175
|
+
pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(conn));
|
2176
|
+
|
2164
2177
|
return (ret) ? Qfalse : Qtrue;
|
2165
2178
|
}
|
2166
2179
|
|
2167
|
-
/*
|
2168
|
-
* call-seq:
|
2169
|
-
* conn.cancel() -> String
|
2170
|
-
*
|
2171
|
-
* Requests cancellation of the command currently being
|
2172
|
-
* processed. (Only implemented in PostgreSQL >= 8.0)
|
2173
|
-
*
|
2174
|
-
* Returns +nil+ on success, or a string containing the
|
2175
|
-
* error message if a failure occurs.
|
2176
|
-
*/
|
2177
2180
|
static VALUE
|
2178
|
-
|
2181
|
+
pgconn_sync_cancel(VALUE self)
|
2179
2182
|
{
|
2180
|
-
#ifdef HAVE_PQGETCANCEL
|
2181
2183
|
char errbuf[256];
|
2182
2184
|
PGcancel *cancel;
|
2183
2185
|
VALUE retval;
|
@@ -2185,9 +2187,9 @@ pgconn_cancel(VALUE self)
|
|
2185
2187
|
|
2186
2188
|
cancel = PQgetCancel(pg_get_pgconn(self));
|
2187
2189
|
if(cancel == NULL)
|
2188
|
-
|
2190
|
+
pg_raise_conn_error( rb_ePGerror, self, "Invalid connection!");
|
2189
2191
|
|
2190
|
-
ret = gvl_PQcancel(cancel, errbuf,
|
2192
|
+
ret = gvl_PQcancel(cancel, errbuf, sizeof(errbuf));
|
2191
2193
|
if(ret == 1)
|
2192
2194
|
retval = Qnil;
|
2193
2195
|
else
|
@@ -2195,9 +2197,6 @@ pgconn_cancel(VALUE self)
|
|
2195
2197
|
|
2196
2198
|
PQfreeCancel(cancel);
|
2197
2199
|
return retval;
|
2198
|
-
#else
|
2199
|
-
rb_notimplement();
|
2200
|
-
#endif
|
2201
2200
|
}
|
2202
2201
|
|
2203
2202
|
|
@@ -2211,7 +2210,7 @@ pgconn_cancel(VALUE self)
|
|
2211
2210
|
static VALUE
|
2212
2211
|
pgconn_notifies(VALUE self)
|
2213
2212
|
{
|
2214
|
-
|
2213
|
+
t_pg_connection *this = pg_get_connection_safe( self );
|
2215
2214
|
PGnotify *notification;
|
2216
2215
|
VALUE hash;
|
2217
2216
|
VALUE sym_relname, sym_be_pid, sym_extra;
|
@@ -2221,17 +2220,17 @@ pgconn_notifies(VALUE self)
|
|
2221
2220
|
sym_be_pid = ID2SYM(rb_intern("be_pid"));
|
2222
2221
|
sym_extra = ID2SYM(rb_intern("extra"));
|
2223
2222
|
|
2224
|
-
notification = gvl_PQnotifies(
|
2223
|
+
notification = gvl_PQnotifies(this->pgconn);
|
2225
2224
|
if (notification == NULL) {
|
2226
2225
|
return Qnil;
|
2227
2226
|
}
|
2228
2227
|
|
2229
2228
|
hash = rb_hash_new();
|
2230
|
-
relname =
|
2229
|
+
relname = rb_str_new2(notification->relname);
|
2231
2230
|
be_pid = INT2NUM(notification->be_pid);
|
2232
|
-
extra =
|
2233
|
-
PG_ENCODING_SET_NOCHECK( relname,
|
2234
|
-
PG_ENCODING_SET_NOCHECK( extra,
|
2231
|
+
extra = rb_str_new2(notification->extra);
|
2232
|
+
PG_ENCODING_SET_NOCHECK( relname, this->enc_idx );
|
2233
|
+
PG_ENCODING_SET_NOCHECK( extra, this->enc_idx );
|
2235
2234
|
|
2236
2235
|
rb_hash_aset(hash, sym_relname, relname);
|
2237
2236
|
rb_hash_aset(hash, sym_be_pid, be_pid);
|
@@ -2241,96 +2240,63 @@ pgconn_notifies(VALUE self)
|
|
2241
2240
|
return hash;
|
2242
2241
|
}
|
2243
2242
|
|
2244
|
-
|
2245
|
-
#if !defined( HAVE_RUBY_VM_H ) && defined( _WIN32 )
|
2243
|
+
#if defined(_WIN32)
|
2246
2244
|
|
2247
|
-
/*
|
2248
|
-
*
|
2245
|
+
/* We use a specialized implementation of rb_io_wait() on Windows.
|
2246
|
+
* This is because rb_io_wait() and rb_wait_for_single_fd() are very slow on Windows.
|
2249
2247
|
*/
|
2250
|
-
void create_crt_fd(fd_set *os_set, fd_set *crt_set)
|
2251
|
-
{
|
2252
|
-
int i;
|
2253
|
-
crt_set->fd_count = os_set->fd_count;
|
2254
|
-
for (i = 0; i < os_set->fd_count; i++) {
|
2255
|
-
WSAPROTOCOL_INFO wsa_pi;
|
2256
|
-
/* dupicate the SOCKET */
|
2257
|
-
int r = WSADuplicateSocket(os_set->fd_array[i], GetCurrentProcessId(), &wsa_pi);
|
2258
|
-
SOCKET s = WSASocket(wsa_pi.iAddressFamily, wsa_pi.iSocketType, wsa_pi.iProtocol, &wsa_pi, 0, 0);
|
2259
|
-
/* create the CRT fd so ruby can get back to the SOCKET */
|
2260
|
-
int fd = _open_osfhandle(s, O_RDWR|O_BINARY);
|
2261
|
-
os_set->fd_array[i] = s;
|
2262
|
-
crt_set->fd_array[i] = fd;
|
2263
|
-
}
|
2264
|
-
}
|
2265
2248
|
|
2266
|
-
|
2267
|
-
|
2268
|
-
*/
|
2269
|
-
void cleanup_crt_fd(fd_set *os_set, fd_set *crt_set)
|
2270
|
-
{
|
2271
|
-
int i;
|
2272
|
-
for (i = 0; i < os_set->fd_count; i++) {
|
2273
|
-
/* cleanup the CRT fd */
|
2274
|
-
_close(crt_set->fd_array[i]);
|
2275
|
-
/* cleanup the duplicated SOCKET */
|
2276
|
-
closesocket(os_set->fd_array[i]);
|
2277
|
-
}
|
2278
|
-
}
|
2249
|
+
#if defined(HAVE_RUBY_FIBER_SCHEDULER_H)
|
2250
|
+
#include <ruby/fiber/scheduler.h>
|
2279
2251
|
#endif
|
2280
2252
|
|
2281
|
-
|
2282
|
-
|
2283
|
-
|
2284
|
-
|
2285
|
-
|
2286
|
-
*/
|
2253
|
+
typedef enum {
|
2254
|
+
PG_RUBY_IO_READABLE = RB_WAITFD_IN,
|
2255
|
+
PG_RUBY_IO_WRITABLE = RB_WAITFD_OUT,
|
2256
|
+
PG_RUBY_IO_PRIORITY = RB_WAITFD_PRI,
|
2257
|
+
} pg_rb_io_event_t;
|
2287
2258
|
|
2288
2259
|
int rb_w32_wait_events( HANDLE *events, int num, DWORD timeout );
|
2289
2260
|
|
2290
|
-
|
2291
|
-
|
2292
|
-
*
|
2261
|
+
static VALUE
|
2262
|
+
pg_rb_thread_io_wait(VALUE io, VALUE events, VALUE timeout) {
|
2263
|
+
rb_io_t *fptr;
|
2264
|
+
struct timeval ptimeout;
|
2293
2265
|
|
2294
|
-
static void *
|
2295
|
-
wait_socket_readable( PGconn *conn, struct timeval *ptimeout, void *(*is_readable)(PGconn *) )
|
2296
|
-
{
|
2297
|
-
int sd = PQsocket( conn );
|
2298
|
-
void *retval;
|
2299
2266
|
struct timeval aborttime={0,0}, currtime, waittime;
|
2300
2267
|
DWORD timeout_milisec = INFINITE;
|
2301
|
-
|
2302
|
-
WSAEVENT hEvent;
|
2268
|
+
HANDLE hEvent = WSACreateEvent();
|
2303
2269
|
|
2304
|
-
|
2305
|
-
|
2306
|
-
|
2307
|
-
hEvent = WSACreateEvent();
|
2270
|
+
long rb_events = NUM2UINT(events);
|
2271
|
+
long w32_events = 0;
|
2272
|
+
DWORD wait_ret;
|
2308
2273
|
|
2309
|
-
|
2310
|
-
if(
|
2311
|
-
|
2312
|
-
|
2313
|
-
}
|
2274
|
+
GetOpenFile((io), fptr);
|
2275
|
+
if( !NIL_P(timeout) ){
|
2276
|
+
ptimeout.tv_sec = (time_t)(NUM2DBL(timeout));
|
2277
|
+
ptimeout.tv_usec = (time_t)((NUM2DBL(timeout) - (double)ptimeout.tv_sec) * 1e6);
|
2314
2278
|
|
2315
|
-
if ( ptimeout ) {
|
2316
2279
|
gettimeofday(&currtime, NULL);
|
2317
|
-
timeradd(&currtime, ptimeout, &aborttime);
|
2280
|
+
timeradd(&currtime, &ptimeout, &aborttime);
|
2318
2281
|
}
|
2319
2282
|
|
2320
|
-
|
2321
|
-
|
2283
|
+
if(rb_events & PG_RUBY_IO_READABLE) w32_events |= FD_READ | FD_ACCEPT | FD_CLOSE;
|
2284
|
+
if(rb_events & PG_RUBY_IO_WRITABLE) w32_events |= FD_WRITE | FD_CONNECT;
|
2285
|
+
if(rb_events & PG_RUBY_IO_PRIORITY) w32_events |= FD_OOB;
|
2286
|
+
|
2287
|
+
for(;;) {
|
2288
|
+
if ( WSAEventSelect(_get_osfhandle(fptr->fd), hEvent, w32_events) == SOCKET_ERROR ) {
|
2322
2289
|
WSACloseEvent( hEvent );
|
2323
2290
|
rb_raise( rb_eConnectionBad, "WSAEventSelect socket error: %d", WSAGetLastError() );
|
2324
2291
|
}
|
2325
2292
|
|
2326
|
-
if (
|
2293
|
+
if ( !NIL_P(timeout) ) {
|
2327
2294
|
gettimeofday(&currtime, NULL);
|
2328
2295
|
timersub(&aborttime, &currtime, &waittime);
|
2329
2296
|
timeout_milisec = (DWORD)( waittime.tv_sec * 1e3 + waittime.tv_usec / 1e3 );
|
2330
2297
|
}
|
2331
2298
|
|
2332
|
-
|
2333
|
-
if( !ptimeout || (waittime.tv_sec >= 0 && waittime.tv_usec >= 0) ){
|
2299
|
+
if( NIL_P(timeout) || (waittime.tv_sec >= 0 && waittime.tv_usec >= 0) ){
|
2334
2300
|
/* Wait for the socket to become readable before checking again */
|
2335
2301
|
wait_ret = rb_w32_wait_events( &hEvent, 1, timeout_milisec );
|
2336
2302
|
} else {
|
@@ -2339,9 +2305,11 @@ wait_socket_readable( PGconn *conn, struct timeval *ptimeout, void *(*is_readabl
|
|
2339
2305
|
|
2340
2306
|
if ( wait_ret == WAIT_TIMEOUT ) {
|
2341
2307
|
WSACloseEvent( hEvent );
|
2342
|
-
return
|
2308
|
+
return UINT2NUM(0);
|
2343
2309
|
} else if ( wait_ret == WAIT_OBJECT_0 ) {
|
2310
|
+
WSACloseEvent( hEvent );
|
2344
2311
|
/* The event we were waiting for. */
|
2312
|
+
return UINT2NUM(rb_events);
|
2345
2313
|
} else if ( wait_ret == WAIT_OBJECT_0 + 1) {
|
2346
2314
|
/* This indicates interruption from timer thread, GC, exception
|
2347
2315
|
* from other threads etc... */
|
@@ -2353,42 +2321,66 @@ wait_socket_readable( PGconn *conn, struct timeval *ptimeout, void *(*is_readabl
|
|
2353
2321
|
WSACloseEvent( hEvent );
|
2354
2322
|
rb_raise( rb_eConnectionBad, "Wait on socket abandoned (WaitForMultipleObjects)" );
|
2355
2323
|
}
|
2356
|
-
|
2357
|
-
/* Check for connection errors (PQisBusy is true on connection errors) */
|
2358
|
-
if ( PQconsumeInput(conn) == 0 ) {
|
2359
|
-
WSACloseEvent( hEvent );
|
2360
|
-
rb_raise( rb_eConnectionBad, "PQconsumeInput() %s", PQerrorMessage(conn) );
|
2361
|
-
}
|
2362
2324
|
}
|
2325
|
+
}
|
2363
2326
|
|
2364
|
-
|
2365
|
-
|
2327
|
+
static VALUE
|
2328
|
+
pg_rb_io_wait(VALUE io, VALUE events, VALUE timeout) {
|
2329
|
+
#if defined(HAVE_RUBY_FIBER_SCHEDULER_H)
|
2330
|
+
/* We don't support Fiber.scheduler on Windows ruby-3.0 because there is no fast way to check whether a scheduler is active.
|
2331
|
+
* Fortunatelly ruby-3.1 offers a C-API for it.
|
2332
|
+
*/
|
2333
|
+
VALUE scheduler = rb_fiber_scheduler_current();
|
2334
|
+
|
2335
|
+
if (!NIL_P(scheduler)) {
|
2336
|
+
return rb_io_wait(io, events, timeout);
|
2337
|
+
}
|
2338
|
+
#endif
|
2339
|
+
return pg_rb_thread_io_wait(io, events, timeout);
|
2366
2340
|
}
|
2367
2341
|
|
2342
|
+
#elif defined(HAVE_RB_IO_WAIT)
|
2343
|
+
|
2344
|
+
/* Use our own function and constants names, to avoid conflicts with truffleruby-head on its road to ruby-3.0 compatibility. */
|
2345
|
+
#define pg_rb_io_wait rb_io_wait
|
2346
|
+
#define PG_RUBY_IO_READABLE RUBY_IO_READABLE
|
2347
|
+
#define PG_RUBY_IO_WRITABLE RUBY_IO_WRITABLE
|
2348
|
+
#define PG_RUBY_IO_PRIORITY RUBY_IO_PRIORITY
|
2349
|
+
|
2368
2350
|
#else
|
2351
|
+
/* For compat with ruby < 3.0 */
|
2352
|
+
|
2353
|
+
typedef enum {
|
2354
|
+
PG_RUBY_IO_READABLE = RB_WAITFD_IN,
|
2355
|
+
PG_RUBY_IO_WRITABLE = RB_WAITFD_OUT,
|
2356
|
+
PG_RUBY_IO_PRIORITY = RB_WAITFD_PRI,
|
2357
|
+
} pg_rb_io_event_t;
|
2358
|
+
|
2359
|
+
static VALUE
|
2360
|
+
pg_rb_io_wait(VALUE io, VALUE events, VALUE timeout) {
|
2361
|
+
rb_io_t *fptr;
|
2362
|
+
struct timeval waittime;
|
2363
|
+
int res;
|
2364
|
+
|
2365
|
+
GetOpenFile((io), fptr);
|
2366
|
+
if( !NIL_P(timeout) ){
|
2367
|
+
waittime.tv_sec = (time_t)(NUM2DBL(timeout));
|
2368
|
+
waittime.tv_usec = (time_t)((NUM2DBL(timeout) - (double)waittime.tv_sec) * 1e6);
|
2369
|
+
}
|
2370
|
+
res = rb_wait_for_single_fd(fptr->fd, NUM2UINT(events), NIL_P(timeout) ? NULL : &waittime);
|
2369
2371
|
|
2370
|
-
|
2372
|
+
return UINT2NUM(res);
|
2373
|
+
}
|
2374
|
+
#endif
|
2371
2375
|
|
2372
2376
|
static void *
|
2373
|
-
wait_socket_readable(
|
2377
|
+
wait_socket_readable( VALUE self, struct timeval *ptimeout, void *(*is_readable)(PGconn *))
|
2374
2378
|
{
|
2375
|
-
|
2376
|
-
int ret;
|
2379
|
+
VALUE ret;
|
2377
2380
|
void *retval;
|
2378
|
-
rb_fdset_t sd_rset;
|
2379
2381
|
struct timeval aborttime={0,0}, currtime, waittime;
|
2380
|
-
|
2381
|
-
|
2382
|
-
#endif
|
2383
|
-
|
2384
|
-
if ( sd < 0 )
|
2385
|
-
rb_raise(rb_eConnectionBad, "PQsocket() can't get socket descriptor");
|
2386
|
-
|
2387
|
-
/* Check for connection errors (PQisBusy is true on connection errors) */
|
2388
|
-
if ( PQconsumeInput(conn) == 0 )
|
2389
|
-
rb_raise( rb_eConnectionBad, "PQconsumeInput() %s", PQerrorMessage(conn) );
|
2390
|
-
|
2391
|
-
rb_fd_init( &sd_rset );
|
2382
|
+
VALUE wait_timeout = Qnil;
|
2383
|
+
PGconn *conn = pg_get_pgconn(self);
|
2392
2384
|
|
2393
2385
|
if ( ptimeout ) {
|
2394
2386
|
gettimeofday(&currtime, NULL);
|
@@ -2396,59 +2388,82 @@ wait_socket_readable( PGconn *conn, struct timeval *ptimeout, void *(*is_readabl
|
|
2396
2388
|
}
|
2397
2389
|
|
2398
2390
|
while ( !(retval=is_readable(conn)) ) {
|
2399
|
-
rb_fd_zero( &sd_rset );
|
2400
|
-
rb_fd_set( sd, &sd_rset );
|
2401
|
-
|
2402
|
-
#ifdef _WIN32
|
2403
|
-
/* Ruby's FD_SET is modified on win32 to convert a file descriptor
|
2404
|
-
* to osfhandle, but we already get a osfhandle from PQsocket().
|
2405
|
-
* Therefore it's overwritten here. */
|
2406
|
-
sd_rset.fd_array[0] = sd;
|
2407
|
-
create_crt_fd(&sd_rset, &crt_sd_rset);
|
2408
|
-
#endif
|
2409
|
-
|
2410
2391
|
if ( ptimeout ) {
|
2411
2392
|
gettimeofday(&currtime, NULL);
|
2412
2393
|
timersub(&aborttime, &currtime, &waittime);
|
2394
|
+
wait_timeout = DBL2NUM((double)(waittime.tv_sec) + (double)(waittime.tv_usec) / 1000000.0);
|
2413
2395
|
}
|
2414
2396
|
|
2415
2397
|
/* Is the given timeout valid? */
|
2416
2398
|
if( !ptimeout || (waittime.tv_sec >= 0 && waittime.tv_usec >= 0) ){
|
2417
|
-
|
2418
|
-
ret = rb_thread_fd_select( sd+1, &sd_rset, NULL, NULL, ptimeout ? &waittime : NULL );
|
2419
|
-
} else {
|
2420
|
-
ret = 0;
|
2421
|
-
}
|
2422
|
-
|
2399
|
+
VALUE socket_io;
|
2423
2400
|
|
2424
|
-
|
2425
|
-
|
2426
|
-
|
2401
|
+
/* before we wait for data, make sure everything has been sent */
|
2402
|
+
pgconn_async_flush(self);
|
2403
|
+
if ((retval=is_readable(conn)))
|
2404
|
+
return retval;
|
2427
2405
|
|
2428
|
-
|
2429
|
-
|
2430
|
-
|
2406
|
+
socket_io = pgconn_socket_io(self);
|
2407
|
+
/* Wait for the socket to become readable before checking again */
|
2408
|
+
ret = pg_rb_io_wait(socket_io, RB_INT2NUM(PG_RUBY_IO_READABLE), wait_timeout);
|
2409
|
+
} else {
|
2410
|
+
ret = Qfalse;
|
2431
2411
|
}
|
2432
2412
|
|
2433
2413
|
/* Return false if the select() timed out */
|
2434
|
-
if ( ret ==
|
2435
|
-
rb_fd_term( &sd_rset );
|
2414
|
+
if ( ret == Qfalse ){
|
2436
2415
|
return NULL;
|
2437
2416
|
}
|
2438
2417
|
|
2439
2418
|
/* Check for connection errors (PQisBusy is true on connection errors) */
|
2440
2419
|
if ( PQconsumeInput(conn) == 0 ){
|
2441
|
-
|
2442
|
-
|
2420
|
+
pgconn_close_socket_io(self);
|
2421
|
+
pg_raise_conn_error(rb_eConnectionBad, self, "PQconsumeInput() %s", PQerrorMessage(conn));
|
2443
2422
|
}
|
2444
2423
|
}
|
2445
2424
|
|
2446
|
-
rb_fd_term( &sd_rset );
|
2447
2425
|
return retval;
|
2448
2426
|
}
|
2449
2427
|
|
2428
|
+
/*
|
2429
|
+
* call-seq:
|
2430
|
+
* conn.flush() -> Boolean
|
2431
|
+
*
|
2432
|
+
* Attempts to flush any queued output data to the server.
|
2433
|
+
* Returns +true+ if data is successfully flushed, +false+
|
2434
|
+
* if not. It can only return +false+ if connection is
|
2435
|
+
* in nonblocking mode.
|
2436
|
+
* Raises PG::Error if some other failure occurred.
|
2437
|
+
*/
|
2438
|
+
static VALUE
|
2439
|
+
pgconn_async_flush(VALUE self)
|
2440
|
+
{
|
2441
|
+
while( pgconn_sync_flush(self) == Qfalse ){
|
2442
|
+
/* wait for the socket to become read- or write-ready */
|
2443
|
+
int events;
|
2444
|
+
VALUE socket_io = pgconn_socket_io(self);
|
2445
|
+
events = RB_NUM2INT(pg_rb_io_wait(socket_io, RB_INT2NUM(PG_RUBY_IO_READABLE | PG_RUBY_IO_WRITABLE), Qnil));
|
2446
|
+
|
2447
|
+
if (events & PG_RUBY_IO_READABLE)
|
2448
|
+
pgconn_consume_input(self);
|
2449
|
+
}
|
2450
|
+
return Qtrue;
|
2451
|
+
}
|
2452
|
+
|
2453
|
+
static VALUE
|
2454
|
+
pgconn_wait_for_flush( VALUE self ){
|
2455
|
+
if( !pg_get_connection_safe(self)->flush_data )
|
2456
|
+
return Qnil;
|
2450
2457
|
|
2451
|
-
|
2458
|
+
return pgconn_async_flush(self);
|
2459
|
+
}
|
2460
|
+
|
2461
|
+
static VALUE
|
2462
|
+
pgconn_flush_data_set( VALUE self, VALUE enabled ){
|
2463
|
+
t_pg_connection *conn = pg_get_connection(self);
|
2464
|
+
conn->flush_data = RTEST(enabled);
|
2465
|
+
return enabled;
|
2466
|
+
}
|
2452
2467
|
|
2453
2468
|
static void *
|
2454
2469
|
notify_readable(PGconn *conn)
|
@@ -2458,27 +2473,20 @@ notify_readable(PGconn *conn)
|
|
2458
2473
|
|
2459
2474
|
/*
|
2460
2475
|
* 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
|
2476
|
+
* conn.wait_for_notify( [ timeout ] ) { |event, pid, payload| block } -> String
|
2464
2477
|
*
|
2465
2478
|
* Blocks while waiting for notification(s), or until the optional
|
2466
2479
|
* _timeout_ is reached, whichever comes first. _timeout_ is
|
2467
2480
|
* measured in seconds and can be fractional.
|
2468
2481
|
*
|
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
|
-
*
|
2482
|
+
* Returns +nil+ if _timeout_ is reached, the name of the NOTIFY event otherwise.
|
2483
|
+
* If used in block form, passes the name of the NOTIFY +event+, the generating
|
2484
|
+
* +pid+ and the optional +payload+ string into the block.
|
2477
2485
|
*/
|
2478
2486
|
static VALUE
|
2479
2487
|
pgconn_wait_for_notify(int argc, VALUE *argv, VALUE self)
|
2480
2488
|
{
|
2481
|
-
|
2489
|
+
t_pg_connection *this = pg_get_connection_safe( self );
|
2482
2490
|
PGnotify *pnotification;
|
2483
2491
|
struct timeval timeout;
|
2484
2492
|
struct timeval *ptimeout = NULL;
|
@@ -2494,20 +2502,18 @@ pgconn_wait_for_notify(int argc, VALUE *argv, VALUE self)
|
|
2494
2502
|
ptimeout = &timeout;
|
2495
2503
|
}
|
2496
2504
|
|
2497
|
-
pnotification = (PGnotify*) wait_socket_readable(
|
2505
|
+
pnotification = (PGnotify*) wait_socket_readable( self, ptimeout, notify_readable);
|
2498
2506
|
|
2499
2507
|
/* Return nil if the select timed out */
|
2500
2508
|
if ( !pnotification ) return Qnil;
|
2501
2509
|
|
2502
|
-
relname =
|
2503
|
-
PG_ENCODING_SET_NOCHECK( relname,
|
2510
|
+
relname = rb_str_new2( pnotification->relname );
|
2511
|
+
PG_ENCODING_SET_NOCHECK( relname, this->enc_idx );
|
2504
2512
|
be_pid = INT2NUM( pnotification->be_pid );
|
2505
|
-
#ifdef HAVE_ST_NOTIFY_EXTRA
|
2506
2513
|
if ( *pnotification->extra ) {
|
2507
|
-
extra =
|
2508
|
-
PG_ENCODING_SET_NOCHECK( extra,
|
2514
|
+
extra = rb_str_new2( pnotification->extra );
|
2515
|
+
PG_ENCODING_SET_NOCHECK( extra, this->enc_idx );
|
2509
2516
|
}
|
2510
|
-
#endif
|
2511
2517
|
PQfreemem( pnotification );
|
2512
2518
|
|
2513
2519
|
if ( rb_block_given_p() )
|
@@ -2517,27 +2523,8 @@ pgconn_wait_for_notify(int argc, VALUE *argv, VALUE self)
|
|
2517
2523
|
}
|
2518
2524
|
|
2519
2525
|
|
2520
|
-
/*
|
2521
|
-
* call-seq:
|
2522
|
-
* conn.put_copy_data( buffer [, encoder] ) -> Boolean
|
2523
|
-
*
|
2524
|
-
* Transmits _buffer_ as copy data to the server.
|
2525
|
-
* Returns true if the data was sent, false if it was
|
2526
|
-
* not sent (false is only possible if the connection
|
2527
|
-
* is in nonblocking mode, and this command would block).
|
2528
|
-
*
|
2529
|
-
* encoder can be a PG::Coder derivation (typically PG::TextEncoder::CopyRow).
|
2530
|
-
* This encodes the received data fields from an Array of Strings. Optionally
|
2531
|
-
* the encoder can type cast the fields form various Ruby types in one step,
|
2532
|
-
* if PG::TextEncoder::CopyRow#type_map is set accordingly.
|
2533
|
-
*
|
2534
|
-
* Raises an exception if an error occurs.
|
2535
|
-
*
|
2536
|
-
* See also #copy_data.
|
2537
|
-
*
|
2538
|
-
*/
|
2539
2526
|
static VALUE
|
2540
|
-
|
2527
|
+
pgconn_sync_put_copy_data(int argc, VALUE *argv, VALUE self)
|
2541
2528
|
{
|
2542
2529
|
int ret;
|
2543
2530
|
int len;
|
@@ -2554,27 +2541,26 @@ pgconn_put_copy_data(int argc, VALUE *argv, VALUE self)
|
|
2554
2541
|
if( NIL_P(this->encoder_for_put_copy_data) ){
|
2555
2542
|
buffer = value;
|
2556
2543
|
} else {
|
2557
|
-
p_coder =
|
2544
|
+
p_coder = RTYPEDDATA_DATA( this->encoder_for_put_copy_data );
|
2558
2545
|
}
|
2559
|
-
} else if( rb_obj_is_kind_of(encoder, rb_cPG_Coder) ) {
|
2560
|
-
Data_Get_Struct( encoder, t_pg_coder, p_coder );
|
2561
2546
|
} else {
|
2562
|
-
|
2563
|
-
|
2547
|
+
/* Check argument type and use argument encoder */
|
2548
|
+
TypedData_Get_Struct(encoder, t_pg_coder, &pg_coder_type, p_coder);
|
2564
2549
|
}
|
2565
2550
|
|
2566
2551
|
if( p_coder ){
|
2567
2552
|
t_pg_coder_enc_func enc_func;
|
2553
|
+
int enc_idx = this->enc_idx;
|
2568
2554
|
|
2569
2555
|
enc_func = pg_coder_enc_func( p_coder );
|
2570
|
-
len = enc_func( p_coder, value, NULL, &intermediate );
|
2556
|
+
len = enc_func( p_coder, value, NULL, &intermediate, enc_idx);
|
2571
2557
|
|
2572
2558
|
if( len == -1 ){
|
2573
2559
|
/* The intermediate value is a String that can be used directly. */
|
2574
2560
|
buffer = intermediate;
|
2575
2561
|
} else {
|
2576
2562
|
buffer = rb_str_new(NULL, len);
|
2577
|
-
len = enc_func( p_coder, value, RSTRING_PTR(buffer), &intermediate);
|
2563
|
+
len = enc_func( p_coder, value, RSTRING_PTR(buffer), &intermediate, enc_idx);
|
2578
2564
|
rb_str_set_len( buffer, len );
|
2579
2565
|
}
|
2580
2566
|
}
|
@@ -2582,75 +2568,39 @@ pgconn_put_copy_data(int argc, VALUE *argv, VALUE self)
|
|
2582
2568
|
Check_Type(buffer, T_STRING);
|
2583
2569
|
|
2584
2570
|
ret = gvl_PQputCopyData(this->pgconn, RSTRING_PTR(buffer), RSTRING_LENINT(buffer));
|
2585
|
-
if(ret == -1)
|
2586
|
-
|
2587
|
-
|
2588
|
-
rb_exc_raise(error);
|
2589
|
-
}
|
2571
|
+
if(ret == -1)
|
2572
|
+
pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(this->pgconn));
|
2573
|
+
|
2590
2574
|
RB_GC_GUARD(intermediate);
|
2591
2575
|
RB_GC_GUARD(buffer);
|
2592
2576
|
|
2593
2577
|
return (ret) ? Qtrue : Qfalse;
|
2594
2578
|
}
|
2595
2579
|
|
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
2580
|
static VALUE
|
2611
|
-
|
2581
|
+
pgconn_sync_put_copy_end(int argc, VALUE *argv, VALUE self)
|
2612
2582
|
{
|
2613
2583
|
VALUE str;
|
2614
|
-
VALUE error;
|
2615
2584
|
int ret;
|
2616
|
-
char *error_message = NULL;
|
2617
|
-
|
2585
|
+
const char *error_message = NULL;
|
2586
|
+
t_pg_connection *this = pg_get_connection_safe( self );
|
2618
2587
|
|
2619
2588
|
if (rb_scan_args(argc, argv, "01", &str) == 0)
|
2620
2589
|
error_message = NULL;
|
2621
2590
|
else
|
2622
|
-
error_message =
|
2591
|
+
error_message = pg_cstr_enc(str, this->enc_idx);
|
2592
|
+
|
2593
|
+
ret = gvl_PQputCopyEnd(this->pgconn, error_message);
|
2594
|
+
if(ret == -1)
|
2595
|
+
pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(this->pgconn));
|
2623
2596
|
|
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
2597
|
return (ret) ? Qtrue : Qfalse;
|
2631
2598
|
}
|
2632
2599
|
|
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 as Array of Strings. Optionally
|
2643
|
-
* the decoder can type cast the fields to various Ruby types in one step,
|
2644
|
-
* if PG::TextDecoder::CopyRow#type_map is set accordingly.
|
2645
|
-
*
|
2646
|
-
* See also #copy_data.
|
2647
|
-
*
|
2648
|
-
*/
|
2649
2600
|
static VALUE
|
2650
|
-
|
2601
|
+
pgconn_sync_get_copy_data(int argc, VALUE *argv, VALUE self )
|
2651
2602
|
{
|
2652
2603
|
VALUE async_in;
|
2653
|
-
VALUE error;
|
2654
2604
|
VALUE result;
|
2655
2605
|
int ret;
|
2656
2606
|
char *buffer;
|
@@ -2662,20 +2612,16 @@ pgconn_get_copy_data(int argc, VALUE *argv, VALUE self )
|
|
2662
2612
|
|
2663
2613
|
if( NIL_P(decoder) ){
|
2664
2614
|
if( !NIL_P(this->decoder_for_get_copy_data) ){
|
2665
|
-
p_coder =
|
2615
|
+
p_coder = RTYPEDDATA_DATA( this->decoder_for_get_copy_data );
|
2666
2616
|
}
|
2667
|
-
} else if( rb_obj_is_kind_of(decoder, rb_cPG_Coder) ) {
|
2668
|
-
Data_Get_Struct( decoder, t_pg_coder, p_coder );
|
2669
2617
|
} else {
|
2670
|
-
|
2671
|
-
|
2618
|
+
/* Check argument type and use argument decoder */
|
2619
|
+
TypedData_Get_Struct(decoder, t_pg_coder, &pg_coder_type, p_coder);
|
2672
2620
|
}
|
2673
2621
|
|
2674
2622
|
ret = gvl_PQgetCopyData(this->pgconn, &buffer, RTEST(async_in));
|
2675
|
-
if(ret == -2)
|
2676
|
-
|
2677
|
-
rb_iv_set(error, "@connection", self);
|
2678
|
-
rb_exc_raise(error);
|
2623
|
+
if(ret == -2){ /* error */
|
2624
|
+
pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(this->pgconn));
|
2679
2625
|
}
|
2680
2626
|
if(ret == -1) { /* No data left */
|
2681
2627
|
return Qnil;
|
@@ -2686,9 +2632,9 @@ pgconn_get_copy_data(int argc, VALUE *argv, VALUE self )
|
|
2686
2632
|
|
2687
2633
|
if( p_coder ){
|
2688
2634
|
t_pg_coder_dec_func dec_func = pg_coder_dec_func( p_coder, p_coder->format );
|
2689
|
-
result = dec_func( p_coder, buffer, ret, 0, 0,
|
2635
|
+
result = dec_func( p_coder, buffer, ret, 0, 0, this->enc_idx );
|
2690
2636
|
} else {
|
2691
|
-
result =
|
2637
|
+
result = rb_str_new(buffer, ret);
|
2692
2638
|
}
|
2693
2639
|
|
2694
2640
|
PQfreemem(buffer);
|
@@ -2697,13 +2643,20 @@ pgconn_get_copy_data(int argc, VALUE *argv, VALUE self )
|
|
2697
2643
|
|
2698
2644
|
/*
|
2699
2645
|
* call-seq:
|
2700
|
-
* conn.set_error_verbosity( verbosity ) ->
|
2646
|
+
* conn.set_error_verbosity( verbosity ) -> Integer
|
2701
2647
|
*
|
2702
2648
|
* Sets connection's verbosity to _verbosity_ and returns
|
2703
2649
|
* the previous setting. Available settings are:
|
2650
|
+
*
|
2704
2651
|
* * PQERRORS_TERSE
|
2705
2652
|
* * PQERRORS_DEFAULT
|
2706
2653
|
* * PQERRORS_VERBOSE
|
2654
|
+
* * PQERRORS_SQLSTATE
|
2655
|
+
*
|
2656
|
+
* Changing the verbosity does not affect the messages available from already-existing PG::Result objects, only subsequently-created ones.
|
2657
|
+
* (But see PG::Result#verbose_error_message if you want to print a previous error with a different verbosity.)
|
2658
|
+
*
|
2659
|
+
* See also corresponding {libpq function}[https://www.postgresql.org/docs/current/libpq-control.html#LIBPQ-PQSETERRORVERBOSITY].
|
2707
2660
|
*/
|
2708
2661
|
static VALUE
|
2709
2662
|
pgconn_set_error_verbosity(VALUE self, VALUE in_verbosity)
|
@@ -2713,6 +2666,37 @@ pgconn_set_error_verbosity(VALUE self, VALUE in_verbosity)
|
|
2713
2666
|
return INT2FIX(PQsetErrorVerbosity(conn, verbosity));
|
2714
2667
|
}
|
2715
2668
|
|
2669
|
+
#ifdef HAVE_PQRESULTVERBOSEERRORMESSAGE
|
2670
|
+
/*
|
2671
|
+
* call-seq:
|
2672
|
+
* conn.set_error_context_visibility( context_visibility ) -> Integer
|
2673
|
+
*
|
2674
|
+
* Sets connection's context display mode to _context_visibility_ and returns
|
2675
|
+
* the previous setting. Available settings are:
|
2676
|
+
* * PQSHOW_CONTEXT_NEVER
|
2677
|
+
* * PQSHOW_CONTEXT_ERRORS
|
2678
|
+
* * PQSHOW_CONTEXT_ALWAYS
|
2679
|
+
*
|
2680
|
+
* This mode controls whether the CONTEXT field is included in messages (unless the verbosity setting is TERSE, in which case CONTEXT is never shown).
|
2681
|
+
* The NEVER mode never includes CONTEXT, while ALWAYS always includes it if available.
|
2682
|
+
* In ERRORS mode (the default), CONTEXT fields are included only for error messages, not for notices and warnings.
|
2683
|
+
*
|
2684
|
+
* Changing this mode does not affect the messages available from already-existing PG::Result objects, only subsequently-created ones.
|
2685
|
+
* (But see PG::Result#verbose_error_message if you want to print a previous error with a different display mode.)
|
2686
|
+
*
|
2687
|
+
* See also corresponding {libpq function}[https://www.postgresql.org/docs/current/libpq-control.html#LIBPQ-PQSETERRORCONTEXTVISIBILITY].
|
2688
|
+
*
|
2689
|
+
* Available since PostgreSQL-9.6
|
2690
|
+
*/
|
2691
|
+
static VALUE
|
2692
|
+
pgconn_set_error_context_visibility(VALUE self, VALUE in_context_visibility)
|
2693
|
+
{
|
2694
|
+
PGconn *conn = pg_get_pgconn(self);
|
2695
|
+
PGContextVisibility context_visibility = NUM2INT(in_context_visibility);
|
2696
|
+
return INT2FIX(PQsetErrorContextVisibility(conn, context_visibility));
|
2697
|
+
}
|
2698
|
+
#endif
|
2699
|
+
|
2716
2700
|
/*
|
2717
2701
|
* call-seq:
|
2718
2702
|
* conn.trace( stream ) -> nil
|
@@ -2731,7 +2715,7 @@ pgconn_trace(VALUE self, VALUE stream)
|
|
2731
2715
|
VALUE new_file;
|
2732
2716
|
t_pg_connection *this = pg_get_connection_safe( self );
|
2733
2717
|
|
2734
|
-
if(rb_respond_to(stream,rb_intern("fileno"))
|
2718
|
+
if(!rb_respond_to(stream,rb_intern("fileno")))
|
2735
2719
|
rb_raise(rb_eArgError, "stream does not respond to method: fileno");
|
2736
2720
|
|
2737
2721
|
fileno = rb_funcall(stream, rb_intern("fileno"), 0);
|
@@ -2864,8 +2848,8 @@ notice_processor_proxy(void *arg, const char *message)
|
|
2864
2848
|
t_pg_connection *this = pg_get_connection( self );
|
2865
2849
|
|
2866
2850
|
if (this->notice_receiver != Qnil) {
|
2867
|
-
VALUE message_str =
|
2868
|
-
PG_ENCODING_SET_NOCHECK( message_str,
|
2851
|
+
VALUE message_str = rb_str_new2(message);
|
2852
|
+
PG_ENCODING_SET_NOCHECK( message_str, this->enc_idx );
|
2869
2853
|
rb_funcall(this->notice_receiver, rb_intern("call"), 1, message_str);
|
2870
2854
|
}
|
2871
2855
|
return;
|
@@ -2875,7 +2859,7 @@ notice_processor_proxy(void *arg, const char *message)
|
|
2875
2859
|
* call-seq:
|
2876
2860
|
* conn.set_notice_processor {|message| ... } -> Proc
|
2877
2861
|
*
|
2878
|
-
* See #set_notice_receiver for the
|
2862
|
+
* See #set_notice_receiver for the description of what this and the
|
2879
2863
|
* notice_processor methods do.
|
2880
2864
|
*
|
2881
2865
|
* This function takes a new block to act as the notice processor and returns
|
@@ -2915,255 +2899,751 @@ pgconn_set_notice_processor(VALUE self)
|
|
2915
2899
|
|
2916
2900
|
/*
|
2917
2901
|
* call-seq:
|
2918
|
-
* conn.get_client_encoding() -> String
|
2902
|
+
* conn.get_client_encoding() -> String
|
2903
|
+
*
|
2904
|
+
* Returns the client encoding as a String.
|
2905
|
+
*/
|
2906
|
+
static VALUE
|
2907
|
+
pgconn_get_client_encoding(VALUE self)
|
2908
|
+
{
|
2909
|
+
char *encoding = (char *)pg_encoding_to_char(PQclientEncoding(pg_get_pgconn(self)));
|
2910
|
+
return rb_str_new2(encoding);
|
2911
|
+
}
|
2912
|
+
|
2913
|
+
|
2914
|
+
/*
|
2915
|
+
* call-seq:
|
2916
|
+
* conn.sync_set_client_encoding( encoding )
|
2917
|
+
*
|
2918
|
+
* This function has the same behavior as #async_set_client_encoding, but is implemented using the synchronous command processing API of libpq.
|
2919
|
+
* See #async_exec for the differences between the two API variants.
|
2920
|
+
* 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.
|
2921
|
+
*/
|
2922
|
+
static VALUE
|
2923
|
+
pgconn_sync_set_client_encoding(VALUE self, VALUE str)
|
2924
|
+
{
|
2925
|
+
PGconn *conn = pg_get_pgconn( self );
|
2926
|
+
|
2927
|
+
Check_Type(str, T_STRING);
|
2928
|
+
|
2929
|
+
if ( (gvl_PQsetClientEncoding(conn, StringValueCStr(str))) == -1 )
|
2930
|
+
pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(conn));
|
2931
|
+
|
2932
|
+
pgconn_set_internal_encoding_index( self );
|
2933
|
+
|
2934
|
+
return Qnil;
|
2935
|
+
}
|
2936
|
+
|
2937
|
+
|
2938
|
+
/*
|
2939
|
+
* call-seq:
|
2940
|
+
* conn.quote_ident( str ) -> String
|
2941
|
+
* conn.quote_ident( array ) -> String
|
2942
|
+
* PG::Connection.quote_ident( str ) -> String
|
2943
|
+
* PG::Connection.quote_ident( array ) -> String
|
2944
|
+
*
|
2945
|
+
* Returns a string that is safe for inclusion in a SQL query as an
|
2946
|
+
* identifier. Note: this is not a quote function for values, but for
|
2947
|
+
* identifiers.
|
2948
|
+
*
|
2949
|
+
* For example, in a typical SQL query: <tt>SELECT FOO FROM MYTABLE</tt>
|
2950
|
+
* The identifier <tt>FOO</tt> is folded to lower case, so it actually
|
2951
|
+
* means <tt>foo</tt>. If you really want to access the case-sensitive
|
2952
|
+
* field name <tt>FOO</tt>, use this function like
|
2953
|
+
* <tt>conn.quote_ident('FOO')</tt>, which will return <tt>"FOO"</tt>
|
2954
|
+
* (with double-quotes). PostgreSQL will see the double-quotes, and
|
2955
|
+
* it will not fold to lower case.
|
2956
|
+
*
|
2957
|
+
* Similarly, this function also protects against special characters,
|
2958
|
+
* and other things that might allow SQL injection if the identifier
|
2959
|
+
* comes from an untrusted source.
|
2960
|
+
*
|
2961
|
+
* If the parameter is an Array, then all it's values are separately quoted
|
2962
|
+
* and then joined by a "." character. This can be used for identifiers in
|
2963
|
+
* the form "schema"."table"."column" .
|
2964
|
+
*
|
2965
|
+
* This method is functional identical to the encoder PG::TextEncoder::Identifier .
|
2966
|
+
*
|
2967
|
+
* If the instance method form is used and the input string character encoding
|
2968
|
+
* is different to the connection encoding, then the string is converted to this
|
2969
|
+
* encoding, so that the returned string is always encoded as PG::Connection#internal_encoding .
|
2970
|
+
*
|
2971
|
+
* In the singleton form (PG::Connection.quote_ident) the character encoding
|
2972
|
+
* of the result string is set to the character encoding of the input string.
|
2973
|
+
*/
|
2974
|
+
static VALUE
|
2975
|
+
pgconn_s_quote_ident(VALUE self, VALUE str_or_array)
|
2976
|
+
{
|
2977
|
+
VALUE ret;
|
2978
|
+
int enc_idx;
|
2979
|
+
|
2980
|
+
if( rb_obj_is_kind_of(self, rb_cPGconn) ){
|
2981
|
+
enc_idx = pg_get_connection(self)->enc_idx;
|
2982
|
+
}else{
|
2983
|
+
enc_idx = RB_TYPE_P(str_or_array, T_STRING) ? ENCODING_GET( str_or_array ) : rb_ascii8bit_encindex();
|
2984
|
+
}
|
2985
|
+
pg_text_enc_identifier(NULL, str_or_array, NULL, &ret, enc_idx);
|
2986
|
+
|
2987
|
+
return ret;
|
2988
|
+
}
|
2989
|
+
|
2990
|
+
|
2991
|
+
static void *
|
2992
|
+
get_result_readable(PGconn *conn)
|
2993
|
+
{
|
2994
|
+
return gvl_PQisBusy(conn) ? NULL : (void*)1;
|
2995
|
+
}
|
2996
|
+
|
2997
|
+
|
2998
|
+
/*
|
2999
|
+
* call-seq:
|
3000
|
+
* conn.block( [ timeout ] ) -> Boolean
|
3001
|
+
*
|
3002
|
+
* Blocks until the server is no longer busy, or until the
|
3003
|
+
* optional _timeout_ is reached, whichever comes first.
|
3004
|
+
* _timeout_ is measured in seconds and can be fractional.
|
3005
|
+
*
|
3006
|
+
* Returns +false+ if _timeout_ is reached, +true+ otherwise.
|
3007
|
+
*
|
3008
|
+
* If +true+ is returned, +conn.is_busy+ will return +false+
|
3009
|
+
* and +conn.get_result+ will not block.
|
3010
|
+
*/
|
3011
|
+
VALUE
|
3012
|
+
pgconn_block( int argc, VALUE *argv, VALUE self ) {
|
3013
|
+
struct timeval timeout;
|
3014
|
+
struct timeval *ptimeout = NULL;
|
3015
|
+
VALUE timeout_in;
|
3016
|
+
double timeout_sec;
|
3017
|
+
void *ret;
|
3018
|
+
|
3019
|
+
if ( rb_scan_args(argc, argv, "01", &timeout_in) == 1 ) {
|
3020
|
+
timeout_sec = NUM2DBL( timeout_in );
|
3021
|
+
timeout.tv_sec = (time_t)timeout_sec;
|
3022
|
+
timeout.tv_usec = (suseconds_t)((timeout_sec - (long)timeout_sec) * 1e6);
|
3023
|
+
ptimeout = &timeout;
|
3024
|
+
}
|
3025
|
+
|
3026
|
+
ret = wait_socket_readable( self, ptimeout, get_result_readable);
|
3027
|
+
|
3028
|
+
if( !ret )
|
3029
|
+
return Qfalse;
|
3030
|
+
|
3031
|
+
return Qtrue;
|
3032
|
+
}
|
3033
|
+
|
3034
|
+
|
3035
|
+
/*
|
3036
|
+
* call-seq:
|
3037
|
+
* conn.sync_get_last_result( ) -> PG::Result
|
3038
|
+
*
|
3039
|
+
* This function has the same behavior as #async_get_last_result, but is implemented using the synchronous command processing API of libpq.
|
3040
|
+
* See #async_exec for the differences between the two API variants.
|
3041
|
+
* 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.
|
3042
|
+
*/
|
3043
|
+
static VALUE
|
3044
|
+
pgconn_sync_get_last_result(VALUE self)
|
3045
|
+
{
|
3046
|
+
PGconn *conn = pg_get_pgconn(self);
|
3047
|
+
VALUE rb_pgresult = Qnil;
|
3048
|
+
PGresult *cur, *prev;
|
3049
|
+
|
3050
|
+
|
3051
|
+
cur = prev = NULL;
|
3052
|
+
while ((cur = gvl_PQgetResult(conn)) != NULL) {
|
3053
|
+
int status;
|
3054
|
+
|
3055
|
+
if (prev) PQclear(prev);
|
3056
|
+
prev = cur;
|
3057
|
+
|
3058
|
+
status = PQresultStatus(cur);
|
3059
|
+
if (status == PGRES_COPY_OUT || status == PGRES_COPY_IN || status == PGRES_COPY_BOTH)
|
3060
|
+
break;
|
3061
|
+
}
|
3062
|
+
|
3063
|
+
if (prev) {
|
3064
|
+
rb_pgresult = pg_new_result( prev, self );
|
3065
|
+
pg_result_check(rb_pgresult);
|
3066
|
+
}
|
3067
|
+
|
3068
|
+
return rb_pgresult;
|
3069
|
+
}
|
3070
|
+
|
3071
|
+
/*
|
3072
|
+
* call-seq:
|
3073
|
+
* conn.get_last_result( ) -> PG::Result
|
3074
|
+
*
|
3075
|
+
* This function retrieves all available results
|
3076
|
+
* on the current connection (from previously issued
|
3077
|
+
* asynchronous commands like +send_query()+) and
|
3078
|
+
* returns the last non-NULL result, or +nil+ if no
|
3079
|
+
* results are available.
|
3080
|
+
*
|
3081
|
+
* If the last result contains a bad result_status, an
|
3082
|
+
* appropriate exception is raised.
|
3083
|
+
*
|
3084
|
+
* This function is similar to #get_result
|
3085
|
+
* except that it is designed to get one and only
|
3086
|
+
* one result and that it checks the result state.
|
3087
|
+
*/
|
3088
|
+
static VALUE
|
3089
|
+
pgconn_async_get_last_result(VALUE self)
|
3090
|
+
{
|
3091
|
+
PGconn *conn = pg_get_pgconn(self);
|
3092
|
+
VALUE rb_pgresult = Qnil;
|
3093
|
+
PGresult *cur, *prev;
|
3094
|
+
|
3095
|
+
cur = prev = NULL;
|
3096
|
+
for(;;) {
|
3097
|
+
int status;
|
3098
|
+
|
3099
|
+
/* wait for input (without blocking) before reading each result */
|
3100
|
+
wait_socket_readable(self, NULL, get_result_readable);
|
3101
|
+
|
3102
|
+
cur = gvl_PQgetResult(conn);
|
3103
|
+
if (cur == NULL)
|
3104
|
+
break;
|
3105
|
+
|
3106
|
+
if (prev) PQclear(prev);
|
3107
|
+
prev = cur;
|
3108
|
+
|
3109
|
+
status = PQresultStatus(cur);
|
3110
|
+
if (status == PGRES_COPY_OUT || status == PGRES_COPY_IN || status == PGRES_COPY_BOTH)
|
3111
|
+
break;
|
3112
|
+
}
|
3113
|
+
|
3114
|
+
if (prev) {
|
3115
|
+
rb_pgresult = pg_new_result( prev, self );
|
3116
|
+
pg_result_check(rb_pgresult);
|
3117
|
+
}
|
3118
|
+
|
3119
|
+
return rb_pgresult;
|
3120
|
+
}
|
3121
|
+
|
3122
|
+
/*
|
3123
|
+
* call-seq:
|
3124
|
+
* conn.discard_results()
|
3125
|
+
*
|
3126
|
+
* Silently discard any prior query result that application didn't eat.
|
3127
|
+
* This is done prior of Connection#exec and sibling methods and can
|
3128
|
+
* be called explicitly when using the async API.
|
3129
|
+
*/
|
3130
|
+
static VALUE
|
3131
|
+
pgconn_discard_results(VALUE self)
|
3132
|
+
{
|
3133
|
+
PGconn *conn = pg_get_pgconn(self);
|
3134
|
+
VALUE socket_io;
|
3135
|
+
|
3136
|
+
if( PQtransactionStatus(conn) == PQTRANS_IDLE ) {
|
3137
|
+
return Qnil;
|
3138
|
+
}
|
3139
|
+
|
3140
|
+
socket_io = pgconn_socket_io(self);
|
3141
|
+
|
3142
|
+
for(;;) {
|
3143
|
+
PGresult *cur;
|
3144
|
+
int status;
|
3145
|
+
|
3146
|
+
/* pgconn_block() raises an exception in case of errors.
|
3147
|
+
* To avoid this call pg_rb_io_wait() and PQconsumeInput() without rb_raise().
|
3148
|
+
*/
|
3149
|
+
while( gvl_PQisBusy(conn) ){
|
3150
|
+
pg_rb_io_wait(socket_io, RB_INT2NUM(PG_RUBY_IO_READABLE), Qnil);
|
3151
|
+
if ( PQconsumeInput(conn) == 0 ) {
|
3152
|
+
pgconn_close_socket_io(self);
|
3153
|
+
return Qfalse;
|
3154
|
+
}
|
3155
|
+
}
|
3156
|
+
|
3157
|
+
cur = gvl_PQgetResult(conn);
|
3158
|
+
if( cur == NULL) break;
|
3159
|
+
|
3160
|
+
status = PQresultStatus(cur);
|
3161
|
+
PQclear(cur);
|
3162
|
+
if (status == PGRES_COPY_IN){
|
3163
|
+
gvl_PQputCopyEnd(conn, "COPY terminated by new PQexec");
|
3164
|
+
}
|
3165
|
+
if (status == PGRES_COPY_OUT){
|
3166
|
+
for(;;) {
|
3167
|
+
char *buffer = NULL;
|
3168
|
+
int st = gvl_PQgetCopyData(conn, &buffer, 1);
|
3169
|
+
if( st == 0 ) {
|
3170
|
+
/* would block -> wait for readable data */
|
3171
|
+
pg_rb_io_wait(socket_io, RB_INT2NUM(PG_RUBY_IO_READABLE), Qnil);
|
3172
|
+
if ( PQconsumeInput(conn) == 0 ) {
|
3173
|
+
pgconn_close_socket_io(self);
|
3174
|
+
return Qfalse;
|
3175
|
+
}
|
3176
|
+
} else if( st > 0 ) {
|
3177
|
+
/* some data retrieved -> discard it */
|
3178
|
+
PQfreemem(buffer);
|
3179
|
+
} else {
|
3180
|
+
/* no more data */
|
3181
|
+
break;
|
3182
|
+
}
|
3183
|
+
}
|
3184
|
+
}
|
3185
|
+
}
|
3186
|
+
|
3187
|
+
return Qtrue;
|
3188
|
+
}
|
3189
|
+
|
3190
|
+
/*
|
3191
|
+
* call-seq:
|
3192
|
+
* conn.exec(sql) -> PG::Result
|
3193
|
+
* conn.exec(sql) {|pg_result| block }
|
3194
|
+
*
|
3195
|
+
* Sends SQL query request specified by _sql_ to PostgreSQL.
|
3196
|
+
* On success, it returns a PG::Result instance with all result rows and columns.
|
3197
|
+
* On failure, it raises a PG::Error.
|
3198
|
+
*
|
3199
|
+
* For backward compatibility, if you pass more than one parameter to this method,
|
3200
|
+
* it will call #exec_params for you. New code should explicitly use #exec_params if
|
3201
|
+
* argument placeholders are used.
|
3202
|
+
*
|
3203
|
+
* If the optional code block is given, it will be passed <i>result</i> as an argument,
|
3204
|
+
* and the PG::Result object will automatically be cleared when the block terminates.
|
3205
|
+
* In this instance, <code>conn.exec</code> returns the value of the block.
|
3206
|
+
*
|
3207
|
+
* #exec is an alias for #async_exec which is almost identical to #sync_exec .
|
3208
|
+
* #sync_exec is implemented on the simpler synchronous command processing API of libpq, whereas
|
3209
|
+
* #async_exec is implemented on the asynchronous API and on ruby's IO mechanisms.
|
3210
|
+
* Only #async_exec is compatible to <tt>Fiber.scheduler</tt> based asynchronous IO processing introduced in ruby-3.0.
|
3211
|
+
* Both methods ensure that other threads can process while waiting for the server to
|
3212
|
+
* complete the request, but #sync_exec blocks all signals to be processed until the query is finished.
|
3213
|
+
* This is most notably visible by a delayed reaction to Control+C.
|
3214
|
+
* It's not recommended to use explicit sync or async variants but #exec instead, unless you have a good reason to do so.
|
3215
|
+
*
|
3216
|
+
* See also corresponding {libpq function}[https://www.postgresql.org/docs/current/libpq-exec.html#LIBPQ-PQEXEC].
|
3217
|
+
*/
|
3218
|
+
static VALUE
|
3219
|
+
pgconn_async_exec(int argc, VALUE *argv, VALUE self)
|
3220
|
+
{
|
3221
|
+
VALUE rb_pgresult = Qnil;
|
3222
|
+
|
3223
|
+
pgconn_discard_results( self );
|
3224
|
+
pgconn_send_query( argc, argv, self );
|
3225
|
+
rb_pgresult = pgconn_async_get_last_result( self );
|
3226
|
+
|
3227
|
+
if ( rb_block_given_p() ) {
|
3228
|
+
return rb_ensure( rb_yield, rb_pgresult, pg_result_clear, rb_pgresult );
|
3229
|
+
}
|
3230
|
+
return rb_pgresult;
|
3231
|
+
}
|
3232
|
+
|
3233
|
+
|
3234
|
+
/*
|
3235
|
+
* call-seq:
|
3236
|
+
* conn.exec_params(sql, params [, result_format [, type_map ]] ) -> nil
|
3237
|
+
* conn.exec_params(sql, params [, result_format [, type_map ]] ) {|pg_result| block }
|
3238
|
+
*
|
3239
|
+
* Sends SQL query request specified by +sql+ to PostgreSQL using placeholders
|
3240
|
+
* for parameters.
|
3241
|
+
*
|
3242
|
+
* Returns a PG::Result instance on success. On failure, it raises a PG::Error.
|
3243
|
+
*
|
3244
|
+
* +params+ is an array of the bind parameters for the SQL query.
|
3245
|
+
* Each element of the +params+ array may be either:
|
3246
|
+
* a hash of the form:
|
3247
|
+
* {:value => String (value of bind parameter)
|
3248
|
+
* :type => Integer (oid of type of bind parameter)
|
3249
|
+
* :format => Integer (0 for text, 1 for binary)
|
3250
|
+
* }
|
3251
|
+
* or, it may be a String. If it is a string, that is equivalent to the hash:
|
3252
|
+
* { :value => <string value>, :type => 0, :format => 0 }
|
3253
|
+
*
|
3254
|
+
* PostgreSQL bind parameters are represented as $1, $2, $3, etc.,
|
3255
|
+
* inside the SQL query. The 0th element of the +params+ array is bound
|
3256
|
+
* to $1, the 1st element is bound to $2, etc. +nil+ is treated as +NULL+.
|
3257
|
+
*
|
3258
|
+
* If the types are not specified, they will be inferred by PostgreSQL.
|
3259
|
+
* Instead of specifying type oids, it's recommended to simply add
|
3260
|
+
* explicit casts in the query to ensure that the right type is used.
|
3261
|
+
*
|
3262
|
+
* For example: "SELECT $1::int"
|
3263
|
+
*
|
3264
|
+
* The optional +result_format+ should be 0 for text results, 1
|
3265
|
+
* for binary.
|
3266
|
+
*
|
3267
|
+
* +type_map+ can be a PG::TypeMap derivation (such as PG::BasicTypeMapForQueries).
|
3268
|
+
* This will type cast the params from various Ruby types before transmission
|
3269
|
+
* based on the encoders defined by the type map. When a type encoder is used
|
3270
|
+
* the format and oid of a given bind parameter are retrieved from the encoder
|
3271
|
+
* instead out of the hash form described above.
|
3272
|
+
*
|
3273
|
+
* If the optional code block is given, it will be passed <i>result</i> as an argument,
|
3274
|
+
* and the PG::Result object will automatically be cleared when the block terminates.
|
3275
|
+
* In this instance, <code>conn.exec</code> returns the value of the block.
|
3276
|
+
*
|
3277
|
+
* 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.
|
3278
|
+
* Unlike #exec, #exec_params allows at most one SQL command in the given string.
|
3279
|
+
* (There can be semicolons in it, but not more than one nonempty command.)
|
3280
|
+
* This is a limitation of the underlying protocol, but has some usefulness as an extra defense against SQL-injection attacks.
|
3281
|
+
*
|
3282
|
+
* See also corresponding {libpq function}[https://www.postgresql.org/docs/current/libpq-exec.html#LIBPQ-PQEXECPARAMS].
|
3283
|
+
*/
|
3284
|
+
static VALUE
|
3285
|
+
pgconn_async_exec_params(int argc, VALUE *argv, VALUE self)
|
3286
|
+
{
|
3287
|
+
VALUE rb_pgresult = Qnil;
|
3288
|
+
|
3289
|
+
pgconn_discard_results( self );
|
3290
|
+
/* If called with no or nil parameters, use PQsendQuery for compatibility */
|
3291
|
+
if ( argc == 1 || (argc >= 2 && argc <= 4 && NIL_P(argv[1]) )) {
|
3292
|
+
pg_deprecated(3, ("forwarding async_exec_params to async_exec is deprecated"));
|
3293
|
+
pgconn_send_query( argc, argv, self );
|
3294
|
+
} else {
|
3295
|
+
pgconn_send_query_params( argc, argv, self );
|
3296
|
+
}
|
3297
|
+
rb_pgresult = pgconn_async_get_last_result( self );
|
3298
|
+
|
3299
|
+
if ( rb_block_given_p() ) {
|
3300
|
+
return rb_ensure( rb_yield, rb_pgresult, pg_result_clear, rb_pgresult );
|
3301
|
+
}
|
3302
|
+
return rb_pgresult;
|
3303
|
+
}
|
3304
|
+
|
3305
|
+
|
3306
|
+
/*
|
3307
|
+
* call-seq:
|
3308
|
+
* conn.prepare(stmt_name, sql [, param_types ] ) -> PG::Result
|
3309
|
+
*
|
3310
|
+
* Prepares statement _sql_ with name _name_ to be executed later.
|
3311
|
+
* Returns a PG::Result instance on success.
|
3312
|
+
* On failure, it raises a PG::Error.
|
3313
|
+
*
|
3314
|
+
* +param_types+ is an optional parameter to specify the Oids of the
|
3315
|
+
* types of the parameters.
|
3316
|
+
*
|
3317
|
+
* If the types are not specified, they will be inferred by PostgreSQL.
|
3318
|
+
* Instead of specifying type oids, it's recommended to simply add
|
3319
|
+
* explicit casts in the query to ensure that the right type is used.
|
3320
|
+
*
|
3321
|
+
* For example: "SELECT $1::int"
|
3322
|
+
*
|
3323
|
+
* PostgreSQL bind parameters are represented as $1, $2, $3, etc.,
|
3324
|
+
* inside the SQL query.
|
3325
|
+
*
|
3326
|
+
* See also corresponding {libpq function}[https://www.postgresql.org/docs/current/libpq-exec.html#LIBPQ-PQPREPARE].
|
3327
|
+
*/
|
3328
|
+
static VALUE
|
3329
|
+
pgconn_async_prepare(int argc, VALUE *argv, VALUE self)
|
3330
|
+
{
|
3331
|
+
VALUE rb_pgresult = Qnil;
|
3332
|
+
|
3333
|
+
pgconn_discard_results( self );
|
3334
|
+
pgconn_send_prepare( argc, argv, self );
|
3335
|
+
rb_pgresult = pgconn_async_get_last_result( self );
|
3336
|
+
|
3337
|
+
if ( rb_block_given_p() ) {
|
3338
|
+
return rb_ensure( rb_yield, rb_pgresult, pg_result_clear, rb_pgresult );
|
3339
|
+
}
|
3340
|
+
return rb_pgresult;
|
3341
|
+
}
|
3342
|
+
|
3343
|
+
|
3344
|
+
/*
|
3345
|
+
* call-seq:
|
3346
|
+
* conn.exec_prepared(statement_name [, params, result_format[, type_map]] ) -> PG::Result
|
3347
|
+
* conn.exec_prepared(statement_name [, params, result_format[, type_map]] ) {|pg_result| block }
|
3348
|
+
*
|
3349
|
+
* Execute prepared named statement specified by _statement_name_.
|
3350
|
+
* Returns a PG::Result instance on success.
|
3351
|
+
* On failure, it raises a PG::Error.
|
3352
|
+
*
|
3353
|
+
* +params+ is an array of the optional bind parameters for the
|
3354
|
+
* SQL query. Each element of the +params+ array may be either:
|
3355
|
+
* a hash of the form:
|
3356
|
+
* {:value => String (value of bind parameter)
|
3357
|
+
* :format => Integer (0 for text, 1 for binary)
|
3358
|
+
* }
|
3359
|
+
* or, it may be a String. If it is a string, that is equivalent to the hash:
|
3360
|
+
* { :value => <string value>, :format => 0 }
|
3361
|
+
*
|
3362
|
+
* PostgreSQL bind parameters are represented as $1, $2, $3, etc.,
|
3363
|
+
* inside the SQL query. The 0th element of the +params+ array is bound
|
3364
|
+
* to $1, the 1st element is bound to $2, etc. +nil+ is treated as +NULL+.
|
3365
|
+
*
|
3366
|
+
* The optional +result_format+ should be 0 for text results, 1
|
3367
|
+
* for binary.
|
3368
|
+
*
|
3369
|
+
* +type_map+ can be a PG::TypeMap derivation (such as PG::BasicTypeMapForQueries).
|
3370
|
+
* This will type cast the params from various Ruby types before transmission
|
3371
|
+
* based on the encoders defined by the type map. When a type encoder is used
|
3372
|
+
* the format and oid of a given bind parameter are retrieved from the encoder
|
3373
|
+
* instead out of the hash form described above.
|
3374
|
+
*
|
3375
|
+
* If the optional code block is given, it will be passed <i>result</i> as an argument,
|
3376
|
+
* and the PG::Result object will automatically be cleared when the block terminates.
|
3377
|
+
* In this instance, <code>conn.exec_prepared</code> returns the value of the block.
|
3378
|
+
*
|
3379
|
+
* See also corresponding {libpq function}[https://www.postgresql.org/docs/current/libpq-exec.html#LIBPQ-PQEXECPREPARED].
|
3380
|
+
*/
|
3381
|
+
static VALUE
|
3382
|
+
pgconn_async_exec_prepared(int argc, VALUE *argv, VALUE self)
|
3383
|
+
{
|
3384
|
+
VALUE rb_pgresult = Qnil;
|
3385
|
+
|
3386
|
+
pgconn_discard_results( self );
|
3387
|
+
pgconn_send_query_prepared( argc, argv, self );
|
3388
|
+
rb_pgresult = pgconn_async_get_last_result( self );
|
3389
|
+
|
3390
|
+
if ( rb_block_given_p() ) {
|
3391
|
+
return rb_ensure( rb_yield, rb_pgresult, pg_result_clear, rb_pgresult );
|
3392
|
+
}
|
3393
|
+
return rb_pgresult;
|
3394
|
+
}
|
3395
|
+
|
3396
|
+
|
3397
|
+
/*
|
3398
|
+
* call-seq:
|
3399
|
+
* conn.describe_portal( portal_name ) -> PG::Result
|
3400
|
+
*
|
3401
|
+
* Retrieve information about the portal _portal_name_.
|
3402
|
+
*
|
3403
|
+
* See also corresponding {libpq function}[https://www.postgresql.org/docs/current/libpq-exec.html#LIBPQ-PQDESCRIBEPORTAL].
|
3404
|
+
*/
|
3405
|
+
static VALUE
|
3406
|
+
pgconn_async_describe_portal(VALUE self, VALUE portal)
|
3407
|
+
{
|
3408
|
+
VALUE rb_pgresult = Qnil;
|
3409
|
+
|
3410
|
+
pgconn_discard_results( self );
|
3411
|
+
pgconn_send_describe_portal( self, portal );
|
3412
|
+
rb_pgresult = pgconn_async_get_last_result( self );
|
3413
|
+
|
3414
|
+
if ( rb_block_given_p() ) {
|
3415
|
+
return rb_ensure( rb_yield, rb_pgresult, pg_result_clear, rb_pgresult );
|
3416
|
+
}
|
3417
|
+
return rb_pgresult;
|
3418
|
+
}
|
3419
|
+
|
3420
|
+
|
3421
|
+
/*
|
3422
|
+
* call-seq:
|
3423
|
+
* conn.describe_prepared( statement_name ) -> PG::Result
|
3424
|
+
*
|
3425
|
+
* Retrieve information about the prepared statement _statement_name_.
|
3426
|
+
*
|
3427
|
+
* See also corresponding {libpq function}[https://www.postgresql.org/docs/current/libpq-exec.html#LIBPQ-PQDESCRIBEPREPARED].
|
3428
|
+
*/
|
3429
|
+
static VALUE
|
3430
|
+
pgconn_async_describe_prepared(VALUE self, VALUE stmt_name)
|
3431
|
+
{
|
3432
|
+
VALUE rb_pgresult = Qnil;
|
3433
|
+
|
3434
|
+
pgconn_discard_results( self );
|
3435
|
+
pgconn_send_describe_prepared( self, stmt_name );
|
3436
|
+
rb_pgresult = pgconn_async_get_last_result( self );
|
3437
|
+
|
3438
|
+
if ( rb_block_given_p() ) {
|
3439
|
+
return rb_ensure( rb_yield, rb_pgresult, pg_result_clear, rb_pgresult );
|
3440
|
+
}
|
3441
|
+
return rb_pgresult;
|
3442
|
+
}
|
3443
|
+
|
3444
|
+
|
3445
|
+
#ifdef HAVE_PQSSLATTRIBUTE
|
3446
|
+
/*
|
3447
|
+
* call-seq:
|
3448
|
+
* conn.ssl_in_use? -> Boolean
|
2919
3449
|
*
|
2920
|
-
* Returns the
|
3450
|
+
* Returns +true+ if the connection uses SSL/TLS, +false+ if not.
|
3451
|
+
*
|
3452
|
+
* Available since PostgreSQL-9.5
|
2921
3453
|
*/
|
2922
3454
|
static VALUE
|
2923
|
-
|
3455
|
+
pgconn_ssl_in_use(VALUE self)
|
2924
3456
|
{
|
2925
|
-
|
2926
|
-
return rb_tainted_str_new2(encoding);
|
3457
|
+
return PQsslInUse(pg_get_pgconn(self)) ? Qtrue : Qfalse;
|
2927
3458
|
}
|
2928
3459
|
|
2929
3460
|
|
2930
3461
|
/*
|
2931
3462
|
* call-seq:
|
2932
|
-
* conn.
|
3463
|
+
* conn.ssl_attribute(attribute_name) -> String
|
2933
3464
|
*
|
2934
|
-
*
|
3465
|
+
* Returns SSL-related information about the connection.
|
3466
|
+
*
|
3467
|
+
* The list of available attributes varies depending on the SSL library being used,
|
3468
|
+
* and the type of connection. If an attribute is not available, returns nil.
|
3469
|
+
*
|
3470
|
+
* The following attributes are commonly available:
|
3471
|
+
*
|
3472
|
+
* [+library+]
|
3473
|
+
* Name of the SSL implementation in use. (Currently, only "OpenSSL" is implemented)
|
3474
|
+
* [+protocol+]
|
3475
|
+
* SSL/TLS version in use. Common values are "SSLv2", "SSLv3", "TLSv1", "TLSv1.1" and "TLSv1.2", but an implementation may return other strings if some other protocol is used.
|
3476
|
+
* [+key_bits+]
|
3477
|
+
* Number of key bits used by the encryption algorithm.
|
3478
|
+
* [+cipher+]
|
3479
|
+
* A short name of the ciphersuite used, e.g. "DHE-RSA-DES-CBC3-SHA". The names are specific to each SSL implementation.
|
3480
|
+
* [+compression+]
|
3481
|
+
* 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".
|
3482
|
+
*
|
3483
|
+
*
|
3484
|
+
* See also #ssl_attribute_names and the {corresponding libpq function}[https://www.postgresql.org/docs/current/libpq-status.html#LIBPQ-PQSSLATTRIBUTE].
|
3485
|
+
*
|
3486
|
+
* Available since PostgreSQL-9.5
|
2935
3487
|
*/
|
2936
3488
|
static VALUE
|
2937
|
-
|
3489
|
+
pgconn_ssl_attribute(VALUE self, VALUE attribute_name)
|
2938
3490
|
{
|
2939
|
-
|
2940
|
-
|
2941
|
-
Check_Type(str, T_STRING);
|
2942
|
-
|
2943
|
-
if ( (PQsetClientEncoding(conn, StringValueCStr(str))) == -1 ) {
|
2944
|
-
rb_raise(rb_ePGerror, "invalid encoding name: %s",StringValueCStr(str));
|
2945
|
-
}
|
2946
|
-
#ifdef M17N_SUPPORTED
|
2947
|
-
pgconn_set_internal_encoding_index( self );
|
2948
|
-
#endif
|
3491
|
+
const char *p_attr;
|
2949
3492
|
|
2950
|
-
|
3493
|
+
p_attr = PQsslAttribute(pg_get_pgconn(self), StringValueCStr(attribute_name));
|
3494
|
+
return p_attr ? rb_str_new_cstr(p_attr) : Qnil;
|
2951
3495
|
}
|
2952
3496
|
|
2953
3497
|
/*
|
2954
3498
|
* call-seq:
|
2955
|
-
* conn.
|
3499
|
+
* conn.ssl_attribute_names -> Array<String>
|
2956
3500
|
*
|
2957
|
-
*
|
2958
|
-
*
|
2959
|
-
*
|
3501
|
+
* Return an array of SSL attribute names available.
|
3502
|
+
*
|
3503
|
+
* See also #ssl_attribute
|
3504
|
+
*
|
3505
|
+
* Available since PostgreSQL-9.5
|
2960
3506
|
*/
|
2961
3507
|
static VALUE
|
2962
|
-
|
3508
|
+
pgconn_ssl_attribute_names(VALUE self)
|
2963
3509
|
{
|
2964
|
-
|
2965
|
-
|
2966
|
-
VALUE
|
2967
|
-
VALUE block_result = Qnil;
|
2968
|
-
int status;
|
2969
|
-
|
2970
|
-
if (rb_block_given_p()) {
|
2971
|
-
result = gvl_PQexec(conn, "BEGIN");
|
2972
|
-
rb_pgresult = pg_new_result(result, self);
|
2973
|
-
pg_result_check(rb_pgresult);
|
2974
|
-
block_result = rb_protect(rb_yield, self, &status);
|
2975
|
-
if(status == 0) {
|
2976
|
-
result = gvl_PQexec(conn, "COMMIT");
|
2977
|
-
rb_pgresult = pg_new_result(result, self);
|
2978
|
-
pg_result_check(rb_pgresult);
|
2979
|
-
}
|
2980
|
-
else {
|
2981
|
-
/* exception occurred, ROLLBACK and re-raise */
|
2982
|
-
result = gvl_PQexec(conn, "ROLLBACK");
|
2983
|
-
rb_pgresult = pg_new_result(result, self);
|
2984
|
-
pg_result_check(rb_pgresult);
|
2985
|
-
rb_jump_tag(status);
|
2986
|
-
}
|
3510
|
+
int i;
|
3511
|
+
const char * const * p_list = PQsslAttributeNames(pg_get_pgconn(self));
|
3512
|
+
VALUE ary = rb_ary_new();
|
2987
3513
|
|
3514
|
+
for ( i = 0; p_list[i]; i++ ) {
|
3515
|
+
rb_ary_push( ary, rb_str_new_cstr( p_list[i] ));
|
2988
3516
|
}
|
2989
|
-
|
2990
|
-
/* no block supplied? */
|
2991
|
-
rb_raise(rb_eArgError, "Must supply block for PG::Connection#transaction");
|
2992
|
-
}
|
2993
|
-
return block_result;
|
3517
|
+
return ary;
|
2994
3518
|
}
|
2995
3519
|
|
2996
3520
|
|
3521
|
+
#endif
|
3522
|
+
|
3523
|
+
|
3524
|
+
#ifdef HAVE_PQENTERPIPELINEMODE
|
2997
3525
|
/*
|
2998
3526
|
* call-seq:
|
2999
|
-
*
|
3000
|
-
* PG::Connection.quote_ident( array ) -> String
|
3001
|
-
* conn.quote_ident( str ) -> String
|
3002
|
-
* conn.quote_ident( array ) -> String
|
3003
|
-
*
|
3004
|
-
* Returns a string that is safe for inclusion in a SQL query as an
|
3005
|
-
* identifier. Note: this is not a quote function for values, but for
|
3006
|
-
* identifiers.
|
3007
|
-
*
|
3008
|
-
* For example, in a typical SQL query: <tt>SELECT FOO FROM MYTABLE</tt>
|
3009
|
-
* The identifier <tt>FOO</tt> is folded to lower case, so it actually
|
3010
|
-
* means <tt>foo</tt>. If you really want to access the case-sensitive
|
3011
|
-
* field name <tt>FOO</tt>, use this function like
|
3012
|
-
* <tt>PG::Connection.quote_ident('FOO')</tt>, which will return <tt>"FOO"</tt>
|
3013
|
-
* (with double-quotes). PostgreSQL will see the double-quotes, and
|
3014
|
-
* it will not fold to lower case.
|
3527
|
+
* conn.pipeline_status -> Integer
|
3015
3528
|
*
|
3016
|
-
*
|
3017
|
-
* and other things that might allow SQL injection if the identifier
|
3018
|
-
* comes from an untrusted source.
|
3529
|
+
* Returns the current pipeline mode status of the libpq connection.
|
3019
3530
|
*
|
3020
|
-
*
|
3021
|
-
* and then joined by a "." character. This can be used for identifiers in
|
3022
|
-
* the form "schema"."table"."column" .
|
3531
|
+
* PQpipelineStatus can return one of the following values:
|
3023
3532
|
*
|
3024
|
-
*
|
3533
|
+
* * PQ_PIPELINE_ON - The libpq connection is in pipeline mode.
|
3534
|
+
* * PQ_PIPELINE_OFF - The libpq connection is not in pipeline mode.
|
3535
|
+
* * PQ_PIPELINE_ABORTED - The libpq connection is in pipeline mode and an error occurred while processing the current pipeline.
|
3536
|
+
* The aborted flag is cleared when PQgetResult returns a result of type PGRES_PIPELINE_SYNC.
|
3025
3537
|
*
|
3538
|
+
* Available since PostgreSQL-14
|
3026
3539
|
*/
|
3027
3540
|
static VALUE
|
3028
|
-
|
3541
|
+
pgconn_pipeline_status(VALUE self)
|
3029
3542
|
{
|
3030
|
-
|
3031
|
-
|
3032
|
-
|
3033
|
-
OBJ_INFECT(ret, in_str);
|
3034
|
-
PG_ENCODING_SET_NOCHECK(ret, ENCODING_GET( rb_obj_is_kind_of(self, rb_cPGconn) ? self : in_str ));
|
3035
|
-
|
3036
|
-
return ret;
|
3543
|
+
int res = PQpipelineStatus(pg_get_pgconn(self));
|
3544
|
+
return INT2FIX(res);
|
3037
3545
|
}
|
3038
3546
|
|
3039
3547
|
|
3040
|
-
|
3041
|
-
|
3548
|
+
/*
|
3549
|
+
* call-seq:
|
3550
|
+
* conn.enter_pipeline_mode -> nil
|
3551
|
+
*
|
3552
|
+
* Causes a connection to enter pipeline mode if it is currently idle or already in pipeline mode.
|
3553
|
+
*
|
3554
|
+
* 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.
|
3555
|
+
* This function does not actually send anything to the server, it just changes the libpq connection state.
|
3556
|
+
*
|
3557
|
+
* Available since PostgreSQL-14
|
3558
|
+
*/
|
3559
|
+
static VALUE
|
3560
|
+
pgconn_enter_pipeline_mode(VALUE self)
|
3042
3561
|
{
|
3043
|
-
|
3044
|
-
|
3562
|
+
PGconn *conn = pg_get_pgconn(self);
|
3563
|
+
int res = PQenterPipelineMode(conn);
|
3564
|
+
if( res != 1 )
|
3565
|
+
pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(conn));
|
3045
3566
|
|
3567
|
+
return Qnil;
|
3568
|
+
}
|
3046
3569
|
|
3047
3570
|
/*
|
3048
3571
|
* call-seq:
|
3049
|
-
* conn.
|
3572
|
+
* conn.exit_pipeline_mode -> nil
|
3050
3573
|
*
|
3051
|
-
*
|
3052
|
-
* optional _timeout_ is reached, whichever comes first.
|
3053
|
-
* _timeout_ is measured in seconds and can be fractional.
|
3574
|
+
* Causes a connection to exit pipeline mode if it is currently in pipeline mode with an empty queue and no pending results.
|
3054
3575
|
*
|
3055
|
-
*
|
3576
|
+
* Takes no action if not in pipeline mode.
|
3577
|
+
* 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.
|
3056
3578
|
*
|
3057
|
-
*
|
3058
|
-
* and +conn.get_result+ will not block.
|
3579
|
+
* Available since PostgreSQL-14
|
3059
3580
|
*/
|
3060
3581
|
static VALUE
|
3061
|
-
|
3062
|
-
|
3063
|
-
|
3064
|
-
|
3065
|
-
|
3066
|
-
|
3067
|
-
|
3068
|
-
struct timeval timeout;
|
3069
|
-
struct timeval *ptimeout = NULL;
|
3070
|
-
VALUE timeout_in;
|
3071
|
-
double timeout_sec;
|
3072
|
-
void *ret;
|
3073
|
-
|
3074
|
-
if ( rb_scan_args(argc, argv, "01", &timeout_in) == 1 ) {
|
3075
|
-
timeout_sec = NUM2DBL( timeout_in );
|
3076
|
-
timeout.tv_sec = (time_t)timeout_sec;
|
3077
|
-
timeout.tv_usec = (suseconds_t)((timeout_sec - (long)timeout_sec) * 1e6);
|
3078
|
-
ptimeout = &timeout;
|
3079
|
-
}
|
3080
|
-
|
3081
|
-
ret = wait_socket_readable( conn, ptimeout, get_result_readable);
|
3082
|
-
|
3083
|
-
if( !ret )
|
3084
|
-
return Qfalse;
|
3582
|
+
pgconn_exit_pipeline_mode(VALUE self)
|
3583
|
+
{
|
3584
|
+
PGconn *conn = pg_get_pgconn(self);
|
3585
|
+
int res = PQexitPipelineMode(conn);
|
3586
|
+
if( res != 1 )
|
3587
|
+
pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(conn));
|
3085
3588
|
|
3086
|
-
return
|
3589
|
+
return Qnil;
|
3087
3590
|
}
|
3088
3591
|
|
3089
3592
|
|
3090
3593
|
/*
|
3091
3594
|
* call-seq:
|
3092
|
-
* conn.
|
3595
|
+
* conn.pipeline_sync -> nil
|
3093
3596
|
*
|
3094
|
-
*
|
3095
|
-
*
|
3096
|
-
* asynchronous commands like +send_query()+) and
|
3097
|
-
* returns the last non-NULL result, or +nil+ if no
|
3098
|
-
* results are available.
|
3597
|
+
* Marks a synchronization point in a pipeline by sending a sync message and flushing the send buffer.
|
3598
|
+
* This serves as the delimiter of an implicit transaction and an error recovery point; see Section 34.5.1.3 of the PostgreSQL documentation.
|
3099
3599
|
*
|
3100
|
-
*
|
3101
|
-
*
|
3102
|
-
*
|
3600
|
+
* Raises PG::Error if the connection is not in pipeline mode or sending a sync message failed.
|
3601
|
+
*
|
3602
|
+
* Available since PostgreSQL-14
|
3103
3603
|
*/
|
3104
3604
|
static VALUE
|
3105
|
-
|
3605
|
+
pgconn_pipeline_sync(VALUE self)
|
3106
3606
|
{
|
3107
3607
|
PGconn *conn = pg_get_pgconn(self);
|
3108
|
-
|
3109
|
-
|
3110
|
-
|
3111
|
-
|
3112
|
-
cur = prev = NULL;
|
3113
|
-
while ((cur = gvl_PQgetResult(conn)) != NULL) {
|
3114
|
-
int status;
|
3115
|
-
|
3116
|
-
if (prev) PQclear(prev);
|
3117
|
-
prev = cur;
|
3118
|
-
|
3119
|
-
status = PQresultStatus(cur);
|
3120
|
-
if (status == PGRES_COPY_OUT || status == PGRES_COPY_IN)
|
3121
|
-
break;
|
3122
|
-
}
|
3123
|
-
|
3124
|
-
if (prev) {
|
3125
|
-
rb_pgresult = pg_new_result( prev, self );
|
3126
|
-
pg_result_check(rb_pgresult);
|
3127
|
-
}
|
3608
|
+
int res = PQpipelineSync(conn);
|
3609
|
+
if( res != 1 )
|
3610
|
+
pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(conn));
|
3128
3611
|
|
3129
|
-
return
|
3612
|
+
return Qnil;
|
3130
3613
|
}
|
3131
3614
|
|
3132
3615
|
/*
|
3133
3616
|
* call-seq:
|
3134
|
-
* conn.
|
3135
|
-
* conn.async_exec(sql [, params, result_format ] ) {|pg_result| block }
|
3617
|
+
* conn.pipeline_sync -> nil
|
3136
3618
|
*
|
3137
|
-
*
|
3138
|
-
*
|
3139
|
-
*
|
3619
|
+
* Sends a request for the server to flush its output buffer.
|
3620
|
+
*
|
3621
|
+
* 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.
|
3622
|
+
* This function is useful to cause the server to flush its output buffer in pipeline mode without establishing a synchronization point.
|
3623
|
+
* Note that the request is not itself flushed to the server automatically; use Connection#flush if necessary.
|
3624
|
+
*
|
3625
|
+
* Available since PostgreSQL-14
|
3140
3626
|
*/
|
3141
3627
|
static VALUE
|
3142
|
-
|
3628
|
+
pgconn_send_flush_request(VALUE self)
|
3143
3629
|
{
|
3144
|
-
|
3145
|
-
|
3146
|
-
|
3147
|
-
|
3148
|
-
pgconn_get_last_result( self );
|
3149
|
-
|
3150
|
-
pgconn_send_query( argc, argv, self );
|
3151
|
-
pgconn_block( 0, NULL, self );
|
3152
|
-
rb_pgresult = pgconn_get_last_result( self );
|
3630
|
+
PGconn *conn = pg_get_pgconn(self);
|
3631
|
+
int res = PQsendFlushRequest(conn);
|
3632
|
+
if( res != 1 )
|
3633
|
+
pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(conn));
|
3153
3634
|
|
3154
|
-
|
3155
|
-
return rb_ensure( rb_yield, rb_pgresult, pg_result_clear, rb_pgresult );
|
3156
|
-
}
|
3157
|
-
return rb_pgresult;
|
3635
|
+
return Qnil;
|
3158
3636
|
}
|
3159
3637
|
|
3638
|
+
#endif
|
3639
|
+
|
3160
3640
|
/**************************************************************************
|
3161
3641
|
* LARGE OBJECT SUPPORT
|
3162
3642
|
**************************************************************************/
|
3163
3643
|
|
3164
3644
|
/*
|
3165
3645
|
* call-seq:
|
3166
|
-
* conn.lo_creat( [mode] ) ->
|
3646
|
+
* conn.lo_creat( [mode] ) -> Integer
|
3167
3647
|
*
|
3168
3648
|
* Creates a large object with mode _mode_. Returns a large object Oid.
|
3169
3649
|
* On failure, it raises PG::Error.
|
@@ -3183,14 +3663,14 @@ pgconn_locreat(int argc, VALUE *argv, VALUE self)
|
|
3183
3663
|
|
3184
3664
|
lo_oid = lo_creat(conn, mode);
|
3185
3665
|
if (lo_oid == 0)
|
3186
|
-
|
3666
|
+
pg_raise_conn_error( rb_ePGerror, self, "lo_creat failed");
|
3187
3667
|
|
3188
3668
|
return UINT2NUM(lo_oid);
|
3189
3669
|
}
|
3190
3670
|
|
3191
3671
|
/*
|
3192
3672
|
* call-seq:
|
3193
|
-
* conn.lo_create( oid ) ->
|
3673
|
+
* conn.lo_create( oid ) -> Integer
|
3194
3674
|
*
|
3195
3675
|
* Creates a large object with oid _oid_. Returns the large object Oid.
|
3196
3676
|
* On failure, it raises PG::Error.
|
@@ -3204,14 +3684,14 @@ pgconn_locreate(VALUE self, VALUE in_lo_oid)
|
|
3204
3684
|
|
3205
3685
|
ret = lo_create(conn, lo_oid);
|
3206
3686
|
if (ret == InvalidOid)
|
3207
|
-
|
3687
|
+
pg_raise_conn_error( rb_ePGerror, self, "lo_create failed");
|
3208
3688
|
|
3209
3689
|
return UINT2NUM(ret);
|
3210
3690
|
}
|
3211
3691
|
|
3212
3692
|
/*
|
3213
3693
|
* call-seq:
|
3214
|
-
* conn.lo_import(file) ->
|
3694
|
+
* conn.lo_import(file) -> Integer
|
3215
3695
|
*
|
3216
3696
|
* Import a file to a large object. Returns a large object Oid.
|
3217
3697
|
*
|
@@ -3228,7 +3708,7 @@ pgconn_loimport(VALUE self, VALUE filename)
|
|
3228
3708
|
|
3229
3709
|
lo_oid = lo_import(conn, StringValueCStr(filename));
|
3230
3710
|
if (lo_oid == 0) {
|
3231
|
-
|
3711
|
+
pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(conn));
|
3232
3712
|
}
|
3233
3713
|
return UINT2NUM(lo_oid);
|
3234
3714
|
}
|
@@ -3249,14 +3729,14 @@ pgconn_loexport(VALUE self, VALUE lo_oid, VALUE filename)
|
|
3249
3729
|
oid = NUM2UINT(lo_oid);
|
3250
3730
|
|
3251
3731
|
if (lo_export(conn, oid, StringValueCStr(filename)) < 0) {
|
3252
|
-
|
3732
|
+
pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(conn));
|
3253
3733
|
}
|
3254
3734
|
return Qnil;
|
3255
3735
|
}
|
3256
3736
|
|
3257
3737
|
/*
|
3258
3738
|
* call-seq:
|
3259
|
-
* conn.lo_open( oid, [mode] ) ->
|
3739
|
+
* conn.lo_open( oid, [mode] ) -> Integer
|
3260
3740
|
*
|
3261
3741
|
* Open a large object of _oid_. Returns a large object descriptor
|
3262
3742
|
* instance on success. The _mode_ argument specifies the mode for
|
@@ -3280,14 +3760,14 @@ pgconn_loopen(int argc, VALUE *argv, VALUE self)
|
|
3280
3760
|
mode = NUM2INT(nmode);
|
3281
3761
|
|
3282
3762
|
if((fd = lo_open(conn, lo_oid, mode)) < 0) {
|
3283
|
-
|
3763
|
+
pg_raise_conn_error( rb_ePGerror, self, "can't open large object: %s", PQerrorMessage(conn));
|
3284
3764
|
}
|
3285
3765
|
return INT2FIX(fd);
|
3286
3766
|
}
|
3287
3767
|
|
3288
3768
|
/*
|
3289
3769
|
* call-seq:
|
3290
|
-
* conn.lo_write( lo_desc, buffer ) ->
|
3770
|
+
* conn.lo_write( lo_desc, buffer ) -> Integer
|
3291
3771
|
*
|
3292
3772
|
* Writes the string _buffer_ to the large object _lo_desc_.
|
3293
3773
|
* Returns the number of bytes written.
|
@@ -3302,11 +3782,11 @@ pgconn_lowrite(VALUE self, VALUE in_lo_desc, VALUE buffer)
|
|
3302
3782
|
Check_Type(buffer, T_STRING);
|
3303
3783
|
|
3304
3784
|
if( RSTRING_LEN(buffer) < 0) {
|
3305
|
-
|
3785
|
+
pg_raise_conn_error( rb_ePGerror, self, "write buffer zero string");
|
3306
3786
|
}
|
3307
3787
|
if((n = lo_write(conn, fd, StringValuePtr(buffer),
|
3308
3788
|
RSTRING_LEN(buffer))) < 0) {
|
3309
|
-
|
3789
|
+
pg_raise_conn_error( rb_ePGerror, self, "lo_write failed: %s", PQerrorMessage(conn));
|
3310
3790
|
}
|
3311
3791
|
|
3312
3792
|
return INT2FIX(n);
|
@@ -3329,23 +3809,19 @@ pgconn_loread(VALUE self, VALUE in_lo_desc, VALUE in_len)
|
|
3329
3809
|
VALUE str;
|
3330
3810
|
char *buffer;
|
3331
3811
|
|
3332
|
-
|
3333
|
-
|
3334
|
-
rb_raise(rb_eNoMemError, "ALLOC failed!");
|
3335
|
-
|
3336
|
-
if (len < 0){
|
3337
|
-
rb_raise(rb_ePGerror,"nagative length %d given", len);
|
3338
|
-
}
|
3812
|
+
if (len < 0)
|
3813
|
+
pg_raise_conn_error( rb_ePGerror, self, "negative length %d given", len);
|
3339
3814
|
|
3815
|
+
buffer = ALLOC_N(char, len);
|
3340
3816
|
if((ret = lo_read(conn, lo_desc, buffer, len)) < 0)
|
3341
|
-
|
3817
|
+
pg_raise_conn_error( rb_ePGerror, self, "lo_read failed");
|
3342
3818
|
|
3343
3819
|
if(ret == 0) {
|
3344
3820
|
xfree(buffer);
|
3345
3821
|
return Qnil;
|
3346
3822
|
}
|
3347
3823
|
|
3348
|
-
str =
|
3824
|
+
str = rb_str_new(buffer, ret);
|
3349
3825
|
xfree(buffer);
|
3350
3826
|
|
3351
3827
|
return str;
|
@@ -3354,7 +3830,7 @@ pgconn_loread(VALUE self, VALUE in_lo_desc, VALUE in_len)
|
|
3354
3830
|
|
3355
3831
|
/*
|
3356
3832
|
* call-seq:
|
3357
|
-
* conn.lo_lseek( lo_desc, offset, whence ) ->
|
3833
|
+
* conn.lo_lseek( lo_desc, offset, whence ) -> Integer
|
3358
3834
|
*
|
3359
3835
|
* Move the large object pointer _lo_desc_ to offset _offset_.
|
3360
3836
|
* Valid values for _whence_ are +SEEK_SET+, +SEEK_CUR+, and +SEEK_END+.
|
@@ -3368,7 +3844,7 @@ pgconn_lolseek(VALUE self, VALUE in_lo_desc, VALUE offset, VALUE whence)
|
|
3368
3844
|
int ret;
|
3369
3845
|
|
3370
3846
|
if((ret = lo_lseek(conn, lo_desc, NUM2INT(offset), NUM2INT(whence))) < 0) {
|
3371
|
-
|
3847
|
+
pg_raise_conn_error( rb_ePGerror, self, "lo_lseek failed");
|
3372
3848
|
}
|
3373
3849
|
|
3374
3850
|
return INT2FIX(ret);
|
@@ -3376,7 +3852,7 @@ pgconn_lolseek(VALUE self, VALUE in_lo_desc, VALUE offset, VALUE whence)
|
|
3376
3852
|
|
3377
3853
|
/*
|
3378
3854
|
* call-seq:
|
3379
|
-
* conn.lo_tell( lo_desc ) ->
|
3855
|
+
* conn.lo_tell( lo_desc ) -> Integer
|
3380
3856
|
*
|
3381
3857
|
* Returns the current position of the large object _lo_desc_.
|
3382
3858
|
*/
|
@@ -3388,7 +3864,7 @@ pgconn_lotell(VALUE self, VALUE in_lo_desc)
|
|
3388
3864
|
int lo_desc = NUM2INT(in_lo_desc);
|
3389
3865
|
|
3390
3866
|
if((position = lo_tell(conn, lo_desc)) < 0)
|
3391
|
-
|
3867
|
+
pg_raise_conn_error( rb_ePGerror, self, "lo_tell failed");
|
3392
3868
|
|
3393
3869
|
return INT2FIX(position);
|
3394
3870
|
}
|
@@ -3407,7 +3883,7 @@ pgconn_lotruncate(VALUE self, VALUE in_lo_desc, VALUE in_len)
|
|
3407
3883
|
size_t len = NUM2INT(in_len);
|
3408
3884
|
|
3409
3885
|
if(lo_truncate(conn,lo_desc,len) < 0)
|
3410
|
-
|
3886
|
+
pg_raise_conn_error( rb_ePGerror, self, "lo_truncate failed");
|
3411
3887
|
|
3412
3888
|
return Qnil;
|
3413
3889
|
}
|
@@ -3425,7 +3901,7 @@ pgconn_loclose(VALUE self, VALUE in_lo_desc)
|
|
3425
3901
|
int lo_desc = NUM2INT(in_lo_desc);
|
3426
3902
|
|
3427
3903
|
if(lo_close(conn,lo_desc) < 0)
|
3428
|
-
|
3904
|
+
pg_raise_conn_error( rb_ePGerror, self, "lo_close failed");
|
3429
3905
|
|
3430
3906
|
return Qnil;
|
3431
3907
|
}
|
@@ -3443,20 +3919,21 @@ pgconn_lounlink(VALUE self, VALUE in_oid)
|
|
3443
3919
|
Oid oid = NUM2UINT(in_oid);
|
3444
3920
|
|
3445
3921
|
if(lo_unlink(conn,oid) < 0)
|
3446
|
-
|
3922
|
+
pg_raise_conn_error( rb_ePGerror, self, "lo_unlink failed");
|
3447
3923
|
|
3448
3924
|
return Qnil;
|
3449
3925
|
}
|
3450
3926
|
|
3451
3927
|
|
3452
|
-
|
3453
|
-
|
3454
|
-
void
|
3928
|
+
static void
|
3455
3929
|
pgconn_set_internal_encoding_index( VALUE self )
|
3456
3930
|
{
|
3457
|
-
|
3458
|
-
|
3459
|
-
|
3931
|
+
int enc_idx;
|
3932
|
+
t_pg_connection *this = pg_get_connection_safe( self );
|
3933
|
+
rb_encoding *enc = pg_conn_enc_get( this->pgconn );
|
3934
|
+
enc_idx = rb_enc_to_index(enc);
|
3935
|
+
if( enc_idx >= (1<<(PG_ENC_IDX_BITS-1)) ) rb_raise(rb_eArgError, "unsupported encoding index %d", enc_idx);
|
3936
|
+
this->enc_idx = enc_idx;
|
3460
3937
|
}
|
3461
3938
|
|
3462
3939
|
/*
|
@@ -3499,20 +3976,19 @@ static VALUE pgconn_external_encoding(VALUE self);
|
|
3499
3976
|
static VALUE
|
3500
3977
|
pgconn_internal_encoding_set(VALUE self, VALUE enc)
|
3501
3978
|
{
|
3502
|
-
VALUE enc_inspect;
|
3503
3979
|
if (NIL_P(enc)) {
|
3504
|
-
|
3980
|
+
pgconn_sync_set_client_encoding( self, rb_usascii_str_new_cstr("SQL_ASCII") );
|
3505
3981
|
return enc;
|
3506
3982
|
}
|
3507
3983
|
else if ( TYPE(enc) == T_STRING && strcasecmp("JOHAB", StringValueCStr(enc)) == 0 ) {
|
3508
|
-
|
3984
|
+
pgconn_sync_set_client_encoding(self, rb_usascii_str_new_cstr("JOHAB"));
|
3509
3985
|
return enc;
|
3510
3986
|
}
|
3511
3987
|
else {
|
3512
3988
|
rb_encoding *rbenc = rb_to_encoding( enc );
|
3513
3989
|
const char *name = pg_get_rb_encoding_as_pg_encoding( rbenc );
|
3514
3990
|
|
3515
|
-
if (
|
3991
|
+
if ( gvl_PQsetClientEncoding(pg_get_pgconn( self ), name) == -1 ) {
|
3516
3992
|
VALUE server_encoding = pgconn_external_encoding( self );
|
3517
3993
|
rb_raise( rb_eEncCompatError, "incompatible character encodings: %s and %s",
|
3518
3994
|
rb_enc_name(rb_to_encoding(server_encoding)), name );
|
@@ -3520,11 +3996,6 @@ pgconn_internal_encoding_set(VALUE self, VALUE enc)
|
|
3520
3996
|
pgconn_set_internal_encoding_index( self );
|
3521
3997
|
return enc;
|
3522
3998
|
}
|
3523
|
-
|
3524
|
-
enc_inspect = rb_inspect(enc);
|
3525
|
-
rb_raise( rb_ePGerror, "unknown encoding: %s", StringValueCStr(enc_inspect) );
|
3526
|
-
|
3527
|
-
return Qnil;
|
3528
3999
|
}
|
3529
4000
|
|
3530
4001
|
|
@@ -3543,17 +4014,58 @@ pgconn_external_encoding(VALUE self)
|
|
3543
4014
|
rb_encoding *enc = NULL;
|
3544
4015
|
const char *pg_encname = NULL;
|
3545
4016
|
|
3546
|
-
/* Use cached value if found */
|
3547
|
-
if ( RTEST(this->external_encoding) ) return this->external_encoding;
|
3548
|
-
|
3549
4017
|
pg_encname = PQparameterStatus( this->pgconn, "server_encoding" );
|
3550
4018
|
enc = pg_get_pg_encname_as_rb_encoding( pg_encname );
|
3551
|
-
|
4019
|
+
return rb_enc_from_encoding( enc );
|
4020
|
+
}
|
4021
|
+
|
4022
|
+
/*
|
4023
|
+
* call-seq:
|
4024
|
+
* conn.set_client_encoding( encoding )
|
4025
|
+
*
|
4026
|
+
* Sets the client encoding to the _encoding_ String.
|
4027
|
+
*/
|
4028
|
+
static VALUE
|
4029
|
+
pgconn_async_set_client_encoding(VALUE self, VALUE encname)
|
4030
|
+
{
|
4031
|
+
VALUE query_format, query;
|
4032
|
+
|
4033
|
+
Check_Type(encname, T_STRING);
|
4034
|
+
query_format = rb_str_new_cstr("set client_encoding to '%s'");
|
4035
|
+
query = rb_funcall(query_format, rb_intern("%"), 1, encname);
|
4036
|
+
|
4037
|
+
pgconn_async_exec(1, &query, self);
|
4038
|
+
pgconn_set_internal_encoding_index( self );
|
4039
|
+
|
4040
|
+
return Qnil;
|
4041
|
+
}
|
4042
|
+
|
4043
|
+
static VALUE
|
4044
|
+
pgconn_set_client_encoding_async1( VALUE args )
|
4045
|
+
{
|
4046
|
+
VALUE self = ((VALUE*)args)[0];
|
4047
|
+
VALUE encname = ((VALUE*)args)[1];
|
4048
|
+
pgconn_async_set_client_encoding(self, encname);
|
4049
|
+
return 0;
|
4050
|
+
}
|
4051
|
+
|
3552
4052
|
|
3553
|
-
|
4053
|
+
static VALUE
|
4054
|
+
pgconn_set_client_encoding_async2( VALUE arg, VALUE ex )
|
4055
|
+
{
|
4056
|
+
UNUSED(arg);
|
4057
|
+
UNUSED(ex);
|
4058
|
+
return 1;
|
3554
4059
|
}
|
3555
4060
|
|
3556
4061
|
|
4062
|
+
static VALUE
|
4063
|
+
pgconn_set_client_encoding_async( VALUE self, VALUE encname )
|
4064
|
+
{
|
4065
|
+
VALUE args[] = { self, encname };
|
4066
|
+
return rb_rescue(pgconn_set_client_encoding_async1, (VALUE)&args, pgconn_set_client_encoding_async2, Qnil);
|
4067
|
+
}
|
4068
|
+
|
3557
4069
|
|
3558
4070
|
/*
|
3559
4071
|
* call-seq:
|
@@ -3572,10 +4084,9 @@ pgconn_set_default_encoding( VALUE self )
|
|
3572
4084
|
|
3573
4085
|
if (( enc = rb_default_internal_encoding() )) {
|
3574
4086
|
encname = pg_get_rb_encoding_as_pg_encoding( enc );
|
3575
|
-
if (
|
3576
|
-
|
4087
|
+
if ( pgconn_set_client_encoding_async(self, rb_str_new_cstr(encname)) != 0 )
|
4088
|
+
rb_warning( "Failed to set the default_internal encoding to %s: '%s'",
|
3577
4089
|
encname, PQerrorMessage(conn) );
|
3578
|
-
pgconn_set_internal_encoding_index( self );
|
3579
4090
|
return rb_enc_from_encoding( enc );
|
3580
4091
|
} else {
|
3581
4092
|
pgconn_set_internal_encoding_index( self );
|
@@ -3584,8 +4095,6 @@ pgconn_set_default_encoding( VALUE self )
|
|
3584
4095
|
}
|
3585
4096
|
|
3586
4097
|
|
3587
|
-
#endif /* M17N_SUPPORTED */
|
3588
|
-
|
3589
4098
|
/*
|
3590
4099
|
* call-seq:
|
3591
4100
|
* res.type_map_for_queries = typemap
|
@@ -3599,12 +4108,12 @@ static VALUE
|
|
3599
4108
|
pgconn_type_map_for_queries_set(VALUE self, VALUE typemap)
|
3600
4109
|
{
|
3601
4110
|
t_pg_connection *this = pg_get_connection( self );
|
4111
|
+
t_typemap *tm;
|
4112
|
+
UNUSED(tm);
|
4113
|
+
|
4114
|
+
/* Check type of method param */
|
4115
|
+
TypedData_Get_Struct(typemap, t_typemap, &pg_typemap_type, tm);
|
3602
4116
|
|
3603
|
-
if ( !rb_obj_is_kind_of(typemap, rb_cTypeMap) ) {
|
3604
|
-
rb_raise( rb_eTypeError, "wrong argument type %s (expected kind of PG::TypeMap)",
|
3605
|
-
rb_obj_classname( typemap ) );
|
3606
|
-
}
|
3607
|
-
Check_Type(typemap, T_DATA);
|
3608
4117
|
this->type_map_for_queries = typemap;
|
3609
4118
|
|
3610
4119
|
return typemap;
|
@@ -3639,12 +4148,10 @@ static VALUE
|
|
3639
4148
|
pgconn_type_map_for_results_set(VALUE self, VALUE typemap)
|
3640
4149
|
{
|
3641
4150
|
t_pg_connection *this = pg_get_connection( self );
|
4151
|
+
t_typemap *tm;
|
4152
|
+
UNUSED(tm);
|
3642
4153
|
|
3643
|
-
|
3644
|
-
rb_raise( rb_eTypeError, "wrong argument type %s (expected kind of PG::TypeMap)",
|
3645
|
-
rb_obj_classname( typemap ) );
|
3646
|
-
}
|
3647
|
-
Check_Type(typemap, T_DATA);
|
4154
|
+
TypedData_Get_Struct(typemap, t_typemap, &pg_typemap_type, tm);
|
3648
4155
|
this->type_map_for_results = typemap;
|
3649
4156
|
|
3650
4157
|
return typemap;
|
@@ -3679,20 +4186,19 @@ pgconn_type_map_for_results_get(VALUE self)
|
|
3679
4186
|
*
|
3680
4187
|
*/
|
3681
4188
|
static VALUE
|
3682
|
-
pgconn_encoder_for_put_copy_data_set(VALUE self, VALUE
|
4189
|
+
pgconn_encoder_for_put_copy_data_set(VALUE self, VALUE encoder)
|
3683
4190
|
{
|
3684
4191
|
t_pg_connection *this = pg_get_connection( self );
|
3685
4192
|
|
3686
|
-
if(
|
3687
|
-
|
3688
|
-
|
3689
|
-
|
3690
|
-
|
3691
|
-
Check_Type(typemap, T_DATA);
|
4193
|
+
if( encoder != Qnil ){
|
4194
|
+
t_pg_coder *co;
|
4195
|
+
UNUSED(co);
|
4196
|
+
/* Check argument type */
|
4197
|
+
TypedData_Get_Struct(encoder, t_pg_coder, &pg_coder_type, co);
|
3692
4198
|
}
|
3693
|
-
this->encoder_for_put_copy_data =
|
4199
|
+
this->encoder_for_put_copy_data = encoder;
|
3694
4200
|
|
3695
|
-
return
|
4201
|
+
return encoder;
|
3696
4202
|
}
|
3697
4203
|
|
3698
4204
|
/*
|
@@ -3704,7 +4210,7 @@ pgconn_encoder_for_put_copy_data_set(VALUE self, VALUE typemap)
|
|
3704
4210
|
*
|
3705
4211
|
* Returns either:
|
3706
4212
|
* * a kind of PG::Coder
|
3707
|
-
* * +nil+ - type encoding is disabled,
|
4213
|
+
* * +nil+ - type encoding is disabled, data must be a String.
|
3708
4214
|
*
|
3709
4215
|
*/
|
3710
4216
|
static VALUE
|
@@ -3728,20 +4234,19 @@ pgconn_encoder_for_put_copy_data_get(VALUE self)
|
|
3728
4234
|
*
|
3729
4235
|
*/
|
3730
4236
|
static VALUE
|
3731
|
-
pgconn_decoder_for_get_copy_data_set(VALUE self, VALUE
|
4237
|
+
pgconn_decoder_for_get_copy_data_set(VALUE self, VALUE decoder)
|
3732
4238
|
{
|
3733
4239
|
t_pg_connection *this = pg_get_connection( self );
|
3734
4240
|
|
3735
|
-
if(
|
3736
|
-
|
3737
|
-
|
3738
|
-
|
3739
|
-
|
3740
|
-
Check_Type(typemap, T_DATA);
|
4241
|
+
if( decoder != Qnil ){
|
4242
|
+
t_pg_coder *co;
|
4243
|
+
UNUSED(co);
|
4244
|
+
/* Check argument type */
|
4245
|
+
TypedData_Get_Struct(decoder, t_pg_coder, &pg_coder_type, co);
|
3741
4246
|
}
|
3742
|
-
this->decoder_for_get_copy_data =
|
4247
|
+
this->decoder_for_get_copy_data = decoder;
|
3743
4248
|
|
3744
|
-
return
|
4249
|
+
return decoder;
|
3745
4250
|
}
|
3746
4251
|
|
3747
4252
|
/*
|
@@ -3764,25 +4269,82 @@ pgconn_decoder_for_get_copy_data_get(VALUE self)
|
|
3764
4269
|
return this->decoder_for_get_copy_data;
|
3765
4270
|
}
|
3766
4271
|
|
4272
|
+
/*
|
4273
|
+
* call-seq:
|
4274
|
+
* conn.field_name_type = Symbol
|
4275
|
+
*
|
4276
|
+
* Set default type of field names of results retrieved by this connection.
|
4277
|
+
* It can be set to one of:
|
4278
|
+
* * +:string+ to use String based field names
|
4279
|
+
* * +:symbol+ to use Symbol based field names
|
4280
|
+
*
|
4281
|
+
* The default is +:string+ .
|
4282
|
+
*
|
4283
|
+
* Settings the type of field names affects only future results.
|
4284
|
+
*
|
4285
|
+
* See further description at PG::Result#field_name_type=
|
4286
|
+
*
|
4287
|
+
*/
|
4288
|
+
static VALUE
|
4289
|
+
pgconn_field_name_type_set(VALUE self, VALUE sym)
|
4290
|
+
{
|
4291
|
+
t_pg_connection *this = pg_get_connection( self );
|
4292
|
+
|
4293
|
+
this->flags &= ~PG_RESULT_FIELD_NAMES_MASK;
|
4294
|
+
if( sym == sym_symbol ) this->flags |= PG_RESULT_FIELD_NAMES_SYMBOL;
|
4295
|
+
else if ( sym == sym_static_symbol ) this->flags |= PG_RESULT_FIELD_NAMES_STATIC_SYMBOL;
|
4296
|
+
else if ( sym == sym_string );
|
4297
|
+
else rb_raise(rb_eArgError, "invalid argument %+"PRIsVALUE, sym);
|
4298
|
+
|
4299
|
+
return sym;
|
4300
|
+
}
|
4301
|
+
|
4302
|
+
/*
|
4303
|
+
* call-seq:
|
4304
|
+
* conn.field_name_type -> Symbol
|
4305
|
+
*
|
4306
|
+
* Get type of field names.
|
4307
|
+
*
|
4308
|
+
* See description at #field_name_type=
|
4309
|
+
*/
|
4310
|
+
static VALUE
|
4311
|
+
pgconn_field_name_type_get(VALUE self)
|
4312
|
+
{
|
4313
|
+
t_pg_connection *this = pg_get_connection( self );
|
4314
|
+
|
4315
|
+
if( this->flags & PG_RESULT_FIELD_NAMES_SYMBOL ){
|
4316
|
+
return sym_symbol;
|
4317
|
+
} else if( this->flags & PG_RESULT_FIELD_NAMES_STATIC_SYMBOL ){
|
4318
|
+
return sym_static_symbol;
|
4319
|
+
} else {
|
4320
|
+
return sym_string;
|
4321
|
+
}
|
4322
|
+
}
|
4323
|
+
|
3767
4324
|
|
4325
|
+
/*
|
4326
|
+
* Document-class: PG::Connection
|
4327
|
+
*/
|
3768
4328
|
void
|
3769
4329
|
init_pg_connection()
|
3770
4330
|
{
|
3771
4331
|
s_id_encode = rb_intern("encode");
|
4332
|
+
s_id_autoclose_set = rb_intern("autoclose=");
|
3772
4333
|
sym_type = ID2SYM(rb_intern("type"));
|
3773
4334
|
sym_format = ID2SYM(rb_intern("format"));
|
3774
4335
|
sym_value = ID2SYM(rb_intern("value"));
|
4336
|
+
sym_string = ID2SYM(rb_intern("string"));
|
4337
|
+
sym_symbol = ID2SYM(rb_intern("symbol"));
|
4338
|
+
sym_static_symbol = ID2SYM(rb_intern("static_symbol"));
|
3775
4339
|
|
3776
4340
|
rb_cPGconn = rb_define_class_under( rb_mPG, "Connection", rb_cObject );
|
4341
|
+
/* Help rdoc to known the Constants module */
|
4342
|
+
/* rb_mPGconstants = rb_define_module_under( rb_mPG, "Constants" ); */
|
3777
4343
|
rb_include_module(rb_cPGconn, rb_mPGconstants);
|
3778
4344
|
|
3779
4345
|
/****** PG::Connection CLASS METHODS ******/
|
3780
4346
|
rb_define_alloc_func( rb_cPGconn, pgconn_s_allocate );
|
3781
4347
|
|
3782
|
-
SINGLETON_ALIAS(rb_cPGconn, "connect", "new");
|
3783
|
-
SINGLETON_ALIAS(rb_cPGconn, "open", "new");
|
3784
|
-
SINGLETON_ALIAS(rb_cPGconn, "setdb", "new");
|
3785
|
-
SINGLETON_ALIAS(rb_cPGconn, "setdblogin", "new");
|
3786
4348
|
rb_define_singleton_method(rb_cPGconn, "escape_string", pgconn_s_escape, 1);
|
3787
4349
|
SINGLETON_ALIAS(rb_cPGconn, "escape", "escape_string");
|
3788
4350
|
rb_define_singleton_method(rb_cPGconn, "escape_bytea", pgconn_s_escape_bytea, 1);
|
@@ -3791,16 +4353,15 @@ init_pg_connection()
|
|
3791
4353
|
rb_define_singleton_method(rb_cPGconn, "quote_ident", pgconn_s_quote_ident, 1);
|
3792
4354
|
rb_define_singleton_method(rb_cPGconn, "connect_start", pgconn_s_connect_start, -1);
|
3793
4355
|
rb_define_singleton_method(rb_cPGconn, "conndefaults", pgconn_s_conndefaults, 0);
|
3794
|
-
|
3795
|
-
rb_define_singleton_method(rb_cPGconn, "
|
3796
|
-
|
4356
|
+
rb_define_singleton_method(rb_cPGconn, "conninfo_parse", pgconn_s_conninfo_parse, 1);
|
4357
|
+
rb_define_singleton_method(rb_cPGconn, "sync_ping", pgconn_s_sync_ping, -1);
|
4358
|
+
rb_define_singleton_method(rb_cPGconn, "sync_connect", pgconn_s_sync_connect, -1);
|
3797
4359
|
|
3798
4360
|
/****** PG::Connection INSTANCE METHODS: Connection Control ******/
|
3799
|
-
rb_define_method(rb_cPGconn, "initialize", pgconn_init, -1);
|
3800
4361
|
rb_define_method(rb_cPGconn, "connect_poll", pgconn_connect_poll, 0);
|
3801
4362
|
rb_define_method(rb_cPGconn, "finish", pgconn_finish, 0);
|
3802
4363
|
rb_define_method(rb_cPGconn, "finished?", pgconn_finished_p, 0);
|
3803
|
-
rb_define_method(rb_cPGconn, "
|
4364
|
+
rb_define_method(rb_cPGconn, "sync_reset", pgconn_sync_reset, 0);
|
3804
4365
|
rb_define_method(rb_cPGconn, "reset_start", pgconn_reset_start, 0);
|
3805
4366
|
rb_define_method(rb_cPGconn, "reset_poll", pgconn_reset_poll, 0);
|
3806
4367
|
rb_define_alias(rb_cPGconn, "close", "finish");
|
@@ -3810,11 +4371,12 @@ init_pg_connection()
|
|
3810
4371
|
rb_define_method(rb_cPGconn, "user", pgconn_user, 0);
|
3811
4372
|
rb_define_method(rb_cPGconn, "pass", pgconn_pass, 0);
|
3812
4373
|
rb_define_method(rb_cPGconn, "host", pgconn_host, 0);
|
4374
|
+
#if defined(HAVE_PQRESULTMEMORYSIZE)
|
4375
|
+
rb_define_method(rb_cPGconn, "hostaddr", pgconn_hostaddr, 0);
|
4376
|
+
#endif
|
3813
4377
|
rb_define_method(rb_cPGconn, "port", pgconn_port, 0);
|
3814
4378
|
rb_define_method(rb_cPGconn, "tty", pgconn_tty, 0);
|
3815
|
-
#ifdef HAVE_PQCONNINFO
|
3816
4379
|
rb_define_method(rb_cPGconn, "conninfo", pgconn_conninfo, 0);
|
3817
|
-
#endif
|
3818
4380
|
rb_define_method(rb_cPGconn, "options", pgconn_options, 0);
|
3819
4381
|
rb_define_method(rb_cPGconn, "status", pgconn_status, 0);
|
3820
4382
|
rb_define_method(rb_cPGconn, "transaction_status", pgconn_transaction_status, 0);
|
@@ -3823,64 +4385,78 @@ init_pg_connection()
|
|
3823
4385
|
rb_define_method(rb_cPGconn, "server_version", pgconn_server_version, 0);
|
3824
4386
|
rb_define_method(rb_cPGconn, "error_message", pgconn_error_message, 0);
|
3825
4387
|
rb_define_method(rb_cPGconn, "socket", pgconn_socket, 0);
|
3826
|
-
#if !defined(_WIN32) || defined(HAVE_RB_W32_WRAP_IO_HANDLE)
|
3827
4388
|
rb_define_method(rb_cPGconn, "socket_io", pgconn_socket_io, 0);
|
3828
|
-
#endif
|
3829
4389
|
rb_define_method(rb_cPGconn, "backend_pid", pgconn_backend_pid, 0);
|
4390
|
+
rb_define_method(rb_cPGconn, "backend_key", pgconn_backend_key, 0);
|
3830
4391
|
rb_define_method(rb_cPGconn, "connection_needs_password", pgconn_connection_needs_password, 0);
|
3831
4392
|
rb_define_method(rb_cPGconn, "connection_used_password", pgconn_connection_used_password, 0);
|
3832
4393
|
/* rb_define_method(rb_cPGconn, "getssl", pgconn_getssl, 0); */
|
3833
4394
|
|
3834
4395
|
/****** PG::Connection INSTANCE METHODS: Command Execution ******/
|
3835
|
-
rb_define_method(rb_cPGconn, "
|
3836
|
-
|
3837
|
-
rb_define_method(rb_cPGconn, "
|
3838
|
-
rb_define_method(rb_cPGconn, "
|
3839
|
-
rb_define_method(rb_cPGconn, "
|
3840
|
-
rb_define_method(rb_cPGconn, "
|
3841
|
-
|
4396
|
+
rb_define_method(rb_cPGconn, "sync_exec", pgconn_sync_exec, -1);
|
4397
|
+
rb_define_method(rb_cPGconn, "sync_exec_params", pgconn_sync_exec_params, -1);
|
4398
|
+
rb_define_method(rb_cPGconn, "sync_prepare", pgconn_sync_prepare, -1);
|
4399
|
+
rb_define_method(rb_cPGconn, "sync_exec_prepared", pgconn_sync_exec_prepared, -1);
|
4400
|
+
rb_define_method(rb_cPGconn, "sync_describe_prepared", pgconn_sync_describe_prepared, 1);
|
4401
|
+
rb_define_method(rb_cPGconn, "sync_describe_portal", pgconn_sync_describe_portal, 1);
|
4402
|
+
|
4403
|
+
rb_define_method(rb_cPGconn, "exec", pgconn_async_exec, -1);
|
4404
|
+
rb_define_method(rb_cPGconn, "exec_params", pgconn_async_exec_params, -1);
|
4405
|
+
rb_define_method(rb_cPGconn, "prepare", pgconn_async_prepare, -1);
|
4406
|
+
rb_define_method(rb_cPGconn, "exec_prepared", pgconn_async_exec_prepared, -1);
|
4407
|
+
rb_define_method(rb_cPGconn, "describe_prepared", pgconn_async_describe_prepared, 1);
|
4408
|
+
rb_define_method(rb_cPGconn, "describe_portal", pgconn_async_describe_portal, 1);
|
4409
|
+
|
4410
|
+
rb_define_alias(rb_cPGconn, "async_exec", "exec");
|
4411
|
+
rb_define_alias(rb_cPGconn, "async_query", "async_exec");
|
4412
|
+
rb_define_alias(rb_cPGconn, "async_exec_params", "exec_params");
|
4413
|
+
rb_define_alias(rb_cPGconn, "async_prepare", "prepare");
|
4414
|
+
rb_define_alias(rb_cPGconn, "async_exec_prepared", "exec_prepared");
|
4415
|
+
rb_define_alias(rb_cPGconn, "async_describe_prepared", "describe_prepared");
|
4416
|
+
rb_define_alias(rb_cPGconn, "async_describe_portal", "describe_portal");
|
4417
|
+
|
3842
4418
|
rb_define_method(rb_cPGconn, "make_empty_pgresult", pgconn_make_empty_pgresult, 1);
|
3843
4419
|
rb_define_method(rb_cPGconn, "escape_string", pgconn_s_escape, 1);
|
3844
4420
|
rb_define_alias(rb_cPGconn, "escape", "escape_string");
|
3845
|
-
#ifdef HAVE_PQESCAPELITERAL
|
3846
4421
|
rb_define_method(rb_cPGconn, "escape_literal", pgconn_escape_literal, 1);
|
3847
|
-
#endif
|
3848
|
-
#ifdef HAVE_PQESCAPEIDENTIFIER
|
3849
4422
|
rb_define_method(rb_cPGconn, "escape_identifier", pgconn_escape_identifier, 1);
|
3850
|
-
#endif
|
3851
4423
|
rb_define_method(rb_cPGconn, "escape_bytea", pgconn_s_escape_bytea, 1);
|
3852
4424
|
rb_define_method(rb_cPGconn, "unescape_bytea", pgconn_s_unescape_bytea, 1);
|
3853
|
-
#ifdef HAVE_PQSETSINGLEROWMODE
|
3854
4425
|
rb_define_method(rb_cPGconn, "set_single_row_mode", pgconn_set_single_row_mode, 0);
|
3855
|
-
#endif
|
3856
4426
|
|
3857
4427
|
/****** PG::Connection INSTANCE METHODS: Asynchronous Command Processing ******/
|
3858
4428
|
rb_define_method(rb_cPGconn, "send_query", pgconn_send_query, -1);
|
4429
|
+
rb_define_method(rb_cPGconn, "send_query_params", pgconn_send_query_params, -1);
|
3859
4430
|
rb_define_method(rb_cPGconn, "send_prepare", pgconn_send_prepare, -1);
|
3860
4431
|
rb_define_method(rb_cPGconn, "send_query_prepared", pgconn_send_query_prepared, -1);
|
3861
4432
|
rb_define_method(rb_cPGconn, "send_describe_prepared", pgconn_send_describe_prepared, 1);
|
3862
4433
|
rb_define_method(rb_cPGconn, "send_describe_portal", pgconn_send_describe_portal, 1);
|
3863
|
-
rb_define_method(rb_cPGconn, "
|
4434
|
+
rb_define_method(rb_cPGconn, "sync_get_result", pgconn_sync_get_result, 0);
|
3864
4435
|
rb_define_method(rb_cPGconn, "consume_input", pgconn_consume_input, 0);
|
3865
4436
|
rb_define_method(rb_cPGconn, "is_busy", pgconn_is_busy, 0);
|
3866
|
-
rb_define_method(rb_cPGconn, "
|
3867
|
-
rb_define_method(rb_cPGconn, "
|
3868
|
-
|
3869
|
-
rb_define_method(rb_cPGconn, "flush",
|
4437
|
+
rb_define_method(rb_cPGconn, "sync_setnonblocking", pgconn_sync_setnonblocking, 1);
|
4438
|
+
rb_define_method(rb_cPGconn, "sync_isnonblocking", pgconn_sync_isnonblocking, 0);
|
4439
|
+
rb_define_method(rb_cPGconn, "sync_flush", pgconn_sync_flush, 0);
|
4440
|
+
rb_define_method(rb_cPGconn, "flush", pgconn_async_flush, 0);
|
4441
|
+
rb_define_alias(rb_cPGconn, "async_flush", "flush");
|
4442
|
+
rb_define_method(rb_cPGconn, "discard_results", pgconn_discard_results, 0);
|
3870
4443
|
|
3871
4444
|
/****** PG::Connection INSTANCE METHODS: Cancelling Queries in Progress ******/
|
3872
|
-
rb_define_method(rb_cPGconn, "
|
4445
|
+
rb_define_method(rb_cPGconn, "sync_cancel", pgconn_sync_cancel, 0);
|
3873
4446
|
|
3874
4447
|
/****** PG::Connection INSTANCE METHODS: NOTIFY ******/
|
3875
4448
|
rb_define_method(rb_cPGconn, "notifies", pgconn_notifies, 0);
|
3876
4449
|
|
3877
4450
|
/****** PG::Connection INSTANCE METHODS: COPY ******/
|
3878
|
-
rb_define_method(rb_cPGconn, "
|
3879
|
-
rb_define_method(rb_cPGconn, "
|
3880
|
-
rb_define_method(rb_cPGconn, "
|
4451
|
+
rb_define_method(rb_cPGconn, "sync_put_copy_data", pgconn_sync_put_copy_data, -1);
|
4452
|
+
rb_define_method(rb_cPGconn, "sync_put_copy_end", pgconn_sync_put_copy_end, -1);
|
4453
|
+
rb_define_method(rb_cPGconn, "sync_get_copy_data", pgconn_sync_get_copy_data, -1);
|
3881
4454
|
|
3882
4455
|
/****** PG::Connection INSTANCE METHODS: Control Functions ******/
|
3883
4456
|
rb_define_method(rb_cPGconn, "set_error_verbosity", pgconn_set_error_verbosity, 1);
|
4457
|
+
#ifdef HAVE_PQRESULTVERBOSEERRORMESSAGE
|
4458
|
+
rb_define_method(rb_cPGconn, "set_error_context_visibility", pgconn_set_error_context_visibility, 1 );
|
4459
|
+
#endif
|
3884
4460
|
rb_define_method(rb_cPGconn, "trace", pgconn_trace, 1);
|
3885
4461
|
rb_define_method(rb_cPGconn, "untrace", pgconn_untrace, 0);
|
3886
4462
|
|
@@ -3890,16 +4466,35 @@ init_pg_connection()
|
|
3890
4466
|
|
3891
4467
|
/****** PG::Connection INSTANCE METHODS: Other ******/
|
3892
4468
|
rb_define_method(rb_cPGconn, "get_client_encoding", pgconn_get_client_encoding, 0);
|
3893
|
-
rb_define_method(rb_cPGconn, "
|
4469
|
+
rb_define_method(rb_cPGconn, "sync_set_client_encoding", pgconn_sync_set_client_encoding, 1);
|
4470
|
+
rb_define_method(rb_cPGconn, "set_client_encoding", pgconn_async_set_client_encoding, 1);
|
4471
|
+
rb_define_alias(rb_cPGconn, "async_set_client_encoding", "set_client_encoding");
|
3894
4472
|
rb_define_alias(rb_cPGconn, "client_encoding=", "set_client_encoding");
|
3895
|
-
rb_define_method(rb_cPGconn, "transaction", pgconn_transaction, 0);
|
3896
4473
|
rb_define_method(rb_cPGconn, "block", pgconn_block, -1);
|
4474
|
+
rb_define_private_method(rb_cPGconn, "flush_data=", pgconn_flush_data_set, 1);
|
3897
4475
|
rb_define_method(rb_cPGconn, "wait_for_notify", pgconn_wait_for_notify, -1);
|
3898
4476
|
rb_define_alias(rb_cPGconn, "notifies_wait", "wait_for_notify");
|
3899
4477
|
rb_define_method(rb_cPGconn, "quote_ident", pgconn_s_quote_ident, 1);
|
3900
|
-
rb_define_method(rb_cPGconn, "
|
3901
|
-
|
3902
|
-
|
4478
|
+
rb_define_method(rb_cPGconn, "sync_get_last_result", pgconn_sync_get_last_result, 0);
|
4479
|
+
rb_define_method(rb_cPGconn, "get_last_result", pgconn_async_get_last_result, 0);
|
4480
|
+
rb_define_alias(rb_cPGconn, "async_get_last_result", "get_last_result");
|
4481
|
+
#ifdef HAVE_PQENCRYPTPASSWORDCONN
|
4482
|
+
rb_define_method(rb_cPGconn, "sync_encrypt_password", pgconn_sync_encrypt_password, -1);
|
4483
|
+
#endif
|
4484
|
+
|
4485
|
+
#ifdef HAVE_PQSSLATTRIBUTE
|
4486
|
+
rb_define_method(rb_cPGconn, "ssl_in_use?", pgconn_ssl_in_use, 0);
|
4487
|
+
rb_define_method(rb_cPGconn, "ssl_attribute", pgconn_ssl_attribute, 1);
|
4488
|
+
rb_define_method(rb_cPGconn, "ssl_attribute_names", pgconn_ssl_attribute_names, 0);
|
4489
|
+
#endif
|
4490
|
+
|
4491
|
+
#ifdef HAVE_PQENTERPIPELINEMODE
|
4492
|
+
rb_define_method(rb_cPGconn, "pipeline_status", pgconn_pipeline_status, 0);
|
4493
|
+
rb_define_method(rb_cPGconn, "enter_pipeline_mode", pgconn_enter_pipeline_mode, 0);
|
4494
|
+
rb_define_method(rb_cPGconn, "exit_pipeline_mode", pgconn_exit_pipeline_mode, 0);
|
4495
|
+
rb_define_method(rb_cPGconn, "pipeline_sync", pgconn_pipeline_sync, 0);
|
4496
|
+
rb_define_method(rb_cPGconn, "send_flush_request", pgconn_send_flush_request, 0);
|
4497
|
+
#endif
|
3903
4498
|
|
3904
4499
|
/****** PG::Connection INSTANCE METHODS: Large Object Support ******/
|
3905
4500
|
rb_define_method(rb_cPGconn, "lo_creat", pgconn_locreat, -1);
|
@@ -3929,12 +4524,10 @@ init_pg_connection()
|
|
3929
4524
|
rb_define_method(rb_cPGconn, "lo_unlink", pgconn_lounlink, 1);
|
3930
4525
|
rb_define_alias(rb_cPGconn, "lounlink", "lo_unlink");
|
3931
4526
|
|
3932
|
-
#ifdef M17N_SUPPORTED
|
3933
4527
|
rb_define_method(rb_cPGconn, "internal_encoding", pgconn_internal_encoding, 0);
|
3934
4528
|
rb_define_method(rb_cPGconn, "internal_encoding=", pgconn_internal_encoding_set, 1);
|
3935
4529
|
rb_define_method(rb_cPGconn, "external_encoding", pgconn_external_encoding, 0);
|
3936
4530
|
rb_define_method(rb_cPGconn, "set_default_encoding", pgconn_set_default_encoding, 0);
|
3937
|
-
#endif /* M17N_SUPPORTED */
|
3938
4531
|
|
3939
4532
|
rb_define_method(rb_cPGconn, "type_map_for_queries=", pgconn_type_map_for_queries_set, 1);
|
3940
4533
|
rb_define_method(rb_cPGconn, "type_map_for_queries", pgconn_type_map_for_queries_get, 0);
|
@@ -3944,5 +4537,7 @@ init_pg_connection()
|
|
3944
4537
|
rb_define_method(rb_cPGconn, "encoder_for_put_copy_data", pgconn_encoder_for_put_copy_data_get, 0);
|
3945
4538
|
rb_define_method(rb_cPGconn, "decoder_for_get_copy_data=", pgconn_decoder_for_get_copy_data_set, 1);
|
3946
4539
|
rb_define_method(rb_cPGconn, "decoder_for_get_copy_data", pgconn_decoder_for_get_copy_data_get, 0);
|
3947
|
-
}
|
3948
4540
|
|
4541
|
+
rb_define_method(rb_cPGconn, "field_name_type=", pgconn_field_name_type_set, 1 );
|
4542
|
+
rb_define_method(rb_cPGconn, "field_name_type", pgconn_field_name_type_get, 0 );
|
4543
|
+
}
|