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