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