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