pg 0.15.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.tar.gz.sig +0 -0
- data/BSDL +2 -2
- data/ChangeLog +0 -3022
- data/History.rdoc +370 -4
- data/Manifest.txt +39 -19
- data/README-Windows.rdoc +17 -28
- data/README.ja.rdoc +1 -2
- data/README.rdoc +113 -14
- data/Rakefile +97 -36
- data/Rakefile.cross +109 -83
- data/ext/errorcodes.def +1032 -0
- data/ext/errorcodes.rb +45 -0
- data/ext/errorcodes.txt +494 -0
- data/ext/extconf.rb +55 -52
- data/ext/gvl_wrappers.c +4 -0
- data/ext/gvl_wrappers.h +94 -38
- data/ext/pg.c +273 -121
- data/ext/pg.h +292 -50
- 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 +1811 -1051
- data/ext/pg_copy_coder.c +599 -0
- data/ext/pg_errors.c +95 -0
- data/ext/pg_record_coder.c +491 -0
- data/ext/pg_result.c +917 -203
- 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.rb +31 -9
- 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 +235 -30
- 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/spec/{lib/helpers.rb → helpers.rb} +154 -52
- data/spec/pg/basic_type_mapping_spec.rb +630 -0
- data/spec/pg/connection_spec.rb +1352 -426
- data/spec/pg/connection_sync_spec.rb +41 -0
- data/spec/pg/result_spec.rb +508 -105
- 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 +35 -16
- metadata +163 -84
- 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 ( !
|
43
|
-
rb_raise(
|
70
|
+
if ( !this->pgconn )
|
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
|
-
|
61
|
-
rb_raise(rb_ePGerror, "Could not unwrap win32 socket handle");
|
88
|
+
#if defined(_WIN32)
|
89
|
+
if( rb_w32_unwrap_io_handle(this->ruby_sd) ){
|
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
|
+
}
|
80
129
|
|
81
|
-
|
130
|
+
return ary;
|
131
|
+
}
|
132
|
+
|
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,7 +188,20 @@ pgconn_gc_free( PGconn *conn )
|
|
113
188
|
static VALUE
|
114
189
|
pgconn_s_allocate( VALUE klass )
|
115
190
|
{
|
116
|
-
|
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
|
+
|
204
|
+
return self;
|
117
205
|
}
|
118
206
|
|
119
207
|
|
@@ -128,32 +216,27 @@ pgconn_s_allocate( VALUE klass )
|
|
128
216
|
*
|
129
217
|
* Create a connection to the specified server.
|
130
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:
|
131
226
|
* [+host+]
|
132
227
|
* server hostname
|
133
|
-
* [+hostaddr+]
|
134
|
-
* server address (avoids hostname lookup, overrides +host+)
|
135
228
|
* [+port+]
|
136
229
|
* server port number
|
230
|
+
* [+options+]
|
231
|
+
* backend options
|
232
|
+
* [+tty+]
|
233
|
+
* (ignored in newer versions of PostgreSQL)
|
137
234
|
* [+dbname+]
|
138
235
|
* connecting database name
|
139
236
|
* [+user+]
|
140
237
|
* login user name
|
141
238
|
* [+password+]
|
142
239
|
* login password
|
143
|
-
* [+connect_timeout+]
|
144
|
-
* maximum time to wait for connection to succeed
|
145
|
-
* [+options+]
|
146
|
-
* backend options
|
147
|
-
* [+tty+]
|
148
|
-
* (ignored in newer versions of PostgreSQL)
|
149
|
-
* [+sslmode+]
|
150
|
-
* (disable|allow|prefer|require)
|
151
|
-
* [+krbsrvname+]
|
152
|
-
* kerberos service name
|
153
|
-
* [+gsslib+]
|
154
|
-
* GSS library to use for GSSAPI authentication
|
155
|
-
* [+service+]
|
156
|
-
* service name to use for additional parameters
|
157
240
|
*
|
158
241
|
* Examples:
|
159
242
|
*
|
@@ -169,7 +252,7 @@ pgconn_s_allocate( VALUE klass )
|
|
169
252
|
* # As an Array
|
170
253
|
* PG::Connection.new( nil, 5432, nil, nil, 'test', nil, nil )
|
171
254
|
*
|
172
|
-
* 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
|
173
256
|
* connection will have its +client_encoding+ set accordingly.
|
174
257
|
*
|
175
258
|
* Raises a PG::Error if the connection fails.
|
@@ -177,28 +260,24 @@ pgconn_s_allocate( VALUE klass )
|
|
177
260
|
static VALUE
|
178
261
|
pgconn_init(int argc, VALUE *argv, VALUE self)
|
179
262
|
{
|
180
|
-
|
263
|
+
t_pg_connection *this;
|
181
264
|
VALUE conninfo;
|
182
265
|
VALUE error;
|
183
266
|
|
267
|
+
this = pg_get_connection( self );
|
184
268
|
conninfo = rb_funcall2( rb_cPGconn, rb_intern("parse_connect_args"), argc, argv );
|
185
|
-
|
269
|
+
this->pgconn = gvl_PQconnectdb(StringValueCStr(conninfo));
|
186
270
|
|
187
|
-
if(
|
188
|
-
rb_raise(rb_ePGerror, "
|
189
|
-
|
190
|
-
Check_Type(self, T_DATA);
|
191
|
-
DATA_PTR(self) = conn;
|
271
|
+
if(this->pgconn == NULL)
|
272
|
+
rb_raise(rb_ePGerror, "PQconnectdb() unable to allocate structure");
|
192
273
|
|
193
|
-
if (PQstatus(
|
194
|
-
error = rb_exc_new2(
|
274
|
+
if (PQstatus(this->pgconn) == CONNECTION_BAD) {
|
275
|
+
error = rb_exc_new2(rb_eConnectionBad, PQerrorMessage(this->pgconn));
|
195
276
|
rb_iv_set(error, "@connection", self);
|
196
277
|
rb_exc_raise(error);
|
197
278
|
}
|
198
279
|
|
199
|
-
#ifdef M17N_SUPPORTED
|
200
280
|
pgconn_set_default_encoding( self );
|
201
|
-
#endif
|
202
281
|
|
203
282
|
if (rb_block_given_p()) {
|
204
283
|
return rb_ensure(rb_yield, self, pgconn_finish, self);
|
@@ -212,40 +291,40 @@ pgconn_init(int argc, VALUE *argv, VALUE self)
|
|
212
291
|
* PG::Connection.connect_start(connection_string) -> conn
|
213
292
|
* PG::Connection.connect_start(host, port, options, tty, dbname, login, password) -> conn
|
214
293
|
*
|
215
|
-
* This is an asynchronous version of PG::Connection.
|
294
|
+
* This is an asynchronous version of PG::Connection.new.
|
216
295
|
*
|
217
296
|
* Use #connect_poll to poll the status of the connection.
|
218
297
|
*
|
219
298
|
* NOTE: this does *not* set the connection's +client_encoding+ for you if
|
220
|
-
* 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,
|
221
300
|
* call #internal_encoding=. You can also set it automatically by setting
|
222
|
-
* 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].
|
223
304
|
*
|
224
305
|
*/
|
225
306
|
static VALUE
|
226
307
|
pgconn_s_connect_start( int argc, VALUE *argv, VALUE klass )
|
227
308
|
{
|
228
|
-
PGconn *conn = NULL;
|
229
309
|
VALUE rb_conn;
|
230
310
|
VALUE conninfo;
|
231
311
|
VALUE error;
|
312
|
+
t_pg_connection *this;
|
232
313
|
|
233
314
|
/*
|
234
315
|
* PG::Connection.connect_start must act as both alloc() and initialize()
|
235
316
|
* because it is not invoked by calling new().
|
236
317
|
*/
|
237
318
|
rb_conn = pgconn_s_allocate( klass );
|
319
|
+
this = pg_get_connection( rb_conn );
|
238
320
|
conninfo = rb_funcall2( klass, rb_intern("parse_connect_args"), argc, argv );
|
239
|
-
|
321
|
+
this->pgconn = gvl_PQconnectStart( StringValueCStr(conninfo) );
|
240
322
|
|
241
|
-
if(
|
323
|
+
if( this->pgconn == NULL )
|
242
324
|
rb_raise(rb_ePGerror, "PQconnectStart() unable to allocate structure");
|
243
325
|
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
if ( PQstatus(conn) == CONNECTION_BAD ) {
|
248
|
-
error = rb_exc_new2(rb_ePGerror, PQerrorMessage(conn));
|
326
|
+
if ( PQstatus(this->pgconn) == CONNECTION_BAD ) {
|
327
|
+
error = rb_exc_new2(rb_eConnectionBad, PQerrorMessage(this->pgconn));
|
249
328
|
rb_iv_set(error, "@connection", rb_conn);
|
250
329
|
rb_exc_raise(error);
|
251
330
|
}
|
@@ -256,15 +335,16 @@ pgconn_s_connect_start( int argc, VALUE *argv, VALUE klass )
|
|
256
335
|
return rb_conn;
|
257
336
|
}
|
258
337
|
|
259
|
-
#ifdef HAVE_PQPING
|
260
338
|
/*
|
261
339
|
* call-seq:
|
262
|
-
* PG::Connection.ping(connection_hash) ->
|
263
|
-
* PG::Connection.ping(connection_string) ->
|
264
|
-
* 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
|
265
343
|
*
|
266
344
|
* Check server status.
|
267
345
|
*
|
346
|
+
* See PG::Connection.new for a description of the parameters.
|
347
|
+
*
|
268
348
|
* Returns one of:
|
269
349
|
* [+PQPING_OK+]
|
270
350
|
* server is accepting connections
|
@@ -282,13 +362,15 @@ pgconn_s_ping( int argc, VALUE *argv, VALUE klass )
|
|
282
362
|
VALUE conninfo;
|
283
363
|
|
284
364
|
conninfo = rb_funcall2( klass, rb_intern("parse_connect_args"), argc, argv );
|
285
|
-
ping = PQping(
|
365
|
+
ping = PQping( StringValueCStr(conninfo) );
|
286
366
|
|
287
367
|
return INT2FIX((int)ping);
|
288
368
|
}
|
289
|
-
|
369
|
+
|
290
370
|
|
291
371
|
/*
|
372
|
+
* Document-method: PG::Connection.conndefaults
|
373
|
+
*
|
292
374
|
* call-seq:
|
293
375
|
* PG::Connection.conndefaults() -> Array
|
294
376
|
*
|
@@ -312,44 +394,72 @@ static VALUE
|
|
312
394
|
pgconn_s_conndefaults(VALUE self)
|
313
395
|
{
|
314
396
|
PQconninfoOption *options = PQconndefaults();
|
315
|
-
VALUE
|
316
|
-
|
317
|
-
|
397
|
+
VALUE array = pgconn_make_conninfo_array( options );
|
398
|
+
|
399
|
+
PQconninfoFree(options);
|
318
400
|
|
319
401
|
UNUSED( self );
|
320
402
|
|
321
|
-
|
322
|
-
|
323
|
-
|
324
|
-
|
325
|
-
|
326
|
-
|
327
|
-
|
328
|
-
|
329
|
-
|
330
|
-
|
331
|
-
|
332
|
-
|
333
|
-
|
334
|
-
|
335
|
-
|
336
|
-
|
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));
|
337
449
|
}
|
338
|
-
|
339
|
-
return
|
450
|
+
|
451
|
+
return rval;
|
340
452
|
}
|
453
|
+
#endif
|
341
454
|
|
342
455
|
|
343
456
|
/*
|
344
457
|
* call-seq:
|
345
458
|
* PG::Connection.encrypt_password( password, username ) -> String
|
346
459
|
*
|
347
|
-
* This
|
348
|
-
*
|
349
|
-
* The arguments are the cleartext password, and the SQL name
|
350
|
-
* 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.
|
351
462
|
*
|
352
|
-
* Return value is the encrypted password.
|
353
463
|
*/
|
354
464
|
static VALUE
|
355
465
|
pgconn_s_encrypt_password(VALUE self, VALUE password, VALUE username)
|
@@ -362,13 +472,10 @@ pgconn_s_encrypt_password(VALUE self, VALUE password, VALUE username)
|
|
362
472
|
Check_Type(password, T_STRING);
|
363
473
|
Check_Type(username, T_STRING);
|
364
474
|
|
365
|
-
encrypted = PQencryptPassword(
|
475
|
+
encrypted = PQencryptPassword(StringValueCStr(password), StringValueCStr(username));
|
366
476
|
rval = rb_str_new2( encrypted );
|
367
477
|
PQfreemem( encrypted );
|
368
478
|
|
369
|
-
OBJ_INFECT( rval, password );
|
370
|
-
OBJ_INFECT( rval, username );
|
371
|
-
|
372
479
|
return rval;
|
373
480
|
}
|
374
481
|
|
@@ -379,7 +486,7 @@ pgconn_s_encrypt_password(VALUE self, VALUE password, VALUE username)
|
|
379
486
|
|
380
487
|
/*
|
381
488
|
* call-seq:
|
382
|
-
* conn.connect_poll() ->
|
489
|
+
* conn.connect_poll() -> Integer
|
383
490
|
*
|
384
491
|
* Returns one of:
|
385
492
|
* [+PGRES_POLLING_READING+]
|
@@ -415,7 +522,7 @@ static VALUE
|
|
415
522
|
pgconn_connect_poll(VALUE self)
|
416
523
|
{
|
417
524
|
PostgresPollingStatusType status;
|
418
|
-
status =
|
525
|
+
status = gvl_PQconnectPoll(pg_get_pgconn(self));
|
419
526
|
return INT2FIX((int)status);
|
420
527
|
}
|
421
528
|
|
@@ -428,9 +535,11 @@ pgconn_connect_poll(VALUE self)
|
|
428
535
|
static VALUE
|
429
536
|
pgconn_finish( VALUE self )
|
430
537
|
{
|
538
|
+
t_pg_connection *this = pg_get_connection_safe( self );
|
539
|
+
|
431
540
|
pgconn_close_socket_io( self );
|
432
|
-
PQfinish(
|
433
|
-
|
541
|
+
PQfinish( this->pgconn );
|
542
|
+
this->pgconn = NULL;
|
434
543
|
return Qnil;
|
435
544
|
}
|
436
545
|
|
@@ -444,7 +553,8 @@ pgconn_finish( VALUE self )
|
|
444
553
|
static VALUE
|
445
554
|
pgconn_finished_p( VALUE self )
|
446
555
|
{
|
447
|
-
|
556
|
+
t_pg_connection *this = pg_get_connection( self );
|
557
|
+
if ( this->pgconn ) return Qfalse;
|
448
558
|
return Qtrue;
|
449
559
|
}
|
450
560
|
|
@@ -460,7 +570,7 @@ static VALUE
|
|
460
570
|
pgconn_reset( VALUE self )
|
461
571
|
{
|
462
572
|
pgconn_close_socket_io( self );
|
463
|
-
|
573
|
+
gvl_PQreset( pg_get_pgconn(self) );
|
464
574
|
return self;
|
465
575
|
}
|
466
576
|
|
@@ -478,14 +588,14 @@ static VALUE
|
|
478
588
|
pgconn_reset_start(VALUE self)
|
479
589
|
{
|
480
590
|
pgconn_close_socket_io( self );
|
481
|
-
if(
|
482
|
-
rb_raise(
|
591
|
+
if(gvl_PQresetStart(pg_get_pgconn(self)) == 0)
|
592
|
+
rb_raise(rb_eUnableToSend, "reset has failed");
|
483
593
|
return Qnil;
|
484
594
|
}
|
485
595
|
|
486
596
|
/*
|
487
597
|
* call-seq:
|
488
|
-
* conn.reset_poll ->
|
598
|
+
* conn.reset_poll -> Integer
|
489
599
|
*
|
490
600
|
* Checks the status of a connection reset operation.
|
491
601
|
* See #connect_start and #connect_poll for
|
@@ -495,10 +605,11 @@ static VALUE
|
|
495
605
|
pgconn_reset_poll(VALUE self)
|
496
606
|
{
|
497
607
|
PostgresPollingStatusType status;
|
498
|
-
status =
|
608
|
+
status = gvl_PQresetPoll(pg_get_pgconn(self));
|
499
609
|
return INT2FIX((int)status);
|
500
610
|
}
|
501
611
|
|
612
|
+
|
502
613
|
/*
|
503
614
|
* call-seq:
|
504
615
|
* conn.db()
|
@@ -510,7 +621,7 @@ pgconn_db(VALUE self)
|
|
510
621
|
{
|
511
622
|
char *db = PQdb(pg_get_pgconn(self));
|
512
623
|
if (!db) return Qnil;
|
513
|
-
return
|
624
|
+
return rb_str_new2(db);
|
514
625
|
}
|
515
626
|
|
516
627
|
/*
|
@@ -524,21 +635,21 @@ pgconn_user(VALUE self)
|
|
524
635
|
{
|
525
636
|
char *user = PQuser(pg_get_pgconn(self));
|
526
637
|
if (!user) return Qnil;
|
527
|
-
return
|
638
|
+
return rb_str_new2(user);
|
528
639
|
}
|
529
640
|
|
530
641
|
/*
|
531
642
|
* call-seq:
|
532
643
|
* conn.pass()
|
533
644
|
*
|
534
|
-
* Returns the authenticated
|
645
|
+
* Returns the authenticated password.
|
535
646
|
*/
|
536
647
|
static VALUE
|
537
648
|
pgconn_pass(VALUE self)
|
538
649
|
{
|
539
650
|
char *user = PQpass(pg_get_pgconn(self));
|
540
651
|
if (!user) return Qnil;
|
541
|
-
return
|
652
|
+
return rb_str_new2(user);
|
542
653
|
}
|
543
654
|
|
544
655
|
/*
|
@@ -552,7 +663,7 @@ pgconn_host(VALUE self)
|
|
552
663
|
{
|
553
664
|
char *host = PQhost(pg_get_pgconn(self));
|
554
665
|
if (!host) return Qnil;
|
555
|
-
return
|
666
|
+
return rb_str_new2(host);
|
556
667
|
}
|
557
668
|
|
558
669
|
/*
|
@@ -579,7 +690,7 @@ pgconn_tty(VALUE self)
|
|
579
690
|
{
|
580
691
|
char *tty = PQtty(pg_get_pgconn(self));
|
581
692
|
if (!tty) return Qnil;
|
582
|
-
return
|
693
|
+
return rb_str_new2(tty);
|
583
694
|
}
|
584
695
|
|
585
696
|
/*
|
@@ -593,8 +704,32 @@ pgconn_options(VALUE self)
|
|
593
704
|
{
|
594
705
|
char *options = PQoptions(pg_get_pgconn(self));
|
595
706
|
if (!options) return Qnil;
|
596
|
-
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;
|
597
730
|
}
|
731
|
+
#endif
|
732
|
+
|
598
733
|
|
599
734
|
/*
|
600
735
|
* call-seq:
|
@@ -646,11 +781,11 @@ pgconn_transaction_status(VALUE self)
|
|
646
781
|
static VALUE
|
647
782
|
pgconn_parameter_status(VALUE self, VALUE param_name)
|
648
783
|
{
|
649
|
-
const char *ret = PQparameterStatus(pg_get_pgconn(self),
|
784
|
+
const char *ret = PQparameterStatus(pg_get_pgconn(self), StringValueCStr(param_name));
|
650
785
|
if(ret == NULL)
|
651
786
|
return Qnil;
|
652
787
|
else
|
653
|
-
return
|
788
|
+
return rb_str_new2(ret);
|
654
789
|
}
|
655
790
|
|
656
791
|
/*
|
@@ -695,12 +830,14 @@ pgconn_error_message(VALUE self)
|
|
695
830
|
{
|
696
831
|
char *error = PQerrorMessage(pg_get_pgconn(self));
|
697
832
|
if (!error) return Qnil;
|
698
|
-
return
|
833
|
+
return rb_str_new2(error);
|
699
834
|
}
|
700
835
|
|
701
836
|
/*
|
702
837
|
* call-seq:
|
703
|
-
* conn.socket() ->
|
838
|
+
* conn.socket() -> Integer
|
839
|
+
*
|
840
|
+
* This method is deprecated. Please use the more portable method #socket_io .
|
704
841
|
*
|
705
842
|
* Returns the socket's file descriptor for this connection.
|
706
843
|
* <tt>IO.for_fd()</tt> can be used to build a proper IO object to the socket.
|
@@ -710,34 +847,31 @@ pgconn_error_message(VALUE self)
|
|
710
847
|
* creates an IO that's associated with the connection object itself,
|
711
848
|
* and so won't go out of scope until the connection does.
|
712
849
|
*
|
713
|
-
* *Note:* On Windows the file descriptor is not
|
850
|
+
* *Note:* On Windows the file descriptor is not usable,
|
714
851
|
* since it can not be used to build a Ruby IO object.
|
715
852
|
*/
|
716
853
|
static VALUE
|
717
854
|
pgconn_socket(VALUE self)
|
718
855
|
{
|
719
856
|
int sd;
|
857
|
+
pg_deprecated(4, ("conn.socket is deprecated and should be replaced by conn.socket_io"));
|
858
|
+
|
720
859
|
if( (sd = PQsocket(pg_get_pgconn(self))) < 0)
|
721
|
-
rb_raise(
|
860
|
+
rb_raise(rb_eConnectionBad, "PQsocket() can't get socket descriptor");
|
722
861
|
return INT2NUM(sd);
|
723
862
|
}
|
724
863
|
|
725
|
-
|
726
|
-
#if !defined(_WIN32) || defined(HAVE_RB_W32_WRAP_IO_HANDLE)
|
727
|
-
|
728
864
|
/*
|
729
865
|
* call-seq:
|
730
866
|
* conn.socket_io() -> IO
|
731
867
|
*
|
732
|
-
* Fetch a
|
868
|
+
* Fetch a memorized IO object created from the Connection's underlying socket.
|
733
869
|
* This object can be used for IO.select to wait for events while running
|
734
870
|
* asynchronous API calls.
|
735
871
|
*
|
736
872
|
* Using this instead of #socket avoids the problem of the underlying connection
|
737
873
|
* being closed by Ruby when an IO created using <tt>IO.for_fd(conn.socket)</tt>
|
738
|
-
* goes out of scope.
|
739
|
-
*
|
740
|
-
* 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.
|
741
875
|
*/
|
742
876
|
static VALUE
|
743
877
|
pgconn_socket_io(VALUE self)
|
@@ -745,36 +879,34 @@ pgconn_socket_io(VALUE self)
|
|
745
879
|
int sd;
|
746
880
|
int ruby_sd;
|
747
881
|
ID id_autoclose = rb_intern("autoclose=");
|
748
|
-
|
882
|
+
t_pg_connection *this = pg_get_connection_safe( self );
|
883
|
+
VALUE socket_io = this->socket_io;
|
749
884
|
|
750
885
|
if ( !RTEST(socket_io) ) {
|
751
|
-
if( (sd = PQsocket(
|
752
|
-
rb_raise(
|
886
|
+
if( (sd = PQsocket(this->pgconn)) < 0)
|
887
|
+
rb_raise(rb_eConnectionBad, "PQsocket() can't get socket descriptor");
|
753
888
|
|
754
889
|
#ifdef _WIN32
|
755
890
|
ruby_sd = rb_w32_wrap_io_handle((HANDLE)(intptr_t)sd, O_RDWR|O_BINARY|O_NOINHERIT);
|
891
|
+
this->ruby_sd = ruby_sd;
|
756
892
|
#else
|
757
893
|
ruby_sd = sd;
|
758
894
|
#endif
|
759
895
|
|
760
896
|
socket_io = rb_funcall( rb_cIO, rb_intern("for_fd"), 1, INT2NUM(ruby_sd) );
|
761
897
|
|
762
|
-
/* Disable autoclose feature
|
763
|
-
|
764
|
-
rb_funcall( socket_io, id_autoclose, 1, Qfalse );
|
765
|
-
}
|
898
|
+
/* Disable autoclose feature */
|
899
|
+
rb_funcall( socket_io, id_autoclose, 1, Qfalse );
|
766
900
|
|
767
|
-
|
901
|
+
this->socket_io = socket_io;
|
768
902
|
}
|
769
903
|
|
770
904
|
return socket_io;
|
771
905
|
}
|
772
906
|
|
773
|
-
#endif
|
774
|
-
|
775
907
|
/*
|
776
908
|
* call-seq:
|
777
|
-
* conn.backend_pid() ->
|
909
|
+
* conn.backend_pid() -> Integer
|
778
910
|
*
|
779
911
|
* Returns the process ID of the backend server
|
780
912
|
* process for this connection.
|
@@ -820,33 +952,31 @@ static VALUE pgconn_exec_params( int, VALUE *, VALUE );
|
|
820
952
|
|
821
953
|
/*
|
822
954
|
* call-seq:
|
823
|
-
* conn.
|
824
|
-
* conn.
|
955
|
+
* conn.sync_exec(sql) -> PG::Result
|
956
|
+
* conn.sync_exec(sql) {|pg_result| block }
|
825
957
|
*
|
826
|
-
*
|
827
|
-
*
|
828
|
-
* On failure, it raises a PG::Error.
|
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.
|
829
960
|
*
|
830
|
-
*
|
831
|
-
*
|
832
|
-
* argument placeholders are used.
|
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:
|
833
963
|
*
|
834
|
-
*
|
835
|
-
*
|
836
|
-
*
|
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
|
837
967
|
*/
|
838
968
|
static VALUE
|
839
969
|
pgconn_exec(int argc, VALUE *argv, VALUE self)
|
840
970
|
{
|
841
|
-
|
971
|
+
t_pg_connection *this = pg_get_connection_safe( self );
|
842
972
|
PGresult *result = NULL;
|
843
973
|
VALUE rb_pgresult;
|
844
974
|
|
845
|
-
/* If called with no parameters, use PQexec */
|
846
|
-
if ( argc == 1 ) {
|
847
|
-
|
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];
|
848
978
|
|
849
|
-
result = gvl_PQexec(
|
979
|
+
result = gvl_PQexec(this->pgconn, pg_cstr_enc(query_str, this->enc_idx));
|
850
980
|
rb_pgresult = pg_new_result(result, self);
|
851
981
|
pg_result_check(rb_pgresult);
|
852
982
|
if (rb_block_given_p()) {
|
@@ -854,159 +984,304 @@ pgconn_exec(int argc, VALUE *argv, VALUE self)
|
|
854
984
|
}
|
855
985
|
return rb_pgresult;
|
856
986
|
}
|
987
|
+
pg_deprecated(0, ("forwarding exec to exec_params is deprecated"));
|
857
988
|
|
858
989
|
/* Otherwise, just call #exec_params instead for backward-compatibility */
|
859
|
-
|
860
|
-
return pgconn_exec_params( argc, argv, self );
|
861
|
-
}
|
990
|
+
return pgconn_exec_params( argc, argv, self );
|
862
991
|
|
863
992
|
}
|
864
993
|
|
865
994
|
|
866
|
-
|
867
|
-
*
|
868
|
-
|
869
|
-
|
870
|
-
*
|
871
|
-
* Sends SQL query request specified by +sql+ to PostgreSQL using placeholders
|
872
|
-
* for parameters.
|
873
|
-
*
|
874
|
-
* Returns a PG::Result instance on success. On failure, it raises a PG::Error.
|
875
|
-
*
|
876
|
-
* +params+ is an array of the bind parameters for the SQL query.
|
877
|
-
* Each element of the +params+ array may be either:
|
878
|
-
* a hash of the form:
|
879
|
-
* {:value => String (value of bind parameter)
|
880
|
-
* :type => Fixnum (oid of type of bind parameter)
|
881
|
-
* :format => Fixnum (0 for text, 1 for binary)
|
882
|
-
* }
|
883
|
-
* or, it may be a String. If it is a string, that is equivalent to the hash:
|
884
|
-
* { :value => <string value>, :type => 0, :format => 0 }
|
885
|
-
*
|
886
|
-
* PostgreSQL bind parameters are represented as $1, $1, $2, etc.,
|
887
|
-
* inside the SQL query. The 0th element of the +params+ array is bound
|
888
|
-
* to $1, the 1st element is bound to $2, etc. +nil+ is treated as +NULL+.
|
889
|
-
*
|
890
|
-
* If the types are not specified, they will be inferred by PostgreSQL.
|
891
|
-
* Instead of specifying type oids, it's recommended to simply add
|
892
|
-
* explicit casts in the query to ensure that the right type is used.
|
893
|
-
*
|
894
|
-
* For example: "SELECT $1::int"
|
895
|
-
*
|
896
|
-
* The optional +result_format+ should be 0 for text results, 1
|
897
|
-
* for binary.
|
898
|
-
*
|
899
|
-
* If the optional code block is given, it will be passed <i>result</i> as an argument,
|
900
|
-
* and the PG::Result object will automatically be cleared when the block terminates.
|
901
|
-
* In this instance, <code>conn.exec</code> returns the value of the block.
|
902
|
-
*/
|
903
|
-
static VALUE
|
904
|
-
pgconn_exec_params( int argc, VALUE *argv, VALUE self )
|
905
|
-
{
|
906
|
-
PGconn *conn = pg_get_pgconn(self);
|
907
|
-
PGresult *result = NULL;
|
908
|
-
VALUE rb_pgresult;
|
909
|
-
VALUE command, params, in_res_fmt;
|
910
|
-
VALUE param, param_type, param_value, param_format;
|
911
|
-
VALUE param_value_tmp;
|
912
|
-
VALUE sym_type, sym_value, sym_format;
|
913
|
-
VALUE gc_array;
|
914
|
-
int i=0;
|
915
|
-
int nParams;
|
916
|
-
Oid *paramTypes;
|
917
|
-
char ** paramValues;
|
918
|
-
int *paramLengths;
|
919
|
-
int *paramFormats;
|
920
|
-
int resultFormat;
|
995
|
+
struct linked_typecast_data {
|
996
|
+
struct linked_typecast_data *next;
|
997
|
+
char data[0];
|
998
|
+
};
|
921
999
|
|
922
|
-
|
1000
|
+
/* This struct is allocated on the stack for all query execution functions. */
|
1001
|
+
struct query_params_data {
|
923
1002
|
|
924
1003
|
/*
|
925
|
-
*
|
926
|
-
* for the second parameter.
|
1004
|
+
* Filled by caller
|
927
1005
|
*/
|
928
|
-
if ( NIL_P(params) ) {
|
929
|
-
return pgconn_exec( 1, argv, self );
|
930
|
-
}
|
931
1006
|
|
932
|
-
|
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;
|
933
1017
|
|
934
|
-
|
935
|
-
|
936
|
-
|
937
|
-
else {
|
938
|
-
resultFormat = NUM2INT(in_res_fmt);
|
939
|
-
}
|
1018
|
+
/*
|
1019
|
+
* Filled by alloc_query_params()
|
1020
|
+
*/
|
940
1021
|
|
941
|
-
|
942
|
-
|
1022
|
+
/* Wraps the pointer of allocated memory, if function parameters dont't
|
1023
|
+
* fit in the memory_pool below.
|
1024
|
+
*/
|
1025
|
+
VALUE heap_pool;
|
943
1026
|
|
944
|
-
|
945
|
-
|
946
|
-
|
947
|
-
|
948
|
-
|
949
|
-
|
950
|
-
|
951
|
-
|
952
|
-
|
953
|
-
|
954
|
-
|
955
|
-
|
956
|
-
|
957
|
-
|
958
|
-
|
959
|
-
|
960
|
-
else
|
961
|
-
param_value = rb_obj_as_string(param_value_tmp);
|
962
|
-
param_format = rb_hash_aref(param, sym_format);
|
963
|
-
}
|
964
|
-
else {
|
965
|
-
param_type = Qnil;
|
966
|
-
if(param == Qnil)
|
967
|
-
param_value = param;
|
968
|
-
else
|
969
|
-
param_value = rb_obj_as_string(param);
|
970
|
-
param_format = Qnil;
|
971
|
-
}
|
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;
|
972
1043
|
|
973
|
-
|
974
|
-
|
975
|
-
|
976
|
-
|
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;
|
977
1048
|
|
978
|
-
|
979
|
-
|
980
|
-
|
981
|
-
}
|
982
|
-
else {
|
983
|
-
Check_Type(param_value, T_STRING);
|
984
|
-
/* make sure param_value doesn't get freed by the GC */
|
985
|
-
rb_ary_push(gc_array, param_value);
|
986
|
-
paramValues[i] = StringValuePtr(param_value);
|
987
|
-
paramLengths[i] = (int)RSTRING_LEN(param_value);
|
988
|
-
}
|
1049
|
+
/* This memory pool is used to place above query function parameters on it. */
|
1050
|
+
char memory_pool[QUERYDATA_BUFFER_SIZE];
|
1051
|
+
};
|
989
1052
|
|
990
|
-
|
991
|
-
|
992
|
-
|
993
|
-
|
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;
|
994
1060
|
}
|
1061
|
+
}
|
995
1062
|
|
996
|
-
|
997
|
-
|
998
|
-
|
999
|
-
|
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
|
+
}
|
1000
1080
|
|
1001
|
-
|
1002
|
-
|
1003
|
-
xfree(paramLengths);
|
1004
|
-
xfree(paramFormats);
|
1081
|
+
return &allocated->data[0];
|
1082
|
+
}
|
1005
1083
|
|
1006
|
-
rb_pgresult = pg_new_result(result, self);
|
1007
|
-
pg_result_check(rb_pgresult);
|
1008
1084
|
|
1009
|
-
|
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);
|
1283
|
+
|
1284
|
+
if (rb_block_given_p()) {
|
1010
1285
|
return rb_ensure(rb_yield, rb_pgresult, pg_result_clear, rb_pgresult);
|
1011
1286
|
}
|
1012
1287
|
|
@@ -1015,28 +1290,16 @@ pgconn_exec_params( int argc, VALUE *argv, VALUE self )
|
|
1015
1290
|
|
1016
1291
|
/*
|
1017
1292
|
* call-seq:
|
1018
|
-
* conn.
|
1293
|
+
* conn.sync_prepare(stmt_name, sql [, param_types ] ) -> PG::Result
|
1019
1294
|
*
|
1020
|
-
*
|
1021
|
-
*
|
1022
|
-
*
|
1023
|
-
*
|
1024
|
-
* +param_types+ is an optional parameter to specify the Oids of the
|
1025
|
-
* types of the parameters.
|
1026
|
-
*
|
1027
|
-
* If the types are not specified, they will be inferred by PostgreSQL.
|
1028
|
-
* Instead of specifying type oids, it's recommended to simply add
|
1029
|
-
* explicit casts in the query to ensure that the right type is used.
|
1030
|
-
*
|
1031
|
-
* For example: "SELECT $1::int"
|
1032
|
-
*
|
1033
|
-
* PostgreSQL bind parameters are represented as $1, $1, $2, etc.,
|
1034
|
-
* inside the SQL query.
|
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.
|
1035
1298
|
*/
|
1036
1299
|
static VALUE
|
1037
1300
|
pgconn_prepare(int argc, VALUE *argv, VALUE self)
|
1038
1301
|
{
|
1039
|
-
|
1302
|
+
t_pg_connection *this = pg_get_connection_safe( self );
|
1040
1303
|
PGresult *result = NULL;
|
1041
1304
|
VALUE rb_pgresult;
|
1042
1305
|
VALUE name, command, in_paramtypes;
|
@@ -1044,10 +1307,13 @@ pgconn_prepare(int argc, VALUE *argv, VALUE self)
|
|
1044
1307
|
int i = 0;
|
1045
1308
|
int nParams = 0;
|
1046
1309
|
Oid *paramTypes = NULL;
|
1310
|
+
const char *name_cstr;
|
1311
|
+
const char *command_cstr;
|
1312
|
+
int enc_idx = this->enc_idx;
|
1047
1313
|
|
1048
1314
|
rb_scan_args(argc, argv, "21", &name, &command, &in_paramtypes);
|
1049
|
-
|
1050
|
-
|
1315
|
+
name_cstr = pg_cstr_enc(name, enc_idx);
|
1316
|
+
command_cstr = pg_cstr_enc(command, enc_idx);
|
1051
1317
|
|
1052
1318
|
if(! NIL_P(in_paramtypes)) {
|
1053
1319
|
Check_Type(in_paramtypes, T_ARRAY);
|
@@ -1055,15 +1321,13 @@ pgconn_prepare(int argc, VALUE *argv, VALUE self)
|
|
1055
1321
|
paramTypes = ALLOC_N(Oid, nParams);
|
1056
1322
|
for(i = 0; i < nParams; i++) {
|
1057
1323
|
param = rb_ary_entry(in_paramtypes, i);
|
1058
|
-
Check_Type(param, T_FIXNUM);
|
1059
1324
|
if(param == Qnil)
|
1060
1325
|
paramTypes[i] = 0;
|
1061
1326
|
else
|
1062
|
-
paramTypes[i] =
|
1327
|
+
paramTypes[i] = NUM2UINT(param);
|
1063
1328
|
}
|
1064
1329
|
}
|
1065
|
-
result = gvl_PQprepare(
|
1066
|
-
nParams, paramTypes);
|
1330
|
+
result = gvl_PQprepare(this->pgconn, name_cstr, command_cstr, nParams, paramTypes);
|
1067
1331
|
|
1068
1332
|
xfree(paramTypes);
|
1069
1333
|
|
@@ -1074,122 +1338,40 @@ pgconn_prepare(int argc, VALUE *argv, VALUE self)
|
|
1074
1338
|
|
1075
1339
|
/*
|
1076
1340
|
* call-seq:
|
1077
|
-
* conn.
|
1078
|
-
* conn.
|
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 }
|
1079
1343
|
*
|
1080
|
-
*
|
1081
|
-
*
|
1082
|
-
*
|
1083
|
-
*
|
1084
|
-
* +params+ is an array of the optional bind parameters for the
|
1085
|
-
* SQL query. Each element of the +params+ array may be either:
|
1086
|
-
* a hash of the form:
|
1087
|
-
* {:value => String (value of bind parameter)
|
1088
|
-
* :format => Fixnum (0 for text, 1 for binary)
|
1089
|
-
* }
|
1090
|
-
* or, it may be a String. If it is a string, that is equivalent to the hash:
|
1091
|
-
* { :value => <string value>, :format => 0 }
|
1092
|
-
*
|
1093
|
-
* PostgreSQL bind parameters are represented as $1, $1, $2, etc.,
|
1094
|
-
* inside the SQL query. The 0th element of the +params+ array is bound
|
1095
|
-
* to $1, the 1st element is bound to $2, etc. +nil+ is treated as +NULL+.
|
1096
|
-
*
|
1097
|
-
* The optional +result_format+ should be 0 for text results, 1
|
1098
|
-
* for binary.
|
1099
|
-
*
|
1100
|
-
* If the optional code block is given, it will be passed <i>result</i> as an argument,
|
1101
|
-
* and the PG::Result object will automatically be cleared when the block terminates.
|
1102
|
-
* In this instance, <code>conn.exec_prepared</code> returns the value of the block.
|
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.
|
1103
1347
|
*/
|
1104
1348
|
static VALUE
|
1105
1349
|
pgconn_exec_prepared(int argc, VALUE *argv, VALUE self)
|
1106
1350
|
{
|
1107
|
-
|
1351
|
+
t_pg_connection *this = pg_get_connection_safe( self );
|
1108
1352
|
PGresult *result = NULL;
|
1109
1353
|
VALUE rb_pgresult;
|
1110
|
-
VALUE name,
|
1111
|
-
VALUE param, param_value, param_format;
|
1112
|
-
VALUE param_value_tmp;
|
1113
|
-
VALUE sym_value, sym_format;
|
1114
|
-
VALUE gc_array;
|
1115
|
-
int i = 0;
|
1354
|
+
VALUE name, in_res_fmt;
|
1116
1355
|
int nParams;
|
1117
|
-
char ** paramValues;
|
1118
|
-
int *paramLengths;
|
1119
|
-
int *paramFormats;
|
1120
1356
|
int resultFormat;
|
1357
|
+
struct query_params_data paramsData = { this->enc_idx };
|
1121
1358
|
|
1359
|
+
rb_scan_args(argc, argv, "13", &name, ¶msData.params, &in_res_fmt, ¶msData.typemap);
|
1360
|
+
paramsData.with_types = 0;
|
1122
1361
|
|
1123
|
-
|
1124
|
-
|
1125
|
-
|
1126
|
-
if(NIL_P(params)) {
|
1127
|
-
params = rb_ary_new2(0);
|
1128
|
-
resultFormat = 0;
|
1129
|
-
}
|
1130
|
-
else {
|
1131
|
-
Check_Type(params, T_ARRAY);
|
1132
|
-
}
|
1133
|
-
|
1134
|
-
if(NIL_P(in_res_fmt)) {
|
1135
|
-
resultFormat = 0;
|
1362
|
+
if(NIL_P(paramsData.params)) {
|
1363
|
+
paramsData.params = rb_ary_new2(0);
|
1136
1364
|
}
|
1137
|
-
|
1138
|
-
resultFormat = NUM2INT(in_res_fmt);
|
1139
|
-
}
|
1140
|
-
|
1141
|
-
gc_array = rb_ary_new();
|
1142
|
-
rb_gc_register_address(&gc_array);
|
1143
|
-
sym_value = ID2SYM(rb_intern("value"));
|
1144
|
-
sym_format = ID2SYM(rb_intern("format"));
|
1145
|
-
nParams = (int)RARRAY_LEN(params);
|
1146
|
-
paramValues = ALLOC_N(char *, nParams);
|
1147
|
-
paramLengths = ALLOC_N(int, nParams);
|
1148
|
-
paramFormats = ALLOC_N(int, nParams);
|
1149
|
-
for(i = 0; i < nParams; i++) {
|
1150
|
-
param = rb_ary_entry(params, i);
|
1151
|
-
if (TYPE(param) == T_HASH) {
|
1152
|
-
param_value_tmp = rb_hash_aref(param, sym_value);
|
1153
|
-
if(param_value_tmp == Qnil)
|
1154
|
-
param_value = param_value_tmp;
|
1155
|
-
else
|
1156
|
-
param_value = rb_obj_as_string(param_value_tmp);
|
1157
|
-
param_format = rb_hash_aref(param, sym_format);
|
1158
|
-
}
|
1159
|
-
else {
|
1160
|
-
if(param == Qnil)
|
1161
|
-
param_value = param;
|
1162
|
-
else
|
1163
|
-
param_value = rb_obj_as_string(param);
|
1164
|
-
param_format = INT2NUM(0);
|
1165
|
-
}
|
1166
|
-
if(param_value == Qnil) {
|
1167
|
-
paramValues[i] = NULL;
|
1168
|
-
paramLengths[i] = 0;
|
1169
|
-
}
|
1170
|
-
else {
|
1171
|
-
Check_Type(param_value, T_STRING);
|
1172
|
-
/* make sure param_value doesn't get freed by the GC */
|
1173
|
-
rb_ary_push(gc_array, param_value);
|
1174
|
-
paramValues[i] = StringValuePtr(param_value);
|
1175
|
-
paramLengths[i] = (int)RSTRING_LEN(param_value);
|
1176
|
-
}
|
1365
|
+
pgconn_query_assign_typemap( self, ¶msData );
|
1177
1366
|
|
1178
|
-
|
1179
|
-
|
1180
|
-
else
|
1181
|
-
paramFormats[i] = NUM2INT(param_format);
|
1182
|
-
}
|
1367
|
+
resultFormat = NIL_P(in_res_fmt) ? 0 : NUM2INT(in_res_fmt);
|
1368
|
+
nParams = alloc_query_params( ¶msData );
|
1183
1369
|
|
1184
|
-
result = gvl_PQexecPrepared(
|
1185
|
-
(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,
|
1186
1372
|
resultFormat);
|
1187
1373
|
|
1188
|
-
|
1189
|
-
|
1190
|
-
xfree(paramValues);
|
1191
|
-
xfree(paramLengths);
|
1192
|
-
xfree(paramFormats);
|
1374
|
+
free_query_params( ¶msData );
|
1193
1375
|
|
1194
1376
|
rb_pgresult = pg_new_result(result, self);
|
1195
1377
|
pg_result_check(rb_pgresult);
|
@@ -1202,26 +1384,26 @@ pgconn_exec_prepared(int argc, VALUE *argv, VALUE self)
|
|
1202
1384
|
|
1203
1385
|
/*
|
1204
1386
|
* call-seq:
|
1205
|
-
* conn.
|
1387
|
+
* conn.sync_describe_prepared( statement_name ) -> PG::Result
|
1206
1388
|
*
|
1207
|
-
*
|
1208
|
-
*
|
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.
|
1209
1392
|
*/
|
1210
1393
|
static VALUE
|
1211
1394
|
pgconn_describe_prepared(VALUE self, VALUE stmt_name)
|
1212
1395
|
{
|
1213
1396
|
PGresult *result;
|
1214
1397
|
VALUE rb_pgresult;
|
1215
|
-
|
1216
|
-
char *stmt;
|
1217
|
-
if(stmt_name
|
1398
|
+
t_pg_connection *this = pg_get_connection_safe( self );
|
1399
|
+
const char *stmt;
|
1400
|
+
if(NIL_P(stmt_name)) {
|
1218
1401
|
stmt = NULL;
|
1219
1402
|
}
|
1220
1403
|
else {
|
1221
|
-
|
1222
|
-
stmt = StringValuePtr(stmt_name);
|
1404
|
+
stmt = pg_cstr_enc(stmt_name, this->enc_idx);
|
1223
1405
|
}
|
1224
|
-
result = gvl_PQdescribePrepared(
|
1406
|
+
result = gvl_PQdescribePrepared(this->pgconn, stmt);
|
1225
1407
|
rb_pgresult = pg_new_result(result, self);
|
1226
1408
|
pg_result_check(rb_pgresult);
|
1227
1409
|
return rb_pgresult;
|
@@ -1230,9 +1412,11 @@ pgconn_describe_prepared(VALUE self, VALUE stmt_name)
|
|
1230
1412
|
|
1231
1413
|
/*
|
1232
1414
|
* call-seq:
|
1233
|
-
* conn.
|
1415
|
+
* conn.sync_describe_portal( portal_name ) -> PG::Result
|
1234
1416
|
*
|
1235
|
-
*
|
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.
|
1236
1420
|
*/
|
1237
1421
|
static VALUE
|
1238
1422
|
pgconn_describe_portal(self, stmt_name)
|
@@ -1240,16 +1424,15 @@ pgconn_describe_portal(self, stmt_name)
|
|
1240
1424
|
{
|
1241
1425
|
PGresult *result;
|
1242
1426
|
VALUE rb_pgresult;
|
1243
|
-
|
1244
|
-
char *stmt;
|
1245
|
-
if(stmt_name
|
1427
|
+
t_pg_connection *this = pg_get_connection_safe( self );
|
1428
|
+
const char *stmt;
|
1429
|
+
if(NIL_P(stmt_name)) {
|
1246
1430
|
stmt = NULL;
|
1247
1431
|
}
|
1248
1432
|
else {
|
1249
|
-
|
1250
|
-
stmt = StringValuePtr(stmt_name);
|
1433
|
+
stmt = pg_cstr_enc(stmt_name, this->enc_idx);
|
1251
1434
|
}
|
1252
|
-
result = gvl_PQdescribePortal(
|
1435
|
+
result = gvl_PQdescribePortal(this->pgconn, stmt);
|
1253
1436
|
rb_pgresult = pg_new_result(result, self);
|
1254
1437
|
pg_result_check(rb_pgresult);
|
1255
1438
|
return rb_pgresult;
|
@@ -1289,10 +1472,6 @@ pgconn_make_empty_pgresult(VALUE self, VALUE status)
|
|
1289
1472
|
* call-seq:
|
1290
1473
|
* conn.escape_string( str ) -> String
|
1291
1474
|
*
|
1292
|
-
* Connection instance method for versions of 8.1 and higher of libpq
|
1293
|
-
* uses PQescapeStringConn, which is safer. Avoid calling as a class method,
|
1294
|
-
* the class method uses the deprecated PQescapeString() API function.
|
1295
|
-
*
|
1296
1475
|
* Returns a SQL-safe version of the String _str_.
|
1297
1476
|
* This is the preferred way to make strings safe for inclusion in
|
1298
1477
|
* SQL queries.
|
@@ -1300,44 +1479,43 @@ pgconn_make_empty_pgresult(VALUE self, VALUE status)
|
|
1300
1479
|
* Consider using exec_params, which avoids the need for passing values
|
1301
1480
|
* inside of SQL commands.
|
1302
1481
|
*
|
1303
|
-
*
|
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.
|
1304
1491
|
*/
|
1305
1492
|
static VALUE
|
1306
1493
|
pgconn_s_escape(VALUE self, VALUE string)
|
1307
1494
|
{
|
1308
|
-
char *escaped;
|
1309
1495
|
size_t size;
|
1310
1496
|
int error;
|
1311
1497
|
VALUE result;
|
1312
|
-
|
1313
|
-
|
1314
|
-
#endif
|
1498
|
+
int enc_idx;
|
1499
|
+
int singleton = !rb_obj_is_kind_of(self, rb_cPGconn);
|
1315
1500
|
|
1316
|
-
|
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
|
+
}
|
1317
1506
|
|
1318
|
-
|
1319
|
-
|
1320
|
-
|
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),
|
1321
1511
|
RSTRING_PTR(string), RSTRING_LEN(string), &error);
|
1322
1512
|
if(error) {
|
1323
|
-
xfree(escaped);
|
1324
1513
|
rb_raise(rb_ePGerror, "%s", PQerrorMessage(pg_get_pgconn(self)));
|
1325
1514
|
}
|
1326
1515
|
} else {
|
1327
|
-
size = PQescapeString(
|
1328
|
-
}
|
1329
|
-
result = rb_str_new(escaped, size);
|
1330
|
-
xfree(escaped);
|
1331
|
-
OBJ_INFECT(result, string);
|
1332
|
-
|
1333
|
-
#ifdef M17N_SUPPORTED
|
1334
|
-
if ( rb_obj_class(self) == rb_cPGconn ) {
|
1335
|
-
enc = pg_conn_enc_get( pg_get_pgconn(self) );
|
1336
|
-
} else {
|
1337
|
-
enc = rb_enc_get(string);
|
1516
|
+
size = PQescapeString(RSTRING_PTR(result), RSTRING_PTR(string), RSTRING_LEN(string));
|
1338
1517
|
}
|
1339
|
-
|
1340
|
-
#endif
|
1518
|
+
rb_str_set_len(result, size);
|
1341
1519
|
|
1342
1520
|
return result;
|
1343
1521
|
}
|
@@ -1346,13 +1524,6 @@ pgconn_s_escape(VALUE self, VALUE string)
|
|
1346
1524
|
* call-seq:
|
1347
1525
|
* conn.escape_bytea( string ) -> String
|
1348
1526
|
*
|
1349
|
-
* Connection instance method for versions of 8.1 and higher of libpq
|
1350
|
-
* uses PQescapeByteaConn, which is safer. Avoid calling as a class method,
|
1351
|
-
* the class method uses the deprecated PQescapeBytea() API function.
|
1352
|
-
*
|
1353
|
-
* Use the instance method version of this function, it is safer than the
|
1354
|
-
* class method.
|
1355
|
-
*
|
1356
1527
|
* Escapes binary data for use within an SQL command with the type +bytea+.
|
1357
1528
|
*
|
1358
1529
|
* Certain byte values must be escaped (but all byte values may be escaped)
|
@@ -1365,6 +1536,12 @@ pgconn_s_escape(VALUE self, VALUE string)
|
|
1365
1536
|
*
|
1366
1537
|
* Consider using exec_params, which avoids the need for passing values inside of
|
1367
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.
|
1368
1545
|
*/
|
1369
1546
|
static VALUE
|
1370
1547
|
pgconn_s_escape_bytea(VALUE self, VALUE str)
|
@@ -1377,14 +1554,13 @@ pgconn_s_escape_bytea(VALUE self, VALUE str)
|
|
1377
1554
|
from = (unsigned char*)RSTRING_PTR(str);
|
1378
1555
|
from_len = RSTRING_LEN(str);
|
1379
1556
|
|
1380
|
-
if(
|
1557
|
+
if ( rb_obj_is_kind_of(self, rb_cPGconn) ) {
|
1381
1558
|
to = PQescapeByteaConn(pg_get_pgconn(self), from, from_len, &to_len);
|
1382
1559
|
} else {
|
1383
1560
|
to = PQescapeBytea( from, from_len, &to_len);
|
1384
1561
|
}
|
1385
1562
|
|
1386
1563
|
ret = rb_str_new((char*)to, to_len - 1);
|
1387
|
-
OBJ_INFECT(ret, str);
|
1388
1564
|
PQfreemem(to);
|
1389
1565
|
return ret;
|
1390
1566
|
}
|
@@ -1409,83 +1585,91 @@ pgconn_s_unescape_bytea(VALUE self, VALUE str)
|
|
1409
1585
|
UNUSED( self );
|
1410
1586
|
|
1411
1587
|
Check_Type(str, T_STRING);
|
1412
|
-
from = (unsigned char*)
|
1588
|
+
from = (unsigned char*)StringValueCStr(str);
|
1413
1589
|
|
1414
1590
|
to = PQunescapeBytea(from, &to_len);
|
1415
1591
|
|
1416
1592
|
ret = rb_str_new((char*)to, to_len);
|
1417
|
-
OBJ_INFECT(ret, str);
|
1418
1593
|
PQfreemem(to);
|
1419
1594
|
return ret;
|
1420
1595
|
}
|
1421
1596
|
|
1422
|
-
#ifdef HAVE_PQESCAPELITERAL
|
1423
1597
|
/*
|
1424
1598
|
* call-seq:
|
1425
1599
|
* conn.escape_literal( str ) -> String
|
1426
1600
|
*
|
1427
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.
|
1428
1604
|
*/
|
1429
1605
|
static VALUE
|
1430
1606
|
pgconn_escape_literal(VALUE self, VALUE string)
|
1431
1607
|
{
|
1432
|
-
|
1608
|
+
t_pg_connection *this = pg_get_connection_safe( self );
|
1433
1609
|
char *escaped = NULL;
|
1434
1610
|
VALUE error;
|
1435
1611
|
VALUE result = Qnil;
|
1612
|
+
int enc_idx = this->enc_idx;
|
1436
1613
|
|
1437
|
-
|
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
|
+
}
|
1438
1618
|
|
1439
|
-
escaped = PQescapeLiteral(
|
1619
|
+
escaped = PQescapeLiteral(this->pgconn, RSTRING_PTR(string), RSTRING_LEN(string));
|
1440
1620
|
if (escaped == NULL)
|
1441
1621
|
{
|
1442
|
-
error = rb_exc_new2(rb_ePGerror, PQerrorMessage(
|
1622
|
+
error = rb_exc_new2(rb_ePGerror, PQerrorMessage(this->pgconn));
|
1443
1623
|
rb_iv_set(error, "@connection", self);
|
1444
1624
|
rb_exc_raise(error);
|
1445
1625
|
return Qnil;
|
1446
1626
|
}
|
1447
1627
|
result = rb_str_new2(escaped);
|
1448
1628
|
PQfreemem(escaped);
|
1449
|
-
|
1629
|
+
PG_ENCODING_SET_NOCHECK(result, enc_idx);
|
1450
1630
|
|
1451
1631
|
return result;
|
1452
1632
|
}
|
1453
|
-
#endif
|
1454
1633
|
|
1455
|
-
#ifdef HAVE_PQESCAPEIDENTIFIER
|
1456
1634
|
/*
|
1457
1635
|
* call-seq:
|
1458
1636
|
* conn.escape_identifier( str ) -> String
|
1459
1637
|
*
|
1460
1638
|
* Escape an arbitrary String +str+ as an identifier.
|
1639
|
+
*
|
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.
|
1461
1643
|
*/
|
1462
1644
|
static VALUE
|
1463
1645
|
pgconn_escape_identifier(VALUE self, VALUE string)
|
1464
1646
|
{
|
1465
|
-
|
1647
|
+
t_pg_connection *this = pg_get_connection_safe( self );
|
1466
1648
|
char *escaped = NULL;
|
1467
1649
|
VALUE error;
|
1468
1650
|
VALUE result = Qnil;
|
1651
|
+
int enc_idx = this->enc_idx;
|
1469
1652
|
|
1470
|
-
|
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
|
+
}
|
1471
1657
|
|
1472
|
-
escaped = PQescapeIdentifier(
|
1658
|
+
escaped = PQescapeIdentifier(this->pgconn, RSTRING_PTR(string), RSTRING_LEN(string));
|
1473
1659
|
if (escaped == NULL)
|
1474
1660
|
{
|
1475
|
-
error = rb_exc_new2(rb_ePGerror, PQerrorMessage(
|
1661
|
+
error = rb_exc_new2(rb_ePGerror, PQerrorMessage(this->pgconn));
|
1476
1662
|
rb_iv_set(error, "@connection", self);
|
1477
1663
|
rb_exc_raise(error);
|
1478
1664
|
return Qnil;
|
1479
1665
|
}
|
1480
1666
|
result = rb_str_new2(escaped);
|
1481
1667
|
PQfreemem(escaped);
|
1482
|
-
|
1668
|
+
PG_ENCODING_SET_NOCHECK(result, enc_idx);
|
1483
1669
|
|
1484
1670
|
return result;
|
1485
1671
|
}
|
1486
|
-
#endif
|
1487
1672
|
|
1488
|
-
#ifdef HAVE_PQSETSINGLEROWMODE
|
1489
1673
|
/*
|
1490
1674
|
* call-seq:
|
1491
1675
|
* conn.set_single_row_mode -> self
|
@@ -1496,7 +1680,7 @@ pgconn_escape_identifier(VALUE self, VALUE string)
|
|
1496
1680
|
* Then call Connection#get_result repeatedly, until it returns nil.
|
1497
1681
|
*
|
1498
1682
|
* Each (but the last) received Result has exactly one row and a
|
1499
|
-
* Result#result_status of PGRES_SINGLE_TUPLE. The last
|
1683
|
+
* Result#result_status of PGRES_SINGLE_TUPLE. The last Result has
|
1500
1684
|
* zero rows and is used to indicate a successful execution of the query.
|
1501
1685
|
* All of these Result objects will contain the same row description data
|
1502
1686
|
* (column names, types, etc) that an ordinary Result object for the query
|
@@ -1521,7 +1705,6 @@ pgconn_escape_identifier(VALUE self, VALUE string)
|
|
1521
1705
|
* # do something with the received row
|
1522
1706
|
* end
|
1523
1707
|
* end
|
1524
|
-
*
|
1525
1708
|
*/
|
1526
1709
|
static VALUE
|
1527
1710
|
pgconn_set_single_row_mode(VALUE self)
|
@@ -1538,22 +1721,60 @@ pgconn_set_single_row_mode(VALUE self)
|
|
1538
1721
|
|
1539
1722
|
return self;
|
1540
1723
|
}
|
1541
|
-
|
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
|
+
}
|
1542
1763
|
|
1543
1764
|
/*
|
1544
1765
|
* call-seq:
|
1545
|
-
* conn.
|
1766
|
+
* conn.send_query_params(sql, params [, result_format [, type_map ]] ) -> nil
|
1546
1767
|
*
|
1547
1768
|
* Sends SQL query request specified by _sql_ to PostgreSQL for
|
1548
1769
|
* asynchronous processing, and immediately returns.
|
1549
1770
|
* On failure, it raises a PG::Error.
|
1550
1771
|
*
|
1551
|
-
* +params+ is an
|
1772
|
+
* +params+ is an array of the bind parameters for the SQL query.
|
1552
1773
|
* Each element of the +params+ array may be either:
|
1553
1774
|
* a hash of the form:
|
1554
1775
|
* {:value => String (value of bind parameter)
|
1555
|
-
* :type =>
|
1556
|
-
* :format =>
|
1776
|
+
* :type => Integer (oid of type of bind parameter)
|
1777
|
+
* :format => Integer (0 for text, 1 for binary)
|
1557
1778
|
* }
|
1558
1779
|
* or, it may be a String. If it is a string, that is equivalent to the hash:
|
1559
1780
|
* { :value => <string value>, :type => 0, :format => 0 }
|
@@ -1570,116 +1791,39 @@ pgconn_set_single_row_mode(VALUE self)
|
|
1570
1791
|
*
|
1571
1792
|
* The optional +result_format+ should be 0 for text results, 1
|
1572
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
|
+
*
|
1573
1801
|
*/
|
1574
1802
|
static VALUE
|
1575
|
-
|
1803
|
+
pgconn_send_query_params(int argc, VALUE *argv, VALUE self)
|
1576
1804
|
{
|
1577
|
-
|
1805
|
+
t_pg_connection *this = pg_get_connection_safe( self );
|
1578
1806
|
int result;
|
1579
|
-
VALUE command,
|
1580
|
-
VALUE param, param_type, param_value, param_format;
|
1581
|
-
VALUE param_value_tmp;
|
1582
|
-
VALUE sym_type, sym_value, sym_format;
|
1583
|
-
VALUE gc_array;
|
1807
|
+
VALUE command, in_res_fmt;
|
1584
1808
|
VALUE error;
|
1585
|
-
int i=0;
|
1586
1809
|
int nParams;
|
1587
|
-
Oid *paramTypes;
|
1588
|
-
char ** paramValues;
|
1589
|
-
int *paramLengths;
|
1590
|
-
int *paramFormats;
|
1591
1810
|
int resultFormat;
|
1811
|
+
struct query_params_data paramsData = { this->enc_idx };
|
1592
1812
|
|
1593
|
-
rb_scan_args(argc, argv, "
|
1594
|
-
|
1595
|
-
|
1596
|
-
/* If called with no parameters, use PQsendQuery */
|
1597
|
-
if(NIL_P(params)) {
|
1598
|
-
if(PQsendQuery(conn,StringValuePtr(command)) == 0) {
|
1599
|
-
error = rb_exc_new2(rb_ePGerror, PQerrorMessage(conn));
|
1600
|
-
rb_iv_set(error, "@connection", self);
|
1601
|
-
rb_exc_raise(error);
|
1602
|
-
}
|
1603
|
-
return Qnil;
|
1604
|
-
}
|
1605
|
-
|
1606
|
-
/* If called with parameters, and optionally result_format,
|
1607
|
-
* use PQsendQueryParams
|
1608
|
-
*/
|
1609
|
-
Check_Type(params, T_ARRAY);
|
1610
|
-
|
1611
|
-
if(NIL_P(in_res_fmt)) {
|
1612
|
-
resultFormat = 0;
|
1613
|
-
}
|
1614
|
-
else {
|
1615
|
-
resultFormat = NUM2INT(in_res_fmt);
|
1616
|
-
}
|
1617
|
-
|
1618
|
-
gc_array = rb_ary_new();
|
1619
|
-
rb_gc_register_address(&gc_array);
|
1620
|
-
sym_type = ID2SYM(rb_intern("type"));
|
1621
|
-
sym_value = ID2SYM(rb_intern("value"));
|
1622
|
-
sym_format = ID2SYM(rb_intern("format"));
|
1623
|
-
nParams = (int)RARRAY_LEN(params);
|
1624
|
-
paramTypes = ALLOC_N(Oid, nParams);
|
1625
|
-
paramValues = ALLOC_N(char *, nParams);
|
1626
|
-
paramLengths = ALLOC_N(int, nParams);
|
1627
|
-
paramFormats = ALLOC_N(int, nParams);
|
1628
|
-
for(i = 0; i < nParams; i++) {
|
1629
|
-
param = rb_ary_entry(params, i);
|
1630
|
-
if (TYPE(param) == T_HASH) {
|
1631
|
-
param_type = rb_hash_aref(param, sym_type);
|
1632
|
-
param_value_tmp = rb_hash_aref(param, sym_value);
|
1633
|
-
if(param_value_tmp == Qnil)
|
1634
|
-
param_value = param_value_tmp;
|
1635
|
-
else
|
1636
|
-
param_value = rb_obj_as_string(param_value_tmp);
|
1637
|
-
param_format = rb_hash_aref(param, sym_format);
|
1638
|
-
}
|
1639
|
-
else {
|
1640
|
-
param_type = INT2NUM(0);
|
1641
|
-
if(param == Qnil)
|
1642
|
-
param_value = param;
|
1643
|
-
else
|
1644
|
-
param_value = rb_obj_as_string(param);
|
1645
|
-
param_format = INT2NUM(0);
|
1646
|
-
}
|
1647
|
-
|
1648
|
-
if(param_type == Qnil)
|
1649
|
-
paramTypes[i] = 0;
|
1650
|
-
else
|
1651
|
-
paramTypes[i] = NUM2INT(param_type);
|
1652
|
-
|
1653
|
-
if(param_value == Qnil) {
|
1654
|
-
paramValues[i] = NULL;
|
1655
|
-
paramLengths[i] = 0;
|
1656
|
-
}
|
1657
|
-
else {
|
1658
|
-
Check_Type(param_value, T_STRING);
|
1659
|
-
/* make sure param_value doesn't get freed by the GC */
|
1660
|
-
rb_ary_push(gc_array, param_value);
|
1661
|
-
paramValues[i] = StringValuePtr(param_value);
|
1662
|
-
paramLengths[i] = (int)RSTRING_LEN(param_value);
|
1663
|
-
}
|
1664
|
-
|
1665
|
-
if(param_format == Qnil)
|
1666
|
-
paramFormats[i] = 0;
|
1667
|
-
else
|
1668
|
-
paramFormats[i] = NUM2INT(param_format);
|
1669
|
-
}
|
1813
|
+
rb_scan_args(argc, argv, "22", &command, ¶msData.params, &in_res_fmt, ¶msData.typemap);
|
1814
|
+
paramsData.with_types = 1;
|
1670
1815
|
|
1671
|
-
|
1672
|
-
|
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 );
|
1673
1819
|
|
1674
|
-
|
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);
|
1675
1822
|
|
1676
|
-
|
1677
|
-
xfree(paramValues);
|
1678
|
-
xfree(paramLengths);
|
1679
|
-
xfree(paramFormats);
|
1823
|
+
free_query_params( ¶msData );
|
1680
1824
|
|
1681
1825
|
if(result == 0) {
|
1682
|
-
error = rb_exc_new2(
|
1826
|
+
error = rb_exc_new2(rb_eUnableToSend, PQerrorMessage(this->pgconn));
|
1683
1827
|
rb_iv_set(error, "@connection", self);
|
1684
1828
|
rb_exc_raise(error);
|
1685
1829
|
}
|
@@ -1709,7 +1853,7 @@ pgconn_send_query(int argc, VALUE *argv, VALUE self)
|
|
1709
1853
|
static VALUE
|
1710
1854
|
pgconn_send_prepare(int argc, VALUE *argv, VALUE self)
|
1711
1855
|
{
|
1712
|
-
|
1856
|
+
t_pg_connection *this = pg_get_connection_safe( self );
|
1713
1857
|
int result;
|
1714
1858
|
VALUE name, command, in_paramtypes;
|
1715
1859
|
VALUE param;
|
@@ -1717,10 +1861,13 @@ pgconn_send_prepare(int argc, VALUE *argv, VALUE self)
|
|
1717
1861
|
int i = 0;
|
1718
1862
|
int nParams = 0;
|
1719
1863
|
Oid *paramTypes = NULL;
|
1864
|
+
const char *name_cstr;
|
1865
|
+
const char *command_cstr;
|
1866
|
+
int enc_idx = this->enc_idx;
|
1720
1867
|
|
1721
1868
|
rb_scan_args(argc, argv, "21", &name, &command, &in_paramtypes);
|
1722
|
-
|
1723
|
-
|
1869
|
+
name_cstr = pg_cstr_enc(name, enc_idx);
|
1870
|
+
command_cstr = pg_cstr_enc(command, enc_idx);
|
1724
1871
|
|
1725
1872
|
if(! NIL_P(in_paramtypes)) {
|
1726
1873
|
Check_Type(in_paramtypes, T_ARRAY);
|
@@ -1728,20 +1875,18 @@ pgconn_send_prepare(int argc, VALUE *argv, VALUE self)
|
|
1728
1875
|
paramTypes = ALLOC_N(Oid, nParams);
|
1729
1876
|
for(i = 0; i < nParams; i++) {
|
1730
1877
|
param = rb_ary_entry(in_paramtypes, i);
|
1731
|
-
Check_Type(param, T_FIXNUM);
|
1732
1878
|
if(param == Qnil)
|
1733
1879
|
paramTypes[i] = 0;
|
1734
1880
|
else
|
1735
|
-
paramTypes[i] =
|
1881
|
+
paramTypes[i] = NUM2UINT(param);
|
1736
1882
|
}
|
1737
1883
|
}
|
1738
|
-
result =
|
1739
|
-
nParams, paramTypes);
|
1884
|
+
result = gvl_PQsendPrepare(this->pgconn, name_cstr, command_cstr, nParams, paramTypes);
|
1740
1885
|
|
1741
1886
|
xfree(paramTypes);
|
1742
1887
|
|
1743
1888
|
if(result == 0) {
|
1744
|
-
error = rb_exc_new2(
|
1889
|
+
error = rb_exc_new2(rb_eUnableToSend, PQerrorMessage(this->pgconn));
|
1745
1890
|
rb_iv_set(error, "@connection", self);
|
1746
1891
|
rb_exc_raise(error);
|
1747
1892
|
}
|
@@ -1750,7 +1895,7 @@ pgconn_send_prepare(int argc, VALUE *argv, VALUE self)
|
|
1750
1895
|
|
1751
1896
|
/*
|
1752
1897
|
* call-seq:
|
1753
|
-
* conn.send_query_prepared( statement_name [, params, result_format ] )
|
1898
|
+
* conn.send_query_prepared( statement_name [, params, result_format[, type_map ]] )
|
1754
1899
|
* -> nil
|
1755
1900
|
*
|
1756
1901
|
* Execute prepared named statement specified by _statement_name_
|
@@ -1761,7 +1906,7 @@ pgconn_send_prepare(int argc, VALUE *argv, VALUE self)
|
|
1761
1906
|
* SQL query. Each element of the +params+ array may be either:
|
1762
1907
|
* a hash of the form:
|
1763
1908
|
* {:value => String (value of bind parameter)
|
1764
|
-
* :format =>
|
1909
|
+
* :format => Integer (0 for text, 1 for binary)
|
1765
1910
|
* }
|
1766
1911
|
* or, it may be a String. If it is a string, that is equivalent to the hash:
|
1767
1912
|
* { :value => <string value>, :format => 0 }
|
@@ -1772,99 +1917,45 @@ pgconn_send_prepare(int argc, VALUE *argv, VALUE self)
|
|
1772
1917
|
*
|
1773
1918
|
* The optional +result_format+ should be 0 for text results, 1
|
1774
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
|
+
*
|
1775
1927
|
*/
|
1776
1928
|
static VALUE
|
1777
1929
|
pgconn_send_query_prepared(int argc, VALUE *argv, VALUE self)
|
1778
1930
|
{
|
1779
|
-
|
1931
|
+
t_pg_connection *this = pg_get_connection_safe( self );
|
1780
1932
|
int result;
|
1781
|
-
VALUE name,
|
1782
|
-
VALUE param, param_value, param_format;
|
1783
|
-
VALUE param_value_tmp;
|
1784
|
-
VALUE sym_value, sym_format;
|
1785
|
-
VALUE gc_array;
|
1933
|
+
VALUE name, in_res_fmt;
|
1786
1934
|
VALUE error;
|
1787
|
-
int i = 0;
|
1788
1935
|
int nParams;
|
1789
|
-
char ** paramValues;
|
1790
|
-
int *paramLengths;
|
1791
|
-
int *paramFormats;
|
1792
1936
|
int resultFormat;
|
1937
|
+
struct query_params_data paramsData = { this->enc_idx };
|
1793
1938
|
|
1794
|
-
rb_scan_args(argc, argv, "
|
1795
|
-
|
1796
|
-
|
1797
|
-
if(NIL_P(params)) {
|
1798
|
-
params = rb_ary_new2(0);
|
1799
|
-
resultFormat = 0;
|
1800
|
-
}
|
1801
|
-
else {
|
1802
|
-
Check_Type(params, T_ARRAY);
|
1803
|
-
}
|
1939
|
+
rb_scan_args(argc, argv, "13", &name, ¶msData.params, &in_res_fmt, ¶msData.typemap);
|
1940
|
+
paramsData.with_types = 0;
|
1804
1941
|
|
1805
|
-
if(NIL_P(
|
1942
|
+
if(NIL_P(paramsData.params)) {
|
1943
|
+
paramsData.params = rb_ary_new2(0);
|
1806
1944
|
resultFormat = 0;
|
1807
1945
|
}
|
1808
|
-
|
1809
|
-
resultFormat = NUM2INT(in_res_fmt);
|
1810
|
-
}
|
1811
|
-
|
1812
|
-
gc_array = rb_ary_new();
|
1813
|
-
rb_gc_register_address(&gc_array);
|
1814
|
-
sym_value = ID2SYM(rb_intern("value"));
|
1815
|
-
sym_format = ID2SYM(rb_intern("format"));
|
1816
|
-
nParams = (int)RARRAY_LEN(params);
|
1817
|
-
paramValues = ALLOC_N(char *, nParams);
|
1818
|
-
paramLengths = ALLOC_N(int, nParams);
|
1819
|
-
paramFormats = ALLOC_N(int, nParams);
|
1820
|
-
for(i = 0; i < nParams; i++) {
|
1821
|
-
param = rb_ary_entry(params, i);
|
1822
|
-
if (TYPE(param) == T_HASH) {
|
1823
|
-
param_value_tmp = rb_hash_aref(param, sym_value);
|
1824
|
-
if(param_value_tmp == Qnil)
|
1825
|
-
param_value = param_value_tmp;
|
1826
|
-
else
|
1827
|
-
param_value = rb_obj_as_string(param_value_tmp);
|
1828
|
-
param_format = rb_hash_aref(param, sym_format);
|
1829
|
-
}
|
1830
|
-
else {
|
1831
|
-
if(param == Qnil)
|
1832
|
-
param_value = param;
|
1833
|
-
else
|
1834
|
-
param_value = rb_obj_as_string(param);
|
1835
|
-
param_format = INT2NUM(0);
|
1836
|
-
}
|
1837
|
-
|
1838
|
-
if(param_value == Qnil) {
|
1839
|
-
paramValues[i] = NULL;
|
1840
|
-
paramLengths[i] = 0;
|
1841
|
-
}
|
1842
|
-
else {
|
1843
|
-
Check_Type(param_value, T_STRING);
|
1844
|
-
/* make sure param_value doesn't get freed by the GC */
|
1845
|
-
rb_ary_push(gc_array, param_value);
|
1846
|
-
paramValues[i] = StringValuePtr(param_value);
|
1847
|
-
paramLengths[i] = (int)RSTRING_LEN(param_value);
|
1848
|
-
}
|
1946
|
+
pgconn_query_assign_typemap( self, ¶msData );
|
1849
1947
|
|
1850
|
-
|
1851
|
-
|
1852
|
-
else
|
1853
|
-
paramFormats[i] = NUM2INT(param_format);
|
1854
|
-
}
|
1948
|
+
resultFormat = NIL_P(in_res_fmt) ? 0 : NUM2INT(in_res_fmt);
|
1949
|
+
nParams = alloc_query_params( ¶msData );
|
1855
1950
|
|
1856
|
-
result =
|
1857
|
-
(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,
|
1858
1953
|
resultFormat);
|
1859
1954
|
|
1860
|
-
|
1861
|
-
|
1862
|
-
xfree(paramValues);
|
1863
|
-
xfree(paramLengths);
|
1864
|
-
xfree(paramFormats);
|
1955
|
+
free_query_params( ¶msData );
|
1865
1956
|
|
1866
1957
|
if(result == 0) {
|
1867
|
-
error = rb_exc_new2(
|
1958
|
+
error = rb_exc_new2(rb_eUnableToSend, PQerrorMessage(this->pgconn));
|
1868
1959
|
rb_iv_set(error, "@connection", self);
|
1869
1960
|
rb_exc_raise(error);
|
1870
1961
|
}
|
@@ -1882,10 +1973,10 @@ static VALUE
|
|
1882
1973
|
pgconn_send_describe_prepared(VALUE self, VALUE stmt_name)
|
1883
1974
|
{
|
1884
1975
|
VALUE error;
|
1885
|
-
|
1976
|
+
t_pg_connection *this = pg_get_connection_safe( self );
|
1886
1977
|
/* returns 0 on failure */
|
1887
|
-
if(
|
1888
|
-
error = rb_exc_new2(
|
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));
|
1889
1980
|
rb_iv_set(error, "@connection", self);
|
1890
1981
|
rb_exc_raise(error);
|
1891
1982
|
}
|
@@ -1904,10 +1995,10 @@ static VALUE
|
|
1904
1995
|
pgconn_send_describe_portal(VALUE self, VALUE portal)
|
1905
1996
|
{
|
1906
1997
|
VALUE error;
|
1907
|
-
|
1998
|
+
t_pg_connection *this = pg_get_connection_safe( self );
|
1908
1999
|
/* returns 0 on failure */
|
1909
|
-
if(
|
1910
|
-
error = rb_exc_new2(
|
2000
|
+
if(gvl_PQsendDescribePortal(this->pgconn, pg_cstr_enc(portal, this->enc_idx)) == 0) {
|
2001
|
+
error = rb_exc_new2(rb_eUnableToSend, PQerrorMessage(this->pgconn));
|
1911
2002
|
rb_iv_set(error, "@connection", self);
|
1912
2003
|
rb_exc_raise(error);
|
1913
2004
|
}
|
@@ -1965,7 +2056,7 @@ pgconn_consume_input(self)
|
|
1965
2056
|
PGconn *conn = pg_get_pgconn(self);
|
1966
2057
|
/* returns 0 on error */
|
1967
2058
|
if(PQconsumeInput(conn) == 0) {
|
1968
|
-
error = rb_exc_new2(
|
2059
|
+
error = rb_exc_new2(rb_eConnectionBad, PQerrorMessage(conn));
|
1969
2060
|
rb_iv_set(error, "@connection", self);
|
1970
2061
|
rb_exc_raise(error);
|
1971
2062
|
}
|
@@ -1983,7 +2074,7 @@ static VALUE
|
|
1983
2074
|
pgconn_is_busy(self)
|
1984
2075
|
VALUE self;
|
1985
2076
|
{
|
1986
|
-
return
|
2077
|
+
return gvl_PQisBusy(pg_get_pgconn(self)) ? Qtrue : Qfalse;
|
1987
2078
|
}
|
1988
2079
|
|
1989
2080
|
/*
|
@@ -2078,7 +2169,6 @@ pgconn_flush(self)
|
|
2078
2169
|
static VALUE
|
2079
2170
|
pgconn_cancel(VALUE self)
|
2080
2171
|
{
|
2081
|
-
#ifdef HAVE_PQGETCANCEL
|
2082
2172
|
char errbuf[256];
|
2083
2173
|
PGcancel *cancel;
|
2084
2174
|
VALUE retval;
|
@@ -2088,7 +2178,7 @@ pgconn_cancel(VALUE self)
|
|
2088
2178
|
if(cancel == NULL)
|
2089
2179
|
rb_raise(rb_ePGerror,"Invalid connection!");
|
2090
2180
|
|
2091
|
-
ret =
|
2181
|
+
ret = gvl_PQcancel(cancel, errbuf, 256);
|
2092
2182
|
if(ret == 1)
|
2093
2183
|
retval = Qnil;
|
2094
2184
|
else
|
@@ -2096,9 +2186,6 @@ pgconn_cancel(VALUE self)
|
|
2096
2186
|
|
2097
2187
|
PQfreeCancel(cancel);
|
2098
2188
|
return retval;
|
2099
|
-
#else
|
2100
|
-
rb_notimplement();
|
2101
|
-
#endif
|
2102
2189
|
}
|
2103
2190
|
|
2104
2191
|
|
@@ -2112,7 +2199,7 @@ pgconn_cancel(VALUE self)
|
|
2112
2199
|
static VALUE
|
2113
2200
|
pgconn_notifies(VALUE self)
|
2114
2201
|
{
|
2115
|
-
|
2202
|
+
t_pg_connection *this = pg_get_connection_safe( self );
|
2116
2203
|
PGnotify *notification;
|
2117
2204
|
VALUE hash;
|
2118
2205
|
VALUE sym_relname, sym_be_pid, sym_extra;
|
@@ -2122,19 +2209,17 @@ pgconn_notifies(VALUE self)
|
|
2122
2209
|
sym_be_pid = ID2SYM(rb_intern("be_pid"));
|
2123
2210
|
sym_extra = ID2SYM(rb_intern("extra"));
|
2124
2211
|
|
2125
|
-
notification =
|
2212
|
+
notification = gvl_PQnotifies(this->pgconn);
|
2126
2213
|
if (notification == NULL) {
|
2127
2214
|
return Qnil;
|
2128
2215
|
}
|
2129
2216
|
|
2130
2217
|
hash = rb_hash_new();
|
2131
|
-
relname =
|
2218
|
+
relname = rb_str_new2(notification->relname);
|
2132
2219
|
be_pid = INT2NUM(notification->be_pid);
|
2133
|
-
extra =
|
2134
|
-
|
2135
|
-
|
2136
|
-
ENCODING_SET( extra, rb_enc_to_index(pg_conn_enc_get( conn )) );
|
2137
|
-
#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 );
|
2138
2223
|
|
2139
2224
|
rb_hash_aset(hash, sym_relname, relname);
|
2140
2225
|
rb_hash_aset(hash, sym_be_pid, be_pid);
|
@@ -2144,87 +2229,60 @@ pgconn_notifies(VALUE self)
|
|
2144
2229
|
return hash;
|
2145
2230
|
}
|
2146
2231
|
|
2147
|
-
/* Win32 + Ruby 1.
|
2148
|
-
#if
|
2149
|
-
|
2232
|
+
/* Win32 + Ruby 1.9+ */
|
2233
|
+
#if defined( _WIN32 )
|
2150
2234
|
/*
|
2151
|
-
*
|
2152
|
-
|
2153
|
-
void create_crt_fd(fd_set *os_set, fd_set *crt_set)
|
2154
|
-
{
|
2155
|
-
int i;
|
2156
|
-
crt_set->fd_count = os_set->fd_count;
|
2157
|
-
for (i = 0; i < os_set->fd_count; i++) {
|
2158
|
-
WSAPROTOCOL_INFO wsa_pi;
|
2159
|
-
/* dupicate the SOCKET */
|
2160
|
-
int r = WSADuplicateSocket(os_set->fd_array[i], GetCurrentProcessId(), &wsa_pi);
|
2161
|
-
SOCKET s = WSASocket(wsa_pi.iAddressFamily, wsa_pi.iSocketType, wsa_pi.iProtocol, &wsa_pi, 0, 0);
|
2162
|
-
/* create the CRT fd so ruby can get back to the SOCKET */
|
2163
|
-
int fd = _open_osfhandle(s, O_RDWR|O_BINARY);
|
2164
|
-
os_set->fd_array[i] = s;
|
2165
|
-
crt_set->fd_array[i] = fd;
|
2166
|
-
}
|
2167
|
-
}
|
2168
|
-
|
2169
|
-
/*
|
2170
|
-
* Clean up the CRT FDs from create_crt_fd()
|
2171
|
-
*/
|
2172
|
-
void cleanup_crt_fd(fd_set *os_set, fd_set *crt_set)
|
2173
|
-
{
|
2174
|
-
int i;
|
2175
|
-
for (i = 0; i < os_set->fd_count; i++) {
|
2176
|
-
/* cleanup the CRT fd */
|
2177
|
-
_close(crt_set->fd_array[i]);
|
2178
|
-
/* cleanup the duplicated SOCKET */
|
2179
|
-
closesocket(os_set->fd_array[i]);
|
2180
|
-
}
|
2181
|
-
}
|
2182
|
-
#endif
|
2183
|
-
|
2184
|
-
/* Win32 + Ruby 1.9+ */
|
2185
|
-
#if defined( HAVE_RUBY_VM_H ) && defined( _WIN32 )
|
2186
|
-
/*
|
2187
|
-
* On Windows, use platform-specific strategies to wait for the socket
|
2188
|
-
* instead of rb_thread_select().
|
2235
|
+
* On Windows, use platform-specific strategies to wait for the socket
|
2236
|
+
* instead of rb_wait_for_single_fd().
|
2189
2237
|
*/
|
2190
2238
|
|
2191
2239
|
int rb_w32_wait_events( HANDLE *events, int num, DWORD timeout );
|
2192
2240
|
|
2193
|
-
/* If WIN32 and Ruby 1.9 do not use rb_thread_select() which sometimes hangs
|
2194
|
-
* and does not wait (nor sleep) any time even if timeout is given.
|
2195
|
-
* Instead use the Winsock events and rb_w32_wait_events(). */
|
2196
|
-
|
2197
2241
|
static void *
|
2198
2242
|
wait_socket_readable( PGconn *conn, struct timeval *ptimeout, void *(*is_readable)(PGconn *) )
|
2199
2243
|
{
|
2200
2244
|
int sd = PQsocket( conn );
|
2201
2245
|
void *retval;
|
2246
|
+
struct timeval aborttime={0,0}, currtime, waittime;
|
2202
2247
|
DWORD timeout_milisec = INFINITE;
|
2203
2248
|
DWORD wait_ret;
|
2204
2249
|
WSAEVENT hEvent;
|
2205
2250
|
|
2206
2251
|
if ( sd < 0 )
|
2207
|
-
|
2252
|
+
rb_raise(rb_eConnectionBad, "PQsocket() can't get socket descriptor");
|
2208
2253
|
|
2209
2254
|
hEvent = WSACreateEvent();
|
2210
2255
|
|
2211
|
-
if ( ptimeout ) {
|
2212
|
-
timeout_milisec = (DWORD)( ptimeout->tv_sec * 1e3 + ptimeout->tv_usec / 1e3 );
|
2213
|
-
}
|
2214
|
-
|
2215
2256
|
/* Check for connection errors (PQisBusy is true on connection errors) */
|
2216
2257
|
if( PQconsumeInput(conn) == 0 ) {
|
2217
2258
|
WSACloseEvent( hEvent );
|
2218
|
-
rb_raise(
|
2259
|
+
rb_raise( rb_eConnectionBad, "PQconsumeInput() %s", PQerrorMessage(conn) );
|
2260
|
+
}
|
2261
|
+
|
2262
|
+
if ( ptimeout ) {
|
2263
|
+
gettimeofday(&currtime, NULL);
|
2264
|
+
timeradd(&currtime, ptimeout, &aborttime);
|
2219
2265
|
}
|
2220
2266
|
|
2221
2267
|
while ( !(retval=is_readable(conn)) ) {
|
2222
2268
|
if ( WSAEventSelect(sd, hEvent, FD_READ|FD_CLOSE) == SOCKET_ERROR ) {
|
2223
2269
|
WSACloseEvent( hEvent );
|
2224
|
-
rb_raise(
|
2270
|
+
rb_raise( rb_eConnectionBad, "WSAEventSelect socket error: %d", WSAGetLastError() );
|
2225
2271
|
}
|
2226
2272
|
|
2227
|
-
|
2273
|
+
if ( ptimeout ) {
|
2274
|
+
gettimeofday(&currtime, NULL);
|
2275
|
+
timersub(&aborttime, &currtime, &waittime);
|
2276
|
+
timeout_milisec = (DWORD)( waittime.tv_sec * 1e3 + waittime.tv_usec / 1e3 );
|
2277
|
+
}
|
2278
|
+
|
2279
|
+
/* Is the given timeout valid? */
|
2280
|
+
if( !ptimeout || (waittime.tv_sec >= 0 && waittime.tv_usec >= 0) ){
|
2281
|
+
/* Wait for the socket to become readable before checking again */
|
2282
|
+
wait_ret = rb_w32_wait_events( &hEvent, 1, timeout_milisec );
|
2283
|
+
} else {
|
2284
|
+
wait_ret = WAIT_TIMEOUT;
|
2285
|
+
}
|
2228
2286
|
|
2229
2287
|
if ( wait_ret == WAIT_TIMEOUT ) {
|
2230
2288
|
WSACloseEvent( hEvent );
|
@@ -2237,16 +2295,16 @@ wait_socket_readable( PGconn *conn, struct timeval *ptimeout, void *(*is_readabl
|
|
2237
2295
|
rb_thread_check_ints();
|
2238
2296
|
} else if ( wait_ret == WAIT_FAILED ) {
|
2239
2297
|
WSACloseEvent( hEvent );
|
2240
|
-
rb_raise(
|
2298
|
+
rb_raise( rb_eConnectionBad, "Wait on socket error (WaitForMultipleObjects): %lu", GetLastError() );
|
2241
2299
|
} else {
|
2242
2300
|
WSACloseEvent( hEvent );
|
2243
|
-
rb_raise(
|
2301
|
+
rb_raise( rb_eConnectionBad, "Wait on socket abandoned (WaitForMultipleObjects)" );
|
2244
2302
|
}
|
2245
2303
|
|
2246
2304
|
/* Check for connection errors (PQisBusy is true on connection errors) */
|
2247
2305
|
if ( PQconsumeInput(conn) == 0 ) {
|
2248
2306
|
WSACloseEvent( hEvent );
|
2249
|
-
rb_raise(
|
2307
|
+
rb_raise( rb_eConnectionBad, "PQconsumeInput() %s", PQerrorMessage(conn) );
|
2250
2308
|
}
|
2251
2309
|
}
|
2252
2310
|
|
@@ -2256,7 +2314,7 @@ wait_socket_readable( PGconn *conn, struct timeval *ptimeout, void *(*is_readabl
|
|
2256
2314
|
|
2257
2315
|
#else
|
2258
2316
|
|
2259
|
-
/* non Win32
|
2317
|
+
/* non Win32 */
|
2260
2318
|
|
2261
2319
|
static void *
|
2262
2320
|
wait_socket_readable( PGconn *conn, struct timeval *ptimeout, void *(*is_readable)(PGconn *))
|
@@ -2264,58 +2322,49 @@ wait_socket_readable( PGconn *conn, struct timeval *ptimeout, void *(*is_readabl
|
|
2264
2322
|
int sd = PQsocket( conn );
|
2265
2323
|
int ret;
|
2266
2324
|
void *retval;
|
2267
|
-
|
2268
|
-
#ifdef _WIN32
|
2269
|
-
rb_fdset_t crt_sd_rset;
|
2270
|
-
#endif
|
2325
|
+
struct timeval aborttime={0,0}, currtime, waittime;
|
2271
2326
|
|
2272
2327
|
if ( sd < 0 )
|
2273
|
-
|
2328
|
+
rb_raise(rb_eConnectionBad, "PQsocket() can't get socket descriptor");
|
2274
2329
|
|
2275
2330
|
/* Check for connection errors (PQisBusy is true on connection errors) */
|
2276
2331
|
if ( PQconsumeInput(conn) == 0 )
|
2277
|
-
rb_raise(
|
2332
|
+
rb_raise( rb_eConnectionBad, "PQconsumeInput() %s", PQerrorMessage(conn) );
|
2278
2333
|
|
2279
|
-
|
2334
|
+
if ( ptimeout ) {
|
2335
|
+
gettimeofday(&currtime, NULL);
|
2336
|
+
timeradd(&currtime, ptimeout, &aborttime);
|
2337
|
+
}
|
2280
2338
|
|
2281
2339
|
while ( !(retval=is_readable(conn)) ) {
|
2282
|
-
|
2283
|
-
|
2284
|
-
|
2285
|
-
|
2286
|
-
/* Ruby's FD_SET is modified on win32 to convert a file descriptor
|
2287
|
-
* to osfhandle, but we already get a osfhandle from PQsocket().
|
2288
|
-
* Therefore it's overwritten here. */
|
2289
|
-
sd_rset.fd_array[0] = sd;
|
2290
|
-
create_crt_fd(&sd_rset, &crt_sd_rset);
|
2291
|
-
#endif
|
2292
|
-
|
2293
|
-
/* Wait for the socket to become readable before checking again */
|
2294
|
-
ret = rb_thread_fd_select( sd+1, &sd_rset, NULL, NULL, ptimeout );
|
2340
|
+
if ( ptimeout ) {
|
2341
|
+
gettimeofday(&currtime, NULL);
|
2342
|
+
timersub(&aborttime, &currtime, &waittime);
|
2343
|
+
}
|
2295
2344
|
|
2296
|
-
|
2297
|
-
|
2298
|
-
|
2345
|
+
/* Is the given timeout valid? */
|
2346
|
+
if( !ptimeout || (waittime.tv_sec >= 0 && waittime.tv_usec >= 0) ){
|
2347
|
+
/* Wait for the socket to become readable before checking again */
|
2348
|
+
ret = rb_wait_for_single_fd( sd, RB_WAITFD_IN, ptimeout ? &waittime : NULL );
|
2349
|
+
} else {
|
2350
|
+
ret = 0;
|
2351
|
+
}
|
2299
2352
|
|
2300
2353
|
if ( ret < 0 ){
|
2301
|
-
|
2302
|
-
rb_sys_fail( "rb_thread_select()" );
|
2354
|
+
rb_sys_fail( "rb_wait_for_single_fd()" );
|
2303
2355
|
}
|
2304
2356
|
|
2305
2357
|
/* Return false if the select() timed out */
|
2306
2358
|
if ( ret == 0 ){
|
2307
|
-
rb_fd_term( &sd_rset );
|
2308
2359
|
return NULL;
|
2309
2360
|
}
|
2310
2361
|
|
2311
2362
|
/* Check for connection errors (PQisBusy is true on connection errors) */
|
2312
2363
|
if ( PQconsumeInput(conn) == 0 ){
|
2313
|
-
|
2314
|
-
rb_raise( rb_ePGerror, "%s", PQerrorMessage(conn) );
|
2364
|
+
rb_raise( rb_eConnectionBad, "PQconsumeInput() %s", PQerrorMessage(conn) );
|
2315
2365
|
}
|
2316
2366
|
}
|
2317
2367
|
|
2318
|
-
rb_fd_term( &sd_rset );
|
2319
2368
|
return retval;
|
2320
2369
|
}
|
2321
2370
|
|
@@ -2325,32 +2374,25 @@ wait_socket_readable( PGconn *conn, struct timeval *ptimeout, void *(*is_readabl
|
|
2325
2374
|
static void *
|
2326
2375
|
notify_readable(PGconn *conn)
|
2327
2376
|
{
|
2328
|
-
return (void*)
|
2377
|
+
return (void*)gvl_PQnotifies(conn);
|
2329
2378
|
}
|
2330
2379
|
|
2331
2380
|
/*
|
2332
2381
|
* call-seq:
|
2333
|
-
* conn.wait_for_notify( [ timeout ] ) -> String
|
2334
|
-
* conn.wait_for_notify( [ timeout ] ) { |event, pid| block }
|
2335
|
-
* conn.wait_for_notify( [ timeout ] ) { |event, pid, payload| block } # PostgreSQL 9.0
|
2382
|
+
* conn.wait_for_notify( [ timeout ] ) { |event, pid, payload| block } -> String
|
2336
2383
|
*
|
2337
2384
|
* Blocks while waiting for notification(s), or until the optional
|
2338
2385
|
* _timeout_ is reached, whichever comes first. _timeout_ is
|
2339
2386
|
* measured in seconds and can be fractional.
|
2340
2387
|
*
|
2341
|
-
* Returns +nil+ if _timeout_ is reached, the name of the NOTIFY
|
2342
|
-
*
|
2343
|
-
*
|
2344
|
-
*
|
2345
|
-
* Under PostgreSQL 9.0 and later, if the notification is sent with
|
2346
|
-
* the optional +payload+ string, it will be given to the block as the
|
2347
|
-
* third argument.
|
2348
|
-
*
|
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.
|
2349
2391
|
*/
|
2350
2392
|
static VALUE
|
2351
2393
|
pgconn_wait_for_notify(int argc, VALUE *argv, VALUE self)
|
2352
2394
|
{
|
2353
|
-
|
2395
|
+
t_pg_connection *this = pg_get_connection_safe( self );
|
2354
2396
|
PGnotify *pnotification;
|
2355
2397
|
struct timeval timeout;
|
2356
2398
|
struct timeval *ptimeout = NULL;
|
@@ -2366,24 +2408,18 @@ pgconn_wait_for_notify(int argc, VALUE *argv, VALUE self)
|
|
2366
2408
|
ptimeout = &timeout;
|
2367
2409
|
}
|
2368
2410
|
|
2369
|
-
pnotification = (PGnotify*) wait_socket_readable(
|
2411
|
+
pnotification = (PGnotify*) wait_socket_readable( this->pgconn, ptimeout, notify_readable);
|
2370
2412
|
|
2371
2413
|
/* Return nil if the select timed out */
|
2372
2414
|
if ( !pnotification ) return Qnil;
|
2373
2415
|
|
2374
|
-
relname =
|
2375
|
-
|
2376
|
-
ENCODING_SET( relname, rb_enc_to_index(pg_conn_enc_get( conn )) );
|
2377
|
-
#endif
|
2416
|
+
relname = rb_str_new2( pnotification->relname );
|
2417
|
+
PG_ENCODING_SET_NOCHECK( relname, this->enc_idx );
|
2378
2418
|
be_pid = INT2NUM( pnotification->be_pid );
|
2379
|
-
#ifdef HAVE_ST_NOTIFY_EXTRA
|
2380
2419
|
if ( *pnotification->extra ) {
|
2381
|
-
extra =
|
2382
|
-
|
2383
|
-
ENCODING_SET( extra, rb_enc_to_index(pg_conn_enc_get( conn )) );
|
2384
|
-
#endif
|
2420
|
+
extra = rb_str_new2( pnotification->extra );
|
2421
|
+
PG_ENCODING_SET_NOCHECK( extra, this->enc_idx );
|
2385
2422
|
}
|
2386
|
-
#endif
|
2387
2423
|
PQfreemem( pnotification );
|
2388
2424
|
|
2389
2425
|
if ( rb_block_given_p() )
|
@@ -2395,30 +2431,79 @@ pgconn_wait_for_notify(int argc, VALUE *argv, VALUE self)
|
|
2395
2431
|
|
2396
2432
|
/*
|
2397
2433
|
* call-seq:
|
2398
|
-
* conn.put_copy_data( buffer ) -> Boolean
|
2434
|
+
* conn.put_copy_data( buffer [, encoder] ) -> Boolean
|
2399
2435
|
*
|
2400
2436
|
* Transmits _buffer_ as copy data to the server.
|
2401
2437
|
* Returns true if the data was sent, false if it was
|
2402
2438
|
* not sent (false is only possible if the connection
|
2403
2439
|
* is in nonblocking mode, and this command would block).
|
2404
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
|
+
*
|
2405
2447
|
* Raises an exception if an error occurs.
|
2448
|
+
*
|
2449
|
+
* See also #copy_data.
|
2450
|
+
*
|
2406
2451
|
*/
|
2407
2452
|
static VALUE
|
2408
|
-
pgconn_put_copy_data(
|
2409
|
-
VALUE self, buffer;
|
2453
|
+
pgconn_put_copy_data(int argc, VALUE *argv, VALUE self)
|
2410
2454
|
{
|
2411
2455
|
int ret;
|
2412
|
-
|
2413
|
-
|
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
|
+
|
2414
2496
|
Check_Type(buffer, T_STRING);
|
2415
2497
|
|
2416
|
-
ret = gvl_PQputCopyData(
|
2498
|
+
ret = gvl_PQputCopyData(this->pgconn, RSTRING_PTR(buffer), RSTRING_LENINT(buffer));
|
2417
2499
|
if(ret == -1) {
|
2418
|
-
error = rb_exc_new2(rb_ePGerror, PQerrorMessage(
|
2500
|
+
VALUE error = rb_exc_new2(rb_ePGerror, PQerrorMessage(this->pgconn));
|
2419
2501
|
rb_iv_set(error, "@connection", self);
|
2420
2502
|
rb_exc_raise(error);
|
2421
2503
|
}
|
2504
|
+
RB_GC_GUARD(intermediate);
|
2505
|
+
RB_GC_GUARD(buffer);
|
2506
|
+
|
2422
2507
|
return (ret) ? Qtrue : Qfalse;
|
2423
2508
|
}
|
2424
2509
|
|
@@ -2442,17 +2527,17 @@ pgconn_put_copy_end(int argc, VALUE *argv, VALUE self)
|
|
2442
2527
|
VALUE str;
|
2443
2528
|
VALUE error;
|
2444
2529
|
int ret;
|
2445
|
-
char *error_message = NULL;
|
2446
|
-
|
2530
|
+
const char *error_message = NULL;
|
2531
|
+
t_pg_connection *this = pg_get_connection_safe( self );
|
2447
2532
|
|
2448
2533
|
if (rb_scan_args(argc, argv, "01", &str) == 0)
|
2449
2534
|
error_message = NULL;
|
2450
2535
|
else
|
2451
|
-
error_message =
|
2536
|
+
error_message = pg_cstr_enc(str, this->enc_idx);
|
2452
2537
|
|
2453
|
-
ret = gvl_PQputCopyEnd(
|
2538
|
+
ret = gvl_PQputCopyEnd(this->pgconn, error_message);
|
2454
2539
|
if(ret == -1) {
|
2455
|
-
error = rb_exc_new2(rb_ePGerror, PQerrorMessage(
|
2540
|
+
error = rb_exc_new2(rb_ePGerror, PQerrorMessage(this->pgconn));
|
2456
2541
|
rb_iv_set(error, "@connection", self);
|
2457
2542
|
rb_exc_raise(error);
|
2458
2543
|
}
|
@@ -2461,32 +2546,51 @@ pgconn_put_copy_end(int argc, VALUE *argv, VALUE self)
|
|
2461
2546
|
|
2462
2547
|
/*
|
2463
2548
|
* call-seq:
|
2464
|
-
* conn.get_copy_data( [ async = false ] ) ->
|
2549
|
+
* conn.get_copy_data( [ async = false [, decoder = nil ]] ) -> Object
|
2465
2550
|
*
|
2466
|
-
* Return
|
2551
|
+
* Return one row of data, +nil+
|
2467
2552
|
* if the copy is done, or +false+ if the call would
|
2468
2553
|
* block (only possible if _async_ is true).
|
2469
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
|
+
*
|
2563
|
+
* See also #copy_data.
|
2564
|
+
*
|
2470
2565
|
*/
|
2471
2566
|
static VALUE
|
2472
2567
|
pgconn_get_copy_data(int argc, VALUE *argv, VALUE self )
|
2473
2568
|
{
|
2474
2569
|
VALUE async_in;
|
2475
2570
|
VALUE error;
|
2476
|
-
VALUE
|
2571
|
+
VALUE result;
|
2477
2572
|
int ret;
|
2478
|
-
int async;
|
2479
2573
|
char *buffer;
|
2480
|
-
|
2574
|
+
VALUE decoder;
|
2575
|
+
t_pg_coder *p_coder = NULL;
|
2576
|
+
t_pg_connection *this = pg_get_connection_safe( self );
|
2481
2577
|
|
2482
|
-
|
2483
|
-
|
2484
|
-
|
2485
|
-
|
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
|
+
}
|
2486
2590
|
|
2487
|
-
ret = gvl_PQgetCopyData(
|
2591
|
+
ret = gvl_PQgetCopyData(this->pgconn, &buffer, RTEST(async_in));
|
2488
2592
|
if(ret == -2) { /* error */
|
2489
|
-
error = rb_exc_new2(rb_ePGerror, PQerrorMessage(
|
2593
|
+
error = rb_exc_new2(rb_ePGerror, PQerrorMessage(this->pgconn));
|
2490
2594
|
rb_iv_set(error, "@connection", self);
|
2491
2595
|
rb_exc_raise(error);
|
2492
2596
|
}
|
@@ -2496,20 +2600,34 @@ pgconn_get_copy_data(int argc, VALUE *argv, VALUE self )
|
|
2496
2600
|
if(ret == 0) { /* would block */
|
2497
2601
|
return Qfalse;
|
2498
2602
|
}
|
2499
|
-
|
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
|
+
|
2500
2611
|
PQfreemem(buffer);
|
2501
|
-
return
|
2612
|
+
return result;
|
2502
2613
|
}
|
2503
2614
|
|
2504
2615
|
/*
|
2505
2616
|
* call-seq:
|
2506
|
-
* conn.set_error_verbosity( verbosity ) ->
|
2617
|
+
* conn.set_error_verbosity( verbosity ) -> Integer
|
2507
2618
|
*
|
2508
2619
|
* Sets connection's verbosity to _verbosity_ and returns
|
2509
2620
|
* the previous setting. Available settings are:
|
2621
|
+
*
|
2510
2622
|
* * PQERRORS_TERSE
|
2511
2623
|
* * PQERRORS_DEFAULT
|
2512
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].
|
2513
2631
|
*/
|
2514
2632
|
static VALUE
|
2515
2633
|
pgconn_set_error_verbosity(VALUE self, VALUE in_verbosity)
|
@@ -2519,6 +2637,37 @@ pgconn_set_error_verbosity(VALUE self, VALUE in_verbosity)
|
|
2519
2637
|
return INT2FIX(PQsetErrorVerbosity(conn, verbosity));
|
2520
2638
|
}
|
2521
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
|
+
|
2522
2671
|
/*
|
2523
2672
|
* call-seq:
|
2524
2673
|
* conn.trace( stream ) -> nil
|
@@ -2535,8 +2684,9 @@ pgconn_trace(VALUE self, VALUE stream)
|
|
2535
2684
|
FILE *new_fp;
|
2536
2685
|
int old_fd, new_fd;
|
2537
2686
|
VALUE new_file;
|
2687
|
+
t_pg_connection *this = pg_get_connection_safe( self );
|
2538
2688
|
|
2539
|
-
if(rb_respond_to(stream,rb_intern("fileno"))
|
2689
|
+
if(!rb_respond_to(stream,rb_intern("fileno")))
|
2540
2690
|
rb_raise(rb_eArgError, "stream does not respond to method: fileno");
|
2541
2691
|
|
2542
2692
|
fileno = rb_funcall(stream, rb_intern("fileno"), 0);
|
@@ -2557,9 +2707,9 @@ pgconn_trace(VALUE self, VALUE stream)
|
|
2557
2707
|
rb_raise(rb_eArgError, "stream is not writable");
|
2558
2708
|
|
2559
2709
|
new_file = rb_funcall(rb_cIO, rb_intern("new"), 1, INT2NUM(new_fd));
|
2560
|
-
|
2710
|
+
this->trace_stream = new_file;
|
2561
2711
|
|
2562
|
-
PQtrace(
|
2712
|
+
PQtrace(this->pgconn, new_fp);
|
2563
2713
|
return Qnil;
|
2564
2714
|
}
|
2565
2715
|
|
@@ -2572,11 +2722,11 @@ pgconn_trace(VALUE self, VALUE stream)
|
|
2572
2722
|
static VALUE
|
2573
2723
|
pgconn_untrace(VALUE self)
|
2574
2724
|
{
|
2575
|
-
|
2576
|
-
|
2577
|
-
|
2578
|
-
rb_funcall(trace_stream, rb_intern("close"), 0);
|
2579
|
-
|
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;
|
2580
2730
|
return Qnil;
|
2581
2731
|
}
|
2582
2732
|
|
@@ -2586,19 +2736,16 @@ pgconn_untrace(VALUE self)
|
|
2586
2736
|
* currently-registered Ruby notice_receiver object.
|
2587
2737
|
*/
|
2588
2738
|
void
|
2589
|
-
notice_receiver_proxy(void *arg, const PGresult *
|
2739
|
+
notice_receiver_proxy(void *arg, const PGresult *pgresult)
|
2590
2740
|
{
|
2591
|
-
VALUE proc;
|
2592
2741
|
VALUE self = (VALUE)arg;
|
2742
|
+
t_pg_connection *this = pg_get_connection( self );
|
2593
2743
|
|
2594
|
-
if (
|
2595
|
-
VALUE
|
2596
|
-
|
2597
|
-
|
2598
|
-
|
2599
|
-
ENCODING_SET( val, rb_enc_to_index(enc) );
|
2600
|
-
#endif
|
2601
|
-
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 );
|
2602
2749
|
}
|
2603
2750
|
return;
|
2604
2751
|
}
|
@@ -2636,7 +2783,7 @@ static VALUE
|
|
2636
2783
|
pgconn_set_notice_receiver(VALUE self)
|
2637
2784
|
{
|
2638
2785
|
VALUE proc, old_proc;
|
2639
|
-
|
2786
|
+
t_pg_connection *this = pg_get_connection_safe( self );
|
2640
2787
|
|
2641
2788
|
/* If default_notice_receiver is unset, assume that the current
|
2642
2789
|
* notice receiver is the default, and save it to a global variable.
|
@@ -2644,19 +2791,19 @@ pgconn_set_notice_receiver(VALUE self)
|
|
2644
2791
|
* always the same, so won't vary among connections.
|
2645
2792
|
*/
|
2646
2793
|
if(default_notice_receiver == NULL)
|
2647
|
-
default_notice_receiver = PQsetNoticeReceiver(
|
2794
|
+
default_notice_receiver = PQsetNoticeReceiver(this->pgconn, NULL, NULL);
|
2648
2795
|
|
2649
|
-
old_proc =
|
2796
|
+
old_proc = this->notice_receiver;
|
2650
2797
|
if( rb_block_given_p() ) {
|
2651
2798
|
proc = rb_block_proc();
|
2652
|
-
PQsetNoticeReceiver(
|
2799
|
+
PQsetNoticeReceiver(this->pgconn, gvl_notice_receiver_proxy, (void *)self);
|
2653
2800
|
} else {
|
2654
2801
|
/* if no block is given, set back to default */
|
2655
2802
|
proc = Qnil;
|
2656
|
-
PQsetNoticeReceiver(
|
2803
|
+
PQsetNoticeReceiver(this->pgconn, default_notice_receiver, NULL);
|
2657
2804
|
}
|
2658
2805
|
|
2659
|
-
|
2806
|
+
this->notice_receiver = proc;
|
2660
2807
|
return old_proc;
|
2661
2808
|
}
|
2662
2809
|
|
@@ -2668,17 +2815,13 @@ pgconn_set_notice_receiver(VALUE self)
|
|
2668
2815
|
void
|
2669
2816
|
notice_processor_proxy(void *arg, const char *message)
|
2670
2817
|
{
|
2671
|
-
VALUE proc;
|
2672
2818
|
VALUE self = (VALUE)arg;
|
2819
|
+
t_pg_connection *this = pg_get_connection( self );
|
2673
2820
|
|
2674
|
-
if (
|
2675
|
-
VALUE message_str =
|
2676
|
-
|
2677
|
-
|
2678
|
-
rb_encoding *enc = pg_conn_enc_get( conn );
|
2679
|
-
ENCODING_SET( message_str, rb_enc_to_index(enc) );
|
2680
|
-
#endif
|
2681
|
-
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);
|
2682
2825
|
}
|
2683
2826
|
return;
|
2684
2827
|
}
|
@@ -2700,7 +2843,7 @@ static VALUE
|
|
2700
2843
|
pgconn_set_notice_processor(VALUE self)
|
2701
2844
|
{
|
2702
2845
|
VALUE proc, old_proc;
|
2703
|
-
|
2846
|
+
t_pg_connection *this = pg_get_connection_safe( self );
|
2704
2847
|
|
2705
2848
|
/* If default_notice_processor is unset, assume that the current
|
2706
2849
|
* notice processor is the default, and save it to a global variable.
|
@@ -2708,19 +2851,19 @@ pgconn_set_notice_processor(VALUE self)
|
|
2708
2851
|
* always the same, so won't vary among connections.
|
2709
2852
|
*/
|
2710
2853
|
if(default_notice_processor == NULL)
|
2711
|
-
default_notice_processor = PQsetNoticeProcessor(
|
2854
|
+
default_notice_processor = PQsetNoticeProcessor(this->pgconn, NULL, NULL);
|
2712
2855
|
|
2713
|
-
old_proc =
|
2856
|
+
old_proc = this->notice_receiver;
|
2714
2857
|
if( rb_block_given_p() ) {
|
2715
2858
|
proc = rb_block_proc();
|
2716
|
-
PQsetNoticeProcessor(
|
2859
|
+
PQsetNoticeProcessor(this->pgconn, gvl_notice_processor_proxy, (void *)self);
|
2717
2860
|
} else {
|
2718
2861
|
/* if no block is given, set back to default */
|
2719
2862
|
proc = Qnil;
|
2720
|
-
PQsetNoticeProcessor(
|
2863
|
+
PQsetNoticeProcessor(this->pgconn, default_notice_processor, NULL);
|
2721
2864
|
}
|
2722
2865
|
|
2723
|
-
|
2866
|
+
this->notice_receiver = proc;
|
2724
2867
|
return old_proc;
|
2725
2868
|
}
|
2726
2869
|
|
@@ -2735,7 +2878,7 @@ static VALUE
|
|
2735
2878
|
pgconn_get_client_encoding(VALUE self)
|
2736
2879
|
{
|
2737
2880
|
char *encoding = (char *)pg_encoding_to_char(PQclientEncoding(pg_get_pgconn(self)));
|
2738
|
-
return
|
2881
|
+
return rb_str_new2(encoding);
|
2739
2882
|
}
|
2740
2883
|
|
2741
2884
|
|
@@ -2752,16 +2895,17 @@ pgconn_set_client_encoding(VALUE self, VALUE str)
|
|
2752
2895
|
|
2753
2896
|
Check_Type(str, T_STRING);
|
2754
2897
|
|
2755
|
-
if ( (
|
2756
|
-
rb_raise(rb_ePGerror, "
|
2898
|
+
if ( (gvl_PQsetClientEncoding(conn, StringValueCStr(str))) == -1 ) {
|
2899
|
+
rb_raise(rb_ePGerror, "%s", PQerrorMessage(conn));
|
2757
2900
|
}
|
2901
|
+
pgconn_set_internal_encoding_index( self );
|
2758
2902
|
|
2759
2903
|
return Qnil;
|
2760
2904
|
}
|
2761
2905
|
|
2762
2906
|
/*
|
2763
2907
|
* call-seq:
|
2764
|
-
* conn.transaction { |conn| ... } ->
|
2908
|
+
* conn.transaction { |conn| ... } -> result of the block
|
2765
2909
|
*
|
2766
2910
|
* Executes a +BEGIN+ at the start of the block,
|
2767
2911
|
* and a +COMMIT+ at the end of the block, or
|
@@ -2773,13 +2917,14 @@ pgconn_transaction(VALUE self)
|
|
2773
2917
|
PGconn *conn = pg_get_pgconn(self);
|
2774
2918
|
PGresult *result;
|
2775
2919
|
VALUE rb_pgresult;
|
2920
|
+
VALUE block_result = Qnil;
|
2776
2921
|
int status;
|
2777
2922
|
|
2778
2923
|
if (rb_block_given_p()) {
|
2779
2924
|
result = gvl_PQexec(conn, "BEGIN");
|
2780
2925
|
rb_pgresult = pg_new_result(result, self);
|
2781
2926
|
pg_result_check(rb_pgresult);
|
2782
|
-
rb_protect(rb_yield, self, &status);
|
2927
|
+
block_result = rb_protect(rb_yield, self, &status);
|
2783
2928
|
if(status == 0) {
|
2784
2929
|
result = gvl_PQexec(conn, "COMMIT");
|
2785
2930
|
rb_pgresult = pg_new_result(result, self);
|
@@ -2798,14 +2943,16 @@ pgconn_transaction(VALUE self)
|
|
2798
2943
|
/* no block supplied? */
|
2799
2944
|
rb_raise(rb_eArgError, "Must supply block for PG::Connection#transaction");
|
2800
2945
|
}
|
2801
|
-
return
|
2946
|
+
return block_result;
|
2802
2947
|
}
|
2803
2948
|
|
2804
2949
|
|
2805
2950
|
/*
|
2806
2951
|
* call-seq:
|
2807
|
-
* PG::Connection.quote_ident( str ) -> String
|
2808
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
|
2809
2956
|
*
|
2810
2957
|
* Returns a string that is safe for inclusion in a SQL query as an
|
2811
2958
|
* identifier. Note: this is not a quote function for values, but for
|
@@ -2815,40 +2962,40 @@ pgconn_transaction(VALUE self)
|
|
2815
2962
|
* The identifier <tt>FOO</tt> is folded to lower case, so it actually
|
2816
2963
|
* means <tt>foo</tt>. If you really want to access the case-sensitive
|
2817
2964
|
* field name <tt>FOO</tt>, use this function like
|
2818
|
-
* <tt>
|
2965
|
+
* <tt>conn.quote_ident('FOO')</tt>, which will return <tt>"FOO"</tt>
|
2819
2966
|
* (with double-quotes). PostgreSQL will see the double-quotes, and
|
2820
2967
|
* it will not fold to lower case.
|
2821
2968
|
*
|
2822
2969
|
* Similarly, this function also protects against special characters,
|
2823
2970
|
* and other things that might allow SQL injection if the identifier
|
2824
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.
|
2825
2985
|
*/
|
2826
2986
|
static VALUE
|
2827
|
-
pgconn_s_quote_ident(VALUE self, VALUE
|
2987
|
+
pgconn_s_quote_ident(VALUE self, VALUE str_or_array)
|
2828
2988
|
{
|
2829
2989
|
VALUE ret;
|
2830
|
-
|
2831
|
-
/* result size at most NAMEDATALEN*2 plus surrounding
|
2832
|
-
* double-quotes. */
|
2833
|
-
char buffer[NAMEDATALEN*2+2];
|
2834
|
-
unsigned int i=0,j=0;
|
2835
|
-
|
2836
|
-
UNUSED( self );
|
2990
|
+
int enc_idx;
|
2837
2991
|
|
2838
|
-
if(
|
2839
|
-
|
2840
|
-
|
2841
|
-
|
2842
|
-
}
|
2843
|
-
buffer[j++] = '"';
|
2844
|
-
for(i = 0; i < strlen(str) && str[i]; i++) {
|
2845
|
-
if(str[i] == '"')
|
2846
|
-
buffer[j++] = '"';
|
2847
|
-
buffer[j++] = str[i];
|
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();
|
2848
2996
|
}
|
2849
|
-
|
2850
|
-
|
2851
|
-
OBJ_INFECT(ret, in_str);
|
2997
|
+
pg_text_enc_identifier(NULL, str_or_array, NULL, &ret, enc_idx);
|
2998
|
+
|
2852
2999
|
return ret;
|
2853
3000
|
}
|
2854
3001
|
|
@@ -2856,7 +3003,7 @@ pgconn_s_quote_ident(VALUE self, VALUE in_str)
|
|
2856
3003
|
static void *
|
2857
3004
|
get_result_readable(PGconn *conn)
|
2858
3005
|
{
|
2859
|
-
return
|
3006
|
+
return gvl_PQisBusy(conn) ? NULL : (void*)1;
|
2860
3007
|
}
|
2861
3008
|
|
2862
3009
|
|
@@ -2877,10 +3024,6 @@ static VALUE
|
|
2877
3024
|
pgconn_block( int argc, VALUE *argv, VALUE self ) {
|
2878
3025
|
PGconn *conn = pg_get_pgconn( self );
|
2879
3026
|
|
2880
|
-
/* If WIN32 and Ruby 1.9 do not use rb_thread_select() which sometimes hangs
|
2881
|
-
* and does not wait (nor sleep) any time even if timeout is given.
|
2882
|
-
* Instead use the Winsock events and rb_w32_wait_events(). */
|
2883
|
-
|
2884
3027
|
struct timeval timeout;
|
2885
3028
|
struct timeval *ptimeout = NULL;
|
2886
3029
|
VALUE timeout_in;
|
@@ -2945,34 +3088,71 @@ pgconn_get_last_result(VALUE self)
|
|
2945
3088
|
return rb_pgresult;
|
2946
3089
|
}
|
2947
3090
|
|
2948
|
-
|
3091
|
+
/*
|
3092
|
+
* call-seq:
|
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
|
+
}
|
2949
3120
|
|
2950
3121
|
/*
|
2951
3122
|
* call-seq:
|
2952
|
-
* conn.
|
2953
|
-
* conn.
|
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.
|
3129
|
+
*
|
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.
|
2954
3133
|
*
|
2955
|
-
*
|
2956
|
-
*
|
2957
|
-
*
|
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.
|
2958
3137
|
*
|
2959
|
-
*
|
2960
|
-
*
|
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.
|
2961
3145
|
*
|
2962
|
-
*
|
2963
|
-
* processing and ruby's +rb_thread_select+ .
|
3146
|
+
* See also corresponding {libpq function}[https://www.postgresql.org/docs/current/libpq-exec.html#LIBPQ-PQEXEC].
|
2964
3147
|
*/
|
2965
3148
|
static VALUE
|
2966
3149
|
pgconn_async_exec(int argc, VALUE *argv, VALUE self)
|
2967
3150
|
{
|
2968
3151
|
VALUE rb_pgresult = Qnil;
|
2969
3152
|
|
2970
|
-
|
2971
|
-
pgconn_block( 0, NULL, self ); /* wait for input (without blocking) before reading the last result */
|
2972
|
-
pgconn_get_last_result( self );
|
2973
|
-
|
3153
|
+
pgconn_discard_results( self );
|
2974
3154
|
pgconn_send_query( argc, argv, self );
|
2975
|
-
pgconn_block( 0, NULL, self );
|
3155
|
+
pgconn_block( 0, NULL, self ); /* wait for input (without blocking) before reading the last result */
|
2976
3156
|
rb_pgresult = pgconn_get_last_result( self );
|
2977
3157
|
|
2978
3158
|
if ( rb_block_given_p() ) {
|
@@ -2981,103 +3161,394 @@ pgconn_async_exec(int argc, VALUE *argv, VALUE self)
|
|
2981
3161
|
return rb_pgresult;
|
2982
3162
|
}
|
2983
3163
|
|
2984
|
-
#endif
|
2985
|
-
|
2986
|
-
/**************************************************************************
|
2987
|
-
* LARGE OBJECT SUPPORT
|
2988
|
-
**************************************************************************/
|
2989
3164
|
|
2990
3165
|
/*
|
2991
3166
|
* call-seq:
|
2992
|
-
* conn.
|
3167
|
+
* conn.exec_params(sql, params [, result_format [, type_map ]] ) -> nil
|
3168
|
+
* conn.exec_params(sql, params [, result_format [, type_map ]] ) {|pg_result| block }
|
2993
3169
|
*
|
2994
|
-
*
|
2995
|
-
*
|
2996
|
-
*/
|
2997
|
-
static VALUE
|
2998
|
-
pgconn_locreat(int argc, VALUE *argv, VALUE self)
|
2999
|
-
{
|
3000
|
-
Oid lo_oid;
|
3001
|
-
int mode;
|
3002
|
-
VALUE nmode;
|
3003
|
-
PGconn *conn = pg_get_pgconn(self);
|
3004
|
-
|
3005
|
-
if (rb_scan_args(argc, argv, "01", &nmode) == 0)
|
3006
|
-
mode = INV_READ;
|
3007
|
-
else
|
3008
|
-
mode = NUM2INT(nmode);
|
3009
|
-
|
3010
|
-
lo_oid = lo_creat(conn, mode);
|
3011
|
-
if (lo_oid == 0)
|
3012
|
-
rb_raise(rb_ePGerror, "lo_creat failed");
|
3013
|
-
|
3014
|
-
return INT2FIX(lo_oid);
|
3015
|
-
}
|
3016
|
-
|
3017
|
-
/*
|
3018
|
-
* call-seq:
|
3019
|
-
* conn.lo_create( oid ) -> Fixnum
|
3170
|
+
* Sends SQL query request specified by +sql+ to PostgreSQL using placeholders
|
3171
|
+
* for parameters.
|
3020
3172
|
*
|
3021
|
-
*
|
3022
|
-
*
|
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].
|
3023
3214
|
*/
|
3024
3215
|
static VALUE
|
3025
|
-
|
3216
|
+
pgconn_async_exec_params(int argc, VALUE *argv, VALUE self)
|
3026
3217
|
{
|
3027
|
-
|
3028
|
-
PGconn *conn = pg_get_pgconn(self);
|
3029
|
-
lo_oid = NUM2INT(in_lo_oid);
|
3218
|
+
VALUE rb_pgresult = Qnil;
|
3030
3219
|
|
3031
|
-
|
3032
|
-
|
3033
|
-
|
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 */
|
3229
|
+
rb_pgresult = pgconn_get_last_result( self );
|
3034
3230
|
|
3035
|
-
|
3231
|
+
if ( rb_block_given_p() ) {
|
3232
|
+
return rb_ensure( rb_yield, rb_pgresult, pg_result_clear, rb_pgresult );
|
3233
|
+
}
|
3234
|
+
return rb_pgresult;
|
3036
3235
|
}
|
3037
3236
|
|
3237
|
+
|
3038
3238
|
/*
|
3039
3239
|
* call-seq:
|
3040
|
-
* conn.
|
3041
|
-
*
|
3042
|
-
* Import a file to a large object. Returns a large object Oid.
|
3240
|
+
* conn.prepare(stmt_name, sql [, param_types ] ) -> PG::Result
|
3043
3241
|
*
|
3242
|
+
* Prepares statement _sql_ with name _name_ to be executed later.
|
3243
|
+
* Returns a PG::Result instance on success.
|
3044
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].
|
3045
3259
|
*/
|
3046
3260
|
static VALUE
|
3047
|
-
|
3261
|
+
pgconn_async_prepare(int argc, VALUE *argv, VALUE self)
|
3048
3262
|
{
|
3049
|
-
|
3050
|
-
|
3051
|
-
PGconn *conn = pg_get_pgconn(self);
|
3263
|
+
VALUE rb_pgresult = Qnil;
|
3052
3264
|
|
3053
|
-
|
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 );
|
3054
3269
|
|
3055
|
-
|
3056
|
-
|
3057
|
-
rb_raise(rb_ePGerror, "%s", PQerrorMessage(conn));
|
3270
|
+
if ( rb_block_given_p() ) {
|
3271
|
+
return rb_ensure( rb_yield, rb_pgresult, pg_result_clear, rb_pgresult );
|
3058
3272
|
}
|
3059
|
-
return
|
3273
|
+
return rb_pgresult;
|
3060
3274
|
}
|
3061
3275
|
|
3276
|
+
|
3062
3277
|
/*
|
3063
3278
|
* call-seq:
|
3064
|
-
* conn.
|
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 }
|
3065
3281
|
*
|
3066
|
-
*
|
3067
|
-
|
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
|
+
*/
|
3068
3314
|
static VALUE
|
3069
|
-
|
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
|
+
|
3460
|
+
/**************************************************************************
|
3461
|
+
* LARGE OBJECT SUPPORT
|
3462
|
+
**************************************************************************/
|
3463
|
+
|
3464
|
+
/*
|
3465
|
+
* call-seq:
|
3466
|
+
* conn.lo_creat( [mode] ) -> Integer
|
3467
|
+
*
|
3468
|
+
* Creates a large object with mode _mode_. Returns a large object Oid.
|
3469
|
+
* On failure, it raises PG::Error.
|
3470
|
+
*/
|
3471
|
+
static VALUE
|
3472
|
+
pgconn_locreat(int argc, VALUE *argv, VALUE self)
|
3473
|
+
{
|
3474
|
+
Oid lo_oid;
|
3475
|
+
int mode;
|
3476
|
+
VALUE nmode;
|
3477
|
+
PGconn *conn = pg_get_pgconn(self);
|
3478
|
+
|
3479
|
+
if (rb_scan_args(argc, argv, "01", &nmode) == 0)
|
3480
|
+
mode = INV_READ;
|
3481
|
+
else
|
3482
|
+
mode = NUM2INT(nmode);
|
3483
|
+
|
3484
|
+
lo_oid = lo_creat(conn, mode);
|
3485
|
+
if (lo_oid == 0)
|
3486
|
+
rb_raise(rb_ePGerror, "lo_creat failed");
|
3487
|
+
|
3488
|
+
return UINT2NUM(lo_oid);
|
3489
|
+
}
|
3490
|
+
|
3491
|
+
/*
|
3492
|
+
* call-seq:
|
3493
|
+
* conn.lo_create( oid ) -> Integer
|
3494
|
+
*
|
3495
|
+
* Creates a large object with oid _oid_. Returns the large object Oid.
|
3496
|
+
* On failure, it raises PG::Error.
|
3497
|
+
*/
|
3498
|
+
static VALUE
|
3499
|
+
pgconn_locreate(VALUE self, VALUE in_lo_oid)
|
3070
3500
|
{
|
3501
|
+
Oid ret, lo_oid;
|
3071
3502
|
PGconn *conn = pg_get_pgconn(self);
|
3072
|
-
|
3503
|
+
lo_oid = NUM2UINT(in_lo_oid);
|
3504
|
+
|
3505
|
+
ret = lo_create(conn, lo_oid);
|
3506
|
+
if (ret == InvalidOid)
|
3507
|
+
rb_raise(rb_ePGerror, "lo_create failed");
|
3508
|
+
|
3509
|
+
return UINT2NUM(ret);
|
3510
|
+
}
|
3511
|
+
|
3512
|
+
/*
|
3513
|
+
* call-seq:
|
3514
|
+
* conn.lo_import(file) -> Integer
|
3515
|
+
*
|
3516
|
+
* Import a file to a large object. Returns a large object Oid.
|
3517
|
+
*
|
3518
|
+
* On failure, it raises a PG::Error.
|
3519
|
+
*/
|
3520
|
+
static VALUE
|
3521
|
+
pgconn_loimport(VALUE self, VALUE filename)
|
3522
|
+
{
|
3523
|
+
Oid lo_oid;
|
3524
|
+
|
3525
|
+
PGconn *conn = pg_get_pgconn(self);
|
3526
|
+
|
3073
3527
|
Check_Type(filename, T_STRING);
|
3074
3528
|
|
3075
|
-
|
3076
|
-
if (
|
3077
|
-
rb_raise(rb_ePGerror, "
|
3529
|
+
lo_oid = lo_import(conn, StringValueCStr(filename));
|
3530
|
+
if (lo_oid == 0) {
|
3531
|
+
rb_raise(rb_ePGerror, "%s", PQerrorMessage(conn));
|
3078
3532
|
}
|
3533
|
+
return UINT2NUM(lo_oid);
|
3534
|
+
}
|
3079
3535
|
|
3080
|
-
|
3536
|
+
/*
|
3537
|
+
* call-seq:
|
3538
|
+
* conn.lo_export( oid, file ) -> nil
|
3539
|
+
*
|
3540
|
+
* Saves a large object of _oid_ to a _file_.
|
3541
|
+
*/
|
3542
|
+
static VALUE
|
3543
|
+
pgconn_loexport(VALUE self, VALUE lo_oid, VALUE filename)
|
3544
|
+
{
|
3545
|
+
PGconn *conn = pg_get_pgconn(self);
|
3546
|
+
Oid oid;
|
3547
|
+
Check_Type(filename, T_STRING);
|
3548
|
+
|
3549
|
+
oid = NUM2UINT(lo_oid);
|
3550
|
+
|
3551
|
+
if (lo_export(conn, oid, StringValueCStr(filename)) < 0) {
|
3081
3552
|
rb_raise(rb_ePGerror, "%s", PQerrorMessage(conn));
|
3082
3553
|
}
|
3083
3554
|
return Qnil;
|
@@ -3085,7 +3556,7 @@ pgconn_loexport(VALUE self, VALUE lo_oid, VALUE filename)
|
|
3085
3556
|
|
3086
3557
|
/*
|
3087
3558
|
* call-seq:
|
3088
|
-
* conn.lo_open( oid, [mode] ) ->
|
3559
|
+
* conn.lo_open( oid, [mode] ) -> Integer
|
3089
3560
|
*
|
3090
3561
|
* Open a large object of _oid_. Returns a large object descriptor
|
3091
3562
|
* instance on success. The _mode_ argument specifies the mode for
|
@@ -3102,7 +3573,7 @@ pgconn_loopen(int argc, VALUE *argv, VALUE self)
|
|
3102
3573
|
PGconn *conn = pg_get_pgconn(self);
|
3103
3574
|
|
3104
3575
|
rb_scan_args(argc, argv, "11", &selfid, &nmode);
|
3105
|
-
lo_oid =
|
3576
|
+
lo_oid = NUM2UINT(selfid);
|
3106
3577
|
if(NIL_P(nmode))
|
3107
3578
|
mode = INV_READ;
|
3108
3579
|
else
|
@@ -3116,7 +3587,7 @@ pgconn_loopen(int argc, VALUE *argv, VALUE self)
|
|
3116
3587
|
|
3117
3588
|
/*
|
3118
3589
|
* call-seq:
|
3119
|
-
* conn.lo_write( lo_desc, buffer ) ->
|
3590
|
+
* conn.lo_write( lo_desc, buffer ) -> Integer
|
3120
3591
|
*
|
3121
3592
|
* Writes the string _buffer_ to the large object _lo_desc_.
|
3122
3593
|
* Returns the number of bytes written.
|
@@ -3174,7 +3645,7 @@ pgconn_loread(VALUE self, VALUE in_lo_desc, VALUE in_len)
|
|
3174
3645
|
return Qnil;
|
3175
3646
|
}
|
3176
3647
|
|
3177
|
-
str =
|
3648
|
+
str = rb_str_new(buffer, ret);
|
3178
3649
|
xfree(buffer);
|
3179
3650
|
|
3180
3651
|
return str;
|
@@ -3183,7 +3654,7 @@ pgconn_loread(VALUE self, VALUE in_lo_desc, VALUE in_len)
|
|
3183
3654
|
|
3184
3655
|
/*
|
3185
3656
|
* call-seq:
|
3186
|
-
* conn.lo_lseek( lo_desc, offset, whence ) ->
|
3657
|
+
* conn.lo_lseek( lo_desc, offset, whence ) -> Integer
|
3187
3658
|
*
|
3188
3659
|
* Move the large object pointer _lo_desc_ to offset _offset_.
|
3189
3660
|
* Valid values for _whence_ are +SEEK_SET+, +SEEK_CUR+, and +SEEK_END+.
|
@@ -3205,7 +3676,7 @@ pgconn_lolseek(VALUE self, VALUE in_lo_desc, VALUE offset, VALUE whence)
|
|
3205
3676
|
|
3206
3677
|
/*
|
3207
3678
|
* call-seq:
|
3208
|
-
* conn.lo_tell( lo_desc ) ->
|
3679
|
+
* conn.lo_tell( lo_desc ) -> Integer
|
3209
3680
|
*
|
3210
3681
|
* Returns the current position of the large object _lo_desc_.
|
3211
3682
|
*/
|
@@ -3269,10 +3740,7 @@ static VALUE
|
|
3269
3740
|
pgconn_lounlink(VALUE self, VALUE in_oid)
|
3270
3741
|
{
|
3271
3742
|
PGconn *conn = pg_get_pgconn(self);
|
3272
|
-
|
3273
|
-
|
3274
|
-
if (oid < 0)
|
3275
|
-
rb_raise(rb_ePGerror, "invalid oid %d",oid);
|
3743
|
+
Oid oid = NUM2UINT(in_oid);
|
3276
3744
|
|
3277
3745
|
if(lo_unlink(conn,oid) < 0)
|
3278
3746
|
rb_raise(rb_ePGerror,"lo_unlink failed");
|
@@ -3281,7 +3749,16 @@ pgconn_lounlink(VALUE self, VALUE in_oid)
|
|
3281
3749
|
}
|
3282
3750
|
|
3283
3751
|
|
3284
|
-
|
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
|
+
}
|
3285
3762
|
|
3286
3763
|
/*
|
3287
3764
|
* call-seq:
|
@@ -3327,7 +3804,7 @@ pgconn_internal_encoding_set(VALUE self, VALUE enc)
|
|
3327
3804
|
pgconn_set_client_encoding( self, rb_usascii_str_new_cstr("SQL_ASCII") );
|
3328
3805
|
return enc;
|
3329
3806
|
}
|
3330
|
-
else if ( TYPE(enc) == T_STRING && strcasecmp("JOHAB",
|
3807
|
+
else if ( TYPE(enc) == T_STRING && strcasecmp("JOHAB", StringValueCStr(enc)) == 0 ) {
|
3331
3808
|
pgconn_set_client_encoding(self, rb_usascii_str_new_cstr("JOHAB"));
|
3332
3809
|
return enc;
|
3333
3810
|
}
|
@@ -3335,17 +3812,14 @@ pgconn_internal_encoding_set(VALUE self, VALUE enc)
|
|
3335
3812
|
rb_encoding *rbenc = rb_to_encoding( enc );
|
3336
3813
|
const char *name = pg_get_rb_encoding_as_pg_encoding( rbenc );
|
3337
3814
|
|
3338
|
-
if (
|
3815
|
+
if ( gvl_PQsetClientEncoding(pg_get_pgconn( self ), name) == -1 ) {
|
3339
3816
|
VALUE server_encoding = pgconn_external_encoding( self );
|
3340
3817
|
rb_raise( rb_eEncCompatError, "incompatible character encodings: %s and %s",
|
3341
3818
|
rb_enc_name(rb_to_encoding(server_encoding)), name );
|
3342
3819
|
}
|
3820
|
+
pgconn_set_internal_encoding_index( self );
|
3343
3821
|
return enc;
|
3344
3822
|
}
|
3345
|
-
|
3346
|
-
rb_raise( rb_ePGerror, "unknown encoding: %s", RSTRING_PTR(rb_inspect(enc)) );
|
3347
|
-
|
3348
|
-
return Qnil;
|
3349
3823
|
}
|
3350
3824
|
|
3351
3825
|
|
@@ -3360,24 +3834,45 @@ pgconn_internal_encoding_set(VALUE self, VALUE enc)
|
|
3360
3834
|
static VALUE
|
3361
3835
|
pgconn_external_encoding(VALUE self)
|
3362
3836
|
{
|
3363
|
-
|
3364
|
-
VALUE encoding = rb_iv_get( self, "@external_encoding" );
|
3837
|
+
t_pg_connection *this = pg_get_connection_safe( self );
|
3365
3838
|
rb_encoding *enc = NULL;
|
3366
3839
|
const char *pg_encname = NULL;
|
3367
3840
|
|
3368
|
-
|
3369
|
-
if ( RTEST(encoding) ) return encoding;
|
3370
|
-
|
3371
|
-
pg_encname = PQparameterStatus( conn, "server_encoding" );
|
3841
|
+
pg_encname = PQparameterStatus( this->pgconn, "server_encoding" );
|
3372
3842
|
enc = pg_get_pg_encname_as_rb_encoding( pg_encname );
|
3373
|
-
|
3843
|
+
return rb_enc_from_encoding( enc );
|
3844
|
+
}
|
3845
|
+
|
3374
3846
|
|
3375
|
-
|
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);
|
3376
3854
|
|
3377
|
-
|
3855
|
+
pgconn_async_exec(1, &query, self);
|
3856
|
+
return 0;
|
3378
3857
|
}
|
3379
3858
|
|
3380
3859
|
|
3860
|
+
static VALUE
|
3861
|
+
pgconn_set_client_encoding_async2( VALUE arg, VALUE ex )
|
3862
|
+
{
|
3863
|
+
UNUSED(arg);
|
3864
|
+
UNUSED(ex);
|
3865
|
+
return 1;
|
3866
|
+
}
|
3867
|
+
|
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
|
+
|
3381
3876
|
|
3382
3877
|
/*
|
3383
3878
|
* call-seq:
|
@@ -3396,24 +3891,266 @@ pgconn_set_default_encoding( VALUE self )
|
|
3396
3891
|
|
3397
3892
|
if (( enc = rb_default_internal_encoding() )) {
|
3398
3893
|
encname = pg_get_rb_encoding_as_pg_encoding( enc );
|
3399
|
-
if (
|
3400
|
-
|
3894
|
+
if ( pgconn_set_client_encoding_async(self, encname) != 0 )
|
3895
|
+
rb_warning( "Failed to set the default_internal encoding to %s: '%s'",
|
3401
3896
|
encname, PQerrorMessage(conn) );
|
3897
|
+
pgconn_set_internal_encoding_index( self );
|
3402
3898
|
return rb_enc_from_encoding( enc );
|
3403
3899
|
} else {
|
3900
|
+
pgconn_set_internal_encoding_index( self );
|
3404
3901
|
return Qnil;
|
3405
3902
|
}
|
3406
3903
|
}
|
3407
3904
|
|
3408
3905
|
|
3409
|
-
|
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 );
|
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;
|
3926
|
+
|
3927
|
+
return typemap;
|
3928
|
+
}
|
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
|
+
}
|
3410
3984
|
|
3411
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 );
|
3412
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
|
+
*/
|
3413
4140
|
void
|
3414
4141
|
init_pg_connection()
|
3415
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
|
+
|
3416
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" ); */
|
3417
4154
|
rb_include_module(rb_cPGconn, rb_mPGconstants);
|
3418
4155
|
|
3419
4156
|
/****** PG::Connection CLASS METHODS ******/
|
@@ -3431,9 +4168,7 @@ init_pg_connection()
|
|
3431
4168
|
rb_define_singleton_method(rb_cPGconn, "quote_ident", pgconn_s_quote_ident, 1);
|
3432
4169
|
rb_define_singleton_method(rb_cPGconn, "connect_start", pgconn_s_connect_start, -1);
|
3433
4170
|
rb_define_singleton_method(rb_cPGconn, "conndefaults", pgconn_s_conndefaults, 0);
|
3434
|
-
#ifdef HAVE_PQPING
|
3435
4171
|
rb_define_singleton_method(rb_cPGconn, "ping", pgconn_s_ping, -1);
|
3436
|
-
#endif
|
3437
4172
|
|
3438
4173
|
/****** PG::Connection INSTANCE METHODS: Connection Control ******/
|
3439
4174
|
rb_define_method(rb_cPGconn, "initialize", pgconn_init, -1);
|
@@ -3443,7 +4178,6 @@ init_pg_connection()
|
|
3443
4178
|
rb_define_method(rb_cPGconn, "reset", pgconn_reset, 0);
|
3444
4179
|
rb_define_method(rb_cPGconn, "reset_start", pgconn_reset_start, 0);
|
3445
4180
|
rb_define_method(rb_cPGconn, "reset_poll", pgconn_reset_poll, 0);
|
3446
|
-
rb_define_method(rb_cPGconn, "conndefaults", pgconn_s_conndefaults, 0);
|
3447
4181
|
rb_define_alias(rb_cPGconn, "close", "finish");
|
3448
4182
|
|
3449
4183
|
/****** PG::Connection INSTANCE METHODS: Connection Status ******/
|
@@ -3453,6 +4187,9 @@ init_pg_connection()
|
|
3453
4187
|
rb_define_method(rb_cPGconn, "host", pgconn_host, 0);
|
3454
4188
|
rb_define_method(rb_cPGconn, "port", pgconn_port, 0);
|
3455
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
|
3456
4193
|
rb_define_method(rb_cPGconn, "options", pgconn_options, 0);
|
3457
4194
|
rb_define_method(rb_cPGconn, "status", pgconn_status, 0);
|
3458
4195
|
rb_define_method(rb_cPGconn, "transaction_status", pgconn_transaction_status, 0);
|
@@ -3461,39 +4198,47 @@ init_pg_connection()
|
|
3461
4198
|
rb_define_method(rb_cPGconn, "server_version", pgconn_server_version, 0);
|
3462
4199
|
rb_define_method(rb_cPGconn, "error_message", pgconn_error_message, 0);
|
3463
4200
|
rb_define_method(rb_cPGconn, "socket", pgconn_socket, 0);
|
3464
|
-
#if !defined(_WIN32) || defined(HAVE_RB_W32_WRAP_IO_HANDLE)
|
3465
4201
|
rb_define_method(rb_cPGconn, "socket_io", pgconn_socket_io, 0);
|
3466
|
-
#endif
|
3467
4202
|
rb_define_method(rb_cPGconn, "backend_pid", pgconn_backend_pid, 0);
|
3468
4203
|
rb_define_method(rb_cPGconn, "connection_needs_password", pgconn_connection_needs_password, 0);
|
3469
4204
|
rb_define_method(rb_cPGconn, "connection_used_password", pgconn_connection_used_password, 0);
|
3470
4205
|
/* rb_define_method(rb_cPGconn, "getssl", pgconn_getssl, 0); */
|
3471
4206
|
|
3472
4207
|
/****** PG::Connection INSTANCE METHODS: Command Execution ******/
|
3473
|
-
rb_define_method(rb_cPGconn, "
|
3474
|
-
|
3475
|
-
rb_define_method(rb_cPGconn, "
|
3476
|
-
rb_define_method(rb_cPGconn, "
|
3477
|
-
rb_define_method(rb_cPGconn, "
|
3478
|
-
rb_define_method(rb_cPGconn, "
|
3479
|
-
|
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
|
+
|
3480
4230
|
rb_define_method(rb_cPGconn, "make_empty_pgresult", pgconn_make_empty_pgresult, 1);
|
3481
4231
|
rb_define_method(rb_cPGconn, "escape_string", pgconn_s_escape, 1);
|
3482
4232
|
rb_define_alias(rb_cPGconn, "escape", "escape_string");
|
3483
|
-
#ifdef HAVE_PQESCAPELITERAL
|
3484
4233
|
rb_define_method(rb_cPGconn, "escape_literal", pgconn_escape_literal, 1);
|
3485
|
-
#endif
|
3486
|
-
#ifdef HAVE_PQESCAPEIDENTIFIER
|
3487
4234
|
rb_define_method(rb_cPGconn, "escape_identifier", pgconn_escape_identifier, 1);
|
3488
|
-
#endif
|
3489
4235
|
rb_define_method(rb_cPGconn, "escape_bytea", pgconn_s_escape_bytea, 1);
|
3490
4236
|
rb_define_method(rb_cPGconn, "unescape_bytea", pgconn_s_unescape_bytea, 1);
|
3491
|
-
#ifdef HAVE_PQSETSINGLEROWMODE
|
3492
4237
|
rb_define_method(rb_cPGconn, "set_single_row_mode", pgconn_set_single_row_mode, 0);
|
3493
|
-
#endif
|
3494
4238
|
|
3495
4239
|
/****** PG::Connection INSTANCE METHODS: Asynchronous Command Processing ******/
|
3496
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);
|
3497
4242
|
rb_define_method(rb_cPGconn, "send_prepare", pgconn_send_prepare, -1);
|
3498
4243
|
rb_define_method(rb_cPGconn, "send_query_prepared", pgconn_send_query_prepared, -1);
|
3499
4244
|
rb_define_method(rb_cPGconn, "send_describe_prepared", pgconn_send_describe_prepared, 1);
|
@@ -3505,6 +4250,7 @@ init_pg_connection()
|
|
3505
4250
|
rb_define_method(rb_cPGconn, "isnonblocking", pgconn_isnonblocking, 0);
|
3506
4251
|
rb_define_alias(rb_cPGconn, "nonblocking?", "isnonblocking");
|
3507
4252
|
rb_define_method(rb_cPGconn, "flush", pgconn_flush, 0);
|
4253
|
+
rb_define_method(rb_cPGconn, "discard_results", pgconn_discard_results, 0);
|
3508
4254
|
|
3509
4255
|
/****** PG::Connection INSTANCE METHODS: Cancelling Queries in Progress ******/
|
3510
4256
|
rb_define_method(rb_cPGconn, "cancel", pgconn_cancel, 0);
|
@@ -3513,12 +4259,15 @@ init_pg_connection()
|
|
3513
4259
|
rb_define_method(rb_cPGconn, "notifies", pgconn_notifies, 0);
|
3514
4260
|
|
3515
4261
|
/****** PG::Connection INSTANCE METHODS: COPY ******/
|
3516
|
-
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);
|
3517
4263
|
rb_define_method(rb_cPGconn, "put_copy_end", pgconn_put_copy_end, -1);
|
3518
4264
|
rb_define_method(rb_cPGconn, "get_copy_data", pgconn_get_copy_data, -1);
|
3519
4265
|
|
3520
4266
|
/****** PG::Connection INSTANCE METHODS: Control Functions ******/
|
3521
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
|
3522
4271
|
rb_define_method(rb_cPGconn, "trace", pgconn_trace, 1);
|
3523
4272
|
rb_define_method(rb_cPGconn, "untrace", pgconn_untrace, 0);
|
3524
4273
|
|
@@ -3535,13 +4284,16 @@ init_pg_connection()
|
|
3535
4284
|
rb_define_method(rb_cPGconn, "wait_for_notify", pgconn_wait_for_notify, -1);
|
3536
4285
|
rb_define_alias(rb_cPGconn, "notifies_wait", "wait_for_notify");
|
3537
4286
|
rb_define_method(rb_cPGconn, "quote_ident", pgconn_s_quote_ident, 1);
|
3538
|
-
#if defined(HAVE_RB_THREAD_CALL_WITHOUT_GVL)
|
3539
|
-
rb_define_alias(rb_cPGconn, "async_exec", "exec");
|
3540
|
-
#else
|
3541
|
-
rb_define_method(rb_cPGconn, "async_exec", pgconn_async_exec, -1);
|
3542
|
-
#endif
|
3543
|
-
rb_define_alias(rb_cPGconn, "async_query", "async_exec");
|
3544
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
|
3545
4297
|
|
3546
4298
|
/****** PG::Connection INSTANCE METHODS: Large Object Support ******/
|
3547
4299
|
rb_define_method(rb_cPGconn, "lo_creat", pgconn_locreat, -1);
|
@@ -3571,12 +4323,20 @@ init_pg_connection()
|
|
3571
4323
|
rb_define_method(rb_cPGconn, "lo_unlink", pgconn_lounlink, 1);
|
3572
4324
|
rb_define_alias(rb_cPGconn, "lounlink", "lo_unlink");
|
3573
4325
|
|
3574
|
-
#ifdef M17N_SUPPORTED
|
3575
4326
|
rb_define_method(rb_cPGconn, "internal_encoding", pgconn_internal_encoding, 0);
|
3576
4327
|
rb_define_method(rb_cPGconn, "internal_encoding=", pgconn_internal_encoding_set, 1);
|
3577
4328
|
rb_define_method(rb_cPGconn, "external_encoding", pgconn_external_encoding, 0);
|
3578
4329
|
rb_define_method(rb_cPGconn, "set_default_encoding", pgconn_set_default_encoding, 0);
|
3579
|
-
#endif /* M17N_SUPPORTED */
|
3580
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 );
|
3581
4342
|
}
|
3582
|
-
|