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