pg 0.17.1 → 1.2.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- checksums.yaml.gz.sig +0 -0
- data/BSDL +2 -2
- data/ChangeLog +0 -3506
- data/History.rdoc +308 -0
- data/Manifest.txt +35 -19
- data/README-Windows.rdoc +17 -28
- data/README.ja.rdoc +1 -2
- data/README.rdoc +113 -14
- data/Rakefile +67 -30
- data/Rakefile.cross +109 -83
- data/ext/errorcodes.def +101 -0
- data/ext/errorcodes.rb +1 -1
- data/ext/errorcodes.txt +33 -2
- data/ext/extconf.rb +55 -58
- data/ext/gvl_wrappers.c +4 -0
- data/ext/gvl_wrappers.h +27 -39
- data/ext/pg.c +262 -130
- data/ext/pg.h +266 -54
- data/ext/pg_binary_decoder.c +229 -0
- data/ext/pg_binary_encoder.c +163 -0
- data/ext/pg_coder.c +561 -0
- data/ext/pg_connection.c +1689 -990
- data/ext/pg_copy_coder.c +599 -0
- data/ext/pg_errors.c +6 -0
- data/ext/pg_record_coder.c +491 -0
- data/ext/pg_result.c +897 -164
- data/ext/pg_text_decoder.c +987 -0
- data/ext/pg_text_encoder.c +814 -0
- data/ext/pg_tuple.c +549 -0
- data/ext/pg_type_map.c +166 -0
- data/ext/pg_type_map_all_strings.c +116 -0
- data/ext/pg_type_map_by_class.c +244 -0
- data/ext/pg_type_map_by_column.c +313 -0
- data/ext/pg_type_map_by_mri_type.c +284 -0
- data/ext/pg_type_map_by_oid.c +356 -0
- data/ext/pg_type_map_in_ruby.c +299 -0
- data/ext/pg_util.c +149 -0
- data/ext/pg_util.h +65 -0
- data/lib/pg/basic_type_mapping.rb +522 -0
- data/lib/pg/binary_decoder.rb +23 -0
- data/lib/pg/coder.rb +104 -0
- data/lib/pg/connection.rb +153 -41
- data/lib/pg/constants.rb +2 -1
- data/lib/pg/exceptions.rb +2 -1
- data/lib/pg/result.rb +33 -6
- data/lib/pg/text_decoder.rb +46 -0
- data/lib/pg/text_encoder.rb +59 -0
- data/lib/pg/tuple.rb +30 -0
- data/lib/pg/type_map_by_column.rb +16 -0
- data/lib/pg.rb +29 -9
- data/spec/{lib/helpers.rb → helpers.rb} +151 -64
- data/spec/pg/basic_type_mapping_spec.rb +630 -0
- data/spec/pg/connection_spec.rb +1180 -477
- data/spec/pg/connection_sync_spec.rb +41 -0
- data/spec/pg/result_spec.rb +456 -120
- data/spec/pg/tuple_spec.rb +333 -0
- data/spec/pg/type_map_by_class_spec.rb +138 -0
- data/spec/pg/type_map_by_column_spec.rb +226 -0
- data/spec/pg/type_map_by_mri_type_spec.rb +136 -0
- data/spec/pg/type_map_by_oid_spec.rb +149 -0
- data/spec/pg/type_map_in_ruby_spec.rb +164 -0
- data/spec/pg/type_map_spec.rb +22 -0
- data/spec/pg/type_spec.rb +1123 -0
- data/spec/pg_spec.rb +26 -20
- data.tar.gz.sig +0 -0
- metadata +148 -91
- metadata.gz.sig +0 -0
- data/sample/array_insert.rb +0 -20
- data/sample/async_api.rb +0 -106
- data/sample/async_copyto.rb +0 -39
- data/sample/async_mixed.rb +0 -56
- data/sample/check_conn.rb +0 -21
- data/sample/copyfrom.rb +0 -81
- data/sample/copyto.rb +0 -19
- data/sample/cursor.rb +0 -21
- data/sample/disk_usage_report.rb +0 -186
- data/sample/issue-119.rb +0 -94
- data/sample/losample.rb +0 -69
- data/sample/minimal-testcase.rb +0 -17
- data/sample/notify_wait.rb +0 -72
- data/sample/pg_statistics.rb +0 -294
- data/sample/replication_monitor.rb +0 -231
- data/sample/test_binary_values.rb +0 -33
- data/sample/wal_shipper.rb +0 -434
- data/sample/warehouse_partitions.rb +0 -320
data/ext/pg_connection.c
CHANGED
@@ -1,91 +1,160 @@
|
|
1
1
|
/*
|
2
2
|
* pg_connection.c - PG::Connection class extension
|
3
|
-
* $Id
|
3
|
+
* $Id$
|
4
4
|
*
|
5
5
|
*/
|
6
6
|
|
7
7
|
#include "pg.h"
|
8
8
|
|
9
|
+
/* Number of bytes that are reserved on the stack for query params. */
|
10
|
+
#define QUERYDATA_BUFFER_SIZE 4000
|
11
|
+
|
9
12
|
|
10
13
|
VALUE rb_cPGconn;
|
14
|
+
static ID s_id_encode;
|
15
|
+
static VALUE sym_type, sym_format, sym_value;
|
16
|
+
static VALUE sym_symbol, sym_string, sym_static_symbol;
|
11
17
|
|
12
18
|
static PQnoticeReceiver default_notice_receiver = NULL;
|
13
19
|
static PQnoticeProcessor default_notice_processor = NULL;
|
14
20
|
|
15
|
-
static PGconn *pgconn_check( VALUE );
|
16
21
|
static VALUE pgconn_finish( VALUE );
|
17
|
-
#ifdef M17N_SUPPORTED
|
18
22
|
static VALUE pgconn_set_default_encoding( VALUE self );
|
19
|
-
|
20
|
-
|
21
|
-
#ifndef HAVE_RB_THREAD_FD_SELECT
|
22
|
-
#define rb_fdset_t fd_set
|
23
|
-
#define rb_fd_init(f)
|
24
|
-
#define rb_fd_zero(f) FD_ZERO(f)
|
25
|
-
#define rb_fd_set(n, f) FD_SET(n, f)
|
26
|
-
#define rb_fd_term(f)
|
27
|
-
#define rb_thread_fd_select rb_thread_select
|
28
|
-
#endif
|
23
|
+
static void pgconn_set_internal_encoding_index( VALUE );
|
29
24
|
|
30
25
|
/*
|
31
26
|
* Global functions
|
32
27
|
*/
|
33
28
|
|
34
29
|
/*
|
35
|
-
* Fetch the data pointer
|
30
|
+
* Fetch the PG::Connection object data pointer.
|
31
|
+
*/
|
32
|
+
t_pg_connection *
|
33
|
+
pg_get_connection( VALUE self )
|
34
|
+
{
|
35
|
+
t_pg_connection *this;
|
36
|
+
Data_Get_Struct( self, t_pg_connection, this);
|
37
|
+
|
38
|
+
return this;
|
39
|
+
}
|
40
|
+
|
41
|
+
/*
|
42
|
+
* Fetch the PG::Connection object data pointer and check it's
|
43
|
+
* PGconn data pointer for sanity.
|
44
|
+
*/
|
45
|
+
static t_pg_connection *
|
46
|
+
pg_get_connection_safe( VALUE self )
|
47
|
+
{
|
48
|
+
t_pg_connection *this;
|
49
|
+
Data_Get_Struct( self, t_pg_connection, this);
|
50
|
+
|
51
|
+
if ( !this->pgconn )
|
52
|
+
rb_raise( rb_eConnectionBad, "connection is closed" );
|
53
|
+
|
54
|
+
return this;
|
55
|
+
}
|
56
|
+
|
57
|
+
/*
|
58
|
+
* Fetch the PGconn data pointer and check it for sanity.
|
59
|
+
*
|
60
|
+
* Note: This function is used externally by the sequel_pg gem,
|
61
|
+
* so do changes carefully.
|
62
|
+
*
|
36
63
|
*/
|
37
64
|
PGconn *
|
38
65
|
pg_get_pgconn( VALUE self )
|
39
66
|
{
|
40
|
-
|
67
|
+
t_pg_connection *this;
|
68
|
+
Data_Get_Struct( self, t_pg_connection, this);
|
41
69
|
|
42
|
-
if ( !
|
70
|
+
if ( !this->pgconn )
|
43
71
|
rb_raise( rb_eConnectionBad, "connection is closed" );
|
44
72
|
|
45
|
-
return
|
73
|
+
return this->pgconn;
|
46
74
|
}
|
47
75
|
|
48
76
|
|
77
|
+
|
49
78
|
/*
|
50
79
|
* Close the associated socket IO object if there is one.
|
51
80
|
*/
|
52
|
-
void
|
81
|
+
static void
|
53
82
|
pgconn_close_socket_io( VALUE self )
|
54
83
|
{
|
55
|
-
|
84
|
+
t_pg_connection *this = pg_get_connection( self );
|
85
|
+
VALUE socket_io = this->socket_io;
|
56
86
|
|
57
87
|
if ( RTEST(socket_io) ) {
|
58
|
-
#if defined(_WIN32)
|
59
|
-
|
60
|
-
if( rb_w32_unwrap_io_handle(ruby_sd) ){
|
88
|
+
#if defined(_WIN32)
|
89
|
+
if( rb_w32_unwrap_io_handle(this->ruby_sd) ){
|
61
90
|
rb_raise(rb_eConnectionBad, "Could not unwrap win32 socket handle");
|
62
91
|
}
|
63
92
|
#endif
|
64
93
|
rb_funcall( socket_io, rb_intern("close"), 0 );
|
65
94
|
}
|
66
95
|
|
67
|
-
|
96
|
+
this->socket_io = Qnil;
|
68
97
|
}
|
69
98
|
|
70
99
|
|
71
100
|
/*
|
72
|
-
*
|
101
|
+
* Create a Ruby Array of Hashes out of a PGconninfoOptions array.
|
73
102
|
*/
|
103
|
+
static VALUE
|
104
|
+
pgconn_make_conninfo_array( const PQconninfoOption *options )
|
105
|
+
{
|
106
|
+
VALUE ary = rb_ary_new();
|
107
|
+
VALUE hash;
|
108
|
+
int i = 0;
|
74
109
|
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
110
|
+
if (!options) return Qnil;
|
111
|
+
|
112
|
+
for(i = 0; options[i].keyword != NULL; i++) {
|
113
|
+
hash = rb_hash_new();
|
114
|
+
if(options[i].keyword)
|
115
|
+
rb_hash_aset(hash, ID2SYM(rb_intern("keyword")), rb_str_new2(options[i].keyword));
|
116
|
+
if(options[i].envvar)
|
117
|
+
rb_hash_aset(hash, ID2SYM(rb_intern("envvar")), rb_str_new2(options[i].envvar));
|
118
|
+
if(options[i].compiled)
|
119
|
+
rb_hash_aset(hash, ID2SYM(rb_intern("compiled")), rb_str_new2(options[i].compiled));
|
120
|
+
if(options[i].val)
|
121
|
+
rb_hash_aset(hash, ID2SYM(rb_intern("val")), rb_str_new2(options[i].val));
|
122
|
+
if(options[i].label)
|
123
|
+
rb_hash_aset(hash, ID2SYM(rb_intern("label")), rb_str_new2(options[i].label));
|
124
|
+
if(options[i].dispchar)
|
125
|
+
rb_hash_aset(hash, ID2SYM(rb_intern("dispchar")), rb_str_new2(options[i].dispchar));
|
126
|
+
rb_hash_aset(hash, ID2SYM(rb_intern("dispsize")), INT2NUM(options[i].dispsize));
|
127
|
+
rb_ary_push(ary, hash);
|
128
|
+
}
|
129
|
+
|
130
|
+
return ary;
|
131
|
+
}
|
80
132
|
|
81
|
-
|
133
|
+
static const char *pg_cstr_enc(VALUE str, int enc_idx){
|
134
|
+
const char *ptr = StringValueCStr(str);
|
135
|
+
if( ENCODING_GET(str) == enc_idx ){
|
136
|
+
return ptr;
|
137
|
+
} else {
|
138
|
+
str = rb_str_export_to_enc(str, rb_enc_from_index(enc_idx));
|
139
|
+
return StringValueCStr(str);
|
140
|
+
}
|
141
|
+
}
|
82
142
|
|
83
|
-
if ( !rb_obj_is_kind_of(self, rb_cPGconn) ) {
|
84
|
-
rb_raise( rb_eTypeError, "wrong argument type %s (expected PG::Connection)",
|
85
|
-
rb_obj_classname( self ) );
|
86
|
-
}
|
87
143
|
|
88
|
-
|
144
|
+
/*
|
145
|
+
* GC Mark function
|
146
|
+
*/
|
147
|
+
static void
|
148
|
+
pgconn_gc_mark( t_pg_connection *this )
|
149
|
+
{
|
150
|
+
rb_gc_mark( this->socket_io );
|
151
|
+
rb_gc_mark( this->notice_receiver );
|
152
|
+
rb_gc_mark( this->notice_processor );
|
153
|
+
rb_gc_mark( this->type_map_for_queries );
|
154
|
+
rb_gc_mark( this->type_map_for_results );
|
155
|
+
rb_gc_mark( this->trace_stream );
|
156
|
+
rb_gc_mark( this->encoder_for_put_copy_data );
|
157
|
+
rb_gc_mark( this->decoder_for_get_copy_data );
|
89
158
|
}
|
90
159
|
|
91
160
|
|
@@ -93,10 +162,16 @@ pgconn_check( VALUE self ) {
|
|
93
162
|
* GC Free function
|
94
163
|
*/
|
95
164
|
static void
|
96
|
-
pgconn_gc_free(
|
165
|
+
pgconn_gc_free( t_pg_connection *this )
|
97
166
|
{
|
98
|
-
|
99
|
-
|
167
|
+
#if defined(_WIN32)
|
168
|
+
if ( RTEST(this->socket_io) )
|
169
|
+
rb_w32_unwrap_io_handle( this->ruby_sd );
|
170
|
+
#endif
|
171
|
+
if (this->pgconn != NULL)
|
172
|
+
PQfinish( this->pgconn );
|
173
|
+
|
174
|
+
xfree(this);
|
100
175
|
}
|
101
176
|
|
102
177
|
|
@@ -113,10 +188,19 @@ pgconn_gc_free( PGconn *conn )
|
|
113
188
|
static VALUE
|
114
189
|
pgconn_s_allocate( VALUE klass )
|
115
190
|
{
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
191
|
+
t_pg_connection *this;
|
192
|
+
VALUE self = Data_Make_Struct( klass, t_pg_connection, pgconn_gc_mark, pgconn_gc_free, this );
|
193
|
+
|
194
|
+
this->pgconn = NULL;
|
195
|
+
this->socket_io = Qnil;
|
196
|
+
this->notice_receiver = Qnil;
|
197
|
+
this->notice_processor = Qnil;
|
198
|
+
this->type_map_for_queries = pg_typemap_all_strings;
|
199
|
+
this->type_map_for_results = pg_typemap_all_strings;
|
200
|
+
this->encoder_for_put_copy_data = Qnil;
|
201
|
+
this->decoder_for_get_copy_data = Qnil;
|
202
|
+
this->trace_stream = Qnil;
|
203
|
+
|
120
204
|
return self;
|
121
205
|
}
|
122
206
|
|
@@ -132,32 +216,27 @@ pgconn_s_allocate( VALUE klass )
|
|
132
216
|
*
|
133
217
|
* Create a connection to the specified server.
|
134
218
|
*
|
219
|
+
* +connection_hash+ must be a ruby Hash with connection parameters.
|
220
|
+
* See the {list of valid parameters}[https://www.postgresql.org/docs/current/libpq-connect.html#LIBPQ-PARAMKEYWORDS] in the PostgreSQL documentation.
|
221
|
+
*
|
222
|
+
* There are two accepted formats for +connection_string+: plain <code>keyword = value</code> strings and URIs.
|
223
|
+
* See the documentation of {connection strings}[https://www.postgresql.org/docs/current/libpq-connect.html#LIBPQ-CONNSTRING].
|
224
|
+
*
|
225
|
+
* The positional parameter form has the same functionality except that the missing parameters will always take on default values. The parameters are:
|
135
226
|
* [+host+]
|
136
227
|
* server hostname
|
137
|
-
* [+hostaddr+]
|
138
|
-
* server address (avoids hostname lookup, overrides +host+)
|
139
228
|
* [+port+]
|
140
229
|
* server port number
|
230
|
+
* [+options+]
|
231
|
+
* backend options
|
232
|
+
* [+tty+]
|
233
|
+
* (ignored in newer versions of PostgreSQL)
|
141
234
|
* [+dbname+]
|
142
235
|
* connecting database name
|
143
236
|
* [+user+]
|
144
237
|
* login user name
|
145
238
|
* [+password+]
|
146
239
|
* login password
|
147
|
-
* [+connect_timeout+]
|
148
|
-
* maximum time to wait for connection to succeed
|
149
|
-
* [+options+]
|
150
|
-
* backend options
|
151
|
-
* [+tty+]
|
152
|
-
* (ignored in newer versions of PostgreSQL)
|
153
|
-
* [+sslmode+]
|
154
|
-
* (disable|allow|prefer|require)
|
155
|
-
* [+krbsrvname+]
|
156
|
-
* kerberos service name
|
157
|
-
* [+gsslib+]
|
158
|
-
* GSS library to use for GSSAPI authentication
|
159
|
-
* [+service+]
|
160
|
-
* service name to use for additional parameters
|
161
240
|
*
|
162
241
|
* Examples:
|
163
242
|
*
|
@@ -173,7 +252,7 @@ pgconn_s_allocate( VALUE klass )
|
|
173
252
|
* # As an Array
|
174
253
|
* PG::Connection.new( nil, 5432, nil, nil, 'test', nil, nil )
|
175
254
|
*
|
176
|
-
* If the Ruby default internal encoding is set (i.e., Encoding.default_internal != nil), the
|
255
|
+
* If the Ruby default internal encoding is set (i.e., <code>Encoding.default_internal != nil</code>), the
|
177
256
|
* connection will have its +client_encoding+ set accordingly.
|
178
257
|
*
|
179
258
|
* Raises a PG::Error if the connection fails.
|
@@ -181,28 +260,24 @@ pgconn_s_allocate( VALUE klass )
|
|
181
260
|
static VALUE
|
182
261
|
pgconn_init(int argc, VALUE *argv, VALUE self)
|
183
262
|
{
|
184
|
-
|
263
|
+
t_pg_connection *this;
|
185
264
|
VALUE conninfo;
|
186
265
|
VALUE error;
|
187
266
|
|
267
|
+
this = pg_get_connection( self );
|
188
268
|
conninfo = rb_funcall2( rb_cPGconn, rb_intern("parse_connect_args"), argc, argv );
|
189
|
-
|
269
|
+
this->pgconn = gvl_PQconnectdb(StringValueCStr(conninfo));
|
190
270
|
|
191
|
-
if(
|
271
|
+
if(this->pgconn == NULL)
|
192
272
|
rb_raise(rb_ePGerror, "PQconnectdb() unable to allocate structure");
|
193
273
|
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
if (PQstatus(conn) == CONNECTION_BAD) {
|
198
|
-
error = rb_exc_new2(rb_eConnectionBad, PQerrorMessage(conn));
|
274
|
+
if (PQstatus(this->pgconn) == CONNECTION_BAD) {
|
275
|
+
error = rb_exc_new2(rb_eConnectionBad, PQerrorMessage(this->pgconn));
|
199
276
|
rb_iv_set(error, "@connection", self);
|
200
277
|
rb_exc_raise(error);
|
201
278
|
}
|
202
279
|
|
203
|
-
#ifdef M17N_SUPPORTED
|
204
280
|
pgconn_set_default_encoding( self );
|
205
|
-
#endif
|
206
281
|
|
207
282
|
if (rb_block_given_p()) {
|
208
283
|
return rb_ensure(rb_yield, self, pgconn_finish, self);
|
@@ -216,40 +291,40 @@ pgconn_init(int argc, VALUE *argv, VALUE self)
|
|
216
291
|
* PG::Connection.connect_start(connection_string) -> conn
|
217
292
|
* PG::Connection.connect_start(host, port, options, tty, dbname, login, password) -> conn
|
218
293
|
*
|
219
|
-
* This is an asynchronous version of PG::Connection.
|
294
|
+
* This is an asynchronous version of PG::Connection.new.
|
220
295
|
*
|
221
296
|
* Use #connect_poll to poll the status of the connection.
|
222
297
|
*
|
223
298
|
* NOTE: this does *not* set the connection's +client_encoding+ for you if
|
224
|
-
* Encoding.default_internal is set. To set it after the connection is established,
|
299
|
+
* +Encoding.default_internal+ is set. To set it after the connection is established,
|
225
300
|
* call #internal_encoding=. You can also set it automatically by setting
|
226
|
-
* ENV['PGCLIENTENCODING']
|
301
|
+
* <code>ENV['PGCLIENTENCODING']</code>, or include the 'options' connection parameter.
|
302
|
+
*
|
303
|
+
* See also the 'sample' directory of this gem and the corresponding {libpq functions}[https://www.postgresql.org/docs/current/libpq-connect.html#LIBPQ-PQCONNECTSTARTPARAMS].
|
227
304
|
*
|
228
305
|
*/
|
229
306
|
static VALUE
|
230
307
|
pgconn_s_connect_start( int argc, VALUE *argv, VALUE klass )
|
231
308
|
{
|
232
|
-
PGconn *conn = NULL;
|
233
309
|
VALUE rb_conn;
|
234
310
|
VALUE conninfo;
|
235
311
|
VALUE error;
|
312
|
+
t_pg_connection *this;
|
236
313
|
|
237
314
|
/*
|
238
315
|
* PG::Connection.connect_start must act as both alloc() and initialize()
|
239
316
|
* because it is not invoked by calling new().
|
240
317
|
*/
|
241
318
|
rb_conn = pgconn_s_allocate( klass );
|
319
|
+
this = pg_get_connection( rb_conn );
|
242
320
|
conninfo = rb_funcall2( klass, rb_intern("parse_connect_args"), argc, argv );
|
243
|
-
|
321
|
+
this->pgconn = gvl_PQconnectStart( StringValueCStr(conninfo) );
|
244
322
|
|
245
|
-
if(
|
323
|
+
if( this->pgconn == NULL )
|
246
324
|
rb_raise(rb_ePGerror, "PQconnectStart() unable to allocate structure");
|
247
325
|
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
if ( PQstatus(conn) == CONNECTION_BAD ) {
|
252
|
-
error = rb_exc_new2(rb_eConnectionBad, PQerrorMessage(conn));
|
326
|
+
if ( PQstatus(this->pgconn) == CONNECTION_BAD ) {
|
327
|
+
error = rb_exc_new2(rb_eConnectionBad, PQerrorMessage(this->pgconn));
|
253
328
|
rb_iv_set(error, "@connection", rb_conn);
|
254
329
|
rb_exc_raise(error);
|
255
330
|
}
|
@@ -260,15 +335,16 @@ pgconn_s_connect_start( int argc, VALUE *argv, VALUE klass )
|
|
260
335
|
return rb_conn;
|
261
336
|
}
|
262
337
|
|
263
|
-
#ifdef HAVE_PQPING
|
264
338
|
/*
|
265
339
|
* call-seq:
|
266
|
-
* PG::Connection.ping(connection_hash) ->
|
267
|
-
* PG::Connection.ping(connection_string) ->
|
268
|
-
* PG::Connection.ping(host, port, options, tty, dbname, login, password) ->
|
340
|
+
* PG::Connection.ping(connection_hash) -> Integer
|
341
|
+
* PG::Connection.ping(connection_string) -> Integer
|
342
|
+
* PG::Connection.ping(host, port, options, tty, dbname, login, password) -> Integer
|
269
343
|
*
|
270
344
|
* Check server status.
|
271
345
|
*
|
346
|
+
* See PG::Connection.new for a description of the parameters.
|
347
|
+
*
|
272
348
|
* Returns one of:
|
273
349
|
* [+PQPING_OK+]
|
274
350
|
* server is accepting connections
|
@@ -286,15 +362,14 @@ pgconn_s_ping( int argc, VALUE *argv, VALUE klass )
|
|
286
362
|
VALUE conninfo;
|
287
363
|
|
288
364
|
conninfo = rb_funcall2( klass, rb_intern("parse_connect_args"), argc, argv );
|
289
|
-
ping = PQping(
|
365
|
+
ping = PQping( StringValueCStr(conninfo) );
|
290
366
|
|
291
367
|
return INT2FIX((int)ping);
|
292
368
|
}
|
293
|
-
#endif
|
294
369
|
|
295
370
|
|
296
371
|
/*
|
297
|
-
* Document-method: conndefaults
|
372
|
+
* Document-method: PG::Connection.conndefaults
|
298
373
|
*
|
299
374
|
* call-seq:
|
300
375
|
* PG::Connection.conndefaults() -> Array
|
@@ -319,44 +394,72 @@ static VALUE
|
|
319
394
|
pgconn_s_conndefaults(VALUE self)
|
320
395
|
{
|
321
396
|
PQconninfoOption *options = PQconndefaults();
|
322
|
-
VALUE
|
323
|
-
|
324
|
-
|
397
|
+
VALUE array = pgconn_make_conninfo_array( options );
|
398
|
+
|
399
|
+
PQconninfoFree(options);
|
325
400
|
|
326
401
|
UNUSED( self );
|
327
402
|
|
328
|
-
|
329
|
-
|
330
|
-
|
331
|
-
|
332
|
-
|
333
|
-
|
334
|
-
|
335
|
-
|
336
|
-
|
337
|
-
|
338
|
-
|
339
|
-
|
340
|
-
|
341
|
-
|
342
|
-
|
343
|
-
|
403
|
+
return array;
|
404
|
+
}
|
405
|
+
|
406
|
+
|
407
|
+
#ifdef HAVE_PQENCRYPTPASSWORDCONN
|
408
|
+
/*
|
409
|
+
* call-seq:
|
410
|
+
* conn.encrypt_password( password, username, algorithm=nil ) -> String
|
411
|
+
*
|
412
|
+
* This function is intended to be used by client applications that wish to send commands like <tt>ALTER USER joe PASSWORD 'pwd'</tt>.
|
413
|
+
* It is good practice not to send the original cleartext password in such a command, because it might be exposed in command logs, activity displays, and so on.
|
414
|
+
* Instead, use this function to convert the password to encrypted form before it is sent.
|
415
|
+
*
|
416
|
+
* The +password+ and +username+ arguments are the cleartext password, and the SQL name of the user it is for.
|
417
|
+
* +algorithm+ specifies the encryption algorithm to use to encrypt the password.
|
418
|
+
* Currently supported algorithms are +md5+ and +scram-sha-256+ (+on+ and +off+ are also accepted as aliases for +md5+, for compatibility with older server versions).
|
419
|
+
* Note that support for +scram-sha-256+ was introduced in PostgreSQL version 10, and will not work correctly with older server versions.
|
420
|
+
* If algorithm is omitted or +nil+, this function will query the server for the current value of the +password_encryption+ setting.
|
421
|
+
* That can block, and will fail if the current transaction is aborted, or if the connection is busy executing another query.
|
422
|
+
* If you wish to use the default algorithm for the server but want to avoid blocking, query +password_encryption+ yourself before calling #encrypt_password, and pass that value as the algorithm.
|
423
|
+
*
|
424
|
+
* Return value is the encrypted password.
|
425
|
+
* The caller can assume the string doesn't contain any special characters that would require escaping.
|
426
|
+
*
|
427
|
+
* Available since PostgreSQL-10.
|
428
|
+
* See also corresponding {libpq function}[https://www.postgresql.org/docs/current/libpq-misc.html#LIBPQ-PQENCRYPTPASSWORDCONN].
|
429
|
+
*/
|
430
|
+
static VALUE
|
431
|
+
pgconn_encrypt_password(int argc, VALUE *argv, VALUE self)
|
432
|
+
{
|
433
|
+
char *encrypted = NULL;
|
434
|
+
VALUE rval = Qnil;
|
435
|
+
VALUE password, username, algorithm;
|
436
|
+
PGconn *conn = pg_get_pgconn(self);
|
437
|
+
|
438
|
+
rb_scan_args( argc, argv, "21", &password, &username, &algorithm );
|
439
|
+
|
440
|
+
Check_Type(password, T_STRING);
|
441
|
+
Check_Type(username, T_STRING);
|
442
|
+
|
443
|
+
encrypted = gvl_PQencryptPasswordConn(conn, StringValueCStr(password), StringValueCStr(username), RTEST(algorithm) ? StringValueCStr(algorithm) : NULL);
|
444
|
+
if ( encrypted ) {
|
445
|
+
rval = rb_str_new2( encrypted );
|
446
|
+
PQfreemem( encrypted );
|
447
|
+
} else {
|
448
|
+
rb_raise(rb_ePGerror, "%s", PQerrorMessage(conn));
|
344
449
|
}
|
345
|
-
|
346
|
-
return
|
450
|
+
|
451
|
+
return rval;
|
347
452
|
}
|
453
|
+
#endif
|
348
454
|
|
349
455
|
|
350
456
|
/*
|
351
457
|
* call-seq:
|
352
458
|
* PG::Connection.encrypt_password( password, username ) -> String
|
353
459
|
*
|
354
|
-
* This
|
355
|
-
*
|
356
|
-
* The arguments are the cleartext password, and the SQL name
|
357
|
-
* of the user it is for.
|
460
|
+
* This is an older, deprecated version of #encrypt_password.
|
461
|
+
* The difference is that this function always uses +md5+ as the encryption algorithm.
|
358
462
|
*
|
359
|
-
* Return value is the encrypted password.
|
360
463
|
*/
|
361
464
|
static VALUE
|
362
465
|
pgconn_s_encrypt_password(VALUE self, VALUE password, VALUE username)
|
@@ -369,13 +472,10 @@ pgconn_s_encrypt_password(VALUE self, VALUE password, VALUE username)
|
|
369
472
|
Check_Type(password, T_STRING);
|
370
473
|
Check_Type(username, T_STRING);
|
371
474
|
|
372
|
-
encrypted = PQencryptPassword(
|
475
|
+
encrypted = PQencryptPassword(StringValueCStr(password), StringValueCStr(username));
|
373
476
|
rval = rb_str_new2( encrypted );
|
374
477
|
PQfreemem( encrypted );
|
375
478
|
|
376
|
-
OBJ_INFECT( rval, password );
|
377
|
-
OBJ_INFECT( rval, username );
|
378
|
-
|
379
479
|
return rval;
|
380
480
|
}
|
381
481
|
|
@@ -386,7 +486,7 @@ pgconn_s_encrypt_password(VALUE self, VALUE password, VALUE username)
|
|
386
486
|
|
387
487
|
/*
|
388
488
|
* call-seq:
|
389
|
-
* conn.connect_poll() ->
|
489
|
+
* conn.connect_poll() -> Integer
|
390
490
|
*
|
391
491
|
* Returns one of:
|
392
492
|
* [+PGRES_POLLING_READING+]
|
@@ -435,9 +535,11 @@ pgconn_connect_poll(VALUE self)
|
|
435
535
|
static VALUE
|
436
536
|
pgconn_finish( VALUE self )
|
437
537
|
{
|
538
|
+
t_pg_connection *this = pg_get_connection_safe( self );
|
539
|
+
|
438
540
|
pgconn_close_socket_io( self );
|
439
|
-
PQfinish(
|
440
|
-
|
541
|
+
PQfinish( this->pgconn );
|
542
|
+
this->pgconn = NULL;
|
441
543
|
return Qnil;
|
442
544
|
}
|
443
545
|
|
@@ -451,7 +553,8 @@ pgconn_finish( VALUE self )
|
|
451
553
|
static VALUE
|
452
554
|
pgconn_finished_p( VALUE self )
|
453
555
|
{
|
454
|
-
|
556
|
+
t_pg_connection *this = pg_get_connection( self );
|
557
|
+
if ( this->pgconn ) return Qfalse;
|
455
558
|
return Qtrue;
|
456
559
|
}
|
457
560
|
|
@@ -492,7 +595,7 @@ pgconn_reset_start(VALUE self)
|
|
492
595
|
|
493
596
|
/*
|
494
597
|
* call-seq:
|
495
|
-
* conn.reset_poll ->
|
598
|
+
* conn.reset_poll -> Integer
|
496
599
|
*
|
497
600
|
* Checks the status of a connection reset operation.
|
498
601
|
* See #connect_start and #connect_poll for
|
@@ -518,7 +621,7 @@ pgconn_db(VALUE self)
|
|
518
621
|
{
|
519
622
|
char *db = PQdb(pg_get_pgconn(self));
|
520
623
|
if (!db) return Qnil;
|
521
|
-
return
|
624
|
+
return rb_str_new2(db);
|
522
625
|
}
|
523
626
|
|
524
627
|
/*
|
@@ -532,21 +635,21 @@ pgconn_user(VALUE self)
|
|
532
635
|
{
|
533
636
|
char *user = PQuser(pg_get_pgconn(self));
|
534
637
|
if (!user) return Qnil;
|
535
|
-
return
|
638
|
+
return rb_str_new2(user);
|
536
639
|
}
|
537
640
|
|
538
641
|
/*
|
539
642
|
* call-seq:
|
540
643
|
* conn.pass()
|
541
644
|
*
|
542
|
-
* Returns the authenticated
|
645
|
+
* Returns the authenticated password.
|
543
646
|
*/
|
544
647
|
static VALUE
|
545
648
|
pgconn_pass(VALUE self)
|
546
649
|
{
|
547
650
|
char *user = PQpass(pg_get_pgconn(self));
|
548
651
|
if (!user) return Qnil;
|
549
|
-
return
|
652
|
+
return rb_str_new2(user);
|
550
653
|
}
|
551
654
|
|
552
655
|
/*
|
@@ -560,7 +663,7 @@ pgconn_host(VALUE self)
|
|
560
663
|
{
|
561
664
|
char *host = PQhost(pg_get_pgconn(self));
|
562
665
|
if (!host) return Qnil;
|
563
|
-
return
|
666
|
+
return rb_str_new2(host);
|
564
667
|
}
|
565
668
|
|
566
669
|
/*
|
@@ -587,7 +690,7 @@ pgconn_tty(VALUE self)
|
|
587
690
|
{
|
588
691
|
char *tty = PQtty(pg_get_pgconn(self));
|
589
692
|
if (!tty) return Qnil;
|
590
|
-
return
|
693
|
+
return rb_str_new2(tty);
|
591
694
|
}
|
592
695
|
|
593
696
|
/*
|
@@ -601,8 +704,32 @@ pgconn_options(VALUE self)
|
|
601
704
|
{
|
602
705
|
char *options = PQoptions(pg_get_pgconn(self));
|
603
706
|
if (!options) return Qnil;
|
604
|
-
return
|
707
|
+
return rb_str_new2(options);
|
708
|
+
}
|
709
|
+
|
710
|
+
|
711
|
+
#ifdef HAVE_PQCONNINFO
|
712
|
+
/*
|
713
|
+
* call-seq:
|
714
|
+
* conn.conninfo -> hash
|
715
|
+
*
|
716
|
+
* Returns the connection options used by a live connection.
|
717
|
+
*
|
718
|
+
* Available since PostgreSQL-9.3
|
719
|
+
*/
|
720
|
+
static VALUE
|
721
|
+
pgconn_conninfo( VALUE self )
|
722
|
+
{
|
723
|
+
PGconn *conn = pg_get_pgconn(self);
|
724
|
+
PQconninfoOption *options = PQconninfo( conn );
|
725
|
+
VALUE array = pgconn_make_conninfo_array( options );
|
726
|
+
|
727
|
+
PQconninfoFree(options);
|
728
|
+
|
729
|
+
return array;
|
605
730
|
}
|
731
|
+
#endif
|
732
|
+
|
606
733
|
|
607
734
|
/*
|
608
735
|
* call-seq:
|
@@ -654,11 +781,11 @@ pgconn_transaction_status(VALUE self)
|
|
654
781
|
static VALUE
|
655
782
|
pgconn_parameter_status(VALUE self, VALUE param_name)
|
656
783
|
{
|
657
|
-
const char *ret = PQparameterStatus(pg_get_pgconn(self),
|
784
|
+
const char *ret = PQparameterStatus(pg_get_pgconn(self), StringValueCStr(param_name));
|
658
785
|
if(ret == NULL)
|
659
786
|
return Qnil;
|
660
787
|
else
|
661
|
-
return
|
788
|
+
return rb_str_new2(ret);
|
662
789
|
}
|
663
790
|
|
664
791
|
/*
|
@@ -703,12 +830,14 @@ pgconn_error_message(VALUE self)
|
|
703
830
|
{
|
704
831
|
char *error = PQerrorMessage(pg_get_pgconn(self));
|
705
832
|
if (!error) return Qnil;
|
706
|
-
return
|
833
|
+
return rb_str_new2(error);
|
707
834
|
}
|
708
835
|
|
709
836
|
/*
|
710
837
|
* call-seq:
|
711
|
-
* conn.socket() ->
|
838
|
+
* conn.socket() -> Integer
|
839
|
+
*
|
840
|
+
* This method is deprecated. Please use the more portable method #socket_io .
|
712
841
|
*
|
713
842
|
* Returns the socket's file descriptor for this connection.
|
714
843
|
* <tt>IO.for_fd()</tt> can be used to build a proper IO object to the socket.
|
@@ -718,34 +847,31 @@ pgconn_error_message(VALUE self)
|
|
718
847
|
* creates an IO that's associated with the connection object itself,
|
719
848
|
* and so won't go out of scope until the connection does.
|
720
849
|
*
|
721
|
-
* *Note:* On Windows the file descriptor is not
|
850
|
+
* *Note:* On Windows the file descriptor is not usable,
|
722
851
|
* since it can not be used to build a Ruby IO object.
|
723
852
|
*/
|
724
853
|
static VALUE
|
725
854
|
pgconn_socket(VALUE self)
|
726
855
|
{
|
727
856
|
int sd;
|
857
|
+
pg_deprecated(4, ("conn.socket is deprecated and should be replaced by conn.socket_io"));
|
858
|
+
|
728
859
|
if( (sd = PQsocket(pg_get_pgconn(self))) < 0)
|
729
860
|
rb_raise(rb_eConnectionBad, "PQsocket() can't get socket descriptor");
|
730
861
|
return INT2NUM(sd);
|
731
862
|
}
|
732
863
|
|
733
|
-
|
734
|
-
#if !defined(_WIN32) || defined(HAVE_RB_W32_WRAP_IO_HANDLE)
|
735
|
-
|
736
864
|
/*
|
737
865
|
* call-seq:
|
738
866
|
* conn.socket_io() -> IO
|
739
867
|
*
|
740
|
-
* Fetch a
|
868
|
+
* Fetch a memorized IO object created from the Connection's underlying socket.
|
741
869
|
* This object can be used for IO.select to wait for events while running
|
742
870
|
* asynchronous API calls.
|
743
871
|
*
|
744
872
|
* Using this instead of #socket avoids the problem of the underlying connection
|
745
873
|
* being closed by Ruby when an IO created using <tt>IO.for_fd(conn.socket)</tt>
|
746
|
-
* goes out of scope.
|
747
|
-
*
|
748
|
-
* This method can also be used on Windows but requires Ruby-2.0+.
|
874
|
+
* goes out of scope. In contrast to #socket, it also works on Windows.
|
749
875
|
*/
|
750
876
|
static VALUE
|
751
877
|
pgconn_socket_io(VALUE self)
|
@@ -753,36 +879,34 @@ pgconn_socket_io(VALUE self)
|
|
753
879
|
int sd;
|
754
880
|
int ruby_sd;
|
755
881
|
ID id_autoclose = rb_intern("autoclose=");
|
756
|
-
|
882
|
+
t_pg_connection *this = pg_get_connection_safe( self );
|
883
|
+
VALUE socket_io = this->socket_io;
|
757
884
|
|
758
885
|
if ( !RTEST(socket_io) ) {
|
759
|
-
if( (sd = PQsocket(
|
886
|
+
if( (sd = PQsocket(this->pgconn)) < 0)
|
760
887
|
rb_raise(rb_eConnectionBad, "PQsocket() can't get socket descriptor");
|
761
888
|
|
762
889
|
#ifdef _WIN32
|
763
890
|
ruby_sd = rb_w32_wrap_io_handle((HANDLE)(intptr_t)sd, O_RDWR|O_BINARY|O_NOINHERIT);
|
891
|
+
this->ruby_sd = ruby_sd;
|
764
892
|
#else
|
765
893
|
ruby_sd = sd;
|
766
894
|
#endif
|
767
895
|
|
768
896
|
socket_io = rb_funcall( rb_cIO, rb_intern("for_fd"), 1, INT2NUM(ruby_sd) );
|
769
897
|
|
770
|
-
/* Disable autoclose feature
|
771
|
-
|
772
|
-
rb_funcall( socket_io, id_autoclose, 1, Qfalse );
|
773
|
-
}
|
898
|
+
/* Disable autoclose feature */
|
899
|
+
rb_funcall( socket_io, id_autoclose, 1, Qfalse );
|
774
900
|
|
775
|
-
|
901
|
+
this->socket_io = socket_io;
|
776
902
|
}
|
777
903
|
|
778
904
|
return socket_io;
|
779
905
|
}
|
780
906
|
|
781
|
-
#endif
|
782
|
-
|
783
907
|
/*
|
784
908
|
* call-seq:
|
785
|
-
* conn.backend_pid() ->
|
909
|
+
* conn.backend_pid() -> Integer
|
786
910
|
*
|
787
911
|
* Returns the process ID of the backend server
|
788
912
|
* process for this connection.
|
@@ -828,40 +952,31 @@ static VALUE pgconn_exec_params( int, VALUE *, VALUE );
|
|
828
952
|
|
829
953
|
/*
|
830
954
|
* call-seq:
|
831
|
-
* conn.
|
832
|
-
* conn.
|
833
|
-
*
|
834
|
-
* Sends SQL query request specified by _sql_ to PostgreSQL.
|
835
|
-
* Returns a PG::Result instance on success.
|
836
|
-
* On failure, it raises a PG::Error.
|
955
|
+
* conn.sync_exec(sql) -> PG::Result
|
956
|
+
* conn.sync_exec(sql) {|pg_result| block }
|
837
957
|
*
|
838
|
-
*
|
839
|
-
*
|
840
|
-
* argument placeholders are used.
|
958
|
+
* This function has the same behavior as #async_exec, but is implemented using the synchronous command processing API of libpq.
|
959
|
+
* It's not recommended to use explicit sync or async variants but #exec instead, unless you have a good reason to do so.
|
841
960
|
*
|
842
|
-
*
|
843
|
-
*
|
844
|
-
* In this instance, <code>conn.exec</code> returns the value of the block.
|
961
|
+
* Both #sync_exec and #async_exec release the GVL while waiting for server response, so that concurrent threads will get executed.
|
962
|
+
* However #async_exec has two advantages:
|
845
963
|
*
|
846
|
-
* #
|
847
|
-
*
|
848
|
-
*
|
849
|
-
* the query is finished. This is most notably visible by a delayed reaction to Control+C.
|
850
|
-
* Both methods ensure that other threads can process while waiting for the server to
|
851
|
-
* complete the request.
|
964
|
+
* 1. #async_exec can be aborted by signals (like Ctrl-C), while #exec blocks signal processing until the query is answered.
|
965
|
+
* 2. Ruby VM gets notified about IO blocked operations.
|
966
|
+
* It can therefore schedule things like garbage collection, while queries are running like in this proposal: https://bugs.ruby-lang.org/issues/14723
|
852
967
|
*/
|
853
968
|
static VALUE
|
854
969
|
pgconn_exec(int argc, VALUE *argv, VALUE self)
|
855
970
|
{
|
856
|
-
|
971
|
+
t_pg_connection *this = pg_get_connection_safe( self );
|
857
972
|
PGresult *result = NULL;
|
858
973
|
VALUE rb_pgresult;
|
859
974
|
|
860
|
-
/* If called with no parameters, use PQexec */
|
861
|
-
if ( argc == 1 ) {
|
862
|
-
|
975
|
+
/* If called with no or nil parameters, use PQexec for compatibility */
|
976
|
+
if ( argc == 1 || (argc >= 2 && argc <= 4 && NIL_P(argv[1]) )) {
|
977
|
+
VALUE query_str = argv[0];
|
863
978
|
|
864
|
-
result = gvl_PQexec(
|
979
|
+
result = gvl_PQexec(this->pgconn, pg_cstr_enc(query_str, this->enc_idx));
|
865
980
|
rb_pgresult = pg_new_result(result, self);
|
866
981
|
pg_result_check(rb_pgresult);
|
867
982
|
if (rb_block_given_p()) {
|
@@ -869,157 +984,302 @@ pgconn_exec(int argc, VALUE *argv, VALUE self)
|
|
869
984
|
}
|
870
985
|
return rb_pgresult;
|
871
986
|
}
|
987
|
+
pg_deprecated(0, ("forwarding exec to exec_params is deprecated"));
|
872
988
|
|
873
989
|
/* Otherwise, just call #exec_params instead for backward-compatibility */
|
874
|
-
|
875
|
-
return pgconn_exec_params( argc, argv, self );
|
876
|
-
}
|
990
|
+
return pgconn_exec_params( argc, argv, self );
|
877
991
|
|
878
992
|
}
|
879
993
|
|
880
994
|
|
881
|
-
|
882
|
-
*
|
883
|
-
|
884
|
-
|
885
|
-
*
|
886
|
-
* Sends SQL query request specified by +sql+ to PostgreSQL using placeholders
|
887
|
-
* for parameters.
|
888
|
-
*
|
889
|
-
* Returns a PG::Result instance on success. On failure, it raises a PG::Error.
|
890
|
-
*
|
891
|
-
* +params+ is an array of the bind parameters for the SQL query.
|
892
|
-
* Each element of the +params+ array may be either:
|
893
|
-
* a hash of the form:
|
894
|
-
* {:value => String (value of bind parameter)
|
895
|
-
* :type => Fixnum (oid of type of bind parameter)
|
896
|
-
* :format => Fixnum (0 for text, 1 for binary)
|
897
|
-
* }
|
898
|
-
* or, it may be a String. If it is a string, that is equivalent to the hash:
|
899
|
-
* { :value => <string value>, :type => 0, :format => 0 }
|
900
|
-
*
|
901
|
-
* PostgreSQL bind parameters are represented as $1, $1, $2, etc.,
|
902
|
-
* inside the SQL query. The 0th element of the +params+ array is bound
|
903
|
-
* to $1, the 1st element is bound to $2, etc. +nil+ is treated as +NULL+.
|
904
|
-
*
|
905
|
-
* If the types are not specified, they will be inferred by PostgreSQL.
|
906
|
-
* Instead of specifying type oids, it's recommended to simply add
|
907
|
-
* explicit casts in the query to ensure that the right type is used.
|
908
|
-
*
|
909
|
-
* For example: "SELECT $1::int"
|
910
|
-
*
|
911
|
-
* The optional +result_format+ should be 0 for text results, 1
|
912
|
-
* for binary.
|
913
|
-
*
|
914
|
-
* If the optional code block is given, it will be passed <i>result</i> as an argument,
|
915
|
-
* and the PG::Result object will automatically be cleared when the block terminates.
|
916
|
-
* In this instance, <code>conn.exec</code> returns the value of the block.
|
917
|
-
*/
|
918
|
-
static VALUE
|
919
|
-
pgconn_exec_params( int argc, VALUE *argv, VALUE self )
|
920
|
-
{
|
921
|
-
PGconn *conn = pg_get_pgconn(self);
|
922
|
-
PGresult *result = NULL;
|
923
|
-
VALUE rb_pgresult;
|
924
|
-
VALUE command, params, in_res_fmt;
|
925
|
-
VALUE param, param_type, param_value, param_format;
|
926
|
-
VALUE param_value_tmp;
|
927
|
-
VALUE sym_type, sym_value, sym_format;
|
928
|
-
VALUE gc_array;
|
929
|
-
int i=0;
|
930
|
-
int nParams;
|
931
|
-
Oid *paramTypes;
|
932
|
-
char ** paramValues;
|
933
|
-
int *paramLengths;
|
934
|
-
int *paramFormats;
|
935
|
-
int resultFormat;
|
995
|
+
struct linked_typecast_data {
|
996
|
+
struct linked_typecast_data *next;
|
997
|
+
char data[0];
|
998
|
+
};
|
936
999
|
|
937
|
-
|
1000
|
+
/* This struct is allocated on the stack for all query execution functions. */
|
1001
|
+
struct query_params_data {
|
938
1002
|
|
939
1003
|
/*
|
940
|
-
*
|
941
|
-
* for the second parameter.
|
1004
|
+
* Filled by caller
|
942
1005
|
*/
|
943
|
-
if ( NIL_P(params) ) {
|
944
|
-
return pgconn_exec( 1, argv, self );
|
945
|
-
}
|
946
1006
|
|
947
|
-
|
1007
|
+
/* The character encoding index of the connection. Any strings
|
1008
|
+
* given as query parameters are converted to this encoding.
|
1009
|
+
*/
|
1010
|
+
int enc_idx;
|
1011
|
+
/* Is the query function to execute one with types array? */
|
1012
|
+
int with_types;
|
1013
|
+
/* Array of query params from user space */
|
1014
|
+
VALUE params;
|
1015
|
+
/* The typemap given from user space */
|
1016
|
+
VALUE typemap;
|
948
1017
|
|
949
|
-
|
950
|
-
|
951
|
-
|
952
|
-
else {
|
953
|
-
resultFormat = NUM2INT(in_res_fmt);
|
954
|
-
}
|
1018
|
+
/*
|
1019
|
+
* Filled by alloc_query_params()
|
1020
|
+
*/
|
955
1021
|
|
956
|
-
|
957
|
-
|
1022
|
+
/* Wraps the pointer of allocated memory, if function parameters dont't
|
1023
|
+
* fit in the memory_pool below.
|
1024
|
+
*/
|
1025
|
+
VALUE heap_pool;
|
958
1026
|
|
959
|
-
|
960
|
-
|
961
|
-
|
962
|
-
|
963
|
-
|
964
|
-
|
965
|
-
|
966
|
-
|
967
|
-
|
968
|
-
|
969
|
-
|
970
|
-
|
971
|
-
|
972
|
-
|
973
|
-
|
974
|
-
|
975
|
-
else
|
976
|
-
param_value = rb_obj_as_string(param_value_tmp);
|
977
|
-
param_format = rb_hash_aref(param, sym_format);
|
978
|
-
}
|
979
|
-
else {
|
980
|
-
param_type = Qnil;
|
981
|
-
if(param == Qnil)
|
982
|
-
param_value = param;
|
983
|
-
else
|
984
|
-
param_value = rb_obj_as_string(param);
|
985
|
-
param_format = Qnil;
|
986
|
-
}
|
1027
|
+
/* Pointer to the value string pointers (either within memory_pool or heap_pool).
|
1028
|
+
* The value strings itself are either directly within RString memory or,
|
1029
|
+
* in case of type casted values, within memory_pool or typecast_heap_chain.
|
1030
|
+
*/
|
1031
|
+
char **values;
|
1032
|
+
/* Pointer to the param lengths (either within memory_pool or heap_pool) */
|
1033
|
+
int *lengths;
|
1034
|
+
/* Pointer to the format codes (either within memory_pool or heap_pool) */
|
1035
|
+
int *formats;
|
1036
|
+
/* Pointer to the OID types (either within memory_pool or heap_pool) */
|
1037
|
+
Oid *types;
|
1038
|
+
|
1039
|
+
/* This array takes the string values for the timeframe of the query,
|
1040
|
+
* if param value convertion is required
|
1041
|
+
*/
|
1042
|
+
VALUE gc_array;
|
987
1043
|
|
988
|
-
|
989
|
-
|
990
|
-
|
991
|
-
|
1044
|
+
/* Wraps a single linked list of allocated memory chunks for type casted params.
|
1045
|
+
* Used when the memory_pool is to small.
|
1046
|
+
*/
|
1047
|
+
VALUE typecast_heap_chain;
|
992
1048
|
|
993
|
-
|
994
|
-
|
995
|
-
|
996
|
-
}
|
997
|
-
else {
|
998
|
-
Check_Type(param_value, T_STRING);
|
999
|
-
/* make sure param_value doesn't get freed by the GC */
|
1000
|
-
rb_ary_push(gc_array, param_value);
|
1001
|
-
paramValues[i] = StringValuePtr(param_value);
|
1002
|
-
paramLengths[i] = (int)RSTRING_LEN(param_value);
|
1003
|
-
}
|
1049
|
+
/* This memory pool is used to place above query function parameters on it. */
|
1050
|
+
char memory_pool[QUERYDATA_BUFFER_SIZE];
|
1051
|
+
};
|
1004
1052
|
|
1005
|
-
|
1006
|
-
|
1007
|
-
|
1008
|
-
|
1053
|
+
static void
|
1054
|
+
free_typecast_heap_chain(struct linked_typecast_data *chain_entry)
|
1055
|
+
{
|
1056
|
+
while(chain_entry){
|
1057
|
+
struct linked_typecast_data *next = chain_entry->next;
|
1058
|
+
xfree(chain_entry);
|
1059
|
+
chain_entry = next;
|
1009
1060
|
}
|
1061
|
+
}
|
1010
1062
|
|
1011
|
-
|
1012
|
-
|
1063
|
+
static char *
|
1064
|
+
alloc_typecast_buf( VALUE *typecast_heap_chain, int len )
|
1065
|
+
{
|
1066
|
+
/* Allocate a new memory chunk from heap */
|
1067
|
+
struct linked_typecast_data *allocated =
|
1068
|
+
(struct linked_typecast_data *)xmalloc(sizeof(struct linked_typecast_data) + len);
|
1069
|
+
|
1070
|
+
/* Did we already wrap a memory chain per T_DATA object? */
|
1071
|
+
if( NIL_P( *typecast_heap_chain ) ){
|
1072
|
+
/* Leave free'ing of the buffer chain to the GC, when paramsData has left the stack */
|
1073
|
+
*typecast_heap_chain = Data_Wrap_Struct( rb_cObject, NULL, free_typecast_heap_chain, allocated );
|
1074
|
+
allocated->next = NULL;
|
1075
|
+
} else {
|
1076
|
+
/* Append to the chain */
|
1077
|
+
allocated->next = DATA_PTR( *typecast_heap_chain );
|
1078
|
+
DATA_PTR( *typecast_heap_chain ) = allocated;
|
1079
|
+
}
|
1013
1080
|
|
1014
|
-
|
1081
|
+
return &allocated->data[0];
|
1082
|
+
}
|
1015
1083
|
|
1016
|
-
xfree(paramTypes);
|
1017
|
-
xfree(paramValues);
|
1018
|
-
xfree(paramLengths);
|
1019
|
-
xfree(paramFormats);
|
1020
1084
|
|
1021
|
-
|
1022
|
-
|
1085
|
+
static int
|
1086
|
+
alloc_query_params(struct query_params_data *paramsData)
|
1087
|
+
{
|
1088
|
+
VALUE param_value;
|
1089
|
+
t_typemap *p_typemap;
|
1090
|
+
int nParams;
|
1091
|
+
int i=0;
|
1092
|
+
t_pg_coder *conv;
|
1093
|
+
unsigned int required_pool_size;
|
1094
|
+
char *memory_pool;
|
1095
|
+
|
1096
|
+
Check_Type(paramsData->params, T_ARRAY);
|
1097
|
+
|
1098
|
+
p_typemap = DATA_PTR( paramsData->typemap );
|
1099
|
+
p_typemap->funcs.fit_to_query( paramsData->typemap, paramsData->params );
|
1100
|
+
|
1101
|
+
paramsData->heap_pool = Qnil;
|
1102
|
+
paramsData->typecast_heap_chain = Qnil;
|
1103
|
+
paramsData->gc_array = Qnil;
|
1104
|
+
|
1105
|
+
nParams = (int)RARRAY_LEN(paramsData->params);
|
1106
|
+
|
1107
|
+
required_pool_size = nParams * (
|
1108
|
+
sizeof(char *) +
|
1109
|
+
sizeof(int) +
|
1110
|
+
sizeof(int) +
|
1111
|
+
(paramsData->with_types ? sizeof(Oid) : 0));
|
1112
|
+
|
1113
|
+
if( sizeof(paramsData->memory_pool) < required_pool_size ){
|
1114
|
+
/* Allocate one combined memory pool for all possible function parameters */
|
1115
|
+
memory_pool = (char*)xmalloc( required_pool_size );
|
1116
|
+
/* Leave free'ing of the buffer to the GC, when paramsData has left the stack */
|
1117
|
+
paramsData->heap_pool = Data_Wrap_Struct( rb_cObject, NULL, -1, memory_pool );
|
1118
|
+
required_pool_size = 0;
|
1119
|
+
}else{
|
1120
|
+
/* Use stack memory for function parameters */
|
1121
|
+
memory_pool = paramsData->memory_pool;
|
1122
|
+
}
|
1123
|
+
|
1124
|
+
paramsData->values = (char **)memory_pool;
|
1125
|
+
paramsData->lengths = (int *)((char*)paramsData->values + sizeof(char *) * nParams);
|
1126
|
+
paramsData->formats = (int *)((char*)paramsData->lengths + sizeof(int) * nParams);
|
1127
|
+
paramsData->types = (Oid *)((char*)paramsData->formats + sizeof(int) * nParams);
|
1128
|
+
|
1129
|
+
{
|
1130
|
+
char *typecast_buf = paramsData->memory_pool + required_pool_size;
|
1131
|
+
|
1132
|
+
for ( i = 0; i < nParams; i++ ) {
|
1133
|
+
param_value = rb_ary_entry(paramsData->params, i);
|
1134
|
+
|
1135
|
+
paramsData->formats[i] = 0;
|
1136
|
+
if( paramsData->with_types )
|
1137
|
+
paramsData->types[i] = 0;
|
1138
|
+
|
1139
|
+
/* Let the given typemap select a coder for this param */
|
1140
|
+
conv = p_typemap->funcs.typecast_query_param(p_typemap, param_value, i);
|
1141
|
+
|
1142
|
+
/* Using a coder object for the param_value? Then set it's format code and oid. */
|
1143
|
+
if( conv ){
|
1144
|
+
paramsData->formats[i] = conv->format;
|
1145
|
+
if( paramsData->with_types )
|
1146
|
+
paramsData->types[i] = conv->oid;
|
1147
|
+
} else {
|
1148
|
+
/* No coder, but got we a hash form for the query param?
|
1149
|
+
* Then take format code and oid from there. */
|
1150
|
+
if (TYPE(param_value) == T_HASH) {
|
1151
|
+
VALUE format_value = rb_hash_aref(param_value, sym_format);
|
1152
|
+
if( !NIL_P(format_value) )
|
1153
|
+
paramsData->formats[i] = NUM2INT(format_value);
|
1154
|
+
if( paramsData->with_types ){
|
1155
|
+
VALUE type_value = rb_hash_aref(param_value, sym_type);
|
1156
|
+
if( !NIL_P(type_value) )
|
1157
|
+
paramsData->types[i] = NUM2UINT(type_value);
|
1158
|
+
}
|
1159
|
+
param_value = rb_hash_aref(param_value, sym_value);
|
1160
|
+
}
|
1161
|
+
}
|
1162
|
+
|
1163
|
+
if( NIL_P(param_value) ){
|
1164
|
+
paramsData->values[i] = NULL;
|
1165
|
+
paramsData->lengths[i] = 0;
|
1166
|
+
} else {
|
1167
|
+
t_pg_coder_enc_func enc_func = pg_coder_enc_func( conv );
|
1168
|
+
VALUE intermediate;
|
1169
|
+
|
1170
|
+
/* 1st pass for retiving the required memory space */
|
1171
|
+
int len = enc_func(conv, param_value, NULL, &intermediate, paramsData->enc_idx);
|
1172
|
+
|
1173
|
+
if( len == -1 ){
|
1174
|
+
/* The intermediate value is a String that can be used directly. */
|
1175
|
+
|
1176
|
+
/* Ensure that the String object is zero terminated as expected by libpq. */
|
1177
|
+
if( paramsData->formats[i] == 0 )
|
1178
|
+
StringValueCStr(intermediate);
|
1179
|
+
/* In case a new string object was generated, make sure it doesn't get freed by the GC */
|
1180
|
+
if( intermediate != param_value ){
|
1181
|
+
if( NIL_P(paramsData->gc_array) )
|
1182
|
+
paramsData->gc_array = rb_ary_new();
|
1183
|
+
rb_ary_push(paramsData->gc_array, intermediate);
|
1184
|
+
}
|
1185
|
+
paramsData->values[i] = RSTRING_PTR(intermediate);
|
1186
|
+
paramsData->lengths[i] = RSTRING_LENINT(intermediate);
|
1187
|
+
|
1188
|
+
} else {
|
1189
|
+
/* Is the stack memory pool too small to take the type casted value? */
|
1190
|
+
if( sizeof(paramsData->memory_pool) < required_pool_size + len + 1){
|
1191
|
+
typecast_buf = alloc_typecast_buf( ¶msData->typecast_heap_chain, len + 1 );
|
1192
|
+
}
|
1193
|
+
|
1194
|
+
/* 2nd pass for writing the data to prepared buffer */
|
1195
|
+
len = enc_func(conv, param_value, typecast_buf, &intermediate, paramsData->enc_idx);
|
1196
|
+
paramsData->values[i] = typecast_buf;
|
1197
|
+
if( paramsData->formats[i] == 0 ){
|
1198
|
+
/* text format strings must be zero terminated and lengths are ignored */
|
1199
|
+
typecast_buf[len] = 0;
|
1200
|
+
typecast_buf += len + 1;
|
1201
|
+
required_pool_size += len + 1;
|
1202
|
+
} else {
|
1203
|
+
paramsData->lengths[i] = len;
|
1204
|
+
typecast_buf += len;
|
1205
|
+
required_pool_size += len;
|
1206
|
+
}
|
1207
|
+
}
|
1208
|
+
|
1209
|
+
RB_GC_GUARD(intermediate);
|
1210
|
+
}
|
1211
|
+
}
|
1212
|
+
}
|
1213
|
+
|
1214
|
+
return nParams;
|
1215
|
+
}
|
1216
|
+
|
1217
|
+
static void
|
1218
|
+
free_query_params(struct query_params_data *paramsData)
|
1219
|
+
{
|
1220
|
+
/* currently nothing to free */
|
1221
|
+
}
|
1222
|
+
|
1223
|
+
void
|
1224
|
+
pgconn_query_assign_typemap( VALUE self, struct query_params_data *paramsData )
|
1225
|
+
{
|
1226
|
+
if(NIL_P(paramsData->typemap)){
|
1227
|
+
/* Use default typemap for queries. It's type is checked when assigned. */
|
1228
|
+
paramsData->typemap = pg_get_connection(self)->type_map_for_queries;
|
1229
|
+
}else{
|
1230
|
+
/* Check type of method param */
|
1231
|
+
if ( !rb_obj_is_kind_of(paramsData->typemap, rb_cTypeMap) ) {
|
1232
|
+
rb_raise( rb_eTypeError, "wrong argument type %s (expected kind of PG::TypeMap)",
|
1233
|
+
rb_obj_classname( paramsData->typemap ) );
|
1234
|
+
}
|
1235
|
+
Check_Type( paramsData->typemap, T_DATA );
|
1236
|
+
}
|
1237
|
+
}
|
1238
|
+
|
1239
|
+
/*
|
1240
|
+
* call-seq:
|
1241
|
+
* conn.sync_exec_params(sql, params[, result_format[, type_map]] ) -> PG::Result
|
1242
|
+
* conn.sync_exec_params(sql, params[, result_format[, type_map]] ) {|pg_result| block }
|
1243
|
+
*
|
1244
|
+
* This function has the same behavior as #async_exec_params, but is implemented using the synchronous command processing API of libpq.
|
1245
|
+
* See #async_exec for the differences between the two API variants.
|
1246
|
+
* It's not recommended to use explicit sync or async variants but #exec_params instead, unless you have a good reason to do so.
|
1247
|
+
*/
|
1248
|
+
static VALUE
|
1249
|
+
pgconn_exec_params( int argc, VALUE *argv, VALUE self )
|
1250
|
+
{
|
1251
|
+
t_pg_connection *this = pg_get_connection_safe( self );
|
1252
|
+
PGresult *result = NULL;
|
1253
|
+
VALUE rb_pgresult;
|
1254
|
+
VALUE command, in_res_fmt;
|
1255
|
+
int nParams;
|
1256
|
+
int resultFormat;
|
1257
|
+
struct query_params_data paramsData = { this->enc_idx };
|
1258
|
+
|
1259
|
+
/* For compatibility we accept 1 to 4 parameters */
|
1260
|
+
rb_scan_args(argc, argv, "13", &command, ¶msData.params, &in_res_fmt, ¶msData.typemap);
|
1261
|
+
paramsData.with_types = 1;
|
1262
|
+
|
1263
|
+
/*
|
1264
|
+
* For backward compatibility no or +nil+ for the second parameter
|
1265
|
+
* is passed to #exec
|
1266
|
+
*/
|
1267
|
+
if ( NIL_P(paramsData.params) ) {
|
1268
|
+
pg_deprecated(1, ("forwarding exec_params to exec is deprecated"));
|
1269
|
+
return pgconn_exec( 1, argv, self );
|
1270
|
+
}
|
1271
|
+
pgconn_query_assign_typemap( self, ¶msData );
|
1272
|
+
|
1273
|
+
resultFormat = NIL_P(in_res_fmt) ? 0 : NUM2INT(in_res_fmt);
|
1274
|
+
nParams = alloc_query_params( ¶msData );
|
1275
|
+
|
1276
|
+
result = gvl_PQexecParams(this->pgconn, pg_cstr_enc(command, paramsData.enc_idx), nParams, paramsData.types,
|
1277
|
+
(const char * const *)paramsData.values, paramsData.lengths, paramsData.formats, resultFormat);
|
1278
|
+
|
1279
|
+
free_query_params( ¶msData );
|
1280
|
+
|
1281
|
+
rb_pgresult = pg_new_result(result, self);
|
1282
|
+
pg_result_check(rb_pgresult);
|
1023
1283
|
|
1024
1284
|
if (rb_block_given_p()) {
|
1025
1285
|
return rb_ensure(rb_yield, rb_pgresult, pg_result_clear, rb_pgresult);
|
@@ -1030,28 +1290,16 @@ pgconn_exec_params( int argc, VALUE *argv, VALUE self )
|
|
1030
1290
|
|
1031
1291
|
/*
|
1032
1292
|
* call-seq:
|
1033
|
-
* conn.
|
1034
|
-
*
|
1035
|
-
* Prepares statement _sql_ with name _name_ to be executed later.
|
1036
|
-
* Returns a PG::Result instance on success.
|
1037
|
-
* On failure, it raises a PG::Error.
|
1038
|
-
*
|
1039
|
-
* +param_types+ is an optional parameter to specify the Oids of the
|
1040
|
-
* types of the parameters.
|
1041
|
-
*
|
1042
|
-
* If the types are not specified, they will be inferred by PostgreSQL.
|
1043
|
-
* Instead of specifying type oids, it's recommended to simply add
|
1044
|
-
* explicit casts in the query to ensure that the right type is used.
|
1045
|
-
*
|
1046
|
-
* For example: "SELECT $1::int"
|
1293
|
+
* conn.sync_prepare(stmt_name, sql [, param_types ] ) -> PG::Result
|
1047
1294
|
*
|
1048
|
-
*
|
1049
|
-
*
|
1295
|
+
* This function has the same behavior as #async_prepare, but is implemented using the synchronous command processing API of libpq.
|
1296
|
+
* See #async_exec for the differences between the two API variants.
|
1297
|
+
* It's not recommended to use explicit sync or async variants but #prepare instead, unless you have a good reason to do so.
|
1050
1298
|
*/
|
1051
1299
|
static VALUE
|
1052
1300
|
pgconn_prepare(int argc, VALUE *argv, VALUE self)
|
1053
1301
|
{
|
1054
|
-
|
1302
|
+
t_pg_connection *this = pg_get_connection_safe( self );
|
1055
1303
|
PGresult *result = NULL;
|
1056
1304
|
VALUE rb_pgresult;
|
1057
1305
|
VALUE name, command, in_paramtypes;
|
@@ -1059,10 +1307,13 @@ pgconn_prepare(int argc, VALUE *argv, VALUE self)
|
|
1059
1307
|
int i = 0;
|
1060
1308
|
int nParams = 0;
|
1061
1309
|
Oid *paramTypes = NULL;
|
1310
|
+
const char *name_cstr;
|
1311
|
+
const char *command_cstr;
|
1312
|
+
int enc_idx = this->enc_idx;
|
1062
1313
|
|
1063
1314
|
rb_scan_args(argc, argv, "21", &name, &command, &in_paramtypes);
|
1064
|
-
|
1065
|
-
|
1315
|
+
name_cstr = pg_cstr_enc(name, enc_idx);
|
1316
|
+
command_cstr = pg_cstr_enc(command, enc_idx);
|
1066
1317
|
|
1067
1318
|
if(! NIL_P(in_paramtypes)) {
|
1068
1319
|
Check_Type(in_paramtypes, T_ARRAY);
|
@@ -1070,15 +1321,13 @@ pgconn_prepare(int argc, VALUE *argv, VALUE self)
|
|
1070
1321
|
paramTypes = ALLOC_N(Oid, nParams);
|
1071
1322
|
for(i = 0; i < nParams; i++) {
|
1072
1323
|
param = rb_ary_entry(in_paramtypes, i);
|
1073
|
-
Check_Type(param, T_FIXNUM);
|
1074
1324
|
if(param == Qnil)
|
1075
1325
|
paramTypes[i] = 0;
|
1076
1326
|
else
|
1077
|
-
paramTypes[i] =
|
1327
|
+
paramTypes[i] = NUM2UINT(param);
|
1078
1328
|
}
|
1079
1329
|
}
|
1080
|
-
result = gvl_PQprepare(
|
1081
|
-
nParams, paramTypes);
|
1330
|
+
result = gvl_PQprepare(this->pgconn, name_cstr, command_cstr, nParams, paramTypes);
|
1082
1331
|
|
1083
1332
|
xfree(paramTypes);
|
1084
1333
|
|
@@ -1089,122 +1338,40 @@ pgconn_prepare(int argc, VALUE *argv, VALUE self)
|
|
1089
1338
|
|
1090
1339
|
/*
|
1091
1340
|
* call-seq:
|
1092
|
-
* conn.
|
1093
|
-
* conn.
|
1094
|
-
*
|
1095
|
-
* Execute prepared named statement specified by _statement_name_.
|
1096
|
-
* Returns a PG::Result instance on success.
|
1097
|
-
* On failure, it raises a PG::Error.
|
1098
|
-
*
|
1099
|
-
* +params+ is an array of the optional bind parameters for the
|
1100
|
-
* SQL query. Each element of the +params+ array may be either:
|
1101
|
-
* a hash of the form:
|
1102
|
-
* {:value => String (value of bind parameter)
|
1103
|
-
* :format => Fixnum (0 for text, 1 for binary)
|
1104
|
-
* }
|
1105
|
-
* or, it may be a String. If it is a string, that is equivalent to the hash:
|
1106
|
-
* { :value => <string value>, :format => 0 }
|
1107
|
-
*
|
1108
|
-
* PostgreSQL bind parameters are represented as $1, $1, $2, etc.,
|
1109
|
-
* inside the SQL query. The 0th element of the +params+ array is bound
|
1110
|
-
* to $1, the 1st element is bound to $2, etc. +nil+ is treated as +NULL+.
|
1111
|
-
*
|
1112
|
-
* The optional +result_format+ should be 0 for text results, 1
|
1113
|
-
* for binary.
|
1341
|
+
* conn.sync_exec_prepared(statement_name [, params, result_format[, type_map]] ) -> PG::Result
|
1342
|
+
* conn.sync_exec_prepared(statement_name [, params, result_format[, type_map]] ) {|pg_result| block }
|
1114
1343
|
*
|
1115
|
-
*
|
1116
|
-
*
|
1117
|
-
*
|
1344
|
+
* This function has the same behavior as #async_exec_prepared, but is implemented using the synchronous command processing API of libpq.
|
1345
|
+
* See #async_exec for the differences between the two API variants.
|
1346
|
+
* It's not recommended to use explicit sync or async variants but #exec_prepared instead, unless you have a good reason to do so.
|
1118
1347
|
*/
|
1119
1348
|
static VALUE
|
1120
1349
|
pgconn_exec_prepared(int argc, VALUE *argv, VALUE self)
|
1121
1350
|
{
|
1122
|
-
|
1351
|
+
t_pg_connection *this = pg_get_connection_safe( self );
|
1123
1352
|
PGresult *result = NULL;
|
1124
1353
|
VALUE rb_pgresult;
|
1125
|
-
VALUE name,
|
1126
|
-
VALUE param, param_value, param_format;
|
1127
|
-
VALUE param_value_tmp;
|
1128
|
-
VALUE sym_value, sym_format;
|
1129
|
-
VALUE gc_array;
|
1130
|
-
int i = 0;
|
1354
|
+
VALUE name, in_res_fmt;
|
1131
1355
|
int nParams;
|
1132
|
-
char ** paramValues;
|
1133
|
-
int *paramLengths;
|
1134
|
-
int *paramFormats;
|
1135
1356
|
int resultFormat;
|
1357
|
+
struct query_params_data paramsData = { this->enc_idx };
|
1136
1358
|
|
1359
|
+
rb_scan_args(argc, argv, "13", &name, ¶msData.params, &in_res_fmt, ¶msData.typemap);
|
1360
|
+
paramsData.with_types = 0;
|
1137
1361
|
|
1138
|
-
|
1139
|
-
|
1140
|
-
|
1141
|
-
if(NIL_P(params)) {
|
1142
|
-
params = rb_ary_new2(0);
|
1143
|
-
resultFormat = 0;
|
1144
|
-
}
|
1145
|
-
else {
|
1146
|
-
Check_Type(params, T_ARRAY);
|
1147
|
-
}
|
1148
|
-
|
1149
|
-
if(NIL_P(in_res_fmt)) {
|
1150
|
-
resultFormat = 0;
|
1151
|
-
}
|
1152
|
-
else {
|
1153
|
-
resultFormat = NUM2INT(in_res_fmt);
|
1362
|
+
if(NIL_P(paramsData.params)) {
|
1363
|
+
paramsData.params = rb_ary_new2(0);
|
1154
1364
|
}
|
1365
|
+
pgconn_query_assign_typemap( self, ¶msData );
|
1155
1366
|
|
1156
|
-
|
1157
|
-
|
1158
|
-
sym_value = ID2SYM(rb_intern("value"));
|
1159
|
-
sym_format = ID2SYM(rb_intern("format"));
|
1160
|
-
nParams = (int)RARRAY_LEN(params);
|
1161
|
-
paramValues = ALLOC_N(char *, nParams);
|
1162
|
-
paramLengths = ALLOC_N(int, nParams);
|
1163
|
-
paramFormats = ALLOC_N(int, nParams);
|
1164
|
-
for(i = 0; i < nParams; i++) {
|
1165
|
-
param = rb_ary_entry(params, i);
|
1166
|
-
if (TYPE(param) == T_HASH) {
|
1167
|
-
param_value_tmp = rb_hash_aref(param, sym_value);
|
1168
|
-
if(param_value_tmp == Qnil)
|
1169
|
-
param_value = param_value_tmp;
|
1170
|
-
else
|
1171
|
-
param_value = rb_obj_as_string(param_value_tmp);
|
1172
|
-
param_format = rb_hash_aref(param, sym_format);
|
1173
|
-
}
|
1174
|
-
else {
|
1175
|
-
if(param == Qnil)
|
1176
|
-
param_value = param;
|
1177
|
-
else
|
1178
|
-
param_value = rb_obj_as_string(param);
|
1179
|
-
param_format = INT2NUM(0);
|
1180
|
-
}
|
1181
|
-
if(param_value == Qnil) {
|
1182
|
-
paramValues[i] = NULL;
|
1183
|
-
paramLengths[i] = 0;
|
1184
|
-
}
|
1185
|
-
else {
|
1186
|
-
Check_Type(param_value, T_STRING);
|
1187
|
-
/* make sure param_value doesn't get freed by the GC */
|
1188
|
-
rb_ary_push(gc_array, param_value);
|
1189
|
-
paramValues[i] = StringValuePtr(param_value);
|
1190
|
-
paramLengths[i] = (int)RSTRING_LEN(param_value);
|
1191
|
-
}
|
1192
|
-
|
1193
|
-
if(param_format == Qnil)
|
1194
|
-
paramFormats[i] = 0;
|
1195
|
-
else
|
1196
|
-
paramFormats[i] = NUM2INT(param_format);
|
1197
|
-
}
|
1367
|
+
resultFormat = NIL_P(in_res_fmt) ? 0 : NUM2INT(in_res_fmt);
|
1368
|
+
nParams = alloc_query_params( ¶msData );
|
1198
1369
|
|
1199
|
-
result = gvl_PQexecPrepared(
|
1200
|
-
(const char * const *)
|
1370
|
+
result = gvl_PQexecPrepared(this->pgconn, pg_cstr_enc(name, paramsData.enc_idx), nParams,
|
1371
|
+
(const char * const *)paramsData.values, paramsData.lengths, paramsData.formats,
|
1201
1372
|
resultFormat);
|
1202
1373
|
|
1203
|
-
|
1204
|
-
|
1205
|
-
xfree(paramValues);
|
1206
|
-
xfree(paramLengths);
|
1207
|
-
xfree(paramFormats);
|
1374
|
+
free_query_params( ¶msData );
|
1208
1375
|
|
1209
1376
|
rb_pgresult = pg_new_result(result, self);
|
1210
1377
|
pg_result_check(rb_pgresult);
|
@@ -1217,26 +1384,26 @@ pgconn_exec_prepared(int argc, VALUE *argv, VALUE self)
|
|
1217
1384
|
|
1218
1385
|
/*
|
1219
1386
|
* call-seq:
|
1220
|
-
* conn.
|
1387
|
+
* conn.sync_describe_prepared( statement_name ) -> PG::Result
|
1221
1388
|
*
|
1222
|
-
*
|
1223
|
-
*
|
1389
|
+
* This function has the same behavior as #async_describe_prepared, but is implemented using the synchronous command processing API of libpq.
|
1390
|
+
* See #async_exec for the differences between the two API variants.
|
1391
|
+
* It's not recommended to use explicit sync or async variants but #describe_prepared instead, unless you have a good reason to do so.
|
1224
1392
|
*/
|
1225
1393
|
static VALUE
|
1226
1394
|
pgconn_describe_prepared(VALUE self, VALUE stmt_name)
|
1227
1395
|
{
|
1228
1396
|
PGresult *result;
|
1229
1397
|
VALUE rb_pgresult;
|
1230
|
-
|
1231
|
-
char *stmt;
|
1232
|
-
if(stmt_name
|
1398
|
+
t_pg_connection *this = pg_get_connection_safe( self );
|
1399
|
+
const char *stmt;
|
1400
|
+
if(NIL_P(stmt_name)) {
|
1233
1401
|
stmt = NULL;
|
1234
1402
|
}
|
1235
1403
|
else {
|
1236
|
-
|
1237
|
-
stmt = StringValuePtr(stmt_name);
|
1404
|
+
stmt = pg_cstr_enc(stmt_name, this->enc_idx);
|
1238
1405
|
}
|
1239
|
-
result = gvl_PQdescribePrepared(
|
1406
|
+
result = gvl_PQdescribePrepared(this->pgconn, stmt);
|
1240
1407
|
rb_pgresult = pg_new_result(result, self);
|
1241
1408
|
pg_result_check(rb_pgresult);
|
1242
1409
|
return rb_pgresult;
|
@@ -1245,9 +1412,11 @@ pgconn_describe_prepared(VALUE self, VALUE stmt_name)
|
|
1245
1412
|
|
1246
1413
|
/*
|
1247
1414
|
* call-seq:
|
1248
|
-
* conn.
|
1415
|
+
* conn.sync_describe_portal( portal_name ) -> PG::Result
|
1249
1416
|
*
|
1250
|
-
*
|
1417
|
+
* This function has the same behavior as #async_describe_portal, but is implemented using the synchronous command processing API of libpq.
|
1418
|
+
* See #async_exec for the differences between the two API variants.
|
1419
|
+
* It's not recommended to use explicit sync or async variants but #describe_portal instead, unless you have a good reason to do so.
|
1251
1420
|
*/
|
1252
1421
|
static VALUE
|
1253
1422
|
pgconn_describe_portal(self, stmt_name)
|
@@ -1255,16 +1424,15 @@ pgconn_describe_portal(self, stmt_name)
|
|
1255
1424
|
{
|
1256
1425
|
PGresult *result;
|
1257
1426
|
VALUE rb_pgresult;
|
1258
|
-
|
1259
|
-
char *stmt;
|
1260
|
-
if(stmt_name
|
1427
|
+
t_pg_connection *this = pg_get_connection_safe( self );
|
1428
|
+
const char *stmt;
|
1429
|
+
if(NIL_P(stmt_name)) {
|
1261
1430
|
stmt = NULL;
|
1262
1431
|
}
|
1263
1432
|
else {
|
1264
|
-
|
1265
|
-
stmt = StringValuePtr(stmt_name);
|
1433
|
+
stmt = pg_cstr_enc(stmt_name, this->enc_idx);
|
1266
1434
|
}
|
1267
|
-
result = gvl_PQdescribePortal(
|
1435
|
+
result = gvl_PQdescribePortal(this->pgconn, stmt);
|
1268
1436
|
rb_pgresult = pg_new_result(result, self);
|
1269
1437
|
pg_result_check(rb_pgresult);
|
1270
1438
|
return rb_pgresult;
|
@@ -1304,10 +1472,6 @@ pgconn_make_empty_pgresult(VALUE self, VALUE status)
|
|
1304
1472
|
* call-seq:
|
1305
1473
|
* conn.escape_string( str ) -> String
|
1306
1474
|
*
|
1307
|
-
* Connection instance method for versions of 8.1 and higher of libpq
|
1308
|
-
* uses PQescapeStringConn, which is safer. Avoid calling as a class method,
|
1309
|
-
* the class method uses the deprecated PQescapeString() API function.
|
1310
|
-
*
|
1311
1475
|
* Returns a SQL-safe version of the String _str_.
|
1312
1476
|
* This is the preferred way to make strings safe for inclusion in
|
1313
1477
|
* SQL queries.
|
@@ -1315,44 +1479,43 @@ pgconn_make_empty_pgresult(VALUE self, VALUE status)
|
|
1315
1479
|
* Consider using exec_params, which avoids the need for passing values
|
1316
1480
|
* inside of SQL commands.
|
1317
1481
|
*
|
1318
|
-
*
|
1482
|
+
* Character encoding of escaped string will be equal to client encoding of connection.
|
1483
|
+
*
|
1484
|
+
* NOTE: This class version of this method can only be used safely in client
|
1485
|
+
* programs that use a single PostgreSQL connection at a time (in this case it can
|
1486
|
+
* find out what it needs to know "behind the scenes"). It might give the wrong
|
1487
|
+
* results if used in programs that use multiple database connections; use the
|
1488
|
+
* same method on the connection object in such cases.
|
1489
|
+
*
|
1490
|
+
* See also convenience functions #escape_literal and #escape_identifier which also add proper quotes around the string.
|
1319
1491
|
*/
|
1320
1492
|
static VALUE
|
1321
1493
|
pgconn_s_escape(VALUE self, VALUE string)
|
1322
1494
|
{
|
1323
|
-
char *escaped;
|
1324
1495
|
size_t size;
|
1325
1496
|
int error;
|
1326
1497
|
VALUE result;
|
1327
|
-
|
1328
|
-
|
1329
|
-
#endif
|
1498
|
+
int enc_idx;
|
1499
|
+
int singleton = !rb_obj_is_kind_of(self, rb_cPGconn);
|
1330
1500
|
|
1331
|
-
|
1501
|
+
StringValueCStr(string);
|
1502
|
+
enc_idx = singleton ? ENCODING_GET(string) : pg_get_connection(self)->enc_idx;
|
1503
|
+
if( ENCODING_GET(string) != enc_idx ){
|
1504
|
+
string = rb_str_export_to_enc(string, rb_enc_from_index(enc_idx));
|
1505
|
+
}
|
1332
1506
|
|
1333
|
-
|
1334
|
-
|
1335
|
-
|
1507
|
+
result = rb_str_new(NULL, RSTRING_LEN(string) * 2 + 1);
|
1508
|
+
PG_ENCODING_SET_NOCHECK(result, enc_idx);
|
1509
|
+
if( !singleton ) {
|
1510
|
+
size = PQescapeStringConn(pg_get_pgconn(self), RSTRING_PTR(result),
|
1336
1511
|
RSTRING_PTR(string), RSTRING_LEN(string), &error);
|
1337
1512
|
if(error) {
|
1338
|
-
xfree(escaped);
|
1339
1513
|
rb_raise(rb_ePGerror, "%s", PQerrorMessage(pg_get_pgconn(self)));
|
1340
1514
|
}
|
1341
1515
|
} else {
|
1342
|
-
size = PQescapeString(
|
1516
|
+
size = PQescapeString(RSTRING_PTR(result), RSTRING_PTR(string), RSTRING_LEN(string));
|
1343
1517
|
}
|
1344
|
-
result
|
1345
|
-
xfree(escaped);
|
1346
|
-
OBJ_INFECT(result, string);
|
1347
|
-
|
1348
|
-
#ifdef M17N_SUPPORTED
|
1349
|
-
if ( rb_obj_class(self) == rb_cPGconn ) {
|
1350
|
-
enc = pg_conn_enc_get( pg_get_pgconn(self) );
|
1351
|
-
} else {
|
1352
|
-
enc = rb_enc_get(string);
|
1353
|
-
}
|
1354
|
-
rb_enc_associate(result, enc);
|
1355
|
-
#endif
|
1518
|
+
rb_str_set_len(result, size);
|
1356
1519
|
|
1357
1520
|
return result;
|
1358
1521
|
}
|
@@ -1361,13 +1524,6 @@ pgconn_s_escape(VALUE self, VALUE string)
|
|
1361
1524
|
* call-seq:
|
1362
1525
|
* conn.escape_bytea( string ) -> String
|
1363
1526
|
*
|
1364
|
-
* Connection instance method for versions of 8.1 and higher of libpq
|
1365
|
-
* uses PQescapeByteaConn, which is safer. Avoid calling as a class method,
|
1366
|
-
* the class method uses the deprecated PQescapeBytea() API function.
|
1367
|
-
*
|
1368
|
-
* Use the instance method version of this function, it is safer than the
|
1369
|
-
* class method.
|
1370
|
-
*
|
1371
1527
|
* Escapes binary data for use within an SQL command with the type +bytea+.
|
1372
1528
|
*
|
1373
1529
|
* Certain byte values must be escaped (but all byte values may be escaped)
|
@@ -1380,6 +1536,12 @@ pgconn_s_escape(VALUE self, VALUE string)
|
|
1380
1536
|
*
|
1381
1537
|
* Consider using exec_params, which avoids the need for passing values inside of
|
1382
1538
|
* SQL commands.
|
1539
|
+
*
|
1540
|
+
* NOTE: This class version of this method can only be used safely in client
|
1541
|
+
* programs that use a single PostgreSQL connection at a time (in this case it can
|
1542
|
+
* find out what it needs to know "behind the scenes"). It might give the wrong
|
1543
|
+
* results if used in programs that use multiple database connections; use the
|
1544
|
+
* same method on the connection object in such cases.
|
1383
1545
|
*/
|
1384
1546
|
static VALUE
|
1385
1547
|
pgconn_s_escape_bytea(VALUE self, VALUE str)
|
@@ -1392,14 +1554,13 @@ pgconn_s_escape_bytea(VALUE self, VALUE str)
|
|
1392
1554
|
from = (unsigned char*)RSTRING_PTR(str);
|
1393
1555
|
from_len = RSTRING_LEN(str);
|
1394
1556
|
|
1395
|
-
if(
|
1557
|
+
if ( rb_obj_is_kind_of(self, rb_cPGconn) ) {
|
1396
1558
|
to = PQescapeByteaConn(pg_get_pgconn(self), from, from_len, &to_len);
|
1397
1559
|
} else {
|
1398
1560
|
to = PQescapeBytea( from, from_len, &to_len);
|
1399
1561
|
}
|
1400
1562
|
|
1401
1563
|
ret = rb_str_new((char*)to, to_len - 1);
|
1402
|
-
OBJ_INFECT(ret, str);
|
1403
1564
|
PQfreemem(to);
|
1404
1565
|
return ret;
|
1405
1566
|
}
|
@@ -1424,94 +1585,91 @@ pgconn_s_unescape_bytea(VALUE self, VALUE str)
|
|
1424
1585
|
UNUSED( self );
|
1425
1586
|
|
1426
1587
|
Check_Type(str, T_STRING);
|
1427
|
-
from = (unsigned char*)
|
1588
|
+
from = (unsigned char*)StringValueCStr(str);
|
1428
1589
|
|
1429
1590
|
to = PQunescapeBytea(from, &to_len);
|
1430
1591
|
|
1431
1592
|
ret = rb_str_new((char*)to, to_len);
|
1432
|
-
OBJ_INFECT(ret, str);
|
1433
1593
|
PQfreemem(to);
|
1434
1594
|
return ret;
|
1435
1595
|
}
|
1436
1596
|
|
1437
|
-
#ifdef HAVE_PQESCAPELITERAL
|
1438
1597
|
/*
|
1439
1598
|
* call-seq:
|
1440
1599
|
* conn.escape_literal( str ) -> String
|
1441
1600
|
*
|
1442
1601
|
* Escape an arbitrary String +str+ as a literal.
|
1602
|
+
*
|
1603
|
+
* See also PG::TextEncoder::QuotedLiteral for a type cast integrated version of this function.
|
1443
1604
|
*/
|
1444
1605
|
static VALUE
|
1445
1606
|
pgconn_escape_literal(VALUE self, VALUE string)
|
1446
1607
|
{
|
1447
|
-
|
1608
|
+
t_pg_connection *this = pg_get_connection_safe( self );
|
1448
1609
|
char *escaped = NULL;
|
1449
1610
|
VALUE error;
|
1450
1611
|
VALUE result = Qnil;
|
1612
|
+
int enc_idx = this->enc_idx;
|
1451
1613
|
|
1452
|
-
|
1614
|
+
StringValueCStr(string);
|
1615
|
+
if( ENCODING_GET(string) != enc_idx ){
|
1616
|
+
string = rb_str_export_to_enc(string, rb_enc_from_index(enc_idx));
|
1617
|
+
}
|
1453
1618
|
|
1454
|
-
escaped = PQescapeLiteral(
|
1619
|
+
escaped = PQescapeLiteral(this->pgconn, RSTRING_PTR(string), RSTRING_LEN(string));
|
1455
1620
|
if (escaped == NULL)
|
1456
1621
|
{
|
1457
|
-
error = rb_exc_new2(rb_ePGerror, PQerrorMessage(
|
1622
|
+
error = rb_exc_new2(rb_ePGerror, PQerrorMessage(this->pgconn));
|
1458
1623
|
rb_iv_set(error, "@connection", self);
|
1459
1624
|
rb_exc_raise(error);
|
1460
1625
|
return Qnil;
|
1461
1626
|
}
|
1462
1627
|
result = rb_str_new2(escaped);
|
1463
1628
|
PQfreemem(escaped);
|
1464
|
-
|
1465
|
-
|
1466
|
-
#ifdef M17N_SUPPORTED
|
1467
|
-
rb_enc_associate(result, pg_conn_enc_get( pg_get_pgconn(self) ));
|
1468
|
-
#endif
|
1629
|
+
PG_ENCODING_SET_NOCHECK(result, enc_idx);
|
1469
1630
|
|
1470
1631
|
return result;
|
1471
1632
|
}
|
1472
|
-
#endif
|
1473
1633
|
|
1474
|
-
#ifdef HAVE_PQESCAPEIDENTIFIER
|
1475
1634
|
/*
|
1476
1635
|
* call-seq:
|
1477
1636
|
* conn.escape_identifier( str ) -> String
|
1478
1637
|
*
|
1479
1638
|
* Escape an arbitrary String +str+ as an identifier.
|
1480
1639
|
*
|
1481
|
-
* This method does the same as #quote_ident
|
1482
|
-
*
|
1640
|
+
* This method does the same as #quote_ident with a String argument,
|
1641
|
+
* but it doesn't support an Array argument and it makes use of libpq
|
1642
|
+
* to process the string.
|
1483
1643
|
*/
|
1484
1644
|
static VALUE
|
1485
1645
|
pgconn_escape_identifier(VALUE self, VALUE string)
|
1486
1646
|
{
|
1487
|
-
|
1647
|
+
t_pg_connection *this = pg_get_connection_safe( self );
|
1488
1648
|
char *escaped = NULL;
|
1489
1649
|
VALUE error;
|
1490
1650
|
VALUE result = Qnil;
|
1651
|
+
int enc_idx = this->enc_idx;
|
1491
1652
|
|
1492
|
-
|
1653
|
+
StringValueCStr(string);
|
1654
|
+
if( ENCODING_GET(string) != enc_idx ){
|
1655
|
+
string = rb_str_export_to_enc(string, rb_enc_from_index(enc_idx));
|
1656
|
+
}
|
1493
1657
|
|
1494
|
-
escaped = PQescapeIdentifier(
|
1658
|
+
escaped = PQescapeIdentifier(this->pgconn, RSTRING_PTR(string), RSTRING_LEN(string));
|
1495
1659
|
if (escaped == NULL)
|
1496
1660
|
{
|
1497
|
-
error = rb_exc_new2(rb_ePGerror, PQerrorMessage(
|
1661
|
+
error = rb_exc_new2(rb_ePGerror, PQerrorMessage(this->pgconn));
|
1498
1662
|
rb_iv_set(error, "@connection", self);
|
1499
1663
|
rb_exc_raise(error);
|
1500
1664
|
return Qnil;
|
1501
1665
|
}
|
1502
1666
|
result = rb_str_new2(escaped);
|
1503
1667
|
PQfreemem(escaped);
|
1504
|
-
|
1505
|
-
|
1506
|
-
#ifdef M17N_SUPPORTED
|
1507
|
-
rb_enc_associate(result, pg_conn_enc_get( pg_get_pgconn(self) ));
|
1508
|
-
#endif
|
1668
|
+
PG_ENCODING_SET_NOCHECK(result, enc_idx);
|
1509
1669
|
|
1510
1670
|
return result;
|
1511
1671
|
}
|
1512
|
-
#endif
|
1513
1672
|
|
1514
|
-
#ifdef HAVE_PQSETSINGLEROWMODE
|
1515
1673
|
/*
|
1516
1674
|
* call-seq:
|
1517
1675
|
* conn.set_single_row_mode -> self
|
@@ -1522,7 +1680,7 @@ pgconn_escape_identifier(VALUE self, VALUE string)
|
|
1522
1680
|
* Then call Connection#get_result repeatedly, until it returns nil.
|
1523
1681
|
*
|
1524
1682
|
* Each (but the last) received Result has exactly one row and a
|
1525
|
-
* Result#result_status of PGRES_SINGLE_TUPLE. The last
|
1683
|
+
* Result#result_status of PGRES_SINGLE_TUPLE. The last Result has
|
1526
1684
|
* zero rows and is used to indicate a successful execution of the query.
|
1527
1685
|
* All of these Result objects will contain the same row description data
|
1528
1686
|
* (column names, types, etc) that an ordinary Result object for the query
|
@@ -1547,7 +1705,6 @@ pgconn_escape_identifier(VALUE self, VALUE string)
|
|
1547
1705
|
* # do something with the received row
|
1548
1706
|
* end
|
1549
1707
|
* end
|
1550
|
-
*
|
1551
1708
|
*/
|
1552
1709
|
static VALUE
|
1553
1710
|
pgconn_set_single_row_mode(VALUE self)
|
@@ -1564,22 +1721,60 @@ pgconn_set_single_row_mode(VALUE self)
|
|
1564
1721
|
|
1565
1722
|
return self;
|
1566
1723
|
}
|
1567
|
-
|
1724
|
+
|
1725
|
+
static VALUE pgconn_send_query_params(int argc, VALUE *argv, VALUE self);
|
1726
|
+
|
1727
|
+
/*
|
1728
|
+
* call-seq:
|
1729
|
+
* conn.send_query(sql) -> nil
|
1730
|
+
*
|
1731
|
+
* Sends SQL query request specified by _sql_ to PostgreSQL for
|
1732
|
+
* asynchronous processing, and immediately returns.
|
1733
|
+
* On failure, it raises a PG::Error.
|
1734
|
+
*
|
1735
|
+
* For backward compatibility, if you pass more than one parameter to this method,
|
1736
|
+
* it will call #send_query_params for you. New code should explicitly use #send_query_params if
|
1737
|
+
* argument placeholders are used.
|
1738
|
+
*
|
1739
|
+
*/
|
1740
|
+
static VALUE
|
1741
|
+
pgconn_send_query(int argc, VALUE *argv, VALUE self)
|
1742
|
+
{
|
1743
|
+
t_pg_connection *this = pg_get_connection_safe( self );
|
1744
|
+
VALUE error;
|
1745
|
+
|
1746
|
+
/* If called with no or nil parameters, use PQexec for compatibility */
|
1747
|
+
if ( argc == 1 || (argc >= 2 && argc <= 4 && NIL_P(argv[1]) )) {
|
1748
|
+
if(gvl_PQsendQuery(this->pgconn, pg_cstr_enc(argv[0], this->enc_idx)) == 0) {
|
1749
|
+
error = rb_exc_new2(rb_eUnableToSend, PQerrorMessage(this->pgconn));
|
1750
|
+
rb_iv_set(error, "@connection", self);
|
1751
|
+
rb_exc_raise(error);
|
1752
|
+
}
|
1753
|
+
return Qnil;
|
1754
|
+
}
|
1755
|
+
|
1756
|
+
pg_deprecated(2, ("forwarding async_exec to async_exec_params and send_query to send_query_params is deprecated"));
|
1757
|
+
|
1758
|
+
/* If called with parameters, and optionally result_format,
|
1759
|
+
* use PQsendQueryParams
|
1760
|
+
*/
|
1761
|
+
return pgconn_send_query_params( argc, argv, self);
|
1762
|
+
}
|
1568
1763
|
|
1569
1764
|
/*
|
1570
1765
|
* call-seq:
|
1571
|
-
* conn.
|
1766
|
+
* conn.send_query_params(sql, params [, result_format [, type_map ]] ) -> nil
|
1572
1767
|
*
|
1573
1768
|
* Sends SQL query request specified by _sql_ to PostgreSQL for
|
1574
1769
|
* asynchronous processing, and immediately returns.
|
1575
1770
|
* On failure, it raises a PG::Error.
|
1576
1771
|
*
|
1577
|
-
* +params+ is an
|
1772
|
+
* +params+ is an array of the bind parameters for the SQL query.
|
1578
1773
|
* Each element of the +params+ array may be either:
|
1579
1774
|
* a hash of the form:
|
1580
1775
|
* {:value => String (value of bind parameter)
|
1581
|
-
* :type =>
|
1582
|
-
* :format =>
|
1776
|
+
* :type => Integer (oid of type of bind parameter)
|
1777
|
+
* :format => Integer (0 for text, 1 for binary)
|
1583
1778
|
* }
|
1584
1779
|
* or, it may be a String. If it is a string, that is equivalent to the hash:
|
1585
1780
|
* { :value => <string value>, :type => 0, :format => 0 }
|
@@ -1596,116 +1791,39 @@ pgconn_set_single_row_mode(VALUE self)
|
|
1596
1791
|
*
|
1597
1792
|
* The optional +result_format+ should be 0 for text results, 1
|
1598
1793
|
* for binary.
|
1794
|
+
*
|
1795
|
+
* +type_map+ can be a PG::TypeMap derivation (such as PG::BasicTypeMapForQueries).
|
1796
|
+
* This will type cast the params from various Ruby types before transmission
|
1797
|
+
* based on the encoders defined by the type map. When a type encoder is used
|
1798
|
+
* the format and oid of a given bind parameter are retrieved from the encoder
|
1799
|
+
* instead out of the hash form described above.
|
1800
|
+
*
|
1599
1801
|
*/
|
1600
1802
|
static VALUE
|
1601
|
-
|
1803
|
+
pgconn_send_query_params(int argc, VALUE *argv, VALUE self)
|
1602
1804
|
{
|
1603
|
-
|
1805
|
+
t_pg_connection *this = pg_get_connection_safe( self );
|
1604
1806
|
int result;
|
1605
|
-
VALUE command,
|
1606
|
-
VALUE param, param_type, param_value, param_format;
|
1607
|
-
VALUE param_value_tmp;
|
1608
|
-
VALUE sym_type, sym_value, sym_format;
|
1609
|
-
VALUE gc_array;
|
1807
|
+
VALUE command, in_res_fmt;
|
1610
1808
|
VALUE error;
|
1611
|
-
int i=0;
|
1612
1809
|
int nParams;
|
1613
|
-
Oid *paramTypes;
|
1614
|
-
char ** paramValues;
|
1615
|
-
int *paramLengths;
|
1616
|
-
int *paramFormats;
|
1617
1810
|
int resultFormat;
|
1811
|
+
struct query_params_data paramsData = { this->enc_idx };
|
1618
1812
|
|
1619
|
-
rb_scan_args(argc, argv, "
|
1620
|
-
|
1621
|
-
|
1622
|
-
/* If called with no parameters, use PQsendQuery */
|
1623
|
-
if(NIL_P(params)) {
|
1624
|
-
if(gvl_PQsendQuery(conn,StringValuePtr(command)) == 0) {
|
1625
|
-
error = rb_exc_new2(rb_eUnableToSend, PQerrorMessage(conn));
|
1626
|
-
rb_iv_set(error, "@connection", self);
|
1627
|
-
rb_exc_raise(error);
|
1628
|
-
}
|
1629
|
-
return Qnil;
|
1630
|
-
}
|
1631
|
-
|
1632
|
-
/* If called with parameters, and optionally result_format,
|
1633
|
-
* use PQsendQueryParams
|
1634
|
-
*/
|
1635
|
-
Check_Type(params, T_ARRAY);
|
1636
|
-
|
1637
|
-
if(NIL_P(in_res_fmt)) {
|
1638
|
-
resultFormat = 0;
|
1639
|
-
}
|
1640
|
-
else {
|
1641
|
-
resultFormat = NUM2INT(in_res_fmt);
|
1642
|
-
}
|
1643
|
-
|
1644
|
-
gc_array = rb_ary_new();
|
1645
|
-
rb_gc_register_address(&gc_array);
|
1646
|
-
sym_type = ID2SYM(rb_intern("type"));
|
1647
|
-
sym_value = ID2SYM(rb_intern("value"));
|
1648
|
-
sym_format = ID2SYM(rb_intern("format"));
|
1649
|
-
nParams = (int)RARRAY_LEN(params);
|
1650
|
-
paramTypes = ALLOC_N(Oid, nParams);
|
1651
|
-
paramValues = ALLOC_N(char *, nParams);
|
1652
|
-
paramLengths = ALLOC_N(int, nParams);
|
1653
|
-
paramFormats = ALLOC_N(int, nParams);
|
1654
|
-
for(i = 0; i < nParams; i++) {
|
1655
|
-
param = rb_ary_entry(params, i);
|
1656
|
-
if (TYPE(param) == T_HASH) {
|
1657
|
-
param_type = rb_hash_aref(param, sym_type);
|
1658
|
-
param_value_tmp = rb_hash_aref(param, sym_value);
|
1659
|
-
if(param_value_tmp == Qnil)
|
1660
|
-
param_value = param_value_tmp;
|
1661
|
-
else
|
1662
|
-
param_value = rb_obj_as_string(param_value_tmp);
|
1663
|
-
param_format = rb_hash_aref(param, sym_format);
|
1664
|
-
}
|
1665
|
-
else {
|
1666
|
-
param_type = INT2NUM(0);
|
1667
|
-
if(param == Qnil)
|
1668
|
-
param_value = param;
|
1669
|
-
else
|
1670
|
-
param_value = rb_obj_as_string(param);
|
1671
|
-
param_format = INT2NUM(0);
|
1672
|
-
}
|
1673
|
-
|
1674
|
-
if(param_type == Qnil)
|
1675
|
-
paramTypes[i] = 0;
|
1676
|
-
else
|
1677
|
-
paramTypes[i] = NUM2INT(param_type);
|
1813
|
+
rb_scan_args(argc, argv, "22", &command, ¶msData.params, &in_res_fmt, ¶msData.typemap);
|
1814
|
+
paramsData.with_types = 1;
|
1678
1815
|
|
1679
|
-
|
1680
|
-
|
1681
|
-
|
1682
|
-
}
|
1683
|
-
else {
|
1684
|
-
Check_Type(param_value, T_STRING);
|
1685
|
-
/* make sure param_value doesn't get freed by the GC */
|
1686
|
-
rb_ary_push(gc_array, param_value);
|
1687
|
-
paramValues[i] = StringValuePtr(param_value);
|
1688
|
-
paramLengths[i] = (int)RSTRING_LEN(param_value);
|
1689
|
-
}
|
1690
|
-
|
1691
|
-
if(param_format == Qnil)
|
1692
|
-
paramFormats[i] = 0;
|
1693
|
-
else
|
1694
|
-
paramFormats[i] = NUM2INT(param_format);
|
1695
|
-
}
|
1696
|
-
|
1697
|
-
result = gvl_PQsendQueryParams(conn, StringValuePtr(command), nParams, paramTypes,
|
1698
|
-
(const char * const *)paramValues, paramLengths, paramFormats, resultFormat);
|
1816
|
+
pgconn_query_assign_typemap( self, ¶msData );
|
1817
|
+
resultFormat = NIL_P(in_res_fmt) ? 0 : NUM2INT(in_res_fmt);
|
1818
|
+
nParams = alloc_query_params( ¶msData );
|
1699
1819
|
|
1700
|
-
|
1820
|
+
result = gvl_PQsendQueryParams(this->pgconn, pg_cstr_enc(command, paramsData.enc_idx), nParams, paramsData.types,
|
1821
|
+
(const char * const *)paramsData.values, paramsData.lengths, paramsData.formats, resultFormat);
|
1701
1822
|
|
1702
|
-
|
1703
|
-
xfree(paramValues);
|
1704
|
-
xfree(paramLengths);
|
1705
|
-
xfree(paramFormats);
|
1823
|
+
free_query_params( ¶msData );
|
1706
1824
|
|
1707
1825
|
if(result == 0) {
|
1708
|
-
error = rb_exc_new2(rb_eUnableToSend, PQerrorMessage(
|
1826
|
+
error = rb_exc_new2(rb_eUnableToSend, PQerrorMessage(this->pgconn));
|
1709
1827
|
rb_iv_set(error, "@connection", self);
|
1710
1828
|
rb_exc_raise(error);
|
1711
1829
|
}
|
@@ -1735,7 +1853,7 @@ pgconn_send_query(int argc, VALUE *argv, VALUE self)
|
|
1735
1853
|
static VALUE
|
1736
1854
|
pgconn_send_prepare(int argc, VALUE *argv, VALUE self)
|
1737
1855
|
{
|
1738
|
-
|
1856
|
+
t_pg_connection *this = pg_get_connection_safe( self );
|
1739
1857
|
int result;
|
1740
1858
|
VALUE name, command, in_paramtypes;
|
1741
1859
|
VALUE param;
|
@@ -1743,10 +1861,13 @@ pgconn_send_prepare(int argc, VALUE *argv, VALUE self)
|
|
1743
1861
|
int i = 0;
|
1744
1862
|
int nParams = 0;
|
1745
1863
|
Oid *paramTypes = NULL;
|
1864
|
+
const char *name_cstr;
|
1865
|
+
const char *command_cstr;
|
1866
|
+
int enc_idx = this->enc_idx;
|
1746
1867
|
|
1747
1868
|
rb_scan_args(argc, argv, "21", &name, &command, &in_paramtypes);
|
1748
|
-
|
1749
|
-
|
1869
|
+
name_cstr = pg_cstr_enc(name, enc_idx);
|
1870
|
+
command_cstr = pg_cstr_enc(command, enc_idx);
|
1750
1871
|
|
1751
1872
|
if(! NIL_P(in_paramtypes)) {
|
1752
1873
|
Check_Type(in_paramtypes, T_ARRAY);
|
@@ -1754,20 +1875,18 @@ pgconn_send_prepare(int argc, VALUE *argv, VALUE self)
|
|
1754
1875
|
paramTypes = ALLOC_N(Oid, nParams);
|
1755
1876
|
for(i = 0; i < nParams; i++) {
|
1756
1877
|
param = rb_ary_entry(in_paramtypes, i);
|
1757
|
-
Check_Type(param, T_FIXNUM);
|
1758
1878
|
if(param == Qnil)
|
1759
1879
|
paramTypes[i] = 0;
|
1760
1880
|
else
|
1761
|
-
paramTypes[i] =
|
1881
|
+
paramTypes[i] = NUM2UINT(param);
|
1762
1882
|
}
|
1763
1883
|
}
|
1764
|
-
result = gvl_PQsendPrepare(
|
1765
|
-
nParams, paramTypes);
|
1884
|
+
result = gvl_PQsendPrepare(this->pgconn, name_cstr, command_cstr, nParams, paramTypes);
|
1766
1885
|
|
1767
1886
|
xfree(paramTypes);
|
1768
1887
|
|
1769
1888
|
if(result == 0) {
|
1770
|
-
error = rb_exc_new2(rb_eUnableToSend, PQerrorMessage(
|
1889
|
+
error = rb_exc_new2(rb_eUnableToSend, PQerrorMessage(this->pgconn));
|
1771
1890
|
rb_iv_set(error, "@connection", self);
|
1772
1891
|
rb_exc_raise(error);
|
1773
1892
|
}
|
@@ -1776,7 +1895,7 @@ pgconn_send_prepare(int argc, VALUE *argv, VALUE self)
|
|
1776
1895
|
|
1777
1896
|
/*
|
1778
1897
|
* call-seq:
|
1779
|
-
* conn.send_query_prepared( statement_name [, params, result_format ] )
|
1898
|
+
* conn.send_query_prepared( statement_name [, params, result_format[, type_map ]] )
|
1780
1899
|
* -> nil
|
1781
1900
|
*
|
1782
1901
|
* Execute prepared named statement specified by _statement_name_
|
@@ -1787,7 +1906,7 @@ pgconn_send_prepare(int argc, VALUE *argv, VALUE self)
|
|
1787
1906
|
* SQL query. Each element of the +params+ array may be either:
|
1788
1907
|
* a hash of the form:
|
1789
1908
|
* {:value => String (value of bind parameter)
|
1790
|
-
* :format =>
|
1909
|
+
* :format => Integer (0 for text, 1 for binary)
|
1791
1910
|
* }
|
1792
1911
|
* or, it may be a String. If it is a string, that is equivalent to the hash:
|
1793
1912
|
* { :value => <string value>, :format => 0 }
|
@@ -1798,99 +1917,45 @@ pgconn_send_prepare(int argc, VALUE *argv, VALUE self)
|
|
1798
1917
|
*
|
1799
1918
|
* The optional +result_format+ should be 0 for text results, 1
|
1800
1919
|
* for binary.
|
1920
|
+
*
|
1921
|
+
* +type_map+ can be a PG::TypeMap derivation (such as PG::BasicTypeMapForQueries).
|
1922
|
+
* This will type cast the params from various Ruby types before transmission
|
1923
|
+
* based on the encoders defined by the type map. When a type encoder is used
|
1924
|
+
* the format and oid of a given bind parameter are retrieved from the encoder
|
1925
|
+
* instead out of the hash form described above.
|
1926
|
+
*
|
1801
1927
|
*/
|
1802
1928
|
static VALUE
|
1803
1929
|
pgconn_send_query_prepared(int argc, VALUE *argv, VALUE self)
|
1804
1930
|
{
|
1805
|
-
|
1931
|
+
t_pg_connection *this = pg_get_connection_safe( self );
|
1806
1932
|
int result;
|
1807
|
-
VALUE name,
|
1808
|
-
VALUE param, param_value, param_format;
|
1809
|
-
VALUE param_value_tmp;
|
1810
|
-
VALUE sym_value, sym_format;
|
1811
|
-
VALUE gc_array;
|
1933
|
+
VALUE name, in_res_fmt;
|
1812
1934
|
VALUE error;
|
1813
|
-
int i = 0;
|
1814
1935
|
int nParams;
|
1815
|
-
char ** paramValues;
|
1816
|
-
int *paramLengths;
|
1817
|
-
int *paramFormats;
|
1818
1936
|
int resultFormat;
|
1937
|
+
struct query_params_data paramsData = { this->enc_idx };
|
1819
1938
|
|
1820
|
-
rb_scan_args(argc, argv, "
|
1821
|
-
|
1822
|
-
|
1823
|
-
if(NIL_P(params)) {
|
1824
|
-
params = rb_ary_new2(0);
|
1825
|
-
resultFormat = 0;
|
1826
|
-
}
|
1827
|
-
else {
|
1828
|
-
Check_Type(params, T_ARRAY);
|
1829
|
-
}
|
1939
|
+
rb_scan_args(argc, argv, "13", &name, ¶msData.params, &in_res_fmt, ¶msData.typemap);
|
1940
|
+
paramsData.with_types = 0;
|
1830
1941
|
|
1831
|
-
if(NIL_P(
|
1942
|
+
if(NIL_P(paramsData.params)) {
|
1943
|
+
paramsData.params = rb_ary_new2(0);
|
1832
1944
|
resultFormat = 0;
|
1833
1945
|
}
|
1834
|
-
|
1835
|
-
resultFormat = NUM2INT(in_res_fmt);
|
1836
|
-
}
|
1837
|
-
|
1838
|
-
gc_array = rb_ary_new();
|
1839
|
-
rb_gc_register_address(&gc_array);
|
1840
|
-
sym_value = ID2SYM(rb_intern("value"));
|
1841
|
-
sym_format = ID2SYM(rb_intern("format"));
|
1842
|
-
nParams = (int)RARRAY_LEN(params);
|
1843
|
-
paramValues = ALLOC_N(char *, nParams);
|
1844
|
-
paramLengths = ALLOC_N(int, nParams);
|
1845
|
-
paramFormats = ALLOC_N(int, nParams);
|
1846
|
-
for(i = 0; i < nParams; i++) {
|
1847
|
-
param = rb_ary_entry(params, i);
|
1848
|
-
if (TYPE(param) == T_HASH) {
|
1849
|
-
param_value_tmp = rb_hash_aref(param, sym_value);
|
1850
|
-
if(param_value_tmp == Qnil)
|
1851
|
-
param_value = param_value_tmp;
|
1852
|
-
else
|
1853
|
-
param_value = rb_obj_as_string(param_value_tmp);
|
1854
|
-
param_format = rb_hash_aref(param, sym_format);
|
1855
|
-
}
|
1856
|
-
else {
|
1857
|
-
if(param == Qnil)
|
1858
|
-
param_value = param;
|
1859
|
-
else
|
1860
|
-
param_value = rb_obj_as_string(param);
|
1861
|
-
param_format = INT2NUM(0);
|
1862
|
-
}
|
1863
|
-
|
1864
|
-
if(param_value == Qnil) {
|
1865
|
-
paramValues[i] = NULL;
|
1866
|
-
paramLengths[i] = 0;
|
1867
|
-
}
|
1868
|
-
else {
|
1869
|
-
Check_Type(param_value, T_STRING);
|
1870
|
-
/* make sure param_value doesn't get freed by the GC */
|
1871
|
-
rb_ary_push(gc_array, param_value);
|
1872
|
-
paramValues[i] = StringValuePtr(param_value);
|
1873
|
-
paramLengths[i] = (int)RSTRING_LEN(param_value);
|
1874
|
-
}
|
1946
|
+
pgconn_query_assign_typemap( self, ¶msData );
|
1875
1947
|
|
1876
|
-
|
1877
|
-
|
1878
|
-
else
|
1879
|
-
paramFormats[i] = NUM2INT(param_format);
|
1880
|
-
}
|
1948
|
+
resultFormat = NIL_P(in_res_fmt) ? 0 : NUM2INT(in_res_fmt);
|
1949
|
+
nParams = alloc_query_params( ¶msData );
|
1881
1950
|
|
1882
|
-
result = gvl_PQsendQueryPrepared(
|
1883
|
-
(const char * const *)
|
1951
|
+
result = gvl_PQsendQueryPrepared(this->pgconn, pg_cstr_enc(name, paramsData.enc_idx), nParams,
|
1952
|
+
(const char * const *)paramsData.values, paramsData.lengths, paramsData.formats,
|
1884
1953
|
resultFormat);
|
1885
1954
|
|
1886
|
-
|
1887
|
-
|
1888
|
-
xfree(paramValues);
|
1889
|
-
xfree(paramLengths);
|
1890
|
-
xfree(paramFormats);
|
1955
|
+
free_query_params( ¶msData );
|
1891
1956
|
|
1892
1957
|
if(result == 0) {
|
1893
|
-
error = rb_exc_new2(rb_eUnableToSend, PQerrorMessage(
|
1958
|
+
error = rb_exc_new2(rb_eUnableToSend, PQerrorMessage(this->pgconn));
|
1894
1959
|
rb_iv_set(error, "@connection", self);
|
1895
1960
|
rb_exc_raise(error);
|
1896
1961
|
}
|
@@ -1908,10 +1973,10 @@ static VALUE
|
|
1908
1973
|
pgconn_send_describe_prepared(VALUE self, VALUE stmt_name)
|
1909
1974
|
{
|
1910
1975
|
VALUE error;
|
1911
|
-
|
1976
|
+
t_pg_connection *this = pg_get_connection_safe( self );
|
1912
1977
|
/* returns 0 on failure */
|
1913
|
-
if(gvl_PQsendDescribePrepared(
|
1914
|
-
error = rb_exc_new2(rb_eUnableToSend, PQerrorMessage(
|
1978
|
+
if(gvl_PQsendDescribePrepared(this->pgconn, pg_cstr_enc(stmt_name, this->enc_idx)) == 0) {
|
1979
|
+
error = rb_exc_new2(rb_eUnableToSend, PQerrorMessage(this->pgconn));
|
1915
1980
|
rb_iv_set(error, "@connection", self);
|
1916
1981
|
rb_exc_raise(error);
|
1917
1982
|
}
|
@@ -1930,10 +1995,10 @@ static VALUE
|
|
1930
1995
|
pgconn_send_describe_portal(VALUE self, VALUE portal)
|
1931
1996
|
{
|
1932
1997
|
VALUE error;
|
1933
|
-
|
1998
|
+
t_pg_connection *this = pg_get_connection_safe( self );
|
1934
1999
|
/* returns 0 on failure */
|
1935
|
-
if(gvl_PQsendDescribePortal(
|
1936
|
-
error = rb_exc_new2(rb_eUnableToSend, PQerrorMessage(
|
2000
|
+
if(gvl_PQsendDescribePortal(this->pgconn, pg_cstr_enc(portal, this->enc_idx)) == 0) {
|
2001
|
+
error = rb_exc_new2(rb_eUnableToSend, PQerrorMessage(this->pgconn));
|
1937
2002
|
rb_iv_set(error, "@connection", self);
|
1938
2003
|
rb_exc_raise(error);
|
1939
2004
|
}
|
@@ -2104,7 +2169,6 @@ pgconn_flush(self)
|
|
2104
2169
|
static VALUE
|
2105
2170
|
pgconn_cancel(VALUE self)
|
2106
2171
|
{
|
2107
|
-
#ifdef HAVE_PQGETCANCEL
|
2108
2172
|
char errbuf[256];
|
2109
2173
|
PGcancel *cancel;
|
2110
2174
|
VALUE retval;
|
@@ -2122,9 +2186,6 @@ pgconn_cancel(VALUE self)
|
|
2122
2186
|
|
2123
2187
|
PQfreeCancel(cancel);
|
2124
2188
|
return retval;
|
2125
|
-
#else
|
2126
|
-
rb_notimplement();
|
2127
|
-
#endif
|
2128
2189
|
}
|
2129
2190
|
|
2130
2191
|
|
@@ -2138,7 +2199,7 @@ pgconn_cancel(VALUE self)
|
|
2138
2199
|
static VALUE
|
2139
2200
|
pgconn_notifies(VALUE self)
|
2140
2201
|
{
|
2141
|
-
|
2202
|
+
t_pg_connection *this = pg_get_connection_safe( self );
|
2142
2203
|
PGnotify *notification;
|
2143
2204
|
VALUE hash;
|
2144
2205
|
VALUE sym_relname, sym_be_pid, sym_extra;
|
@@ -2148,19 +2209,17 @@ pgconn_notifies(VALUE self)
|
|
2148
2209
|
sym_be_pid = ID2SYM(rb_intern("be_pid"));
|
2149
2210
|
sym_extra = ID2SYM(rb_intern("extra"));
|
2150
2211
|
|
2151
|
-
notification = gvl_PQnotifies(
|
2212
|
+
notification = gvl_PQnotifies(this->pgconn);
|
2152
2213
|
if (notification == NULL) {
|
2153
2214
|
return Qnil;
|
2154
2215
|
}
|
2155
2216
|
|
2156
2217
|
hash = rb_hash_new();
|
2157
|
-
relname =
|
2218
|
+
relname = rb_str_new2(notification->relname);
|
2158
2219
|
be_pid = INT2NUM(notification->be_pid);
|
2159
|
-
extra =
|
2160
|
-
|
2161
|
-
|
2162
|
-
ENCODING_SET( extra, rb_enc_to_index(pg_conn_enc_get( conn )) );
|
2163
|
-
#endif
|
2220
|
+
extra = rb_str_new2(notification->extra);
|
2221
|
+
PG_ENCODING_SET_NOCHECK( relname, this->enc_idx );
|
2222
|
+
PG_ENCODING_SET_NOCHECK( extra, this->enc_idx );
|
2164
2223
|
|
2165
2224
|
rb_hash_aset(hash, sym_relname, relname);
|
2166
2225
|
rb_hash_aset(hash, sym_be_pid, be_pid);
|
@@ -2170,56 +2229,15 @@ pgconn_notifies(VALUE self)
|
|
2170
2229
|
return hash;
|
2171
2230
|
}
|
2172
2231
|
|
2173
|
-
/* Win32 + Ruby 1.8 */
|
2174
|
-
#if !defined( HAVE_RUBY_VM_H ) && defined( _WIN32 )
|
2175
|
-
|
2176
|
-
/*
|
2177
|
-
* Duplicate the sockets from libpq and create temporary CRT FDs
|
2178
|
-
*/
|
2179
|
-
void create_crt_fd(fd_set *os_set, fd_set *crt_set)
|
2180
|
-
{
|
2181
|
-
int i;
|
2182
|
-
crt_set->fd_count = os_set->fd_count;
|
2183
|
-
for (i = 0; i < os_set->fd_count; i++) {
|
2184
|
-
WSAPROTOCOL_INFO wsa_pi;
|
2185
|
-
/* dupicate the SOCKET */
|
2186
|
-
int r = WSADuplicateSocket(os_set->fd_array[i], GetCurrentProcessId(), &wsa_pi);
|
2187
|
-
SOCKET s = WSASocket(wsa_pi.iAddressFamily, wsa_pi.iSocketType, wsa_pi.iProtocol, &wsa_pi, 0, 0);
|
2188
|
-
/* create the CRT fd so ruby can get back to the SOCKET */
|
2189
|
-
int fd = _open_osfhandle(s, O_RDWR|O_BINARY);
|
2190
|
-
os_set->fd_array[i] = s;
|
2191
|
-
crt_set->fd_array[i] = fd;
|
2192
|
-
}
|
2193
|
-
}
|
2194
|
-
|
2195
|
-
/*
|
2196
|
-
* Clean up the CRT FDs from create_crt_fd()
|
2197
|
-
*/
|
2198
|
-
void cleanup_crt_fd(fd_set *os_set, fd_set *crt_set)
|
2199
|
-
{
|
2200
|
-
int i;
|
2201
|
-
for (i = 0; i < os_set->fd_count; i++) {
|
2202
|
-
/* cleanup the CRT fd */
|
2203
|
-
_close(crt_set->fd_array[i]);
|
2204
|
-
/* cleanup the duplicated SOCKET */
|
2205
|
-
closesocket(os_set->fd_array[i]);
|
2206
|
-
}
|
2207
|
-
}
|
2208
|
-
#endif
|
2209
|
-
|
2210
2232
|
/* Win32 + Ruby 1.9+ */
|
2211
|
-
#if defined(
|
2233
|
+
#if defined( _WIN32 )
|
2212
2234
|
/*
|
2213
2235
|
* On Windows, use platform-specific strategies to wait for the socket
|
2214
|
-
* instead of
|
2236
|
+
* instead of rb_wait_for_single_fd().
|
2215
2237
|
*/
|
2216
2238
|
|
2217
2239
|
int rb_w32_wait_events( HANDLE *events, int num, DWORD timeout );
|
2218
2240
|
|
2219
|
-
/* If WIN32 and Ruby 1.9 do not use rb_thread_select() which sometimes hangs
|
2220
|
-
* and does not wait (nor sleep) any time even if timeout is given.
|
2221
|
-
* Instead use the Winsock events and rb_w32_wait_events(). */
|
2222
|
-
|
2223
2241
|
static void *
|
2224
2242
|
wait_socket_readable( PGconn *conn, struct timeval *ptimeout, void *(*is_readable)(PGconn *) )
|
2225
2243
|
{
|
@@ -2296,7 +2314,7 @@ wait_socket_readable( PGconn *conn, struct timeval *ptimeout, void *(*is_readabl
|
|
2296
2314
|
|
2297
2315
|
#else
|
2298
2316
|
|
2299
|
-
/* non Win32
|
2317
|
+
/* non Win32 */
|
2300
2318
|
|
2301
2319
|
static void *
|
2302
2320
|
wait_socket_readable( PGconn *conn, struct timeval *ptimeout, void *(*is_readable)(PGconn *))
|
@@ -2304,11 +2322,7 @@ wait_socket_readable( PGconn *conn, struct timeval *ptimeout, void *(*is_readabl
|
|
2304
2322
|
int sd = PQsocket( conn );
|
2305
2323
|
int ret;
|
2306
2324
|
void *retval;
|
2307
|
-
rb_fdset_t sd_rset;
|
2308
2325
|
struct timeval aborttime={0,0}, currtime, waittime;
|
2309
|
-
#ifdef _WIN32
|
2310
|
-
rb_fdset_t crt_sd_rset;
|
2311
|
-
#endif
|
2312
2326
|
|
2313
2327
|
if ( sd < 0 )
|
2314
2328
|
rb_raise(rb_eConnectionBad, "PQsocket() can't get socket descriptor");
|
@@ -2317,25 +2331,12 @@ wait_socket_readable( PGconn *conn, struct timeval *ptimeout, void *(*is_readabl
|
|
2317
2331
|
if ( PQconsumeInput(conn) == 0 )
|
2318
2332
|
rb_raise( rb_eConnectionBad, "PQconsumeInput() %s", PQerrorMessage(conn) );
|
2319
2333
|
|
2320
|
-
rb_fd_init( &sd_rset );
|
2321
|
-
|
2322
2334
|
if ( ptimeout ) {
|
2323
2335
|
gettimeofday(&currtime, NULL);
|
2324
2336
|
timeradd(&currtime, ptimeout, &aborttime);
|
2325
2337
|
}
|
2326
2338
|
|
2327
2339
|
while ( !(retval=is_readable(conn)) ) {
|
2328
|
-
rb_fd_zero( &sd_rset );
|
2329
|
-
rb_fd_set( sd, &sd_rset );
|
2330
|
-
|
2331
|
-
#ifdef _WIN32
|
2332
|
-
/* Ruby's FD_SET is modified on win32 to convert a file descriptor
|
2333
|
-
* to osfhandle, but we already get a osfhandle from PQsocket().
|
2334
|
-
* Therefore it's overwritten here. */
|
2335
|
-
sd_rset.fd_array[0] = sd;
|
2336
|
-
create_crt_fd(&sd_rset, &crt_sd_rset);
|
2337
|
-
#endif
|
2338
|
-
|
2339
2340
|
if ( ptimeout ) {
|
2340
2341
|
gettimeofday(&currtime, NULL);
|
2341
2342
|
timersub(&aborttime, &currtime, &waittime);
|
@@ -2344,35 +2345,26 @@ wait_socket_readable( PGconn *conn, struct timeval *ptimeout, void *(*is_readabl
|
|
2344
2345
|
/* Is the given timeout valid? */
|
2345
2346
|
if( !ptimeout || (waittime.tv_sec >= 0 && waittime.tv_usec >= 0) ){
|
2346
2347
|
/* Wait for the socket to become readable before checking again */
|
2347
|
-
ret =
|
2348
|
+
ret = rb_wait_for_single_fd( sd, RB_WAITFD_IN, ptimeout ? &waittime : NULL );
|
2348
2349
|
} else {
|
2349
2350
|
ret = 0;
|
2350
2351
|
}
|
2351
2352
|
|
2352
|
-
|
2353
|
-
#ifdef _WIN32
|
2354
|
-
cleanup_crt_fd(&sd_rset, &crt_sd_rset);
|
2355
|
-
#endif
|
2356
|
-
|
2357
2353
|
if ( ret < 0 ){
|
2358
|
-
|
2359
|
-
rb_sys_fail( "rb_thread_select()" );
|
2354
|
+
rb_sys_fail( "rb_wait_for_single_fd()" );
|
2360
2355
|
}
|
2361
2356
|
|
2362
2357
|
/* Return false if the select() timed out */
|
2363
2358
|
if ( ret == 0 ){
|
2364
|
-
rb_fd_term( &sd_rset );
|
2365
2359
|
return NULL;
|
2366
2360
|
}
|
2367
2361
|
|
2368
2362
|
/* Check for connection errors (PQisBusy is true on connection errors) */
|
2369
2363
|
if ( PQconsumeInput(conn) == 0 ){
|
2370
|
-
rb_fd_term( &sd_rset );
|
2371
2364
|
rb_raise( rb_eConnectionBad, "PQconsumeInput() %s", PQerrorMessage(conn) );
|
2372
2365
|
}
|
2373
2366
|
}
|
2374
2367
|
|
2375
|
-
rb_fd_term( &sd_rset );
|
2376
2368
|
return retval;
|
2377
2369
|
}
|
2378
2370
|
|
@@ -2387,27 +2379,20 @@ notify_readable(PGconn *conn)
|
|
2387
2379
|
|
2388
2380
|
/*
|
2389
2381
|
* call-seq:
|
2390
|
-
* conn.wait_for_notify( [ timeout ] ) -> String
|
2391
|
-
* conn.wait_for_notify( [ timeout ] ) { |event, pid| block }
|
2392
|
-
* conn.wait_for_notify( [ timeout ] ) { |event, pid, payload| block } # PostgreSQL 9.0
|
2382
|
+
* conn.wait_for_notify( [ timeout ] ) { |event, pid, payload| block } -> String
|
2393
2383
|
*
|
2394
2384
|
* Blocks while waiting for notification(s), or until the optional
|
2395
2385
|
* _timeout_ is reached, whichever comes first. _timeout_ is
|
2396
2386
|
* measured in seconds and can be fractional.
|
2397
2387
|
*
|
2398
|
-
* Returns +nil+ if _timeout_ is reached, the name of the NOTIFY
|
2399
|
-
*
|
2400
|
-
*
|
2401
|
-
*
|
2402
|
-
* Under PostgreSQL 9.0 and later, if the notification is sent with
|
2403
|
-
* the optional +payload+ string, it will be given to the block as the
|
2404
|
-
* third argument.
|
2405
|
-
*
|
2388
|
+
* Returns +nil+ if _timeout_ is reached, the name of the NOTIFY event otherwise.
|
2389
|
+
* If used in block form, passes the name of the NOTIFY +event+, the generating
|
2390
|
+
* +pid+ and the optional +payload+ string into the block.
|
2406
2391
|
*/
|
2407
2392
|
static VALUE
|
2408
2393
|
pgconn_wait_for_notify(int argc, VALUE *argv, VALUE self)
|
2409
2394
|
{
|
2410
|
-
|
2395
|
+
t_pg_connection *this = pg_get_connection_safe( self );
|
2411
2396
|
PGnotify *pnotification;
|
2412
2397
|
struct timeval timeout;
|
2413
2398
|
struct timeval *ptimeout = NULL;
|
@@ -2423,24 +2408,18 @@ pgconn_wait_for_notify(int argc, VALUE *argv, VALUE self)
|
|
2423
2408
|
ptimeout = &timeout;
|
2424
2409
|
}
|
2425
2410
|
|
2426
|
-
pnotification = (PGnotify*) wait_socket_readable(
|
2411
|
+
pnotification = (PGnotify*) wait_socket_readable( this->pgconn, ptimeout, notify_readable);
|
2427
2412
|
|
2428
2413
|
/* Return nil if the select timed out */
|
2429
2414
|
if ( !pnotification ) return Qnil;
|
2430
2415
|
|
2431
|
-
relname =
|
2432
|
-
|
2433
|
-
ENCODING_SET( relname, rb_enc_to_index(pg_conn_enc_get( conn )) );
|
2434
|
-
#endif
|
2416
|
+
relname = rb_str_new2( pnotification->relname );
|
2417
|
+
PG_ENCODING_SET_NOCHECK( relname, this->enc_idx );
|
2435
2418
|
be_pid = INT2NUM( pnotification->be_pid );
|
2436
|
-
#ifdef HAVE_ST_NOTIFY_EXTRA
|
2437
2419
|
if ( *pnotification->extra ) {
|
2438
|
-
extra =
|
2439
|
-
|
2440
|
-
ENCODING_SET( extra, rb_enc_to_index(pg_conn_enc_get( conn )) );
|
2441
|
-
#endif
|
2420
|
+
extra = rb_str_new2( pnotification->extra );
|
2421
|
+
PG_ENCODING_SET_NOCHECK( extra, this->enc_idx );
|
2442
2422
|
}
|
2443
|
-
#endif
|
2444
2423
|
PQfreemem( pnotification );
|
2445
2424
|
|
2446
2425
|
if ( rb_block_given_p() )
|
@@ -2452,33 +2431,79 @@ pgconn_wait_for_notify(int argc, VALUE *argv, VALUE self)
|
|
2452
2431
|
|
2453
2432
|
/*
|
2454
2433
|
* call-seq:
|
2455
|
-
* conn.put_copy_data( buffer ) -> Boolean
|
2434
|
+
* conn.put_copy_data( buffer [, encoder] ) -> Boolean
|
2456
2435
|
*
|
2457
2436
|
* Transmits _buffer_ as copy data to the server.
|
2458
2437
|
* Returns true if the data was sent, false if it was
|
2459
2438
|
* not sent (false is only possible if the connection
|
2460
2439
|
* is in nonblocking mode, and this command would block).
|
2461
2440
|
*
|
2441
|
+
* _encoder_ can be a PG::Coder derivation (typically PG::TextEncoder::CopyRow).
|
2442
|
+
* This encodes the data fields given as _buffer_ from an Array of Strings to
|
2443
|
+
* PostgreSQL's COPY text format inclusive proper escaping. Optionally
|
2444
|
+
* the encoder can type cast the fields from various Ruby types in one step,
|
2445
|
+
* if PG::TextEncoder::CopyRow#type_map is set accordingly.
|
2446
|
+
*
|
2462
2447
|
* Raises an exception if an error occurs.
|
2463
2448
|
*
|
2464
2449
|
* See also #copy_data.
|
2465
2450
|
*
|
2466
2451
|
*/
|
2467
2452
|
static VALUE
|
2468
|
-
pgconn_put_copy_data(
|
2469
|
-
VALUE self, buffer;
|
2453
|
+
pgconn_put_copy_data(int argc, VALUE *argv, VALUE self)
|
2470
2454
|
{
|
2471
2455
|
int ret;
|
2472
|
-
|
2473
|
-
|
2456
|
+
int len;
|
2457
|
+
t_pg_connection *this = pg_get_connection_safe( self );
|
2458
|
+
VALUE value;
|
2459
|
+
VALUE buffer = Qnil;
|
2460
|
+
VALUE encoder;
|
2461
|
+
VALUE intermediate;
|
2462
|
+
t_pg_coder *p_coder = NULL;
|
2463
|
+
|
2464
|
+
rb_scan_args( argc, argv, "11", &value, &encoder );
|
2465
|
+
|
2466
|
+
if( NIL_P(encoder) ){
|
2467
|
+
if( NIL_P(this->encoder_for_put_copy_data) ){
|
2468
|
+
buffer = value;
|
2469
|
+
} else {
|
2470
|
+
p_coder = DATA_PTR( this->encoder_for_put_copy_data );
|
2471
|
+
}
|
2472
|
+
} else if( rb_obj_is_kind_of(encoder, rb_cPG_Coder) ) {
|
2473
|
+
Data_Get_Struct( encoder, t_pg_coder, p_coder );
|
2474
|
+
} else {
|
2475
|
+
rb_raise( rb_eTypeError, "wrong encoder type %s (expected some kind of PG::Coder)",
|
2476
|
+
rb_obj_classname( encoder ) );
|
2477
|
+
}
|
2478
|
+
|
2479
|
+
if( p_coder ){
|
2480
|
+
t_pg_coder_enc_func enc_func;
|
2481
|
+
int enc_idx = this->enc_idx;
|
2482
|
+
|
2483
|
+
enc_func = pg_coder_enc_func( p_coder );
|
2484
|
+
len = enc_func( p_coder, value, NULL, &intermediate, enc_idx);
|
2485
|
+
|
2486
|
+
if( len == -1 ){
|
2487
|
+
/* The intermediate value is a String that can be used directly. */
|
2488
|
+
buffer = intermediate;
|
2489
|
+
} else {
|
2490
|
+
buffer = rb_str_new(NULL, len);
|
2491
|
+
len = enc_func( p_coder, value, RSTRING_PTR(buffer), &intermediate, enc_idx);
|
2492
|
+
rb_str_set_len( buffer, len );
|
2493
|
+
}
|
2494
|
+
}
|
2495
|
+
|
2474
2496
|
Check_Type(buffer, T_STRING);
|
2475
2497
|
|
2476
|
-
ret = gvl_PQputCopyData(
|
2498
|
+
ret = gvl_PQputCopyData(this->pgconn, RSTRING_PTR(buffer), RSTRING_LENINT(buffer));
|
2477
2499
|
if(ret == -1) {
|
2478
|
-
error = rb_exc_new2(rb_ePGerror, PQerrorMessage(
|
2500
|
+
VALUE error = rb_exc_new2(rb_ePGerror, PQerrorMessage(this->pgconn));
|
2479
2501
|
rb_iv_set(error, "@connection", self);
|
2480
2502
|
rb_exc_raise(error);
|
2481
2503
|
}
|
2504
|
+
RB_GC_GUARD(intermediate);
|
2505
|
+
RB_GC_GUARD(buffer);
|
2506
|
+
|
2482
2507
|
return (ret) ? Qtrue : Qfalse;
|
2483
2508
|
}
|
2484
2509
|
|
@@ -2502,17 +2527,17 @@ pgconn_put_copy_end(int argc, VALUE *argv, VALUE self)
|
|
2502
2527
|
VALUE str;
|
2503
2528
|
VALUE error;
|
2504
2529
|
int ret;
|
2505
|
-
char *error_message = NULL;
|
2506
|
-
|
2530
|
+
const char *error_message = NULL;
|
2531
|
+
t_pg_connection *this = pg_get_connection_safe( self );
|
2507
2532
|
|
2508
2533
|
if (rb_scan_args(argc, argv, "01", &str) == 0)
|
2509
2534
|
error_message = NULL;
|
2510
2535
|
else
|
2511
|
-
error_message =
|
2536
|
+
error_message = pg_cstr_enc(str, this->enc_idx);
|
2512
2537
|
|
2513
|
-
ret = gvl_PQputCopyEnd(
|
2538
|
+
ret = gvl_PQputCopyEnd(this->pgconn, error_message);
|
2514
2539
|
if(ret == -1) {
|
2515
|
-
error = rb_exc_new2(rb_ePGerror, PQerrorMessage(
|
2540
|
+
error = rb_exc_new2(rb_ePGerror, PQerrorMessage(this->pgconn));
|
2516
2541
|
rb_iv_set(error, "@connection", self);
|
2517
2542
|
rb_exc_raise(error);
|
2518
2543
|
}
|
@@ -2521,12 +2546,20 @@ pgconn_put_copy_end(int argc, VALUE *argv, VALUE self)
|
|
2521
2546
|
|
2522
2547
|
/*
|
2523
2548
|
* call-seq:
|
2524
|
-
* conn.get_copy_data( [ async = false ] ) ->
|
2549
|
+
* conn.get_copy_data( [ async = false [, decoder = nil ]] ) -> Object
|
2525
2550
|
*
|
2526
|
-
* Return
|
2551
|
+
* Return one row of data, +nil+
|
2527
2552
|
* if the copy is done, or +false+ if the call would
|
2528
2553
|
* block (only possible if _async_ is true).
|
2529
2554
|
*
|
2555
|
+
* If _decoder_ is not set or +nil+, data is returned as binary string.
|
2556
|
+
*
|
2557
|
+
* If _decoder_ is set to a PG::Coder derivation, the return type depends on this decoder.
|
2558
|
+
* PG::TextDecoder::CopyRow decodes the received data fields from one row of PostgreSQL's
|
2559
|
+
* COPY text format to an Array of Strings.
|
2560
|
+
* Optionally the decoder can type cast the single fields to various Ruby types in one step,
|
2561
|
+
* if PG::TextDecoder::CopyRow#type_map is set accordingly.
|
2562
|
+
*
|
2530
2563
|
* See also #copy_data.
|
2531
2564
|
*
|
2532
2565
|
*/
|
@@ -2535,20 +2568,29 @@ pgconn_get_copy_data(int argc, VALUE *argv, VALUE self )
|
|
2535
2568
|
{
|
2536
2569
|
VALUE async_in;
|
2537
2570
|
VALUE error;
|
2538
|
-
VALUE
|
2571
|
+
VALUE result;
|
2539
2572
|
int ret;
|
2540
|
-
int async;
|
2541
2573
|
char *buffer;
|
2542
|
-
|
2574
|
+
VALUE decoder;
|
2575
|
+
t_pg_coder *p_coder = NULL;
|
2576
|
+
t_pg_connection *this = pg_get_connection_safe( self );
|
2543
2577
|
|
2544
|
-
|
2545
|
-
|
2546
|
-
|
2547
|
-
|
2578
|
+
rb_scan_args(argc, argv, "02", &async_in, &decoder);
|
2579
|
+
|
2580
|
+
if( NIL_P(decoder) ){
|
2581
|
+
if( !NIL_P(this->decoder_for_get_copy_data) ){
|
2582
|
+
p_coder = DATA_PTR( this->decoder_for_get_copy_data );
|
2583
|
+
}
|
2584
|
+
} else if( rb_obj_is_kind_of(decoder, rb_cPG_Coder) ) {
|
2585
|
+
Data_Get_Struct( decoder, t_pg_coder, p_coder );
|
2586
|
+
} else {
|
2587
|
+
rb_raise( rb_eTypeError, "wrong decoder type %s (expected some kind of PG::Coder)",
|
2588
|
+
rb_obj_classname( decoder ) );
|
2589
|
+
}
|
2548
2590
|
|
2549
|
-
ret = gvl_PQgetCopyData(
|
2591
|
+
ret = gvl_PQgetCopyData(this->pgconn, &buffer, RTEST(async_in));
|
2550
2592
|
if(ret == -2) { /* error */
|
2551
|
-
error = rb_exc_new2(rb_ePGerror, PQerrorMessage(
|
2593
|
+
error = rb_exc_new2(rb_ePGerror, PQerrorMessage(this->pgconn));
|
2552
2594
|
rb_iv_set(error, "@connection", self);
|
2553
2595
|
rb_exc_raise(error);
|
2554
2596
|
}
|
@@ -2558,20 +2600,34 @@ pgconn_get_copy_data(int argc, VALUE *argv, VALUE self )
|
|
2558
2600
|
if(ret == 0) { /* would block */
|
2559
2601
|
return Qfalse;
|
2560
2602
|
}
|
2561
|
-
|
2603
|
+
|
2604
|
+
if( p_coder ){
|
2605
|
+
t_pg_coder_dec_func dec_func = pg_coder_dec_func( p_coder, p_coder->format );
|
2606
|
+
result = dec_func( p_coder, buffer, ret, 0, 0, this->enc_idx );
|
2607
|
+
} else {
|
2608
|
+
result = rb_str_new(buffer, ret);
|
2609
|
+
}
|
2610
|
+
|
2562
2611
|
PQfreemem(buffer);
|
2563
|
-
return
|
2612
|
+
return result;
|
2564
2613
|
}
|
2565
2614
|
|
2566
2615
|
/*
|
2567
2616
|
* call-seq:
|
2568
|
-
* conn.set_error_verbosity( verbosity ) ->
|
2617
|
+
* conn.set_error_verbosity( verbosity ) -> Integer
|
2569
2618
|
*
|
2570
2619
|
* Sets connection's verbosity to _verbosity_ and returns
|
2571
2620
|
* the previous setting. Available settings are:
|
2621
|
+
*
|
2572
2622
|
* * PQERRORS_TERSE
|
2573
2623
|
* * PQERRORS_DEFAULT
|
2574
2624
|
* * PQERRORS_VERBOSE
|
2625
|
+
* * PQERRORS_SQLSTATE
|
2626
|
+
*
|
2627
|
+
* Changing the verbosity does not affect the messages available from already-existing PG::Result objects, only subsequently-created ones.
|
2628
|
+
* (But see PG::Result#verbose_error_message if you want to print a previous error with a different verbosity.)
|
2629
|
+
*
|
2630
|
+
* See also corresponding {libpq function}[https://www.postgresql.org/docs/current/libpq-control.html#LIBPQ-PQSETERRORVERBOSITY].
|
2575
2631
|
*/
|
2576
2632
|
static VALUE
|
2577
2633
|
pgconn_set_error_verbosity(VALUE self, VALUE in_verbosity)
|
@@ -2581,6 +2637,37 @@ pgconn_set_error_verbosity(VALUE self, VALUE in_verbosity)
|
|
2581
2637
|
return INT2FIX(PQsetErrorVerbosity(conn, verbosity));
|
2582
2638
|
}
|
2583
2639
|
|
2640
|
+
#ifdef HAVE_PQRESULTVERBOSEERRORMESSAGE
|
2641
|
+
/*
|
2642
|
+
* call-seq:
|
2643
|
+
* conn.set_error_context_visibility( context_visibility ) -> Integer
|
2644
|
+
*
|
2645
|
+
* Sets connection's context display mode to _context_visibility_ and returns
|
2646
|
+
* the previous setting. Available settings are:
|
2647
|
+
* * PQSHOW_CONTEXT_NEVER
|
2648
|
+
* * PQSHOW_CONTEXT_ERRORS
|
2649
|
+
* * PQSHOW_CONTEXT_ALWAYS
|
2650
|
+
*
|
2651
|
+
* This mode controls whether the CONTEXT field is included in messages (unless the verbosity setting is TERSE, in which case CONTEXT is never shown).
|
2652
|
+
* The NEVER mode never includes CONTEXT, while ALWAYS always includes it if available.
|
2653
|
+
* In ERRORS mode (the default), CONTEXT fields are included only for error messages, not for notices and warnings.
|
2654
|
+
*
|
2655
|
+
* Changing this mode does not affect the messages available from already-existing PG::Result objects, only subsequently-created ones.
|
2656
|
+
* (But see PG::Result#verbose_error_message if you want to print a previous error with a different display mode.)
|
2657
|
+
*
|
2658
|
+
* See also corresponding {libpq function}[https://www.postgresql.org/docs/current/libpq-control.html#LIBPQ-PQSETERRORCONTEXTVISIBILITY].
|
2659
|
+
*
|
2660
|
+
* Available since PostgreSQL-9.6
|
2661
|
+
*/
|
2662
|
+
static VALUE
|
2663
|
+
pgconn_set_error_context_visibility(VALUE self, VALUE in_context_visibility)
|
2664
|
+
{
|
2665
|
+
PGconn *conn = pg_get_pgconn(self);
|
2666
|
+
PGContextVisibility context_visibility = NUM2INT(in_context_visibility);
|
2667
|
+
return INT2FIX(PQsetErrorContextVisibility(conn, context_visibility));
|
2668
|
+
}
|
2669
|
+
#endif
|
2670
|
+
|
2584
2671
|
/*
|
2585
2672
|
* call-seq:
|
2586
2673
|
* conn.trace( stream ) -> nil
|
@@ -2597,8 +2684,9 @@ pgconn_trace(VALUE self, VALUE stream)
|
|
2597
2684
|
FILE *new_fp;
|
2598
2685
|
int old_fd, new_fd;
|
2599
2686
|
VALUE new_file;
|
2687
|
+
t_pg_connection *this = pg_get_connection_safe( self );
|
2600
2688
|
|
2601
|
-
if(rb_respond_to(stream,rb_intern("fileno"))
|
2689
|
+
if(!rb_respond_to(stream,rb_intern("fileno")))
|
2602
2690
|
rb_raise(rb_eArgError, "stream does not respond to method: fileno");
|
2603
2691
|
|
2604
2692
|
fileno = rb_funcall(stream, rb_intern("fileno"), 0);
|
@@ -2619,9 +2707,9 @@ pgconn_trace(VALUE self, VALUE stream)
|
|
2619
2707
|
rb_raise(rb_eArgError, "stream is not writable");
|
2620
2708
|
|
2621
2709
|
new_file = rb_funcall(rb_cIO, rb_intern("new"), 1, INT2NUM(new_fd));
|
2622
|
-
|
2710
|
+
this->trace_stream = new_file;
|
2623
2711
|
|
2624
|
-
PQtrace(
|
2712
|
+
PQtrace(this->pgconn, new_fp);
|
2625
2713
|
return Qnil;
|
2626
2714
|
}
|
2627
2715
|
|
@@ -2634,11 +2722,11 @@ pgconn_trace(VALUE self, VALUE stream)
|
|
2634
2722
|
static VALUE
|
2635
2723
|
pgconn_untrace(VALUE self)
|
2636
2724
|
{
|
2637
|
-
|
2638
|
-
|
2639
|
-
|
2640
|
-
rb_funcall(trace_stream, rb_intern("close"), 0);
|
2641
|
-
|
2725
|
+
t_pg_connection *this = pg_get_connection_safe( self );
|
2726
|
+
|
2727
|
+
PQuntrace(this->pgconn);
|
2728
|
+
rb_funcall(this->trace_stream, rb_intern("close"), 0);
|
2729
|
+
this->trace_stream = Qnil;
|
2642
2730
|
return Qnil;
|
2643
2731
|
}
|
2644
2732
|
|
@@ -2648,19 +2736,16 @@ pgconn_untrace(VALUE self)
|
|
2648
2736
|
* currently-registered Ruby notice_receiver object.
|
2649
2737
|
*/
|
2650
2738
|
void
|
2651
|
-
notice_receiver_proxy(void *arg, const PGresult *
|
2739
|
+
notice_receiver_proxy(void *arg, const PGresult *pgresult)
|
2652
2740
|
{
|
2653
|
-
VALUE proc;
|
2654
2741
|
VALUE self = (VALUE)arg;
|
2742
|
+
t_pg_connection *this = pg_get_connection( self );
|
2655
2743
|
|
2656
|
-
if (
|
2657
|
-
VALUE
|
2658
|
-
|
2659
|
-
|
2660
|
-
|
2661
|
-
ENCODING_SET( val, rb_enc_to_index(enc) );
|
2662
|
-
#endif
|
2663
|
-
rb_funcall(proc, rb_intern("call"), 1, val);
|
2744
|
+
if (this->notice_receiver != Qnil) {
|
2745
|
+
VALUE result = pg_new_result_autoclear( (PGresult *)pgresult, self );
|
2746
|
+
|
2747
|
+
rb_funcall(this->notice_receiver, rb_intern("call"), 1, result);
|
2748
|
+
pg_result_clear( result );
|
2664
2749
|
}
|
2665
2750
|
return;
|
2666
2751
|
}
|
@@ -2698,7 +2783,7 @@ static VALUE
|
|
2698
2783
|
pgconn_set_notice_receiver(VALUE self)
|
2699
2784
|
{
|
2700
2785
|
VALUE proc, old_proc;
|
2701
|
-
|
2786
|
+
t_pg_connection *this = pg_get_connection_safe( self );
|
2702
2787
|
|
2703
2788
|
/* If default_notice_receiver is unset, assume that the current
|
2704
2789
|
* notice receiver is the default, and save it to a global variable.
|
@@ -2706,19 +2791,19 @@ pgconn_set_notice_receiver(VALUE self)
|
|
2706
2791
|
* always the same, so won't vary among connections.
|
2707
2792
|
*/
|
2708
2793
|
if(default_notice_receiver == NULL)
|
2709
|
-
default_notice_receiver = PQsetNoticeReceiver(
|
2794
|
+
default_notice_receiver = PQsetNoticeReceiver(this->pgconn, NULL, NULL);
|
2710
2795
|
|
2711
|
-
old_proc =
|
2796
|
+
old_proc = this->notice_receiver;
|
2712
2797
|
if( rb_block_given_p() ) {
|
2713
2798
|
proc = rb_block_proc();
|
2714
|
-
PQsetNoticeReceiver(
|
2799
|
+
PQsetNoticeReceiver(this->pgconn, gvl_notice_receiver_proxy, (void *)self);
|
2715
2800
|
} else {
|
2716
2801
|
/* if no block is given, set back to default */
|
2717
2802
|
proc = Qnil;
|
2718
|
-
PQsetNoticeReceiver(
|
2803
|
+
PQsetNoticeReceiver(this->pgconn, default_notice_receiver, NULL);
|
2719
2804
|
}
|
2720
2805
|
|
2721
|
-
|
2806
|
+
this->notice_receiver = proc;
|
2722
2807
|
return old_proc;
|
2723
2808
|
}
|
2724
2809
|
|
@@ -2730,17 +2815,13 @@ pgconn_set_notice_receiver(VALUE self)
|
|
2730
2815
|
void
|
2731
2816
|
notice_processor_proxy(void *arg, const char *message)
|
2732
2817
|
{
|
2733
|
-
VALUE proc;
|
2734
2818
|
VALUE self = (VALUE)arg;
|
2819
|
+
t_pg_connection *this = pg_get_connection( self );
|
2735
2820
|
|
2736
|
-
if (
|
2737
|
-
VALUE message_str =
|
2738
|
-
|
2739
|
-
|
2740
|
-
rb_encoding *enc = pg_conn_enc_get( conn );
|
2741
|
-
ENCODING_SET( message_str, rb_enc_to_index(enc) );
|
2742
|
-
#endif
|
2743
|
-
rb_funcall(proc, rb_intern("call"), 1, message_str);
|
2821
|
+
if (this->notice_receiver != Qnil) {
|
2822
|
+
VALUE message_str = rb_str_new2(message);
|
2823
|
+
PG_ENCODING_SET_NOCHECK( message_str, this->enc_idx );
|
2824
|
+
rb_funcall(this->notice_receiver, rb_intern("call"), 1, message_str);
|
2744
2825
|
}
|
2745
2826
|
return;
|
2746
2827
|
}
|
@@ -2762,7 +2843,7 @@ static VALUE
|
|
2762
2843
|
pgconn_set_notice_processor(VALUE self)
|
2763
2844
|
{
|
2764
2845
|
VALUE proc, old_proc;
|
2765
|
-
|
2846
|
+
t_pg_connection *this = pg_get_connection_safe( self );
|
2766
2847
|
|
2767
2848
|
/* If default_notice_processor is unset, assume that the current
|
2768
2849
|
* notice processor is the default, and save it to a global variable.
|
@@ -2770,19 +2851,19 @@ pgconn_set_notice_processor(VALUE self)
|
|
2770
2851
|
* always the same, so won't vary among connections.
|
2771
2852
|
*/
|
2772
2853
|
if(default_notice_processor == NULL)
|
2773
|
-
default_notice_processor = PQsetNoticeProcessor(
|
2854
|
+
default_notice_processor = PQsetNoticeProcessor(this->pgconn, NULL, NULL);
|
2774
2855
|
|
2775
|
-
old_proc =
|
2856
|
+
old_proc = this->notice_receiver;
|
2776
2857
|
if( rb_block_given_p() ) {
|
2777
2858
|
proc = rb_block_proc();
|
2778
|
-
PQsetNoticeProcessor(
|
2859
|
+
PQsetNoticeProcessor(this->pgconn, gvl_notice_processor_proxy, (void *)self);
|
2779
2860
|
} else {
|
2780
2861
|
/* if no block is given, set back to default */
|
2781
2862
|
proc = Qnil;
|
2782
|
-
PQsetNoticeProcessor(
|
2863
|
+
PQsetNoticeProcessor(this->pgconn, default_notice_processor, NULL);
|
2783
2864
|
}
|
2784
2865
|
|
2785
|
-
|
2866
|
+
this->notice_receiver = proc;
|
2786
2867
|
return old_proc;
|
2787
2868
|
}
|
2788
2869
|
|
@@ -2797,7 +2878,7 @@ static VALUE
|
|
2797
2878
|
pgconn_get_client_encoding(VALUE self)
|
2798
2879
|
{
|
2799
2880
|
char *encoding = (char *)pg_encoding_to_char(PQclientEncoding(pg_get_pgconn(self)));
|
2800
|
-
return
|
2881
|
+
return rb_str_new2(encoding);
|
2801
2882
|
}
|
2802
2883
|
|
2803
2884
|
|
@@ -2814,9 +2895,10 @@ pgconn_set_client_encoding(VALUE self, VALUE str)
|
|
2814
2895
|
|
2815
2896
|
Check_Type(str, T_STRING);
|
2816
2897
|
|
2817
|
-
if ( (
|
2818
|
-
rb_raise(rb_ePGerror, "
|
2898
|
+
if ( (gvl_PQsetClientEncoding(conn, StringValueCStr(str))) == -1 ) {
|
2899
|
+
rb_raise(rb_ePGerror, "%s", PQerrorMessage(conn));
|
2819
2900
|
}
|
2901
|
+
pgconn_set_internal_encoding_index( self );
|
2820
2902
|
|
2821
2903
|
return Qnil;
|
2822
2904
|
}
|
@@ -2867,8 +2949,10 @@ pgconn_transaction(VALUE self)
|
|
2867
2949
|
|
2868
2950
|
/*
|
2869
2951
|
* call-seq:
|
2870
|
-
* PG::Connection.quote_ident( str ) -> String
|
2871
2952
|
* conn.quote_ident( str ) -> String
|
2953
|
+
* conn.quote_ident( array ) -> String
|
2954
|
+
* PG::Connection.quote_ident( str ) -> String
|
2955
|
+
* PG::Connection.quote_ident( array ) -> String
|
2872
2956
|
*
|
2873
2957
|
* Returns a string that is safe for inclusion in a SQL query as an
|
2874
2958
|
* identifier. Note: this is not a quote function for values, but for
|
@@ -2878,52 +2962,39 @@ pgconn_transaction(VALUE self)
|
|
2878
2962
|
* The identifier <tt>FOO</tt> is folded to lower case, so it actually
|
2879
2963
|
* means <tt>foo</tt>. If you really want to access the case-sensitive
|
2880
2964
|
* field name <tt>FOO</tt>, use this function like
|
2881
|
-
* <tt>
|
2965
|
+
* <tt>conn.quote_ident('FOO')</tt>, which will return <tt>"FOO"</tt>
|
2882
2966
|
* (with double-quotes). PostgreSQL will see the double-quotes, and
|
2883
2967
|
* it will not fold to lower case.
|
2884
2968
|
*
|
2885
2969
|
* Similarly, this function also protects against special characters,
|
2886
2970
|
* and other things that might allow SQL injection if the identifier
|
2887
2971
|
* comes from an untrusted source.
|
2972
|
+
*
|
2973
|
+
* If the parameter is an Array, then all it's values are separately quoted
|
2974
|
+
* and then joined by a "." character. This can be used for identifiers in
|
2975
|
+
* the form "schema"."table"."column" .
|
2976
|
+
*
|
2977
|
+
* This method is functional identical to the encoder PG::TextEncoder::Identifier .
|
2978
|
+
*
|
2979
|
+
* If the instance method form is used and the input string character encoding
|
2980
|
+
* is different to the connection encoding, then the string is converted to this
|
2981
|
+
* encoding, so that the returned string is always encoded as PG::Connection#internal_encoding .
|
2982
|
+
*
|
2983
|
+
* In the singleton form (PG::Connection.quote_ident) the character encoding
|
2984
|
+
* of the result string is set to the character encoding of the input string.
|
2888
2985
|
*/
|
2889
2986
|
static VALUE
|
2890
|
-
pgconn_s_quote_ident(VALUE self, VALUE
|
2987
|
+
pgconn_s_quote_ident(VALUE self, VALUE str_or_array)
|
2891
2988
|
{
|
2892
2989
|
VALUE ret;
|
2893
|
-
|
2894
|
-
/* result size at most NAMEDATALEN*2 plus surrounding
|
2895
|
-
* double-quotes. */
|
2896
|
-
char buffer[NAMEDATALEN*2+2];
|
2897
|
-
unsigned int i=0,j=0;
|
2898
|
-
#ifdef M17N_SUPPORTED
|
2899
|
-
rb_encoding* enc;
|
2900
|
-
#endif
|
2990
|
+
int enc_idx;
|
2901
2991
|
|
2902
|
-
|
2903
|
-
|
2904
|
-
|
2905
|
-
|
2906
|
-
"Input string is longer than NAMEDATALEN-1 (%d)",
|
2907
|
-
NAMEDATALEN-1);
|
2908
|
-
}
|
2909
|
-
buffer[j++] = '"';
|
2910
|
-
for(i = 0; i < strlen(str) && str[i]; i++) {
|
2911
|
-
if(str[i] == '"')
|
2912
|
-
buffer[j++] = '"';
|
2913
|
-
buffer[j++] = str[i];
|
2914
|
-
}
|
2915
|
-
buffer[j++] = '"';
|
2916
|
-
ret = rb_str_new(buffer,j);
|
2917
|
-
OBJ_INFECT(ret, in_str);
|
2918
|
-
|
2919
|
-
#ifdef M17N_SUPPORTED
|
2920
|
-
if ( rb_obj_class(self) == rb_cPGconn ) {
|
2921
|
-
enc = pg_conn_enc_get( pg_get_pgconn(self) );
|
2922
|
-
} else {
|
2923
|
-
enc = rb_enc_get(in_str);
|
2992
|
+
if( rb_obj_is_kind_of(self, rb_cPGconn) ){
|
2993
|
+
enc_idx = pg_get_connection(self)->enc_idx;
|
2994
|
+
}else{
|
2995
|
+
enc_idx = RB_TYPE_P(str_or_array, T_STRING) ? ENCODING_GET( str_or_array ) : rb_ascii8bit_encindex();
|
2924
2996
|
}
|
2925
|
-
|
2926
|
-
#endif
|
2997
|
+
pg_text_enc_identifier(NULL, str_or_array, NULL, &ret, enc_idx);
|
2927
2998
|
|
2928
2999
|
return ret;
|
2929
3000
|
}
|
@@ -2953,10 +3024,6 @@ static VALUE
|
|
2953
3024
|
pgconn_block( int argc, VALUE *argv, VALUE self ) {
|
2954
3025
|
PGconn *conn = pg_get_pgconn( self );
|
2955
3026
|
|
2956
|
-
/* If WIN32 and Ruby 1.9 do not use rb_thread_select() which sometimes hangs
|
2957
|
-
* and does not wait (nor sleep) any time even if timeout is given.
|
2958
|
-
* Instead use the Winsock events and rb_w32_wait_events(). */
|
2959
|
-
|
2960
3027
|
struct timeval timeout;
|
2961
3028
|
struct timeval *ptimeout = NULL;
|
2962
3029
|
VALUE timeout_in;
|
@@ -3023,24 +3090,142 @@ pgconn_get_last_result(VALUE self)
|
|
3023
3090
|
|
3024
3091
|
/*
|
3025
3092
|
* call-seq:
|
3026
|
-
* conn.
|
3027
|
-
*
|
3093
|
+
* conn.discard_results()
|
3094
|
+
*
|
3095
|
+
* Silently discard any prior query result that application didn't eat.
|
3096
|
+
* This is done prior of Connection#exec and sibling methods and can
|
3097
|
+
* be called explicitly when using the async API.
|
3098
|
+
*/
|
3099
|
+
static VALUE
|
3100
|
+
pgconn_discard_results(VALUE self)
|
3101
|
+
{
|
3102
|
+
PGconn *conn = pg_get_pgconn(self);
|
3103
|
+
|
3104
|
+
PGresult *cur;
|
3105
|
+
while ((cur = gvl_PQgetResult(conn)) != NULL) {
|
3106
|
+
int status = PQresultStatus(cur);
|
3107
|
+
PQclear(cur);
|
3108
|
+
if (status == PGRES_COPY_IN){
|
3109
|
+
gvl_PQputCopyEnd(conn, "COPY terminated by new PQexec");
|
3110
|
+
}
|
3111
|
+
if (status == PGRES_COPY_OUT){
|
3112
|
+
char *buffer = NULL;
|
3113
|
+
while( gvl_PQgetCopyData(conn, &buffer, 0) > 0)
|
3114
|
+
PQfreemem(buffer);
|
3115
|
+
}
|
3116
|
+
}
|
3117
|
+
|
3118
|
+
return Qnil;
|
3119
|
+
}
|
3120
|
+
|
3121
|
+
/*
|
3122
|
+
* call-seq:
|
3123
|
+
* conn.exec(sql) -> PG::Result
|
3124
|
+
* conn.exec(sql) {|pg_result| block }
|
3125
|
+
*
|
3126
|
+
* Sends SQL query request specified by _sql_ to PostgreSQL.
|
3127
|
+
* On success, it returns a PG::Result instance with all result rows and columns.
|
3128
|
+
* On failure, it raises a PG::Error.
|
3028
3129
|
*
|
3029
|
-
*
|
3030
|
-
*
|
3031
|
-
*
|
3130
|
+
* For backward compatibility, if you pass more than one parameter to this method,
|
3131
|
+
* it will call #exec_params for you. New code should explicitly use #exec_params if
|
3132
|
+
* argument placeholders are used.
|
3133
|
+
*
|
3134
|
+
* If the optional code block is given, it will be passed <i>result</i> as an argument,
|
3135
|
+
* and the PG::Result object will automatically be cleared when the block terminates.
|
3136
|
+
* In this instance, <code>conn.exec</code> returns the value of the block.
|
3137
|
+
*
|
3138
|
+
* #exec is an alias for #async_exec which is almost identical to #sync_exec .
|
3139
|
+
* #sync_exec is implemented on the simpler synchronous command processing API of libpq, whereas
|
3140
|
+
* #async_exec is implemented on the asynchronous API and on ruby's IO mechanisms.
|
3141
|
+
* Both methods ensure that other threads can process while waiting for the server to
|
3142
|
+
* complete the request, but #sync_exec blocks all signals to be processed until the query is finished.
|
3143
|
+
* This is most notably visible by a delayed reaction to Control+C.
|
3144
|
+
* It's not recommended to use explicit sync or async variants but #exec instead, unless you have a good reason to do so.
|
3145
|
+
*
|
3146
|
+
* See also corresponding {libpq function}[https://www.postgresql.org/docs/current/libpq-exec.html#LIBPQ-PQEXEC].
|
3032
3147
|
*/
|
3033
3148
|
static VALUE
|
3034
3149
|
pgconn_async_exec(int argc, VALUE *argv, VALUE self)
|
3035
3150
|
{
|
3036
3151
|
VALUE rb_pgresult = Qnil;
|
3037
3152
|
|
3038
|
-
|
3153
|
+
pgconn_discard_results( self );
|
3154
|
+
pgconn_send_query( argc, argv, self );
|
3039
3155
|
pgconn_block( 0, NULL, self ); /* wait for input (without blocking) before reading the last result */
|
3040
|
-
pgconn_get_last_result( self );
|
3156
|
+
rb_pgresult = pgconn_get_last_result( self );
|
3041
3157
|
|
3042
|
-
|
3043
|
-
|
3158
|
+
if ( rb_block_given_p() ) {
|
3159
|
+
return rb_ensure( rb_yield, rb_pgresult, pg_result_clear, rb_pgresult );
|
3160
|
+
}
|
3161
|
+
return rb_pgresult;
|
3162
|
+
}
|
3163
|
+
|
3164
|
+
|
3165
|
+
/*
|
3166
|
+
* call-seq:
|
3167
|
+
* conn.exec_params(sql, params [, result_format [, type_map ]] ) -> nil
|
3168
|
+
* conn.exec_params(sql, params [, result_format [, type_map ]] ) {|pg_result| block }
|
3169
|
+
*
|
3170
|
+
* Sends SQL query request specified by +sql+ to PostgreSQL using placeholders
|
3171
|
+
* for parameters.
|
3172
|
+
*
|
3173
|
+
* Returns a PG::Result instance on success. On failure, it raises a PG::Error.
|
3174
|
+
*
|
3175
|
+
* +params+ is an array of the bind parameters for the SQL query.
|
3176
|
+
* Each element of the +params+ array may be either:
|
3177
|
+
* a hash of the form:
|
3178
|
+
* {:value => String (value of bind parameter)
|
3179
|
+
* :type => Integer (oid of type of bind parameter)
|
3180
|
+
* :format => Integer (0 for text, 1 for binary)
|
3181
|
+
* }
|
3182
|
+
* or, it may be a String. If it is a string, that is equivalent to the hash:
|
3183
|
+
* { :value => <string value>, :type => 0, :format => 0 }
|
3184
|
+
*
|
3185
|
+
* PostgreSQL bind parameters are represented as $1, $1, $2, etc.,
|
3186
|
+
* inside the SQL query. The 0th element of the +params+ array is bound
|
3187
|
+
* to $1, the 1st element is bound to $2, etc. +nil+ is treated as +NULL+.
|
3188
|
+
*
|
3189
|
+
* If the types are not specified, they will be inferred by PostgreSQL.
|
3190
|
+
* Instead of specifying type oids, it's recommended to simply add
|
3191
|
+
* explicit casts in the query to ensure that the right type is used.
|
3192
|
+
*
|
3193
|
+
* For example: "SELECT $1::int"
|
3194
|
+
*
|
3195
|
+
* The optional +result_format+ should be 0 for text results, 1
|
3196
|
+
* for binary.
|
3197
|
+
*
|
3198
|
+
* +type_map+ can be a PG::TypeMap derivation (such as PG::BasicTypeMapForQueries).
|
3199
|
+
* This will type cast the params from various Ruby types before transmission
|
3200
|
+
* based on the encoders defined by the type map. When a type encoder is used
|
3201
|
+
* the format and oid of a given bind parameter are retrieved from the encoder
|
3202
|
+
* instead out of the hash form described above.
|
3203
|
+
*
|
3204
|
+
* If the optional code block is given, it will be passed <i>result</i> as an argument,
|
3205
|
+
* and the PG::Result object will automatically be cleared when the block terminates.
|
3206
|
+
* In this instance, <code>conn.exec</code> returns the value of the block.
|
3207
|
+
*
|
3208
|
+
* 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.
|
3209
|
+
* Unlike #exec, #exec_params allows at most one SQL command in the given string.
|
3210
|
+
* (There can be semicolons in it, but not more than one nonempty command.)
|
3211
|
+
* This is a limitation of the underlying protocol, but has some usefulness as an extra defense against SQL-injection attacks.
|
3212
|
+
*
|
3213
|
+
* See also corresponding {libpq function}[https://www.postgresql.org/docs/current/libpq-exec.html#LIBPQ-PQEXECPARAMS].
|
3214
|
+
*/
|
3215
|
+
static VALUE
|
3216
|
+
pgconn_async_exec_params(int argc, VALUE *argv, VALUE self)
|
3217
|
+
{
|
3218
|
+
VALUE rb_pgresult = Qnil;
|
3219
|
+
|
3220
|
+
pgconn_discard_results( self );
|
3221
|
+
/* If called with no or nil parameters, use PQsendQuery for compatibility */
|
3222
|
+
if ( argc == 1 || (argc >= 2 && argc <= 4 && NIL_P(argv[1]) )) {
|
3223
|
+
pg_deprecated(3, ("forwarding async_exec_params to async_exec is deprecated"));
|
3224
|
+
pgconn_send_query( argc, argv, self );
|
3225
|
+
} else {
|
3226
|
+
pgconn_send_query_params( argc, argv, self );
|
3227
|
+
}
|
3228
|
+
pgconn_block( 0, NULL, self ); /* wait for input (without blocking) before reading the last result */
|
3044
3229
|
rb_pgresult = pgconn_get_last_result( self );
|
3045
3230
|
|
3046
3231
|
if ( rb_block_given_p() ) {
|
@@ -3049,13 +3234,236 @@ pgconn_async_exec(int argc, VALUE *argv, VALUE self)
|
|
3049
3234
|
return rb_pgresult;
|
3050
3235
|
}
|
3051
3236
|
|
3237
|
+
|
3238
|
+
/*
|
3239
|
+
* call-seq:
|
3240
|
+
* conn.prepare(stmt_name, sql [, param_types ] ) -> PG::Result
|
3241
|
+
*
|
3242
|
+
* Prepares statement _sql_ with name _name_ to be executed later.
|
3243
|
+
* Returns a PG::Result instance on success.
|
3244
|
+
* On failure, it raises a PG::Error.
|
3245
|
+
*
|
3246
|
+
* +param_types+ is an optional parameter to specify the Oids of the
|
3247
|
+
* types of the parameters.
|
3248
|
+
*
|
3249
|
+
* If the types are not specified, they will be inferred by PostgreSQL.
|
3250
|
+
* Instead of specifying type oids, it's recommended to simply add
|
3251
|
+
* explicit casts in the query to ensure that the right type is used.
|
3252
|
+
*
|
3253
|
+
* For example: "SELECT $1::int"
|
3254
|
+
*
|
3255
|
+
* PostgreSQL bind parameters are represented as $1, $1, $2, etc.,
|
3256
|
+
* inside the SQL query.
|
3257
|
+
*
|
3258
|
+
* See also corresponding {libpq function}[https://www.postgresql.org/docs/current/libpq-exec.html#LIBPQ-PQPREPARE].
|
3259
|
+
*/
|
3260
|
+
static VALUE
|
3261
|
+
pgconn_async_prepare(int argc, VALUE *argv, VALUE self)
|
3262
|
+
{
|
3263
|
+
VALUE rb_pgresult = Qnil;
|
3264
|
+
|
3265
|
+
pgconn_discard_results( self );
|
3266
|
+
pgconn_send_prepare( argc, argv, self );
|
3267
|
+
pgconn_block( 0, NULL, self ); /* wait for input (without blocking) before reading the last result */
|
3268
|
+
rb_pgresult = pgconn_get_last_result( self );
|
3269
|
+
|
3270
|
+
if ( rb_block_given_p() ) {
|
3271
|
+
return rb_ensure( rb_yield, rb_pgresult, pg_result_clear, rb_pgresult );
|
3272
|
+
}
|
3273
|
+
return rb_pgresult;
|
3274
|
+
}
|
3275
|
+
|
3276
|
+
|
3277
|
+
/*
|
3278
|
+
* call-seq:
|
3279
|
+
* conn.exec_prepared(statement_name [, params, result_format[, type_map]] ) -> PG::Result
|
3280
|
+
* conn.exec_prepared(statement_name [, params, result_format[, type_map]] ) {|pg_result| block }
|
3281
|
+
*
|
3282
|
+
* Execute prepared named statement specified by _statement_name_.
|
3283
|
+
* Returns a PG::Result instance on success.
|
3284
|
+
* On failure, it raises a PG::Error.
|
3285
|
+
*
|
3286
|
+
* +params+ is an array of the optional bind parameters for the
|
3287
|
+
* SQL query. Each element of the +params+ array may be either:
|
3288
|
+
* a hash of the form:
|
3289
|
+
* {:value => String (value of bind parameter)
|
3290
|
+
* :format => Integer (0 for text, 1 for binary)
|
3291
|
+
* }
|
3292
|
+
* or, it may be a String. If it is a string, that is equivalent to the hash:
|
3293
|
+
* { :value => <string value>, :format => 0 }
|
3294
|
+
*
|
3295
|
+
* PostgreSQL bind parameters are represented as $1, $1, $2, etc.,
|
3296
|
+
* inside the SQL query. The 0th element of the +params+ array is bound
|
3297
|
+
* to $1, the 1st element is bound to $2, etc. +nil+ is treated as +NULL+.
|
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_prepared</code> returns the value of the block.
|
3311
|
+
*
|
3312
|
+
* See also corresponding {libpq function}[https://www.postgresql.org/docs/current/libpq-exec.html#LIBPQ-PQEXECPREPARED].
|
3313
|
+
*/
|
3314
|
+
static VALUE
|
3315
|
+
pgconn_async_exec_prepared(int argc, VALUE *argv, VALUE self)
|
3316
|
+
{
|
3317
|
+
VALUE rb_pgresult = Qnil;
|
3318
|
+
|
3319
|
+
pgconn_discard_results( self );
|
3320
|
+
pgconn_send_query_prepared( argc, argv, self );
|
3321
|
+
pgconn_block( 0, NULL, self ); /* wait for input (without blocking) before reading the last result */
|
3322
|
+
rb_pgresult = pgconn_get_last_result( self );
|
3323
|
+
|
3324
|
+
if ( rb_block_given_p() ) {
|
3325
|
+
return rb_ensure( rb_yield, rb_pgresult, pg_result_clear, rb_pgresult );
|
3326
|
+
}
|
3327
|
+
return rb_pgresult;
|
3328
|
+
}
|
3329
|
+
|
3330
|
+
|
3331
|
+
/*
|
3332
|
+
* call-seq:
|
3333
|
+
* conn.describe_portal( portal_name ) -> PG::Result
|
3334
|
+
*
|
3335
|
+
* Retrieve information about the portal _portal_name_.
|
3336
|
+
*
|
3337
|
+
* See also corresponding {libpq function}[https://www.postgresql.org/docs/current/libpq-exec.html#LIBPQ-PQDESCRIBEPORTAL].
|
3338
|
+
*/
|
3339
|
+
static VALUE
|
3340
|
+
pgconn_async_describe_portal(VALUE self, VALUE portal)
|
3341
|
+
{
|
3342
|
+
VALUE rb_pgresult = Qnil;
|
3343
|
+
|
3344
|
+
pgconn_discard_results( self );
|
3345
|
+
pgconn_send_describe_portal( self, portal );
|
3346
|
+
pgconn_block( 0, NULL, self ); /* wait for input (without blocking) before reading the last result */
|
3347
|
+
rb_pgresult = pgconn_get_last_result( self );
|
3348
|
+
|
3349
|
+
if ( rb_block_given_p() ) {
|
3350
|
+
return rb_ensure( rb_yield, rb_pgresult, pg_result_clear, rb_pgresult );
|
3351
|
+
}
|
3352
|
+
return rb_pgresult;
|
3353
|
+
}
|
3354
|
+
|
3355
|
+
|
3356
|
+
/*
|
3357
|
+
* call-seq:
|
3358
|
+
* conn.describe_prepared( statement_name ) -> PG::Result
|
3359
|
+
*
|
3360
|
+
* Retrieve information about the prepared statement _statement_name_.
|
3361
|
+
*
|
3362
|
+
* See also corresponding {libpq function}[https://www.postgresql.org/docs/current/libpq-exec.html#LIBPQ-PQDESCRIBEPREPARED].
|
3363
|
+
*/
|
3364
|
+
static VALUE
|
3365
|
+
pgconn_async_describe_prepared(VALUE self, VALUE stmt_name)
|
3366
|
+
{
|
3367
|
+
VALUE rb_pgresult = Qnil;
|
3368
|
+
|
3369
|
+
pgconn_discard_results( self );
|
3370
|
+
pgconn_send_describe_prepared( self, stmt_name );
|
3371
|
+
pgconn_block( 0, NULL, self ); /* wait for input (without blocking) before reading the last result */
|
3372
|
+
rb_pgresult = pgconn_get_last_result( self );
|
3373
|
+
|
3374
|
+
if ( rb_block_given_p() ) {
|
3375
|
+
return rb_ensure( rb_yield, rb_pgresult, pg_result_clear, rb_pgresult );
|
3376
|
+
}
|
3377
|
+
return rb_pgresult;
|
3378
|
+
}
|
3379
|
+
|
3380
|
+
|
3381
|
+
#ifdef HAVE_PQSSLATTRIBUTE
|
3382
|
+
/*
|
3383
|
+
* call-seq:
|
3384
|
+
* conn.ssl_in_use? -> Boolean
|
3385
|
+
*
|
3386
|
+
* Returns +true+ if the connection uses SSL/TLS, +false+ if not.
|
3387
|
+
*
|
3388
|
+
* Available since PostgreSQL-9.5
|
3389
|
+
*/
|
3390
|
+
static VALUE
|
3391
|
+
pgconn_ssl_in_use(VALUE self)
|
3392
|
+
{
|
3393
|
+
return PQsslInUse(pg_get_pgconn(self)) ? Qtrue : Qfalse;
|
3394
|
+
}
|
3395
|
+
|
3396
|
+
|
3397
|
+
/*
|
3398
|
+
* call-seq:
|
3399
|
+
* conn.ssl_attribute(attribute_name) -> String
|
3400
|
+
*
|
3401
|
+
* Returns SSL-related information about the connection.
|
3402
|
+
*
|
3403
|
+
* The list of available attributes varies depending on the SSL library being used,
|
3404
|
+
* and the type of connection. If an attribute is not available, returns nil.
|
3405
|
+
*
|
3406
|
+
* The following attributes are commonly available:
|
3407
|
+
*
|
3408
|
+
* [+library+]
|
3409
|
+
* Name of the SSL implementation in use. (Currently, only "OpenSSL" is implemented)
|
3410
|
+
* [+protocol+]
|
3411
|
+
* 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.
|
3412
|
+
* [+key_bits+]
|
3413
|
+
* Number of key bits used by the encryption algorithm.
|
3414
|
+
* [+cipher+]
|
3415
|
+
* A short name of the ciphersuite used, e.g. "DHE-RSA-DES-CBC3-SHA". The names are specific to each SSL implementation.
|
3416
|
+
* [+compression+]
|
3417
|
+
* 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".
|
3418
|
+
*
|
3419
|
+
*
|
3420
|
+
* See also #ssl_attribute_names and the {corresponding libpq function}[https://www.postgresql.org/docs/current/libpq-status.html#LIBPQ-PQSSLATTRIBUTE].
|
3421
|
+
*
|
3422
|
+
* Available since PostgreSQL-9.5
|
3423
|
+
*/
|
3424
|
+
static VALUE
|
3425
|
+
pgconn_ssl_attribute(VALUE self, VALUE attribute_name)
|
3426
|
+
{
|
3427
|
+
const char *p_attr;
|
3428
|
+
|
3429
|
+
p_attr = PQsslAttribute(pg_get_pgconn(self), StringValueCStr(attribute_name));
|
3430
|
+
return p_attr ? rb_str_new_cstr(p_attr) : Qnil;
|
3431
|
+
}
|
3432
|
+
|
3433
|
+
/*
|
3434
|
+
* call-seq:
|
3435
|
+
* conn.ssl_attribute_names -> Array<String>
|
3436
|
+
*
|
3437
|
+
* Return an array of SSL attribute names available.
|
3438
|
+
*
|
3439
|
+
* See also #ssl_attribute
|
3440
|
+
*
|
3441
|
+
* Available since PostgreSQL-9.5
|
3442
|
+
*/
|
3443
|
+
static VALUE
|
3444
|
+
pgconn_ssl_attribute_names(VALUE self)
|
3445
|
+
{
|
3446
|
+
int i;
|
3447
|
+
const char * const * p_list = PQsslAttributeNames(pg_get_pgconn(self));
|
3448
|
+
VALUE ary = rb_ary_new();
|
3449
|
+
|
3450
|
+
for ( i = 0; p_list[i]; i++ ) {
|
3451
|
+
rb_ary_push( ary, rb_str_new_cstr( p_list[i] ));
|
3452
|
+
}
|
3453
|
+
return ary;
|
3454
|
+
}
|
3455
|
+
|
3456
|
+
|
3457
|
+
#endif
|
3458
|
+
|
3459
|
+
|
3052
3460
|
/**************************************************************************
|
3053
3461
|
* LARGE OBJECT SUPPORT
|
3054
3462
|
**************************************************************************/
|
3055
3463
|
|
3056
3464
|
/*
|
3057
3465
|
* call-seq:
|
3058
|
-
* conn.lo_creat( [mode] ) ->
|
3466
|
+
* conn.lo_creat( [mode] ) -> Integer
|
3059
3467
|
*
|
3060
3468
|
* Creates a large object with mode _mode_. Returns a large object Oid.
|
3061
3469
|
* On failure, it raises PG::Error.
|
@@ -3077,12 +3485,12 @@ pgconn_locreat(int argc, VALUE *argv, VALUE self)
|
|
3077
3485
|
if (lo_oid == 0)
|
3078
3486
|
rb_raise(rb_ePGerror, "lo_creat failed");
|
3079
3487
|
|
3080
|
-
return
|
3488
|
+
return UINT2NUM(lo_oid);
|
3081
3489
|
}
|
3082
3490
|
|
3083
3491
|
/*
|
3084
3492
|
* call-seq:
|
3085
|
-
* conn.lo_create( oid ) ->
|
3493
|
+
* conn.lo_create( oid ) -> Integer
|
3086
3494
|
*
|
3087
3495
|
* Creates a large object with oid _oid_. Returns the large object Oid.
|
3088
3496
|
* On failure, it raises PG::Error.
|
@@ -3092,18 +3500,18 @@ pgconn_locreate(VALUE self, VALUE in_lo_oid)
|
|
3092
3500
|
{
|
3093
3501
|
Oid ret, lo_oid;
|
3094
3502
|
PGconn *conn = pg_get_pgconn(self);
|
3095
|
-
lo_oid =
|
3503
|
+
lo_oid = NUM2UINT(in_lo_oid);
|
3096
3504
|
|
3097
3505
|
ret = lo_create(conn, lo_oid);
|
3098
3506
|
if (ret == InvalidOid)
|
3099
3507
|
rb_raise(rb_ePGerror, "lo_create failed");
|
3100
3508
|
|
3101
|
-
return
|
3509
|
+
return UINT2NUM(ret);
|
3102
3510
|
}
|
3103
3511
|
|
3104
3512
|
/*
|
3105
3513
|
* call-seq:
|
3106
|
-
* conn.lo_import(file) ->
|
3514
|
+
* conn.lo_import(file) -> Integer
|
3107
3515
|
*
|
3108
3516
|
* Import a file to a large object. Returns a large object Oid.
|
3109
3517
|
*
|
@@ -3118,11 +3526,11 @@ pgconn_loimport(VALUE self, VALUE filename)
|
|
3118
3526
|
|
3119
3527
|
Check_Type(filename, T_STRING);
|
3120
3528
|
|
3121
|
-
lo_oid = lo_import(conn,
|
3529
|
+
lo_oid = lo_import(conn, StringValueCStr(filename));
|
3122
3530
|
if (lo_oid == 0) {
|
3123
3531
|
rb_raise(rb_ePGerror, "%s", PQerrorMessage(conn));
|
3124
3532
|
}
|
3125
|
-
return
|
3533
|
+
return UINT2NUM(lo_oid);
|
3126
3534
|
}
|
3127
3535
|
|
3128
3536
|
/*
|
@@ -3135,15 +3543,12 @@ static VALUE
|
|
3135
3543
|
pgconn_loexport(VALUE self, VALUE lo_oid, VALUE filename)
|
3136
3544
|
{
|
3137
3545
|
PGconn *conn = pg_get_pgconn(self);
|
3138
|
-
|
3546
|
+
Oid oid;
|
3139
3547
|
Check_Type(filename, T_STRING);
|
3140
3548
|
|
3141
|
-
oid =
|
3142
|
-
if (oid < 0) {
|
3143
|
-
rb_raise(rb_ePGerror, "invalid large object oid %d",oid);
|
3144
|
-
}
|
3549
|
+
oid = NUM2UINT(lo_oid);
|
3145
3550
|
|
3146
|
-
if (lo_export(conn, oid,
|
3551
|
+
if (lo_export(conn, oid, StringValueCStr(filename)) < 0) {
|
3147
3552
|
rb_raise(rb_ePGerror, "%s", PQerrorMessage(conn));
|
3148
3553
|
}
|
3149
3554
|
return Qnil;
|
@@ -3151,7 +3556,7 @@ pgconn_loexport(VALUE self, VALUE lo_oid, VALUE filename)
|
|
3151
3556
|
|
3152
3557
|
/*
|
3153
3558
|
* call-seq:
|
3154
|
-
* conn.lo_open( oid, [mode] ) ->
|
3559
|
+
* conn.lo_open( oid, [mode] ) -> Integer
|
3155
3560
|
*
|
3156
3561
|
* Open a large object of _oid_. Returns a large object descriptor
|
3157
3562
|
* instance on success. The _mode_ argument specifies the mode for
|
@@ -3168,7 +3573,7 @@ pgconn_loopen(int argc, VALUE *argv, VALUE self)
|
|
3168
3573
|
PGconn *conn = pg_get_pgconn(self);
|
3169
3574
|
|
3170
3575
|
rb_scan_args(argc, argv, "11", &selfid, &nmode);
|
3171
|
-
lo_oid =
|
3576
|
+
lo_oid = NUM2UINT(selfid);
|
3172
3577
|
if(NIL_P(nmode))
|
3173
3578
|
mode = INV_READ;
|
3174
3579
|
else
|
@@ -3182,7 +3587,7 @@ pgconn_loopen(int argc, VALUE *argv, VALUE self)
|
|
3182
3587
|
|
3183
3588
|
/*
|
3184
3589
|
* call-seq:
|
3185
|
-
* conn.lo_write( lo_desc, buffer ) ->
|
3590
|
+
* conn.lo_write( lo_desc, buffer ) -> Integer
|
3186
3591
|
*
|
3187
3592
|
* Writes the string _buffer_ to the large object _lo_desc_.
|
3188
3593
|
* Returns the number of bytes written.
|
@@ -3240,7 +3645,7 @@ pgconn_loread(VALUE self, VALUE in_lo_desc, VALUE in_len)
|
|
3240
3645
|
return Qnil;
|
3241
3646
|
}
|
3242
3647
|
|
3243
|
-
str =
|
3648
|
+
str = rb_str_new(buffer, ret);
|
3244
3649
|
xfree(buffer);
|
3245
3650
|
|
3246
3651
|
return str;
|
@@ -3249,7 +3654,7 @@ pgconn_loread(VALUE self, VALUE in_lo_desc, VALUE in_len)
|
|
3249
3654
|
|
3250
3655
|
/*
|
3251
3656
|
* call-seq:
|
3252
|
-
* conn.lo_lseek( lo_desc, offset, whence ) ->
|
3657
|
+
* conn.lo_lseek( lo_desc, offset, whence ) -> Integer
|
3253
3658
|
*
|
3254
3659
|
* Move the large object pointer _lo_desc_ to offset _offset_.
|
3255
3660
|
* Valid values for _whence_ are +SEEK_SET+, +SEEK_CUR+, and +SEEK_END+.
|
@@ -3271,7 +3676,7 @@ pgconn_lolseek(VALUE self, VALUE in_lo_desc, VALUE offset, VALUE whence)
|
|
3271
3676
|
|
3272
3677
|
/*
|
3273
3678
|
* call-seq:
|
3274
|
-
* conn.lo_tell( lo_desc ) ->
|
3679
|
+
* conn.lo_tell( lo_desc ) -> Integer
|
3275
3680
|
*
|
3276
3681
|
* Returns the current position of the large object _lo_desc_.
|
3277
3682
|
*/
|
@@ -3335,10 +3740,7 @@ static VALUE
|
|
3335
3740
|
pgconn_lounlink(VALUE self, VALUE in_oid)
|
3336
3741
|
{
|
3337
3742
|
PGconn *conn = pg_get_pgconn(self);
|
3338
|
-
|
3339
|
-
|
3340
|
-
if (oid < 0)
|
3341
|
-
rb_raise(rb_ePGerror, "invalid oid %d",oid);
|
3743
|
+
Oid oid = NUM2UINT(in_oid);
|
3342
3744
|
|
3343
3745
|
if(lo_unlink(conn,oid) < 0)
|
3344
3746
|
rb_raise(rb_ePGerror,"lo_unlink failed");
|
@@ -3347,7 +3749,16 @@ pgconn_lounlink(VALUE self, VALUE in_oid)
|
|
3347
3749
|
}
|
3348
3750
|
|
3349
3751
|
|
3350
|
-
|
3752
|
+
static void
|
3753
|
+
pgconn_set_internal_encoding_index( VALUE self )
|
3754
|
+
{
|
3755
|
+
int enc_idx;
|
3756
|
+
t_pg_connection *this = pg_get_connection_safe( self );
|
3757
|
+
rb_encoding *enc = pg_conn_enc_get( this->pgconn );
|
3758
|
+
enc_idx = rb_enc_to_index(enc);
|
3759
|
+
if( enc_idx >= (1<<(PG_ENC_IDX_BITS-1)) ) rb_raise(rb_eArgError, "unsupported encoding index %d", enc_idx);
|
3760
|
+
this->enc_idx = enc_idx;
|
3761
|
+
}
|
3351
3762
|
|
3352
3763
|
/*
|
3353
3764
|
* call-seq:
|
@@ -3393,7 +3804,7 @@ pgconn_internal_encoding_set(VALUE self, VALUE enc)
|
|
3393
3804
|
pgconn_set_client_encoding( self, rb_usascii_str_new_cstr("SQL_ASCII") );
|
3394
3805
|
return enc;
|
3395
3806
|
}
|
3396
|
-
else if ( TYPE(enc) == T_STRING && strcasecmp("JOHAB",
|
3807
|
+
else if ( TYPE(enc) == T_STRING && strcasecmp("JOHAB", StringValueCStr(enc)) == 0 ) {
|
3397
3808
|
pgconn_set_client_encoding(self, rb_usascii_str_new_cstr("JOHAB"));
|
3398
3809
|
return enc;
|
3399
3810
|
}
|
@@ -3401,17 +3812,14 @@ pgconn_internal_encoding_set(VALUE self, VALUE enc)
|
|
3401
3812
|
rb_encoding *rbenc = rb_to_encoding( enc );
|
3402
3813
|
const char *name = pg_get_rb_encoding_as_pg_encoding( rbenc );
|
3403
3814
|
|
3404
|
-
if (
|
3815
|
+
if ( gvl_PQsetClientEncoding(pg_get_pgconn( self ), name) == -1 ) {
|
3405
3816
|
VALUE server_encoding = pgconn_external_encoding( self );
|
3406
3817
|
rb_raise( rb_eEncCompatError, "incompatible character encodings: %s and %s",
|
3407
3818
|
rb_enc_name(rb_to_encoding(server_encoding)), name );
|
3408
3819
|
}
|
3820
|
+
pgconn_set_internal_encoding_index( self );
|
3409
3821
|
return enc;
|
3410
3822
|
}
|
3411
|
-
|
3412
|
-
rb_raise( rb_ePGerror, "unknown encoding: %s", RSTRING_PTR(rb_inspect(enc)) );
|
3413
|
-
|
3414
|
-
return Qnil;
|
3415
3823
|
}
|
3416
3824
|
|
3417
3825
|
|
@@ -3426,24 +3834,45 @@ pgconn_internal_encoding_set(VALUE self, VALUE enc)
|
|
3426
3834
|
static VALUE
|
3427
3835
|
pgconn_external_encoding(VALUE self)
|
3428
3836
|
{
|
3429
|
-
|
3430
|
-
VALUE encoding = rb_iv_get( self, "@external_encoding" );
|
3837
|
+
t_pg_connection *this = pg_get_connection_safe( self );
|
3431
3838
|
rb_encoding *enc = NULL;
|
3432
3839
|
const char *pg_encname = NULL;
|
3433
3840
|
|
3434
|
-
|
3435
|
-
if ( RTEST(encoding) ) return encoding;
|
3436
|
-
|
3437
|
-
pg_encname = PQparameterStatus( conn, "server_encoding" );
|
3841
|
+
pg_encname = PQparameterStatus( this->pgconn, "server_encoding" );
|
3438
3842
|
enc = pg_get_pg_encname_as_rb_encoding( pg_encname );
|
3439
|
-
|
3843
|
+
return rb_enc_from_encoding( enc );
|
3844
|
+
}
|
3845
|
+
|
3846
|
+
|
3847
|
+
static VALUE
|
3848
|
+
pgconn_set_client_encoding_async1( VALUE args )
|
3849
|
+
{
|
3850
|
+
VALUE self = ((VALUE*)args)[0];
|
3851
|
+
VALUE encname = ((VALUE*)args)[1];
|
3852
|
+
VALUE query_format = rb_str_new_cstr("set client_encoding to '%s'");
|
3853
|
+
VALUE query = rb_funcall(query_format, rb_intern("%"), 1, encname);
|
3854
|
+
|
3855
|
+
pgconn_async_exec(1, &query, self);
|
3856
|
+
return 0;
|
3857
|
+
}
|
3440
3858
|
|
3441
|
-
rb_iv_set( self, "@external_encoding", encoding );
|
3442
3859
|
|
3443
|
-
|
3860
|
+
static VALUE
|
3861
|
+
pgconn_set_client_encoding_async2( VALUE arg, VALUE ex )
|
3862
|
+
{
|
3863
|
+
UNUSED(arg);
|
3864
|
+
UNUSED(ex);
|
3865
|
+
return 1;
|
3444
3866
|
}
|
3445
3867
|
|
3446
3868
|
|
3869
|
+
static VALUE
|
3870
|
+
pgconn_set_client_encoding_async( VALUE self, const char *encname )
|
3871
|
+
{
|
3872
|
+
VALUE args[] = { self, rb_str_new_cstr(encname) };
|
3873
|
+
return rb_rescue(pgconn_set_client_encoding_async1, (VALUE)&args, pgconn_set_client_encoding_async2, Qnil);
|
3874
|
+
}
|
3875
|
+
|
3447
3876
|
|
3448
3877
|
/*
|
3449
3878
|
* call-seq:
|
@@ -3462,24 +3891,266 @@ pgconn_set_default_encoding( VALUE self )
|
|
3462
3891
|
|
3463
3892
|
if (( enc = rb_default_internal_encoding() )) {
|
3464
3893
|
encname = pg_get_rb_encoding_as_pg_encoding( enc );
|
3465
|
-
if (
|
3466
|
-
|
3894
|
+
if ( pgconn_set_client_encoding_async(self, encname) != 0 )
|
3895
|
+
rb_warning( "Failed to set the default_internal encoding to %s: '%s'",
|
3467
3896
|
encname, PQerrorMessage(conn) );
|
3897
|
+
pgconn_set_internal_encoding_index( self );
|
3468
3898
|
return rb_enc_from_encoding( enc );
|
3469
3899
|
} else {
|
3900
|
+
pgconn_set_internal_encoding_index( self );
|
3470
3901
|
return Qnil;
|
3471
3902
|
}
|
3472
3903
|
}
|
3473
3904
|
|
3474
3905
|
|
3475
|
-
|
3906
|
+
/*
|
3907
|
+
* call-seq:
|
3908
|
+
* res.type_map_for_queries = typemap
|
3909
|
+
*
|
3910
|
+
* Set the default TypeMap that is used for type casts of query bind parameters.
|
3911
|
+
*
|
3912
|
+
* +typemap+ must be a kind of PG::TypeMap .
|
3913
|
+
*
|
3914
|
+
*/
|
3915
|
+
static VALUE
|
3916
|
+
pgconn_type_map_for_queries_set(VALUE self, VALUE typemap)
|
3917
|
+
{
|
3918
|
+
t_pg_connection *this = pg_get_connection( self );
|
3476
3919
|
|
3920
|
+
if ( !rb_obj_is_kind_of(typemap, rb_cTypeMap) ) {
|
3921
|
+
rb_raise( rb_eTypeError, "wrong argument type %s (expected kind of PG::TypeMap)",
|
3922
|
+
rb_obj_classname( typemap ) );
|
3923
|
+
}
|
3924
|
+
Check_Type(typemap, T_DATA);
|
3925
|
+
this->type_map_for_queries = typemap;
|
3477
3926
|
|
3927
|
+
return typemap;
|
3928
|
+
}
|
3478
3929
|
|
3930
|
+
/*
|
3931
|
+
* call-seq:
|
3932
|
+
* res.type_map_for_queries -> TypeMap
|
3933
|
+
*
|
3934
|
+
* Returns the default TypeMap that is currently set for type casts of query
|
3935
|
+
* bind parameters.
|
3936
|
+
*
|
3937
|
+
*/
|
3938
|
+
static VALUE
|
3939
|
+
pgconn_type_map_for_queries_get(VALUE self)
|
3940
|
+
{
|
3941
|
+
t_pg_connection *this = pg_get_connection( self );
|
3942
|
+
|
3943
|
+
return this->type_map_for_queries;
|
3944
|
+
}
|
3945
|
+
|
3946
|
+
/*
|
3947
|
+
* call-seq:
|
3948
|
+
* res.type_map_for_results = typemap
|
3949
|
+
*
|
3950
|
+
* Set the default TypeMap that is used for type casts of result values.
|
3951
|
+
*
|
3952
|
+
* +typemap+ must be a kind of PG::TypeMap .
|
3953
|
+
*
|
3954
|
+
*/
|
3955
|
+
static VALUE
|
3956
|
+
pgconn_type_map_for_results_set(VALUE self, VALUE typemap)
|
3957
|
+
{
|
3958
|
+
t_pg_connection *this = pg_get_connection( self );
|
3959
|
+
|
3960
|
+
if ( !rb_obj_is_kind_of(typemap, rb_cTypeMap) ) {
|
3961
|
+
rb_raise( rb_eTypeError, "wrong argument type %s (expected kind of PG::TypeMap)",
|
3962
|
+
rb_obj_classname( typemap ) );
|
3963
|
+
}
|
3964
|
+
Check_Type(typemap, T_DATA);
|
3965
|
+
this->type_map_for_results = typemap;
|
3966
|
+
|
3967
|
+
return typemap;
|
3968
|
+
}
|
3969
|
+
|
3970
|
+
/*
|
3971
|
+
* call-seq:
|
3972
|
+
* res.type_map_for_results -> TypeMap
|
3973
|
+
*
|
3974
|
+
* Returns the default TypeMap that is currently set for type casts of result values.
|
3975
|
+
*
|
3976
|
+
*/
|
3977
|
+
static VALUE
|
3978
|
+
pgconn_type_map_for_results_get(VALUE self)
|
3979
|
+
{
|
3980
|
+
t_pg_connection *this = pg_get_connection( self );
|
3981
|
+
|
3982
|
+
return this->type_map_for_results;
|
3983
|
+
}
|
3984
|
+
|
3985
|
+
|
3986
|
+
/*
|
3987
|
+
* call-seq:
|
3988
|
+
* res.encoder_for_put_copy_data = encoder
|
3989
|
+
*
|
3990
|
+
* Set the default coder that is used for type casting of parameters
|
3991
|
+
* to #put_copy_data .
|
3992
|
+
*
|
3993
|
+
* +encoder+ can be:
|
3994
|
+
* * a kind of PG::Coder
|
3995
|
+
* * +nil+ - disable type encoding, data must be a String.
|
3996
|
+
*
|
3997
|
+
*/
|
3998
|
+
static VALUE
|
3999
|
+
pgconn_encoder_for_put_copy_data_set(VALUE self, VALUE typemap)
|
4000
|
+
{
|
4001
|
+
t_pg_connection *this = pg_get_connection( self );
|
4002
|
+
|
4003
|
+
if( typemap != Qnil ){
|
4004
|
+
if ( !rb_obj_is_kind_of(typemap, rb_cPG_Coder) ) {
|
4005
|
+
rb_raise( rb_eTypeError, "wrong argument type %s (expected kind of PG::Coder)",
|
4006
|
+
rb_obj_classname( typemap ) );
|
4007
|
+
}
|
4008
|
+
Check_Type(typemap, T_DATA);
|
4009
|
+
}
|
4010
|
+
this->encoder_for_put_copy_data = typemap;
|
4011
|
+
|
4012
|
+
return typemap;
|
4013
|
+
}
|
4014
|
+
|
4015
|
+
/*
|
4016
|
+
* call-seq:
|
4017
|
+
* res.encoder_for_put_copy_data -> PG::Coder
|
4018
|
+
*
|
4019
|
+
* Returns the default coder object that is currently set for type casting of parameters
|
4020
|
+
* to #put_copy_data .
|
4021
|
+
*
|
4022
|
+
* Returns either:
|
4023
|
+
* * a kind of PG::Coder
|
4024
|
+
* * +nil+ - type encoding is disabled, data must be a String.
|
4025
|
+
*
|
4026
|
+
*/
|
4027
|
+
static VALUE
|
4028
|
+
pgconn_encoder_for_put_copy_data_get(VALUE self)
|
4029
|
+
{
|
4030
|
+
t_pg_connection *this = pg_get_connection( self );
|
4031
|
+
|
4032
|
+
return this->encoder_for_put_copy_data;
|
4033
|
+
}
|
4034
|
+
|
4035
|
+
/*
|
4036
|
+
* call-seq:
|
4037
|
+
* res.decoder_for_get_copy_data = decoder
|
4038
|
+
*
|
4039
|
+
* Set the default coder that is used for type casting of received data
|
4040
|
+
* by #get_copy_data .
|
4041
|
+
*
|
4042
|
+
* +decoder+ can be:
|
4043
|
+
* * a kind of PG::Coder
|
4044
|
+
* * +nil+ - disable type decoding, returned data will be a String.
|
4045
|
+
*
|
4046
|
+
*/
|
4047
|
+
static VALUE
|
4048
|
+
pgconn_decoder_for_get_copy_data_set(VALUE self, VALUE typemap)
|
4049
|
+
{
|
4050
|
+
t_pg_connection *this = pg_get_connection( self );
|
4051
|
+
|
4052
|
+
if( typemap != Qnil ){
|
4053
|
+
if ( !rb_obj_is_kind_of(typemap, rb_cPG_Coder) ) {
|
4054
|
+
rb_raise( rb_eTypeError, "wrong argument type %s (expected kind of PG::Coder)",
|
4055
|
+
rb_obj_classname( typemap ) );
|
4056
|
+
}
|
4057
|
+
Check_Type(typemap, T_DATA);
|
4058
|
+
}
|
4059
|
+
this->decoder_for_get_copy_data = typemap;
|
4060
|
+
|
4061
|
+
return typemap;
|
4062
|
+
}
|
4063
|
+
|
4064
|
+
/*
|
4065
|
+
* call-seq:
|
4066
|
+
* res.decoder_for_get_copy_data -> PG::Coder
|
4067
|
+
*
|
4068
|
+
* Returns the default coder object that is currently set for type casting of received
|
4069
|
+
* data by #get_copy_data .
|
4070
|
+
*
|
4071
|
+
* Returns either:
|
4072
|
+
* * a kind of PG::Coder
|
4073
|
+
* * +nil+ - type encoding is disabled, returned data will be a String.
|
4074
|
+
*
|
4075
|
+
*/
|
4076
|
+
static VALUE
|
4077
|
+
pgconn_decoder_for_get_copy_data_get(VALUE self)
|
4078
|
+
{
|
4079
|
+
t_pg_connection *this = pg_get_connection( self );
|
4080
|
+
|
4081
|
+
return this->decoder_for_get_copy_data;
|
4082
|
+
}
|
4083
|
+
|
4084
|
+
/*
|
4085
|
+
* call-seq:
|
4086
|
+
* conn.field_name_type = Symbol
|
4087
|
+
*
|
4088
|
+
* Set default type of field names of results retrieved by this connection.
|
4089
|
+
* It can be set to one of:
|
4090
|
+
* * +:string+ to use String based field names
|
4091
|
+
* * +:symbol+ to use Symbol based field names
|
4092
|
+
*
|
4093
|
+
* The default is +:string+ .
|
4094
|
+
*
|
4095
|
+
* Settings the type of field names affects only future results.
|
4096
|
+
*
|
4097
|
+
* See further description at PG::Result#field_name_type=
|
4098
|
+
*
|
4099
|
+
*/
|
4100
|
+
static VALUE
|
4101
|
+
pgconn_field_name_type_set(VALUE self, VALUE sym)
|
4102
|
+
{
|
4103
|
+
t_pg_connection *this = pg_get_connection( self );
|
4104
|
+
|
4105
|
+
this->flags &= ~PG_RESULT_FIELD_NAMES_MASK;
|
4106
|
+
if( sym == sym_symbol ) this->flags |= PG_RESULT_FIELD_NAMES_SYMBOL;
|
4107
|
+
else if ( sym == sym_static_symbol ) this->flags |= PG_RESULT_FIELD_NAMES_STATIC_SYMBOL;
|
4108
|
+
else if ( sym == sym_string );
|
4109
|
+
else rb_raise(rb_eArgError, "invalid argument %+"PRIsVALUE, sym);
|
4110
|
+
|
4111
|
+
return sym;
|
4112
|
+
}
|
4113
|
+
|
4114
|
+
/*
|
4115
|
+
* call-seq:
|
4116
|
+
* conn.field_name_type -> Symbol
|
4117
|
+
*
|
4118
|
+
* Get type of field names.
|
4119
|
+
*
|
4120
|
+
* See description at #field_name_type=
|
4121
|
+
*/
|
4122
|
+
static VALUE
|
4123
|
+
pgconn_field_name_type_get(VALUE self)
|
4124
|
+
{
|
4125
|
+
t_pg_connection *this = pg_get_connection( self );
|
4126
|
+
|
4127
|
+
if( this->flags & PG_RESULT_FIELD_NAMES_SYMBOL ){
|
4128
|
+
return sym_symbol;
|
4129
|
+
} else if( this->flags & PG_RESULT_FIELD_NAMES_STATIC_SYMBOL ){
|
4130
|
+
return sym_static_symbol;
|
4131
|
+
} else {
|
4132
|
+
return sym_string;
|
4133
|
+
}
|
4134
|
+
}
|
4135
|
+
|
4136
|
+
|
4137
|
+
/*
|
4138
|
+
* Document-class: PG::Connection
|
4139
|
+
*/
|
3479
4140
|
void
|
3480
4141
|
init_pg_connection()
|
3481
4142
|
{
|
4143
|
+
s_id_encode = rb_intern("encode");
|
4144
|
+
sym_type = ID2SYM(rb_intern("type"));
|
4145
|
+
sym_format = ID2SYM(rb_intern("format"));
|
4146
|
+
sym_value = ID2SYM(rb_intern("value"));
|
4147
|
+
sym_string = ID2SYM(rb_intern("string"));
|
4148
|
+
sym_symbol = ID2SYM(rb_intern("symbol"));
|
4149
|
+
sym_static_symbol = ID2SYM(rb_intern("static_symbol"));
|
4150
|
+
|
3482
4151
|
rb_cPGconn = rb_define_class_under( rb_mPG, "Connection", rb_cObject );
|
4152
|
+
/* Help rdoc to known the Constants module */
|
4153
|
+
/* rb_mPGconstants = rb_define_module_under( rb_mPG, "Constants" ); */
|
3483
4154
|
rb_include_module(rb_cPGconn, rb_mPGconstants);
|
3484
4155
|
|
3485
4156
|
/****** PG::Connection CLASS METHODS ******/
|
@@ -3497,9 +4168,7 @@ init_pg_connection()
|
|
3497
4168
|
rb_define_singleton_method(rb_cPGconn, "quote_ident", pgconn_s_quote_ident, 1);
|
3498
4169
|
rb_define_singleton_method(rb_cPGconn, "connect_start", pgconn_s_connect_start, -1);
|
3499
4170
|
rb_define_singleton_method(rb_cPGconn, "conndefaults", pgconn_s_conndefaults, 0);
|
3500
|
-
#ifdef HAVE_PQPING
|
3501
4171
|
rb_define_singleton_method(rb_cPGconn, "ping", pgconn_s_ping, -1);
|
3502
|
-
#endif
|
3503
4172
|
|
3504
4173
|
/****** PG::Connection INSTANCE METHODS: Connection Control ******/
|
3505
4174
|
rb_define_method(rb_cPGconn, "initialize", pgconn_init, -1);
|
@@ -3518,6 +4187,9 @@ init_pg_connection()
|
|
3518
4187
|
rb_define_method(rb_cPGconn, "host", pgconn_host, 0);
|
3519
4188
|
rb_define_method(rb_cPGconn, "port", pgconn_port, 0);
|
3520
4189
|
rb_define_method(rb_cPGconn, "tty", pgconn_tty, 0);
|
4190
|
+
#ifdef HAVE_PQCONNINFO
|
4191
|
+
rb_define_method(rb_cPGconn, "conninfo", pgconn_conninfo, 0);
|
4192
|
+
#endif
|
3521
4193
|
rb_define_method(rb_cPGconn, "options", pgconn_options, 0);
|
3522
4194
|
rb_define_method(rb_cPGconn, "status", pgconn_status, 0);
|
3523
4195
|
rb_define_method(rb_cPGconn, "transaction_status", pgconn_transaction_status, 0);
|
@@ -3526,39 +4198,47 @@ init_pg_connection()
|
|
3526
4198
|
rb_define_method(rb_cPGconn, "server_version", pgconn_server_version, 0);
|
3527
4199
|
rb_define_method(rb_cPGconn, "error_message", pgconn_error_message, 0);
|
3528
4200
|
rb_define_method(rb_cPGconn, "socket", pgconn_socket, 0);
|
3529
|
-
#if !defined(_WIN32) || defined(HAVE_RB_W32_WRAP_IO_HANDLE)
|
3530
4201
|
rb_define_method(rb_cPGconn, "socket_io", pgconn_socket_io, 0);
|
3531
|
-
#endif
|
3532
4202
|
rb_define_method(rb_cPGconn, "backend_pid", pgconn_backend_pid, 0);
|
3533
4203
|
rb_define_method(rb_cPGconn, "connection_needs_password", pgconn_connection_needs_password, 0);
|
3534
4204
|
rb_define_method(rb_cPGconn, "connection_used_password", pgconn_connection_used_password, 0);
|
3535
4205
|
/* rb_define_method(rb_cPGconn, "getssl", pgconn_getssl, 0); */
|
3536
4206
|
|
3537
4207
|
/****** PG::Connection INSTANCE METHODS: Command Execution ******/
|
3538
|
-
rb_define_method(rb_cPGconn, "
|
3539
|
-
|
3540
|
-
rb_define_method(rb_cPGconn, "
|
3541
|
-
rb_define_method(rb_cPGconn, "
|
3542
|
-
rb_define_method(rb_cPGconn, "
|
3543
|
-
rb_define_method(rb_cPGconn, "
|
3544
|
-
|
4208
|
+
rb_define_method(rb_cPGconn, "sync_exec", pgconn_exec, -1);
|
4209
|
+
rb_define_method(rb_cPGconn, "sync_exec_params", pgconn_exec_params, -1);
|
4210
|
+
rb_define_method(rb_cPGconn, "sync_prepare", pgconn_prepare, -1);
|
4211
|
+
rb_define_method(rb_cPGconn, "sync_exec_prepared", pgconn_exec_prepared, -1);
|
4212
|
+
rb_define_method(rb_cPGconn, "sync_describe_prepared", pgconn_describe_prepared, 1);
|
4213
|
+
rb_define_method(rb_cPGconn, "sync_describe_portal", pgconn_describe_portal, 1);
|
4214
|
+
|
4215
|
+
rb_define_method(rb_cPGconn, "exec", pgconn_async_exec, -1);
|
4216
|
+
rb_define_method(rb_cPGconn, "exec_params", pgconn_async_exec_params, -1);
|
4217
|
+
rb_define_method(rb_cPGconn, "prepare", pgconn_async_prepare, -1);
|
4218
|
+
rb_define_method(rb_cPGconn, "exec_prepared", pgconn_async_exec_prepared, -1);
|
4219
|
+
rb_define_method(rb_cPGconn, "describe_prepared", pgconn_async_describe_prepared, 1);
|
4220
|
+
rb_define_method(rb_cPGconn, "describe_portal", pgconn_async_describe_portal, 1);
|
4221
|
+
|
4222
|
+
rb_define_alias(rb_cPGconn, "async_exec", "exec");
|
4223
|
+
rb_define_alias(rb_cPGconn, "async_query", "async_exec");
|
4224
|
+
rb_define_alias(rb_cPGconn, "async_exec_params", "exec_params");
|
4225
|
+
rb_define_alias(rb_cPGconn, "async_prepare", "prepare");
|
4226
|
+
rb_define_alias(rb_cPGconn, "async_exec_prepared", "exec_prepared");
|
4227
|
+
rb_define_alias(rb_cPGconn, "async_describe_prepared", "describe_prepared");
|
4228
|
+
rb_define_alias(rb_cPGconn, "async_describe_portal", "describe_portal");
|
4229
|
+
|
3545
4230
|
rb_define_method(rb_cPGconn, "make_empty_pgresult", pgconn_make_empty_pgresult, 1);
|
3546
4231
|
rb_define_method(rb_cPGconn, "escape_string", pgconn_s_escape, 1);
|
3547
4232
|
rb_define_alias(rb_cPGconn, "escape", "escape_string");
|
3548
|
-
#ifdef HAVE_PQESCAPELITERAL
|
3549
4233
|
rb_define_method(rb_cPGconn, "escape_literal", pgconn_escape_literal, 1);
|
3550
|
-
#endif
|
3551
|
-
#ifdef HAVE_PQESCAPEIDENTIFIER
|
3552
4234
|
rb_define_method(rb_cPGconn, "escape_identifier", pgconn_escape_identifier, 1);
|
3553
|
-
#endif
|
3554
4235
|
rb_define_method(rb_cPGconn, "escape_bytea", pgconn_s_escape_bytea, 1);
|
3555
4236
|
rb_define_method(rb_cPGconn, "unescape_bytea", pgconn_s_unescape_bytea, 1);
|
3556
|
-
#ifdef HAVE_PQSETSINGLEROWMODE
|
3557
4237
|
rb_define_method(rb_cPGconn, "set_single_row_mode", pgconn_set_single_row_mode, 0);
|
3558
|
-
#endif
|
3559
4238
|
|
3560
4239
|
/****** PG::Connection INSTANCE METHODS: Asynchronous Command Processing ******/
|
3561
4240
|
rb_define_method(rb_cPGconn, "send_query", pgconn_send_query, -1);
|
4241
|
+
rb_define_method(rb_cPGconn, "send_query_params", pgconn_send_query_params, -1);
|
3562
4242
|
rb_define_method(rb_cPGconn, "send_prepare", pgconn_send_prepare, -1);
|
3563
4243
|
rb_define_method(rb_cPGconn, "send_query_prepared", pgconn_send_query_prepared, -1);
|
3564
4244
|
rb_define_method(rb_cPGconn, "send_describe_prepared", pgconn_send_describe_prepared, 1);
|
@@ -3570,6 +4250,7 @@ init_pg_connection()
|
|
3570
4250
|
rb_define_method(rb_cPGconn, "isnonblocking", pgconn_isnonblocking, 0);
|
3571
4251
|
rb_define_alias(rb_cPGconn, "nonblocking?", "isnonblocking");
|
3572
4252
|
rb_define_method(rb_cPGconn, "flush", pgconn_flush, 0);
|
4253
|
+
rb_define_method(rb_cPGconn, "discard_results", pgconn_discard_results, 0);
|
3573
4254
|
|
3574
4255
|
/****** PG::Connection INSTANCE METHODS: Cancelling Queries in Progress ******/
|
3575
4256
|
rb_define_method(rb_cPGconn, "cancel", pgconn_cancel, 0);
|
@@ -3578,12 +4259,15 @@ init_pg_connection()
|
|
3578
4259
|
rb_define_method(rb_cPGconn, "notifies", pgconn_notifies, 0);
|
3579
4260
|
|
3580
4261
|
/****** PG::Connection INSTANCE METHODS: COPY ******/
|
3581
|
-
rb_define_method(rb_cPGconn, "put_copy_data", pgconn_put_copy_data, 1);
|
4262
|
+
rb_define_method(rb_cPGconn, "put_copy_data", pgconn_put_copy_data, -1);
|
3582
4263
|
rb_define_method(rb_cPGconn, "put_copy_end", pgconn_put_copy_end, -1);
|
3583
4264
|
rb_define_method(rb_cPGconn, "get_copy_data", pgconn_get_copy_data, -1);
|
3584
4265
|
|
3585
4266
|
/****** PG::Connection INSTANCE METHODS: Control Functions ******/
|
3586
4267
|
rb_define_method(rb_cPGconn, "set_error_verbosity", pgconn_set_error_verbosity, 1);
|
4268
|
+
#ifdef HAVE_PQRESULTVERBOSEERRORMESSAGE
|
4269
|
+
rb_define_method(rb_cPGconn, "set_error_context_visibility", pgconn_set_error_context_visibility, 1 );
|
4270
|
+
#endif
|
3587
4271
|
rb_define_method(rb_cPGconn, "trace", pgconn_trace, 1);
|
3588
4272
|
rb_define_method(rb_cPGconn, "untrace", pgconn_untrace, 0);
|
3589
4273
|
|
@@ -3600,9 +4284,16 @@ init_pg_connection()
|
|
3600
4284
|
rb_define_method(rb_cPGconn, "wait_for_notify", pgconn_wait_for_notify, -1);
|
3601
4285
|
rb_define_alias(rb_cPGconn, "notifies_wait", "wait_for_notify");
|
3602
4286
|
rb_define_method(rb_cPGconn, "quote_ident", pgconn_s_quote_ident, 1);
|
3603
|
-
rb_define_method(rb_cPGconn, "async_exec", pgconn_async_exec, -1);
|
3604
|
-
rb_define_alias(rb_cPGconn, "async_query", "async_exec");
|
3605
4287
|
rb_define_method(rb_cPGconn, "get_last_result", pgconn_get_last_result, 0);
|
4288
|
+
#ifdef HAVE_PQENCRYPTPASSWORDCONN
|
4289
|
+
rb_define_method(rb_cPGconn, "encrypt_password", pgconn_encrypt_password, -1);
|
4290
|
+
#endif
|
4291
|
+
|
4292
|
+
#ifdef HAVE_PQSSLATTRIBUTE
|
4293
|
+
rb_define_method(rb_cPGconn, "ssl_in_use?", pgconn_ssl_in_use, 0);
|
4294
|
+
rb_define_method(rb_cPGconn, "ssl_attribute", pgconn_ssl_attribute, 1);
|
4295
|
+
rb_define_method(rb_cPGconn, "ssl_attribute_names", pgconn_ssl_attribute_names, 0);
|
4296
|
+
#endif
|
3606
4297
|
|
3607
4298
|
/****** PG::Connection INSTANCE METHODS: Large Object Support ******/
|
3608
4299
|
rb_define_method(rb_cPGconn, "lo_creat", pgconn_locreat, -1);
|
@@ -3632,12 +4323,20 @@ init_pg_connection()
|
|
3632
4323
|
rb_define_method(rb_cPGconn, "lo_unlink", pgconn_lounlink, 1);
|
3633
4324
|
rb_define_alias(rb_cPGconn, "lounlink", "lo_unlink");
|
3634
4325
|
|
3635
|
-
#ifdef M17N_SUPPORTED
|
3636
4326
|
rb_define_method(rb_cPGconn, "internal_encoding", pgconn_internal_encoding, 0);
|
3637
4327
|
rb_define_method(rb_cPGconn, "internal_encoding=", pgconn_internal_encoding_set, 1);
|
3638
4328
|
rb_define_method(rb_cPGconn, "external_encoding", pgconn_external_encoding, 0);
|
3639
4329
|
rb_define_method(rb_cPGconn, "set_default_encoding", pgconn_set_default_encoding, 0);
|
3640
|
-
#endif /* M17N_SUPPORTED */
|
3641
4330
|
|
4331
|
+
rb_define_method(rb_cPGconn, "type_map_for_queries=", pgconn_type_map_for_queries_set, 1);
|
4332
|
+
rb_define_method(rb_cPGconn, "type_map_for_queries", pgconn_type_map_for_queries_get, 0);
|
4333
|
+
rb_define_method(rb_cPGconn, "type_map_for_results=", pgconn_type_map_for_results_set, 1);
|
4334
|
+
rb_define_method(rb_cPGconn, "type_map_for_results", pgconn_type_map_for_results_get, 0);
|
4335
|
+
rb_define_method(rb_cPGconn, "encoder_for_put_copy_data=", pgconn_encoder_for_put_copy_data_set, 1);
|
4336
|
+
rb_define_method(rb_cPGconn, "encoder_for_put_copy_data", pgconn_encoder_for_put_copy_data_get, 0);
|
4337
|
+
rb_define_method(rb_cPGconn, "decoder_for_get_copy_data=", pgconn_decoder_for_get_copy_data_set, 1);
|
4338
|
+
rb_define_method(rb_cPGconn, "decoder_for_get_copy_data", pgconn_decoder_for_get_copy_data_get, 0);
|
4339
|
+
|
4340
|
+
rb_define_method(rb_cPGconn, "field_name_type=", pgconn_field_name_type_set, 1 );
|
4341
|
+
rb_define_method(rb_cPGconn, "field_name_type", pgconn_field_name_type_get, 0 );
|
3642
4342
|
}
|
3643
|
-
|