pg 0.17.1 → 0.18.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- checksums.yaml.gz.sig +0 -0
- data/ChangeLog +2407 -2
- data/History.rdoc +68 -0
- data/Manifest.txt +29 -1
- data/README-Windows.rdoc +15 -26
- data/README.rdoc +52 -2
- data/Rakefile +56 -18
- data/Rakefile.cross +77 -49
- data/ext/extconf.rb +33 -26
- data/ext/pg.c +142 -21
- data/ext/pg.h +242 -6
- data/ext/pg_binary_decoder.c +162 -0
- data/ext/pg_binary_encoder.c +162 -0
- data/ext/pg_coder.c +479 -0
- data/ext/pg_connection.c +858 -553
- data/ext/pg_copy_coder.c +561 -0
- data/ext/pg_errors.c +6 -0
- data/ext/pg_result.c +479 -128
- data/ext/pg_text_decoder.c +421 -0
- data/ext/pg_text_encoder.c +663 -0
- data/ext/pg_type_map.c +159 -0
- data/ext/pg_type_map_all_strings.c +116 -0
- data/ext/pg_type_map_by_class.c +239 -0
- data/ext/pg_type_map_by_column.c +312 -0
- data/ext/pg_type_map_by_mri_type.c +284 -0
- data/ext/pg_type_map_by_oid.c +355 -0
- data/ext/pg_type_map_in_ruby.c +299 -0
- data/ext/util.c +149 -0
- data/ext/util.h +65 -0
- data/lib/pg/basic_type_mapping.rb +399 -0
- data/lib/pg/coder.rb +83 -0
- data/lib/pg/connection.rb +81 -29
- data/lib/pg/result.rb +13 -3
- data/lib/pg/text_decoder.rb +44 -0
- data/lib/pg/text_encoder.rb +27 -0
- data/lib/pg/type_map_by_column.rb +15 -0
- data/lib/pg.rb +12 -2
- data/spec/{lib/helpers.rb → helpers.rb} +101 -39
- data/spec/pg/basic_type_mapping_spec.rb +251 -0
- data/spec/pg/connection_spec.rb +516 -218
- data/spec/pg/result_spec.rb +216 -112
- data/spec/pg/type_map_by_class_spec.rb +138 -0
- data/spec/pg/type_map_by_column_spec.rb +222 -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 +697 -0
- data/spec/pg_spec.rb +24 -18
- data.tar.gz.sig +0 -0
- metadata +111 -45
- metadata.gz.sig +0 -0
data/ext/pg_connection.c
CHANGED
@@ -1,21 +1,26 @@
|
|
1
1
|
/*
|
2
2
|
* pg_connection.c - PG::Connection class extension
|
3
|
-
* $Id: pg_connection.c,v
|
3
|
+
* $Id: pg_connection.c,v eb4d3c003bd6 2015/05/25 20:04:04 ged $
|
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;
|
11
16
|
|
12
17
|
static PQnoticeReceiver default_notice_receiver = NULL;
|
13
18
|
static PQnoticeProcessor default_notice_processor = NULL;
|
14
19
|
|
15
|
-
static PGconn *pgconn_check( VALUE );
|
16
20
|
static VALUE pgconn_finish( VALUE );
|
17
21
|
#ifdef M17N_SUPPORTED
|
18
22
|
static VALUE pgconn_set_default_encoding( VALUE self );
|
23
|
+
void pgconn_set_internal_encoding_index( VALUE );
|
19
24
|
#endif
|
20
25
|
|
21
26
|
#ifndef HAVE_RB_THREAD_FD_SELECT
|
@@ -32,27 +37,62 @@ static VALUE pgconn_set_default_encoding( VALUE self );
|
|
32
37
|
*/
|
33
38
|
|
34
39
|
/*
|
35
|
-
* Fetch the data pointer
|
40
|
+
* Fetch the PG::Connection object data pointer.
|
41
|
+
*/
|
42
|
+
t_pg_connection *
|
43
|
+
pg_get_connection( VALUE self )
|
44
|
+
{
|
45
|
+
t_pg_connection *this;
|
46
|
+
Data_Get_Struct( self, t_pg_connection, this);
|
47
|
+
|
48
|
+
return this;
|
49
|
+
}
|
50
|
+
|
51
|
+
/*
|
52
|
+
* Fetch the PG::Connection object data pointer and check it's
|
53
|
+
* PGconn data pointer for sanity.
|
54
|
+
*/
|
55
|
+
t_pg_connection *
|
56
|
+
pg_get_connection_safe( VALUE self )
|
57
|
+
{
|
58
|
+
t_pg_connection *this;
|
59
|
+
Data_Get_Struct( self, t_pg_connection, this);
|
60
|
+
|
61
|
+
if ( !this->pgconn )
|
62
|
+
rb_raise( rb_eConnectionBad, "connection is closed" );
|
63
|
+
|
64
|
+
return this;
|
65
|
+
}
|
66
|
+
|
67
|
+
/*
|
68
|
+
* Fetch the PGconn data pointer and check it for sanity.
|
69
|
+
*
|
70
|
+
* Note: This function is used externally by the sequel_pg gem,
|
71
|
+
* so do changes carefully.
|
72
|
+
*
|
36
73
|
*/
|
37
74
|
PGconn *
|
38
75
|
pg_get_pgconn( VALUE self )
|
39
76
|
{
|
40
|
-
|
77
|
+
t_pg_connection *this;
|
78
|
+
Data_Get_Struct( self, t_pg_connection, this);
|
41
79
|
|
42
|
-
if ( !
|
80
|
+
if ( !this->pgconn )
|
43
81
|
rb_raise( rb_eConnectionBad, "connection is closed" );
|
44
82
|
|
45
|
-
return
|
83
|
+
return this->pgconn;
|
46
84
|
}
|
47
85
|
|
48
86
|
|
87
|
+
|
49
88
|
/*
|
50
89
|
* Close the associated socket IO object if there is one.
|
51
90
|
*/
|
52
91
|
void
|
53
92
|
pgconn_close_socket_io( VALUE self )
|
54
93
|
{
|
55
|
-
|
94
|
+
t_pg_connection *this = pg_get_connection( self );
|
95
|
+
VALUE socket_io = this->socket_io;
|
56
96
|
|
57
97
|
if ( RTEST(socket_io) ) {
|
58
98
|
#if defined(_WIN32) && defined(HAVE_RB_W32_WRAP_IO_HANDLE)
|
@@ -64,28 +104,59 @@ pgconn_close_socket_io( VALUE self )
|
|
64
104
|
rb_funcall( socket_io, rb_intern("close"), 0 );
|
65
105
|
}
|
66
106
|
|
67
|
-
|
107
|
+
this->socket_io = Qnil;
|
68
108
|
}
|
69
109
|
|
70
110
|
|
71
111
|
/*
|
72
|
-
*
|
112
|
+
* Create a Ruby Array of Hashes out of a PGconninfoOptions array.
|
73
113
|
*/
|
114
|
+
static VALUE
|
115
|
+
pgconn_make_conninfo_array( const PQconninfoOption *options )
|
116
|
+
{
|
117
|
+
VALUE ary = rb_ary_new();
|
118
|
+
VALUE hash;
|
119
|
+
int i = 0;
|
74
120
|
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
121
|
+
if (!options) return Qnil;
|
122
|
+
|
123
|
+
for(i = 0; options[i].keyword != NULL; i++) {
|
124
|
+
hash = rb_hash_new();
|
125
|
+
if(options[i].keyword)
|
126
|
+
rb_hash_aset(hash, ID2SYM(rb_intern("keyword")), rb_str_new2(options[i].keyword));
|
127
|
+
if(options[i].envvar)
|
128
|
+
rb_hash_aset(hash, ID2SYM(rb_intern("envvar")), rb_str_new2(options[i].envvar));
|
129
|
+
if(options[i].compiled)
|
130
|
+
rb_hash_aset(hash, ID2SYM(rb_intern("compiled")), rb_str_new2(options[i].compiled));
|
131
|
+
if(options[i].val)
|
132
|
+
rb_hash_aset(hash, ID2SYM(rb_intern("val")), rb_str_new2(options[i].val));
|
133
|
+
if(options[i].label)
|
134
|
+
rb_hash_aset(hash, ID2SYM(rb_intern("label")), rb_str_new2(options[i].label));
|
135
|
+
if(options[i].dispchar)
|
136
|
+
rb_hash_aset(hash, ID2SYM(rb_intern("dispchar")), rb_str_new2(options[i].dispchar));
|
137
|
+
rb_hash_aset(hash, ID2SYM(rb_intern("dispsize")), INT2NUM(options[i].dispsize));
|
138
|
+
rb_ary_push(ary, hash);
|
139
|
+
}
|
80
140
|
|
81
|
-
|
141
|
+
return ary;
|
142
|
+
}
|
82
143
|
|
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
144
|
|
88
|
-
|
145
|
+
/*
|
146
|
+
* GC Mark function
|
147
|
+
*/
|
148
|
+
static void
|
149
|
+
pgconn_gc_mark( t_pg_connection *this )
|
150
|
+
{
|
151
|
+
rb_gc_mark( this->socket_io );
|
152
|
+
rb_gc_mark( this->notice_receiver );
|
153
|
+
rb_gc_mark( this->notice_processor );
|
154
|
+
rb_gc_mark( this->type_map_for_queries );
|
155
|
+
rb_gc_mark( this->type_map_for_results );
|
156
|
+
rb_gc_mark( this->trace_stream );
|
157
|
+
rb_gc_mark( this->external_encoding );
|
158
|
+
rb_gc_mark( this->encoder_for_put_copy_data );
|
159
|
+
rb_gc_mark( this->decoder_for_get_copy_data );
|
89
160
|
}
|
90
161
|
|
91
162
|
|
@@ -93,10 +164,12 @@ pgconn_check( VALUE self ) {
|
|
93
164
|
* GC Free function
|
94
165
|
*/
|
95
166
|
static void
|
96
|
-
pgconn_gc_free(
|
167
|
+
pgconn_gc_free( t_pg_connection *this )
|
97
168
|
{
|
98
|
-
if (
|
99
|
-
PQfinish(
|
169
|
+
if (this->pgconn != NULL)
|
170
|
+
PQfinish( this->pgconn );
|
171
|
+
|
172
|
+
xfree(this);
|
100
173
|
}
|
101
174
|
|
102
175
|
|
@@ -113,10 +186,20 @@ pgconn_gc_free( PGconn *conn )
|
|
113
186
|
static VALUE
|
114
187
|
pgconn_s_allocate( VALUE klass )
|
115
188
|
{
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
189
|
+
t_pg_connection *this;
|
190
|
+
VALUE self = Data_Make_Struct( klass, t_pg_connection, pgconn_gc_mark, pgconn_gc_free, this );
|
191
|
+
|
192
|
+
this->pgconn = NULL;
|
193
|
+
this->socket_io = Qnil;
|
194
|
+
this->notice_receiver = Qnil;
|
195
|
+
this->notice_processor = Qnil;
|
196
|
+
this->type_map_for_queries = pg_typemap_all_strings;
|
197
|
+
this->type_map_for_results = pg_typemap_all_strings;
|
198
|
+
this->encoder_for_put_copy_data = Qnil;
|
199
|
+
this->decoder_for_get_copy_data = Qnil;
|
200
|
+
this->trace_stream = Qnil;
|
201
|
+
this->external_encoding = Qnil;
|
202
|
+
|
120
203
|
return self;
|
121
204
|
}
|
122
205
|
|
@@ -181,21 +264,19 @@ pgconn_s_allocate( VALUE klass )
|
|
181
264
|
static VALUE
|
182
265
|
pgconn_init(int argc, VALUE *argv, VALUE self)
|
183
266
|
{
|
184
|
-
|
267
|
+
t_pg_connection *this;
|
185
268
|
VALUE conninfo;
|
186
269
|
VALUE error;
|
187
270
|
|
271
|
+
this = pg_get_connection( self );
|
188
272
|
conninfo = rb_funcall2( rb_cPGconn, rb_intern("parse_connect_args"), argc, argv );
|
189
|
-
|
273
|
+
this->pgconn = gvl_PQconnectdb(StringValueCStr(conninfo));
|
190
274
|
|
191
|
-
if(
|
275
|
+
if(this->pgconn == NULL)
|
192
276
|
rb_raise(rb_ePGerror, "PQconnectdb() unable to allocate structure");
|
193
277
|
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
if (PQstatus(conn) == CONNECTION_BAD) {
|
198
|
-
error = rb_exc_new2(rb_eConnectionBad, PQerrorMessage(conn));
|
278
|
+
if (PQstatus(this->pgconn) == CONNECTION_BAD) {
|
279
|
+
error = rb_exc_new2(rb_eConnectionBad, PQerrorMessage(this->pgconn));
|
199
280
|
rb_iv_set(error, "@connection", self);
|
200
281
|
rb_exc_raise(error);
|
201
282
|
}
|
@@ -229,27 +310,25 @@ pgconn_init(int argc, VALUE *argv, VALUE self)
|
|
229
310
|
static VALUE
|
230
311
|
pgconn_s_connect_start( int argc, VALUE *argv, VALUE klass )
|
231
312
|
{
|
232
|
-
PGconn *conn = NULL;
|
233
313
|
VALUE rb_conn;
|
234
314
|
VALUE conninfo;
|
235
315
|
VALUE error;
|
316
|
+
t_pg_connection *this;
|
236
317
|
|
237
318
|
/*
|
238
319
|
* PG::Connection.connect_start must act as both alloc() and initialize()
|
239
320
|
* because it is not invoked by calling new().
|
240
321
|
*/
|
241
322
|
rb_conn = pgconn_s_allocate( klass );
|
323
|
+
this = pg_get_connection( rb_conn );
|
242
324
|
conninfo = rb_funcall2( klass, rb_intern("parse_connect_args"), argc, argv );
|
243
|
-
|
325
|
+
this->pgconn = gvl_PQconnectStart( StringValueCStr(conninfo) );
|
244
326
|
|
245
|
-
if(
|
327
|
+
if( this->pgconn == NULL )
|
246
328
|
rb_raise(rb_ePGerror, "PQconnectStart() unable to allocate structure");
|
247
329
|
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
if ( PQstatus(conn) == CONNECTION_BAD ) {
|
252
|
-
error = rb_exc_new2(rb_eConnectionBad, PQerrorMessage(conn));
|
330
|
+
if ( PQstatus(this->pgconn) == CONNECTION_BAD ) {
|
331
|
+
error = rb_exc_new2(rb_eConnectionBad, PQerrorMessage(this->pgconn));
|
253
332
|
rb_iv_set(error, "@connection", rb_conn);
|
254
333
|
rb_exc_raise(error);
|
255
334
|
}
|
@@ -286,7 +365,7 @@ pgconn_s_ping( int argc, VALUE *argv, VALUE klass )
|
|
286
365
|
VALUE conninfo;
|
287
366
|
|
288
367
|
conninfo = rb_funcall2( klass, rb_intern("parse_connect_args"), argc, argv );
|
289
|
-
ping = PQping(
|
368
|
+
ping = PQping( StringValueCStr(conninfo) );
|
290
369
|
|
291
370
|
return INT2FIX((int)ping);
|
292
371
|
}
|
@@ -319,31 +398,13 @@ static VALUE
|
|
319
398
|
pgconn_s_conndefaults(VALUE self)
|
320
399
|
{
|
321
400
|
PQconninfoOption *options = PQconndefaults();
|
322
|
-
VALUE
|
323
|
-
|
324
|
-
|
401
|
+
VALUE array = pgconn_make_conninfo_array( options );
|
402
|
+
|
403
|
+
PQconninfoFree(options);
|
325
404
|
|
326
405
|
UNUSED( self );
|
327
406
|
|
328
|
-
|
329
|
-
hash = rb_hash_new();
|
330
|
-
if(options[i].keyword)
|
331
|
-
rb_hash_aset(hash, ID2SYM(rb_intern("keyword")), rb_str_new2(options[i].keyword));
|
332
|
-
if(options[i].envvar)
|
333
|
-
rb_hash_aset(hash, ID2SYM(rb_intern("envvar")), rb_str_new2(options[i].envvar));
|
334
|
-
if(options[i].compiled)
|
335
|
-
rb_hash_aset(hash, ID2SYM(rb_intern("compiled")), rb_str_new2(options[i].compiled));
|
336
|
-
if(options[i].val)
|
337
|
-
rb_hash_aset(hash, ID2SYM(rb_intern("val")), rb_str_new2(options[i].val));
|
338
|
-
if(options[i].label)
|
339
|
-
rb_hash_aset(hash, ID2SYM(rb_intern("label")), rb_str_new2(options[i].label));
|
340
|
-
if(options[i].dispchar)
|
341
|
-
rb_hash_aset(hash, ID2SYM(rb_intern("dispchar")), rb_str_new2(options[i].dispchar));
|
342
|
-
rb_hash_aset(hash, ID2SYM(rb_intern("dispsize")), INT2NUM(options[i].dispsize));
|
343
|
-
rb_ary_push(ary, hash);
|
344
|
-
}
|
345
|
-
PQconninfoFree(options);
|
346
|
-
return ary;
|
407
|
+
return array;
|
347
408
|
}
|
348
409
|
|
349
410
|
|
@@ -369,7 +430,7 @@ pgconn_s_encrypt_password(VALUE self, VALUE password, VALUE username)
|
|
369
430
|
Check_Type(password, T_STRING);
|
370
431
|
Check_Type(username, T_STRING);
|
371
432
|
|
372
|
-
encrypted = PQencryptPassword(
|
433
|
+
encrypted = PQencryptPassword(StringValueCStr(password), StringValueCStr(username));
|
373
434
|
rval = rb_str_new2( encrypted );
|
374
435
|
PQfreemem( encrypted );
|
375
436
|
|
@@ -435,9 +496,11 @@ pgconn_connect_poll(VALUE self)
|
|
435
496
|
static VALUE
|
436
497
|
pgconn_finish( VALUE self )
|
437
498
|
{
|
499
|
+
t_pg_connection *this = pg_get_connection_safe( self );
|
500
|
+
|
438
501
|
pgconn_close_socket_io( self );
|
439
|
-
PQfinish(
|
440
|
-
|
502
|
+
PQfinish( this->pgconn );
|
503
|
+
this->pgconn = NULL;
|
441
504
|
return Qnil;
|
442
505
|
}
|
443
506
|
|
@@ -451,7 +514,8 @@ pgconn_finish( VALUE self )
|
|
451
514
|
static VALUE
|
452
515
|
pgconn_finished_p( VALUE self )
|
453
516
|
{
|
454
|
-
|
517
|
+
t_pg_connection *this = pg_get_connection( self );
|
518
|
+
if ( this->pgconn ) return Qfalse;
|
455
519
|
return Qtrue;
|
456
520
|
}
|
457
521
|
|
@@ -604,6 +668,29 @@ pgconn_options(VALUE self)
|
|
604
668
|
return rb_tainted_str_new2(options);
|
605
669
|
}
|
606
670
|
|
671
|
+
|
672
|
+
#ifdef HAVE_PQCONNINFO
|
673
|
+
/*
|
674
|
+
* call-seq:
|
675
|
+
* conn.conninfo -> hash
|
676
|
+
*
|
677
|
+
* Returns the connection options used by a live connection.
|
678
|
+
*
|
679
|
+
*/
|
680
|
+
static VALUE
|
681
|
+
pgconn_conninfo( VALUE self )
|
682
|
+
{
|
683
|
+
PGconn *conn = pg_get_pgconn(self);
|
684
|
+
PQconninfoOption *options = PQconninfo( conn );
|
685
|
+
VALUE array = pgconn_make_conninfo_array( options );
|
686
|
+
|
687
|
+
PQconninfoFree(options);
|
688
|
+
|
689
|
+
return array;
|
690
|
+
}
|
691
|
+
#endif
|
692
|
+
|
693
|
+
|
607
694
|
/*
|
608
695
|
* call-seq:
|
609
696
|
* conn.status()
|
@@ -654,7 +741,7 @@ pgconn_transaction_status(VALUE self)
|
|
654
741
|
static VALUE
|
655
742
|
pgconn_parameter_status(VALUE self, VALUE param_name)
|
656
743
|
{
|
657
|
-
const char *ret = PQparameterStatus(pg_get_pgconn(self),
|
744
|
+
const char *ret = PQparameterStatus(pg_get_pgconn(self), StringValueCStr(param_name));
|
658
745
|
if(ret == NULL)
|
659
746
|
return Qnil;
|
660
747
|
else
|
@@ -753,10 +840,11 @@ pgconn_socket_io(VALUE self)
|
|
753
840
|
int sd;
|
754
841
|
int ruby_sd;
|
755
842
|
ID id_autoclose = rb_intern("autoclose=");
|
756
|
-
|
843
|
+
t_pg_connection *this = pg_get_connection_safe( self );
|
844
|
+
VALUE socket_io = this->socket_io;
|
757
845
|
|
758
846
|
if ( !RTEST(socket_io) ) {
|
759
|
-
if( (sd = PQsocket(
|
847
|
+
if( (sd = PQsocket(this->pgconn)) < 0)
|
760
848
|
rb_raise(rb_eConnectionBad, "PQsocket() can't get socket descriptor");
|
761
849
|
|
762
850
|
#ifdef _WIN32
|
@@ -772,7 +860,7 @@ pgconn_socket_io(VALUE self)
|
|
772
860
|
rb_funcall( socket_io, id_autoclose, 1, Qfalse );
|
773
861
|
}
|
774
862
|
|
775
|
-
|
863
|
+
this->socket_io = socket_io;
|
776
864
|
}
|
777
865
|
|
778
866
|
return socket_io;
|
@@ -861,7 +949,7 @@ pgconn_exec(int argc, VALUE *argv, VALUE self)
|
|
861
949
|
if ( argc == 1 ) {
|
862
950
|
Check_Type(argv[0], T_STRING);
|
863
951
|
|
864
|
-
result = gvl_PQexec(conn,
|
952
|
+
result = gvl_PQexec(conn, StringValueCStr(argv[0]));
|
865
953
|
rb_pgresult = pg_new_result(result, self);
|
866
954
|
pg_result_check(rb_pgresult);
|
867
955
|
if (rb_block_given_p()) {
|
@@ -878,10 +966,250 @@ pgconn_exec(int argc, VALUE *argv, VALUE self)
|
|
878
966
|
}
|
879
967
|
|
880
968
|
|
969
|
+
struct linked_typecast_data {
|
970
|
+
struct linked_typecast_data *next;
|
971
|
+
char data[0];
|
972
|
+
};
|
973
|
+
|
974
|
+
/* This struct is allocated on the stack for all query execution functions. */
|
975
|
+
struct query_params_data {
|
976
|
+
|
977
|
+
/*
|
978
|
+
* Filled by caller
|
979
|
+
*/
|
980
|
+
|
981
|
+
/* Is the query function to execute one with types array? */
|
982
|
+
int with_types;
|
983
|
+
/* Array of query params from user space */
|
984
|
+
VALUE params;
|
985
|
+
/* The typemap given from user space */
|
986
|
+
VALUE typemap;
|
987
|
+
|
988
|
+
/*
|
989
|
+
* Filled by alloc_query_params()
|
990
|
+
*/
|
991
|
+
|
992
|
+
/* Wraps the pointer of allocated memory, if function parameters dont't
|
993
|
+
* fit in the memory_pool below.
|
994
|
+
*/
|
995
|
+
VALUE heap_pool;
|
996
|
+
|
997
|
+
/* Pointer to the value string pointers (either within memory_pool or heap_pool).
|
998
|
+
* The value strings itself are either directly within RString memory or,
|
999
|
+
* in case of type casted values, within memory_pool or typecast_heap_chain.
|
1000
|
+
*/
|
1001
|
+
char **values;
|
1002
|
+
/* Pointer to the param lengths (either within memory_pool or heap_pool) */
|
1003
|
+
int *lengths;
|
1004
|
+
/* Pointer to the format codes (either within memory_pool or heap_pool) */
|
1005
|
+
int *formats;
|
1006
|
+
/* Pointer to the OID types (either within memory_pool or heap_pool) */
|
1007
|
+
Oid *types;
|
1008
|
+
|
1009
|
+
/* This array takes the string values for the timeframe of the query,
|
1010
|
+
* if param value convertion is required
|
1011
|
+
*/
|
1012
|
+
VALUE gc_array;
|
1013
|
+
|
1014
|
+
/* Wraps a single linked list of allocated memory chunks for type casted params.
|
1015
|
+
* Used when the memory_pool is to small.
|
1016
|
+
*/
|
1017
|
+
VALUE typecast_heap_chain;
|
1018
|
+
|
1019
|
+
/* This memory pool is used to place above query function parameters on it. */
|
1020
|
+
char memory_pool[QUERYDATA_BUFFER_SIZE];
|
1021
|
+
};
|
1022
|
+
|
1023
|
+
static void
|
1024
|
+
free_typecast_heap_chain(struct linked_typecast_data *chain_entry)
|
1025
|
+
{
|
1026
|
+
while(chain_entry){
|
1027
|
+
struct linked_typecast_data *next = chain_entry->next;
|
1028
|
+
xfree(chain_entry);
|
1029
|
+
chain_entry = next;
|
1030
|
+
}
|
1031
|
+
}
|
1032
|
+
|
1033
|
+
static char *
|
1034
|
+
alloc_typecast_buf( VALUE *typecast_heap_chain, int len )
|
1035
|
+
{
|
1036
|
+
/* Allocate a new memory chunk from heap */
|
1037
|
+
struct linked_typecast_data *allocated =
|
1038
|
+
(struct linked_typecast_data *)xmalloc(sizeof(struct linked_typecast_data) + len);
|
1039
|
+
|
1040
|
+
/* Did we already wrap a memory chain per T_DATA object? */
|
1041
|
+
if( NIL_P( *typecast_heap_chain ) ){
|
1042
|
+
/* Leave free'ing of the buffer chain to the GC, when paramsData has left the stack */
|
1043
|
+
*typecast_heap_chain = Data_Wrap_Struct( rb_cObject, NULL, free_typecast_heap_chain, allocated );
|
1044
|
+
allocated->next = NULL;
|
1045
|
+
} else {
|
1046
|
+
/* Append to the chain */
|
1047
|
+
allocated->next = DATA_PTR( *typecast_heap_chain );
|
1048
|
+
DATA_PTR( *typecast_heap_chain ) = allocated;
|
1049
|
+
}
|
1050
|
+
|
1051
|
+
return &allocated->data[0];
|
1052
|
+
}
|
1053
|
+
|
1054
|
+
|
1055
|
+
static int
|
1056
|
+
alloc_query_params(struct query_params_data *paramsData)
|
1057
|
+
{
|
1058
|
+
VALUE param_value;
|
1059
|
+
t_typemap *p_typemap;
|
1060
|
+
int nParams;
|
1061
|
+
int i=0;
|
1062
|
+
t_pg_coder *conv;
|
1063
|
+
unsigned int required_pool_size;
|
1064
|
+
char *memory_pool;
|
1065
|
+
|
1066
|
+
Check_Type(paramsData->params, T_ARRAY);
|
1067
|
+
|
1068
|
+
p_typemap = DATA_PTR( paramsData->typemap );
|
1069
|
+
p_typemap->funcs.fit_to_query( paramsData->typemap, paramsData->params );
|
1070
|
+
|
1071
|
+
paramsData->heap_pool = Qnil;
|
1072
|
+
paramsData->typecast_heap_chain = Qnil;
|
1073
|
+
paramsData->gc_array = Qnil;
|
1074
|
+
|
1075
|
+
nParams = (int)RARRAY_LEN(paramsData->params);
|
1076
|
+
|
1077
|
+
required_pool_size = nParams * (
|
1078
|
+
sizeof(char *) +
|
1079
|
+
sizeof(int) +
|
1080
|
+
sizeof(int) +
|
1081
|
+
(paramsData->with_types ? sizeof(Oid) : 0));
|
1082
|
+
|
1083
|
+
if( sizeof(paramsData->memory_pool) < required_pool_size ){
|
1084
|
+
/* Allocate one combined memory pool for all possible function parameters */
|
1085
|
+
memory_pool = (char*)xmalloc( required_pool_size );
|
1086
|
+
/* Leave free'ing of the buffer to the GC, when paramsData has left the stack */
|
1087
|
+
paramsData->heap_pool = Data_Wrap_Struct( rb_cObject, NULL, -1, memory_pool );
|
1088
|
+
required_pool_size = 0;
|
1089
|
+
}else{
|
1090
|
+
/* Use stack memory for function parameters */
|
1091
|
+
memory_pool = paramsData->memory_pool;
|
1092
|
+
}
|
1093
|
+
|
1094
|
+
paramsData->values = (char **)memory_pool;
|
1095
|
+
paramsData->lengths = (int *)((char*)paramsData->values + sizeof(char *) * nParams);
|
1096
|
+
paramsData->formats = (int *)((char*)paramsData->lengths + sizeof(int) * nParams);
|
1097
|
+
paramsData->types = (Oid *)((char*)paramsData->formats + sizeof(int) * nParams);
|
1098
|
+
|
1099
|
+
{
|
1100
|
+
char *typecast_buf = paramsData->memory_pool + required_pool_size;
|
1101
|
+
|
1102
|
+
for ( i = 0; i < nParams; i++ ) {
|
1103
|
+
param_value = rb_ary_entry(paramsData->params, i);
|
1104
|
+
|
1105
|
+
paramsData->formats[i] = 0;
|
1106
|
+
if( paramsData->with_types )
|
1107
|
+
paramsData->types[i] = 0;
|
1108
|
+
|
1109
|
+
/* Let the given typemap select a coder for this param */
|
1110
|
+
conv = p_typemap->funcs.typecast_query_param(p_typemap, param_value, i);
|
1111
|
+
|
1112
|
+
/* Using a coder object for the param_value? Then set it's format code and oid. */
|
1113
|
+
if( conv ){
|
1114
|
+
paramsData->formats[i] = conv->format;
|
1115
|
+
if( paramsData->with_types )
|
1116
|
+
paramsData->types[i] = conv->oid;
|
1117
|
+
} else {
|
1118
|
+
/* No coder, but got we a hash form for the query param?
|
1119
|
+
* Then take format code and oid from there. */
|
1120
|
+
if (TYPE(param_value) == T_HASH) {
|
1121
|
+
VALUE format_value = rb_hash_aref(param_value, sym_format);
|
1122
|
+
if( !NIL_P(format_value) )
|
1123
|
+
paramsData->formats[i] = NUM2INT(format_value);
|
1124
|
+
if( paramsData->with_types ){
|
1125
|
+
VALUE type_value = rb_hash_aref(param_value, sym_type);
|
1126
|
+
if( !NIL_P(type_value) )
|
1127
|
+
paramsData->types[i] = NUM2UINT(type_value);
|
1128
|
+
}
|
1129
|
+
param_value = rb_hash_aref(param_value, sym_value);
|
1130
|
+
}
|
1131
|
+
}
|
1132
|
+
|
1133
|
+
if( NIL_P(param_value) ){
|
1134
|
+
paramsData->values[i] = NULL;
|
1135
|
+
paramsData->lengths[i] = 0;
|
1136
|
+
} else {
|
1137
|
+
t_pg_coder_enc_func enc_func = pg_coder_enc_func( conv );
|
1138
|
+
VALUE intermediate;
|
1139
|
+
|
1140
|
+
/* 1st pass for retiving the required memory space */
|
1141
|
+
int len = enc_func(conv, param_value, NULL, &intermediate);
|
1142
|
+
|
1143
|
+
if( len == -1 ){
|
1144
|
+
/* The intermediate value is a String that can be used directly. */
|
1145
|
+
|
1146
|
+
/* Ensure that the String object is zero terminated as expected by libpq. */
|
1147
|
+
if( paramsData->formats[i] == 0 )
|
1148
|
+
StringValueCStr(intermediate);
|
1149
|
+
/* In case a new string object was generated, make sure it doesn't get freed by the GC */
|
1150
|
+
if( intermediate != param_value ){
|
1151
|
+
if( NIL_P(paramsData->gc_array) )
|
1152
|
+
paramsData->gc_array = rb_ary_new();
|
1153
|
+
rb_ary_push(paramsData->gc_array, intermediate);
|
1154
|
+
}
|
1155
|
+
paramsData->values[i] = RSTRING_PTR(intermediate);
|
1156
|
+
paramsData->lengths[i] = RSTRING_LENINT(intermediate);
|
1157
|
+
|
1158
|
+
} else {
|
1159
|
+
/* Is the stack memory pool too small to take the type casted value? */
|
1160
|
+
if( sizeof(paramsData->memory_pool) < required_pool_size + len + 1){
|
1161
|
+
typecast_buf = alloc_typecast_buf( ¶msData->typecast_heap_chain, len + 1 );
|
1162
|
+
}
|
1163
|
+
|
1164
|
+
/* 2nd pass for writing the data to prepared buffer */
|
1165
|
+
len = enc_func(conv, param_value, typecast_buf, &intermediate);
|
1166
|
+
paramsData->values[i] = typecast_buf;
|
1167
|
+
if( paramsData->formats[i] == 0 ){
|
1168
|
+
/* text format strings must be zero terminated and lengths are ignored */
|
1169
|
+
typecast_buf[len] = 0;
|
1170
|
+
typecast_buf += len + 1;
|
1171
|
+
required_pool_size += len + 1;
|
1172
|
+
} else {
|
1173
|
+
paramsData->lengths[i] = len;
|
1174
|
+
typecast_buf += len;
|
1175
|
+
required_pool_size += len;
|
1176
|
+
}
|
1177
|
+
}
|
1178
|
+
|
1179
|
+
RB_GC_GUARD(intermediate);
|
1180
|
+
}
|
1181
|
+
}
|
1182
|
+
}
|
1183
|
+
|
1184
|
+
return nParams;
|
1185
|
+
}
|
1186
|
+
|
1187
|
+
static void
|
1188
|
+
free_query_params(struct query_params_data *paramsData)
|
1189
|
+
{
|
1190
|
+
/* currently nothing to free */
|
1191
|
+
}
|
1192
|
+
|
1193
|
+
void
|
1194
|
+
pgconn_query_assign_typemap( VALUE self, struct query_params_data *paramsData )
|
1195
|
+
{
|
1196
|
+
if(NIL_P(paramsData->typemap)){
|
1197
|
+
/* Use default typemap for queries. It's type is checked when assigned. */
|
1198
|
+
paramsData->typemap = pg_get_connection(self)->type_map_for_queries;
|
1199
|
+
}else{
|
1200
|
+
/* Check type of method param */
|
1201
|
+
if ( !rb_obj_is_kind_of(paramsData->typemap, rb_cTypeMap) ) {
|
1202
|
+
rb_raise( rb_eTypeError, "wrong argument type %s (expected kind of PG::TypeMap)",
|
1203
|
+
rb_obj_classname( paramsData->typemap ) );
|
1204
|
+
}
|
1205
|
+
Check_Type( paramsData->typemap, T_DATA );
|
1206
|
+
}
|
1207
|
+
}
|
1208
|
+
|
881
1209
|
/*
|
882
1210
|
* call-seq:
|
883
|
-
* conn.exec_params(sql, params[, result_format ] ) -> PG::Result
|
884
|
-
* conn.exec_params(sql, params[, result_format ] ) {|pg_result| block }
|
1211
|
+
* conn.exec_params(sql, params[, result_format[, type_map]] ) -> PG::Result
|
1212
|
+
* conn.exec_params(sql, params[, result_format[, type_map]] ) {|pg_result| block }
|
885
1213
|
*
|
886
1214
|
* Sends SQL query request specified by +sql+ to PostgreSQL using placeholders
|
887
1215
|
* for parameters.
|
@@ -911,6 +1239,12 @@ pgconn_exec(int argc, VALUE *argv, VALUE self)
|
|
911
1239
|
* The optional +result_format+ should be 0 for text results, 1
|
912
1240
|
* for binary.
|
913
1241
|
*
|
1242
|
+
* type_map can be a PG::TypeMap derivation (such as PG::BasicTypeMapForQueries).
|
1243
|
+
* This will type cast the params form various Ruby types before transmission
|
1244
|
+
* based on the encoders defined by the type map. When a type encoder is used
|
1245
|
+
* the format and oid of a given bind parameter are retrieved from the encoder
|
1246
|
+
* instead out of the hash form described above.
|
1247
|
+
*
|
914
1248
|
* If the optional code block is given, it will be passed <i>result</i> as an argument,
|
915
1249
|
* and the PG::Result object will automatically be cleared when the block terminates.
|
916
1250
|
* In this instance, <code>conn.exec</code> returns the value of the block.
|
@@ -921,102 +1255,30 @@ pgconn_exec_params( int argc, VALUE *argv, VALUE self )
|
|
921
1255
|
PGconn *conn = pg_get_pgconn(self);
|
922
1256
|
PGresult *result = NULL;
|
923
1257
|
VALUE rb_pgresult;
|
924
|
-
VALUE command,
|
925
|
-
VALUE param, param_type, param_value, param_format;
|
926
|
-
VALUE param_value_tmp;
|
927
|
-
VALUE sym_type, sym_value, sym_format;
|
928
|
-
VALUE gc_array;
|
929
|
-
int i=0;
|
1258
|
+
VALUE command, in_res_fmt;
|
930
1259
|
int nParams;
|
931
|
-
Oid *paramTypes;
|
932
|
-
char ** paramValues;
|
933
|
-
int *paramLengths;
|
934
|
-
int *paramFormats;
|
935
1260
|
int resultFormat;
|
1261
|
+
struct query_params_data paramsData;
|
936
1262
|
|
937
|
-
rb_scan_args(argc, argv, "
|
1263
|
+
rb_scan_args(argc, argv, "13", &command, ¶msData.params, &in_res_fmt, ¶msData.typemap);
|
1264
|
+
paramsData.with_types = 1;
|
938
1265
|
|
939
1266
|
/*
|
940
1267
|
* Handle the edge-case where the caller is coming from #exec, but passed an explict +nil+
|
941
1268
|
* for the second parameter.
|
942
1269
|
*/
|
943
|
-
if ( NIL_P(params) ) {
|
1270
|
+
if ( NIL_P(paramsData.params) ) {
|
944
1271
|
return pgconn_exec( 1, argv, self );
|
945
|
-
}
|
946
|
-
|
947
|
-
Check_Type(params, T_ARRAY);
|
948
|
-
|
949
|
-
if ( NIL_P(in_res_fmt) ) {
|
950
|
-
resultFormat = 0;
|
951
|
-
}
|
952
|
-
else {
|
953
|
-
resultFormat = NUM2INT(in_res_fmt);
|
954
|
-
}
|
955
|
-
|
956
|
-
gc_array = rb_ary_new();
|
957
|
-
rb_gc_register_address(&gc_array);
|
958
|
-
|
959
|
-
sym_type = ID2SYM(rb_intern("type"));
|
960
|
-
sym_value = ID2SYM(rb_intern("value"));
|
961
|
-
sym_format = ID2SYM(rb_intern("format"));
|
962
|
-
nParams = (int)RARRAY_LEN(params);
|
963
|
-
paramTypes = ALLOC_N(Oid, nParams);
|
964
|
-
paramValues = ALLOC_N(char *, nParams);
|
965
|
-
paramLengths = ALLOC_N(int, nParams);
|
966
|
-
paramFormats = ALLOC_N(int, nParams);
|
967
|
-
|
968
|
-
for ( i = 0; i < nParams; i++ ) {
|
969
|
-
param = rb_ary_entry(params, i);
|
970
|
-
if (TYPE(param) == T_HASH) {
|
971
|
-
param_type = rb_hash_aref(param, sym_type);
|
972
|
-
param_value_tmp = rb_hash_aref(param, sym_value);
|
973
|
-
if(param_value_tmp == Qnil)
|
974
|
-
param_value = param_value_tmp;
|
975
|
-
else
|
976
|
-
param_value = rb_obj_as_string(param_value_tmp);
|
977
|
-
param_format = rb_hash_aref(param, sym_format);
|
978
|
-
}
|
979
|
-
else {
|
980
|
-
param_type = Qnil;
|
981
|
-
if(param == Qnil)
|
982
|
-
param_value = param;
|
983
|
-
else
|
984
|
-
param_value = rb_obj_as_string(param);
|
985
|
-
param_format = Qnil;
|
986
|
-
}
|
987
|
-
|
988
|
-
if(param_type == Qnil)
|
989
|
-
paramTypes[i] = 0;
|
990
|
-
else
|
991
|
-
paramTypes[i] = NUM2INT(param_type);
|
992
|
-
|
993
|
-
if(param_value == Qnil) {
|
994
|
-
paramValues[i] = NULL;
|
995
|
-
paramLengths[i] = 0;
|
996
|
-
}
|
997
|
-
else {
|
998
|
-
Check_Type(param_value, T_STRING);
|
999
|
-
/* make sure param_value doesn't get freed by the GC */
|
1000
|
-
rb_ary_push(gc_array, param_value);
|
1001
|
-
paramValues[i] = StringValuePtr(param_value);
|
1002
|
-
paramLengths[i] = (int)RSTRING_LEN(param_value);
|
1003
|
-
}
|
1004
|
-
|
1005
|
-
if(param_format == Qnil)
|
1006
|
-
paramFormats[i] = 0;
|
1007
|
-
else
|
1008
|
-
paramFormats[i] = NUM2INT(param_format);
|
1009
1272
|
}
|
1273
|
+
pgconn_query_assign_typemap( self, ¶msData );
|
1010
1274
|
|
1011
|
-
|
1012
|
-
|
1275
|
+
resultFormat = NIL_P(in_res_fmt) ? 0 : NUM2INT(in_res_fmt);
|
1276
|
+
nParams = alloc_query_params( ¶msData );
|
1013
1277
|
|
1014
|
-
|
1278
|
+
result = gvl_PQexecParams(conn, StringValueCStr(command), nParams, paramsData.types,
|
1279
|
+
(const char * const *)paramsData.values, paramsData.lengths, paramsData.formats, resultFormat);
|
1015
1280
|
|
1016
|
-
|
1017
|
-
xfree(paramValues);
|
1018
|
-
xfree(paramLengths);
|
1019
|
-
xfree(paramFormats);
|
1281
|
+
free_query_params( ¶msData );
|
1020
1282
|
|
1021
1283
|
rb_pgresult = pg_new_result(result, self);
|
1022
1284
|
pg_result_check(rb_pgresult);
|
@@ -1070,14 +1332,13 @@ pgconn_prepare(int argc, VALUE *argv, VALUE self)
|
|
1070
1332
|
paramTypes = ALLOC_N(Oid, nParams);
|
1071
1333
|
for(i = 0; i < nParams; i++) {
|
1072
1334
|
param = rb_ary_entry(in_paramtypes, i);
|
1073
|
-
Check_Type(param, T_FIXNUM);
|
1074
1335
|
if(param == Qnil)
|
1075
1336
|
paramTypes[i] = 0;
|
1076
1337
|
else
|
1077
|
-
paramTypes[i] =
|
1338
|
+
paramTypes[i] = NUM2UINT(param);
|
1078
1339
|
}
|
1079
1340
|
}
|
1080
|
-
result = gvl_PQprepare(conn,
|
1341
|
+
result = gvl_PQprepare(conn, StringValueCStr(name), StringValueCStr(command),
|
1081
1342
|
nParams, paramTypes);
|
1082
1343
|
|
1083
1344
|
xfree(paramTypes);
|
@@ -1089,8 +1350,8 @@ pgconn_prepare(int argc, VALUE *argv, VALUE self)
|
|
1089
1350
|
|
1090
1351
|
/*
|
1091
1352
|
* call-seq:
|
1092
|
-
* conn.exec_prepared(statement_name [, params, result_format ] ) -> PG::Result
|
1093
|
-
* conn.exec_prepared(statement_name [, params, result_format ] ) {|pg_result| block }
|
1353
|
+
* conn.exec_prepared(statement_name [, params, result_format[, type_map]] ) -> PG::Result
|
1354
|
+
* conn.exec_prepared(statement_name [, params, result_format[, type_map]] ) {|pg_result| block }
|
1094
1355
|
*
|
1095
1356
|
* Execute prepared named statement specified by _statement_name_.
|
1096
1357
|
* Returns a PG::Result instance on success.
|
@@ -1112,6 +1373,12 @@ pgconn_prepare(int argc, VALUE *argv, VALUE self)
|
|
1112
1373
|
* The optional +result_format+ should be 0 for text results, 1
|
1113
1374
|
* for binary.
|
1114
1375
|
*
|
1376
|
+
* type_map can be a PG::TypeMap derivation (such as PG::BasicTypeMapForQueries).
|
1377
|
+
* This will type cast the params form various Ruby types before transmission
|
1378
|
+
* based on the encoders defined by the type map. When a type encoder is used
|
1379
|
+
* the format and oid of a given bind parameter are retrieved from the encoder
|
1380
|
+
* instead out of the hash form described above.
|
1381
|
+
*
|
1115
1382
|
* If the optional code block is given, it will be passed <i>result</i> as an argument,
|
1116
1383
|
* and the PG::Result object will automatically be cleared when the block terminates.
|
1117
1384
|
* In this instance, <code>conn.exec_prepared</code> returns the value of the block.
|
@@ -1122,89 +1389,28 @@ pgconn_exec_prepared(int argc, VALUE *argv, VALUE self)
|
|
1122
1389
|
PGconn *conn = pg_get_pgconn(self);
|
1123
1390
|
PGresult *result = NULL;
|
1124
1391
|
VALUE rb_pgresult;
|
1125
|
-
VALUE name,
|
1126
|
-
VALUE param, param_value, param_format;
|
1127
|
-
VALUE param_value_tmp;
|
1128
|
-
VALUE sym_value, sym_format;
|
1129
|
-
VALUE gc_array;
|
1130
|
-
int i = 0;
|
1392
|
+
VALUE name, in_res_fmt;
|
1131
1393
|
int nParams;
|
1132
|
-
char ** paramValues;
|
1133
|
-
int *paramLengths;
|
1134
|
-
int *paramFormats;
|
1135
1394
|
int resultFormat;
|
1395
|
+
struct query_params_data paramsData;
|
1136
1396
|
|
1137
|
-
|
1138
|
-
|
1397
|
+
rb_scan_args(argc, argv, "13", &name, ¶msData.params, &in_res_fmt, ¶msData.typemap);
|
1398
|
+
paramsData.with_types = 0;
|
1139
1399
|
Check_Type(name, T_STRING);
|
1140
1400
|
|
1141
|
-
if(NIL_P(params)) {
|
1142
|
-
params = rb_ary_new2(0);
|
1143
|
-
resultFormat = 0;
|
1144
|
-
}
|
1145
|
-
else {
|
1146
|
-
Check_Type(params, T_ARRAY);
|
1147
|
-
}
|
1148
|
-
|
1149
|
-
if(NIL_P(in_res_fmt)) {
|
1150
|
-
resultFormat = 0;
|
1151
|
-
}
|
1152
|
-
else {
|
1153
|
-
resultFormat = NUM2INT(in_res_fmt);
|
1401
|
+
if(NIL_P(paramsData.params)) {
|
1402
|
+
paramsData.params = rb_ary_new2(0);
|
1154
1403
|
}
|
1404
|
+
pgconn_query_assign_typemap( self, ¶msData );
|
1155
1405
|
|
1156
|
-
|
1157
|
-
|
1158
|
-
sym_value = ID2SYM(rb_intern("value"));
|
1159
|
-
sym_format = ID2SYM(rb_intern("format"));
|
1160
|
-
nParams = (int)RARRAY_LEN(params);
|
1161
|
-
paramValues = ALLOC_N(char *, nParams);
|
1162
|
-
paramLengths = ALLOC_N(int, nParams);
|
1163
|
-
paramFormats = ALLOC_N(int, nParams);
|
1164
|
-
for(i = 0; i < nParams; i++) {
|
1165
|
-
param = rb_ary_entry(params, i);
|
1166
|
-
if (TYPE(param) == T_HASH) {
|
1167
|
-
param_value_tmp = rb_hash_aref(param, sym_value);
|
1168
|
-
if(param_value_tmp == Qnil)
|
1169
|
-
param_value = param_value_tmp;
|
1170
|
-
else
|
1171
|
-
param_value = rb_obj_as_string(param_value_tmp);
|
1172
|
-
param_format = rb_hash_aref(param, sym_format);
|
1173
|
-
}
|
1174
|
-
else {
|
1175
|
-
if(param == Qnil)
|
1176
|
-
param_value = param;
|
1177
|
-
else
|
1178
|
-
param_value = rb_obj_as_string(param);
|
1179
|
-
param_format = INT2NUM(0);
|
1180
|
-
}
|
1181
|
-
if(param_value == Qnil) {
|
1182
|
-
paramValues[i] = NULL;
|
1183
|
-
paramLengths[i] = 0;
|
1184
|
-
}
|
1185
|
-
else {
|
1186
|
-
Check_Type(param_value, T_STRING);
|
1187
|
-
/* make sure param_value doesn't get freed by the GC */
|
1188
|
-
rb_ary_push(gc_array, param_value);
|
1189
|
-
paramValues[i] = StringValuePtr(param_value);
|
1190
|
-
paramLengths[i] = (int)RSTRING_LEN(param_value);
|
1191
|
-
}
|
1406
|
+
resultFormat = NIL_P(in_res_fmt) ? 0 : NUM2INT(in_res_fmt);
|
1407
|
+
nParams = alloc_query_params( ¶msData );
|
1192
1408
|
|
1193
|
-
|
1194
|
-
|
1195
|
-
else
|
1196
|
-
paramFormats[i] = NUM2INT(param_format);
|
1197
|
-
}
|
1198
|
-
|
1199
|
-
result = gvl_PQexecPrepared(conn, StringValuePtr(name), nParams,
|
1200
|
-
(const char * const *)paramValues, paramLengths, paramFormats,
|
1409
|
+
result = gvl_PQexecPrepared(conn, StringValueCStr(name), nParams,
|
1410
|
+
(const char * const *)paramsData.values, paramsData.lengths, paramsData.formats,
|
1201
1411
|
resultFormat);
|
1202
1412
|
|
1203
|
-
|
1204
|
-
|
1205
|
-
xfree(paramValues);
|
1206
|
-
xfree(paramLengths);
|
1207
|
-
xfree(paramFormats);
|
1413
|
+
free_query_params( ¶msData );
|
1208
1414
|
|
1209
1415
|
rb_pgresult = pg_new_result(result, self);
|
1210
1416
|
pg_result_check(rb_pgresult);
|
@@ -1234,7 +1440,7 @@ pgconn_describe_prepared(VALUE self, VALUE stmt_name)
|
|
1234
1440
|
}
|
1235
1441
|
else {
|
1236
1442
|
Check_Type(stmt_name, T_STRING);
|
1237
|
-
stmt =
|
1443
|
+
stmt = StringValueCStr(stmt_name);
|
1238
1444
|
}
|
1239
1445
|
result = gvl_PQdescribePrepared(conn, stmt);
|
1240
1446
|
rb_pgresult = pg_new_result(result, self);
|
@@ -1262,7 +1468,7 @@ pgconn_describe_portal(self, stmt_name)
|
|
1262
1468
|
}
|
1263
1469
|
else {
|
1264
1470
|
Check_Type(stmt_name, T_STRING);
|
1265
|
-
stmt =
|
1471
|
+
stmt = StringValueCStr(stmt_name);
|
1266
1472
|
}
|
1267
1473
|
result = gvl_PQdescribePortal(conn, stmt);
|
1268
1474
|
rb_pgresult = pg_new_result(result, self);
|
@@ -1324,14 +1530,11 @@ pgconn_s_escape(VALUE self, VALUE string)
|
|
1324
1530
|
size_t size;
|
1325
1531
|
int error;
|
1326
1532
|
VALUE result;
|
1327
|
-
#ifdef M17N_SUPPORTED
|
1328
|
-
rb_encoding* enc;
|
1329
|
-
#endif
|
1330
1533
|
|
1331
1534
|
Check_Type(string, T_STRING);
|
1332
1535
|
|
1333
1536
|
escaped = ALLOC_N(char, RSTRING_LEN(string) * 2 + 1);
|
1334
|
-
if(
|
1537
|
+
if( rb_obj_is_kind_of(self, rb_cPGconn) ) {
|
1335
1538
|
size = PQescapeStringConn(pg_get_pgconn(self), escaped,
|
1336
1539
|
RSTRING_PTR(string), RSTRING_LEN(string), &error);
|
1337
1540
|
if(error) {
|
@@ -1339,20 +1542,12 @@ pgconn_s_escape(VALUE self, VALUE string)
|
|
1339
1542
|
rb_raise(rb_ePGerror, "%s", PQerrorMessage(pg_get_pgconn(self)));
|
1340
1543
|
}
|
1341
1544
|
} else {
|
1342
|
-
size = PQescapeString(escaped, RSTRING_PTR(string), (
|
1545
|
+
size = PQescapeString(escaped, RSTRING_PTR(string), RSTRING_LENINT(string));
|
1343
1546
|
}
|
1344
1547
|
result = rb_str_new(escaped, size);
|
1345
1548
|
xfree(escaped);
|
1346
1549
|
OBJ_INFECT(result, string);
|
1347
|
-
|
1348
|
-
#ifdef M17N_SUPPORTED
|
1349
|
-
if ( rb_obj_class(self) == rb_cPGconn ) {
|
1350
|
-
enc = pg_conn_enc_get( pg_get_pgconn(self) );
|
1351
|
-
} else {
|
1352
|
-
enc = rb_enc_get(string);
|
1353
|
-
}
|
1354
|
-
rb_enc_associate(result, enc);
|
1355
|
-
#endif
|
1550
|
+
PG_ENCODING_SET_NOCHECK(result, ENCODING_GET( rb_obj_is_kind_of(self, rb_cPGconn) ? self : string ));
|
1356
1551
|
|
1357
1552
|
return result;
|
1358
1553
|
}
|
@@ -1392,7 +1587,7 @@ pgconn_s_escape_bytea(VALUE self, VALUE str)
|
|
1392
1587
|
from = (unsigned char*)RSTRING_PTR(str);
|
1393
1588
|
from_len = RSTRING_LEN(str);
|
1394
1589
|
|
1395
|
-
if(
|
1590
|
+
if ( rb_obj_is_kind_of(self, rb_cPGconn) ) {
|
1396
1591
|
to = PQescapeByteaConn(pg_get_pgconn(self), from, from_len, &to_len);
|
1397
1592
|
} else {
|
1398
1593
|
to = PQescapeBytea( from, from_len, &to_len);
|
@@ -1424,7 +1619,7 @@ pgconn_s_unescape_bytea(VALUE self, VALUE str)
|
|
1424
1619
|
UNUSED( self );
|
1425
1620
|
|
1426
1621
|
Check_Type(str, T_STRING);
|
1427
|
-
from = (unsigned char*)
|
1622
|
+
from = (unsigned char*)StringValueCStr(str);
|
1428
1623
|
|
1429
1624
|
to = PQunescapeBytea(from, &to_len);
|
1430
1625
|
|
@@ -1462,10 +1657,7 @@ pgconn_escape_literal(VALUE self, VALUE string)
|
|
1462
1657
|
result = rb_str_new2(escaped);
|
1463
1658
|
PQfreemem(escaped);
|
1464
1659
|
OBJ_INFECT(result, string);
|
1465
|
-
|
1466
|
-
#ifdef M17N_SUPPORTED
|
1467
|
-
rb_enc_associate(result, pg_conn_enc_get( pg_get_pgconn(self) ));
|
1468
|
-
#endif
|
1660
|
+
PG_ENCODING_SET_NOCHECK(result, ENCODING_GET(self));
|
1469
1661
|
|
1470
1662
|
return result;
|
1471
1663
|
}
|
@@ -1502,10 +1694,7 @@ pgconn_escape_identifier(VALUE self, VALUE string)
|
|
1502
1694
|
result = rb_str_new2(escaped);
|
1503
1695
|
PQfreemem(escaped);
|
1504
1696
|
OBJ_INFECT(result, string);
|
1505
|
-
|
1506
|
-
#ifdef M17N_SUPPORTED
|
1507
|
-
rb_enc_associate(result, pg_conn_enc_get( pg_get_pgconn(self) ));
|
1508
|
-
#endif
|
1697
|
+
PG_ENCODING_SET_NOCHECK(result, ENCODING_GET(self));
|
1509
1698
|
|
1510
1699
|
return result;
|
1511
1700
|
}
|
@@ -1522,7 +1711,7 @@ pgconn_escape_identifier(VALUE self, VALUE string)
|
|
1522
1711
|
* Then call Connection#get_result repeatedly, until it returns nil.
|
1523
1712
|
*
|
1524
1713
|
* Each (but the last) received Result has exactly one row and a
|
1525
|
-
* Result#result_status of PGRES_SINGLE_TUPLE. The last
|
1714
|
+
* Result#result_status of PGRES_SINGLE_TUPLE. The last Result has
|
1526
1715
|
* zero rows and is used to indicate a successful execution of the query.
|
1527
1716
|
* All of these Result objects will contain the same row description data
|
1528
1717
|
* (column names, types, etc) that an ordinary Result object for the query
|
@@ -1568,7 +1757,7 @@ pgconn_set_single_row_mode(VALUE self)
|
|
1568
1757
|
|
1569
1758
|
/*
|
1570
1759
|
* call-seq:
|
1571
|
-
* conn.send_query(sql [, params, result_format ] ) -> nil
|
1760
|
+
* conn.send_query(sql [, params, result_format[, type_map ]] ) -> nil
|
1572
1761
|
*
|
1573
1762
|
* Sends SQL query request specified by _sql_ to PostgreSQL for
|
1574
1763
|
* asynchronous processing, and immediately returns.
|
@@ -1596,32 +1785,32 @@ pgconn_set_single_row_mode(VALUE self)
|
|
1596
1785
|
*
|
1597
1786
|
* The optional +result_format+ should be 0 for text results, 1
|
1598
1787
|
* for binary.
|
1788
|
+
*
|
1789
|
+
* type_map can be a PG::TypeMap derivation (such as PG::BasicTypeMapForQueries).
|
1790
|
+
* This will type cast the params form various Ruby types before transmission
|
1791
|
+
* based on the encoders defined by the type map. When a type encoder is used
|
1792
|
+
* the format and oid of a given bind parameter are retrieved from the encoder
|
1793
|
+
* instead out of the hash form described above.
|
1794
|
+
*
|
1599
1795
|
*/
|
1600
1796
|
static VALUE
|
1601
1797
|
pgconn_send_query(int argc, VALUE *argv, VALUE self)
|
1602
1798
|
{
|
1603
1799
|
PGconn *conn = pg_get_pgconn(self);
|
1604
1800
|
int result;
|
1605
|
-
VALUE command,
|
1606
|
-
VALUE param, param_type, param_value, param_format;
|
1607
|
-
VALUE param_value_tmp;
|
1608
|
-
VALUE sym_type, sym_value, sym_format;
|
1609
|
-
VALUE gc_array;
|
1801
|
+
VALUE command, in_res_fmt;
|
1610
1802
|
VALUE error;
|
1611
|
-
int i=0;
|
1612
1803
|
int nParams;
|
1613
|
-
Oid *paramTypes;
|
1614
|
-
char ** paramValues;
|
1615
|
-
int *paramLengths;
|
1616
|
-
int *paramFormats;
|
1617
1804
|
int resultFormat;
|
1805
|
+
struct query_params_data paramsData;
|
1618
1806
|
|
1619
|
-
rb_scan_args(argc, argv, "
|
1807
|
+
rb_scan_args(argc, argv, "13", &command, ¶msData.params, &in_res_fmt, ¶msData.typemap);
|
1808
|
+
paramsData.with_types = 1;
|
1620
1809
|
Check_Type(command, T_STRING);
|
1621
1810
|
|
1622
1811
|
/* If called with no parameters, use PQsendQuery */
|
1623
|
-
if(NIL_P(params)) {
|
1624
|
-
if(gvl_PQsendQuery(conn,
|
1812
|
+
if(NIL_P(paramsData.params)) {
|
1813
|
+
if(gvl_PQsendQuery(conn,StringValueCStr(command)) == 0) {
|
1625
1814
|
error = rb_exc_new2(rb_eUnableToSend, PQerrorMessage(conn));
|
1626
1815
|
rb_iv_set(error, "@connection", self);
|
1627
1816
|
rb_exc_raise(error);
|
@@ -1632,77 +1821,15 @@ pgconn_send_query(int argc, VALUE *argv, VALUE self)
|
|
1632
1821
|
/* If called with parameters, and optionally result_format,
|
1633
1822
|
* use PQsendQueryParams
|
1634
1823
|
*/
|
1635
|
-
Check_Type(params, T_ARRAY);
|
1636
|
-
|
1637
|
-
if(NIL_P(in_res_fmt)) {
|
1638
|
-
resultFormat = 0;
|
1639
|
-
}
|
1640
|
-
else {
|
1641
|
-
resultFormat = NUM2INT(in_res_fmt);
|
1642
|
-
}
|
1643
|
-
|
1644
|
-
gc_array = rb_ary_new();
|
1645
|
-
rb_gc_register_address(&gc_array);
|
1646
|
-
sym_type = ID2SYM(rb_intern("type"));
|
1647
|
-
sym_value = ID2SYM(rb_intern("value"));
|
1648
|
-
sym_format = ID2SYM(rb_intern("format"));
|
1649
|
-
nParams = (int)RARRAY_LEN(params);
|
1650
|
-
paramTypes = ALLOC_N(Oid, nParams);
|
1651
|
-
paramValues = ALLOC_N(char *, nParams);
|
1652
|
-
paramLengths = ALLOC_N(int, nParams);
|
1653
|
-
paramFormats = ALLOC_N(int, nParams);
|
1654
|
-
for(i = 0; i < nParams; i++) {
|
1655
|
-
param = rb_ary_entry(params, i);
|
1656
|
-
if (TYPE(param) == T_HASH) {
|
1657
|
-
param_type = rb_hash_aref(param, sym_type);
|
1658
|
-
param_value_tmp = rb_hash_aref(param, sym_value);
|
1659
|
-
if(param_value_tmp == Qnil)
|
1660
|
-
param_value = param_value_tmp;
|
1661
|
-
else
|
1662
|
-
param_value = rb_obj_as_string(param_value_tmp);
|
1663
|
-
param_format = rb_hash_aref(param, sym_format);
|
1664
|
-
}
|
1665
|
-
else {
|
1666
|
-
param_type = INT2NUM(0);
|
1667
|
-
if(param == Qnil)
|
1668
|
-
param_value = param;
|
1669
|
-
else
|
1670
|
-
param_value = rb_obj_as_string(param);
|
1671
|
-
param_format = INT2NUM(0);
|
1672
|
-
}
|
1673
|
-
|
1674
|
-
if(param_type == Qnil)
|
1675
|
-
paramTypes[i] = 0;
|
1676
|
-
else
|
1677
|
-
paramTypes[i] = NUM2INT(param_type);
|
1678
|
-
|
1679
|
-
if(param_value == Qnil) {
|
1680
|
-
paramValues[i] = NULL;
|
1681
|
-
paramLengths[i] = 0;
|
1682
|
-
}
|
1683
|
-
else {
|
1684
|
-
Check_Type(param_value, T_STRING);
|
1685
|
-
/* make sure param_value doesn't get freed by the GC */
|
1686
|
-
rb_ary_push(gc_array, param_value);
|
1687
|
-
paramValues[i] = StringValuePtr(param_value);
|
1688
|
-
paramLengths[i] = (int)RSTRING_LEN(param_value);
|
1689
|
-
}
|
1690
1824
|
|
1691
|
-
|
1692
|
-
|
1693
|
-
|
1694
|
-
paramFormats[i] = NUM2INT(param_format);
|
1695
|
-
}
|
1825
|
+
pgconn_query_assign_typemap( self, ¶msData );
|
1826
|
+
resultFormat = NIL_P(in_res_fmt) ? 0 : NUM2INT(in_res_fmt);
|
1827
|
+
nParams = alloc_query_params( ¶msData );
|
1696
1828
|
|
1697
|
-
result = gvl_PQsendQueryParams(conn,
|
1698
|
-
(const char * const *)
|
1829
|
+
result = gvl_PQsendQueryParams(conn, StringValueCStr(command), nParams, paramsData.types,
|
1830
|
+
(const char * const *)paramsData.values, paramsData.lengths, paramsData.formats, resultFormat);
|
1699
1831
|
|
1700
|
-
|
1701
|
-
|
1702
|
-
xfree(paramTypes);
|
1703
|
-
xfree(paramValues);
|
1704
|
-
xfree(paramLengths);
|
1705
|
-
xfree(paramFormats);
|
1832
|
+
free_query_params( ¶msData );
|
1706
1833
|
|
1707
1834
|
if(result == 0) {
|
1708
1835
|
error = rb_exc_new2(rb_eUnableToSend, PQerrorMessage(conn));
|
@@ -1754,14 +1881,13 @@ pgconn_send_prepare(int argc, VALUE *argv, VALUE self)
|
|
1754
1881
|
paramTypes = ALLOC_N(Oid, nParams);
|
1755
1882
|
for(i = 0; i < nParams; i++) {
|
1756
1883
|
param = rb_ary_entry(in_paramtypes, i);
|
1757
|
-
Check_Type(param, T_FIXNUM);
|
1758
1884
|
if(param == Qnil)
|
1759
1885
|
paramTypes[i] = 0;
|
1760
1886
|
else
|
1761
|
-
paramTypes[i] =
|
1887
|
+
paramTypes[i] = NUM2UINT(param);
|
1762
1888
|
}
|
1763
1889
|
}
|
1764
|
-
result = gvl_PQsendPrepare(conn,
|
1890
|
+
result = gvl_PQsendPrepare(conn, StringValueCStr(name), StringValueCStr(command),
|
1765
1891
|
nParams, paramTypes);
|
1766
1892
|
|
1767
1893
|
xfree(paramTypes);
|
@@ -1776,7 +1902,7 @@ pgconn_send_prepare(int argc, VALUE *argv, VALUE self)
|
|
1776
1902
|
|
1777
1903
|
/*
|
1778
1904
|
* call-seq:
|
1779
|
-
* conn.send_query_prepared( statement_name [, params, result_format ] )
|
1905
|
+
* conn.send_query_prepared( statement_name [, params, result_format[, type_map ]] )
|
1780
1906
|
* -> nil
|
1781
1907
|
*
|
1782
1908
|
* Execute prepared named statement specified by _statement_name_
|
@@ -1798,96 +1924,43 @@ pgconn_send_prepare(int argc, VALUE *argv, VALUE self)
|
|
1798
1924
|
*
|
1799
1925
|
* The optional +result_format+ should be 0 for text results, 1
|
1800
1926
|
* for binary.
|
1927
|
+
*
|
1928
|
+
* type_map can be a PG::TypeMap derivation (such as PG::BasicTypeMapForQueries).
|
1929
|
+
* This will type cast the params form various Ruby types before transmission
|
1930
|
+
* based on the encoders defined by the type map. When a type encoder is used
|
1931
|
+
* the format and oid of a given bind parameter are retrieved from the encoder
|
1932
|
+
* instead out of the hash form described above.
|
1933
|
+
*
|
1801
1934
|
*/
|
1802
1935
|
static VALUE
|
1803
1936
|
pgconn_send_query_prepared(int argc, VALUE *argv, VALUE self)
|
1804
1937
|
{
|
1805
1938
|
PGconn *conn = pg_get_pgconn(self);
|
1806
1939
|
int result;
|
1807
|
-
VALUE name,
|
1808
|
-
VALUE param, param_value, param_format;
|
1809
|
-
VALUE param_value_tmp;
|
1810
|
-
VALUE sym_value, sym_format;
|
1811
|
-
VALUE gc_array;
|
1940
|
+
VALUE name, in_res_fmt;
|
1812
1941
|
VALUE error;
|
1813
|
-
int i = 0;
|
1814
1942
|
int nParams;
|
1815
|
-
char ** paramValues;
|
1816
|
-
int *paramLengths;
|
1817
|
-
int *paramFormats;
|
1818
1943
|
int resultFormat;
|
1944
|
+
struct query_params_data paramsData;
|
1819
1945
|
|
1820
|
-
rb_scan_args(argc, argv, "
|
1946
|
+
rb_scan_args(argc, argv, "13", &name, ¶msData.params, &in_res_fmt, ¶msData.typemap);
|
1947
|
+
paramsData.with_types = 0;
|
1821
1948
|
Check_Type(name, T_STRING);
|
1822
1949
|
|
1823
|
-
if(NIL_P(params)) {
|
1824
|
-
params = rb_ary_new2(0);
|
1825
|
-
resultFormat = 0;
|
1826
|
-
}
|
1827
|
-
else {
|
1828
|
-
Check_Type(params, T_ARRAY);
|
1829
|
-
}
|
1830
|
-
|
1831
|
-
if(NIL_P(in_res_fmt)) {
|
1950
|
+
if(NIL_P(paramsData.params)) {
|
1951
|
+
paramsData.params = rb_ary_new2(0);
|
1832
1952
|
resultFormat = 0;
|
1833
1953
|
}
|
1834
|
-
|
1835
|
-
resultFormat = NUM2INT(in_res_fmt);
|
1836
|
-
}
|
1837
|
-
|
1838
|
-
gc_array = rb_ary_new();
|
1839
|
-
rb_gc_register_address(&gc_array);
|
1840
|
-
sym_value = ID2SYM(rb_intern("value"));
|
1841
|
-
sym_format = ID2SYM(rb_intern("format"));
|
1842
|
-
nParams = (int)RARRAY_LEN(params);
|
1843
|
-
paramValues = ALLOC_N(char *, nParams);
|
1844
|
-
paramLengths = ALLOC_N(int, nParams);
|
1845
|
-
paramFormats = ALLOC_N(int, nParams);
|
1846
|
-
for(i = 0; i < nParams; i++) {
|
1847
|
-
param = rb_ary_entry(params, i);
|
1848
|
-
if (TYPE(param) == T_HASH) {
|
1849
|
-
param_value_tmp = rb_hash_aref(param, sym_value);
|
1850
|
-
if(param_value_tmp == Qnil)
|
1851
|
-
param_value = param_value_tmp;
|
1852
|
-
else
|
1853
|
-
param_value = rb_obj_as_string(param_value_tmp);
|
1854
|
-
param_format = rb_hash_aref(param, sym_format);
|
1855
|
-
}
|
1856
|
-
else {
|
1857
|
-
if(param == Qnil)
|
1858
|
-
param_value = param;
|
1859
|
-
else
|
1860
|
-
param_value = rb_obj_as_string(param);
|
1861
|
-
param_format = INT2NUM(0);
|
1862
|
-
}
|
1863
|
-
|
1864
|
-
if(param_value == Qnil) {
|
1865
|
-
paramValues[i] = NULL;
|
1866
|
-
paramLengths[i] = 0;
|
1867
|
-
}
|
1868
|
-
else {
|
1869
|
-
Check_Type(param_value, T_STRING);
|
1870
|
-
/* make sure param_value doesn't get freed by the GC */
|
1871
|
-
rb_ary_push(gc_array, param_value);
|
1872
|
-
paramValues[i] = StringValuePtr(param_value);
|
1873
|
-
paramLengths[i] = (int)RSTRING_LEN(param_value);
|
1874
|
-
}
|
1954
|
+
pgconn_query_assign_typemap( self, ¶msData );
|
1875
1955
|
|
1876
|
-
|
1877
|
-
|
1878
|
-
else
|
1879
|
-
paramFormats[i] = NUM2INT(param_format);
|
1880
|
-
}
|
1956
|
+
resultFormat = NIL_P(in_res_fmt) ? 0 : NUM2INT(in_res_fmt);
|
1957
|
+
nParams = alloc_query_params( ¶msData );
|
1881
1958
|
|
1882
|
-
result = gvl_PQsendQueryPrepared(conn,
|
1883
|
-
(const char * const *)
|
1959
|
+
result = gvl_PQsendQueryPrepared(conn, StringValueCStr(name), nParams,
|
1960
|
+
(const char * const *)paramsData.values, paramsData.lengths, paramsData.formats,
|
1884
1961
|
resultFormat);
|
1885
1962
|
|
1886
|
-
|
1887
|
-
|
1888
|
-
xfree(paramValues);
|
1889
|
-
xfree(paramLengths);
|
1890
|
-
xfree(paramFormats);
|
1963
|
+
free_query_params( ¶msData );
|
1891
1964
|
|
1892
1965
|
if(result == 0) {
|
1893
1966
|
error = rb_exc_new2(rb_eUnableToSend, PQerrorMessage(conn));
|
@@ -1910,7 +1983,7 @@ pgconn_send_describe_prepared(VALUE self, VALUE stmt_name)
|
|
1910
1983
|
VALUE error;
|
1911
1984
|
PGconn *conn = pg_get_pgconn(self);
|
1912
1985
|
/* returns 0 on failure */
|
1913
|
-
if(gvl_PQsendDescribePrepared(conn,
|
1986
|
+
if(gvl_PQsendDescribePrepared(conn,StringValueCStr(stmt_name)) == 0) {
|
1914
1987
|
error = rb_exc_new2(rb_eUnableToSend, PQerrorMessage(conn));
|
1915
1988
|
rb_iv_set(error, "@connection", self);
|
1916
1989
|
rb_exc_raise(error);
|
@@ -1932,7 +2005,7 @@ pgconn_send_describe_portal(VALUE self, VALUE portal)
|
|
1932
2005
|
VALUE error;
|
1933
2006
|
PGconn *conn = pg_get_pgconn(self);
|
1934
2007
|
/* returns 0 on failure */
|
1935
|
-
if(gvl_PQsendDescribePortal(conn,
|
2008
|
+
if(gvl_PQsendDescribePortal(conn,StringValueCStr(portal)) == 0) {
|
1936
2009
|
error = rb_exc_new2(rb_eUnableToSend, PQerrorMessage(conn));
|
1937
2010
|
rb_iv_set(error, "@connection", self);
|
1938
2011
|
rb_exc_raise(error);
|
@@ -2157,10 +2230,8 @@ pgconn_notifies(VALUE self)
|
|
2157
2230
|
relname = rb_tainted_str_new2(notification->relname);
|
2158
2231
|
be_pid = INT2NUM(notification->be_pid);
|
2159
2232
|
extra = rb_tainted_str_new2(notification->extra);
|
2160
|
-
|
2161
|
-
|
2162
|
-
ENCODING_SET( extra, rb_enc_to_index(pg_conn_enc_get( conn )) );
|
2163
|
-
#endif
|
2233
|
+
PG_ENCODING_SET_NOCHECK( relname, ENCODING_GET(self) );
|
2234
|
+
PG_ENCODING_SET_NOCHECK( extra, ENCODING_GET(self) );
|
2164
2235
|
|
2165
2236
|
rb_hash_aset(hash, sym_relname, relname);
|
2166
2237
|
rb_hash_aset(hash, sym_be_pid, be_pid);
|
@@ -2429,16 +2500,12 @@ pgconn_wait_for_notify(int argc, VALUE *argv, VALUE self)
|
|
2429
2500
|
if ( !pnotification ) return Qnil;
|
2430
2501
|
|
2431
2502
|
relname = rb_tainted_str_new2( pnotification->relname );
|
2432
|
-
|
2433
|
-
ENCODING_SET( relname, rb_enc_to_index(pg_conn_enc_get( conn )) );
|
2434
|
-
#endif
|
2503
|
+
PG_ENCODING_SET_NOCHECK( relname, ENCODING_GET(self) );
|
2435
2504
|
be_pid = INT2NUM( pnotification->be_pid );
|
2436
2505
|
#ifdef HAVE_ST_NOTIFY_EXTRA
|
2437
2506
|
if ( *pnotification->extra ) {
|
2438
2507
|
extra = rb_tainted_str_new2( pnotification->extra );
|
2439
|
-
|
2440
|
-
ENCODING_SET( extra, rb_enc_to_index(pg_conn_enc_get( conn )) );
|
2441
|
-
#endif
|
2508
|
+
PG_ENCODING_SET_NOCHECK( extra, ENCODING_GET(self) );
|
2442
2509
|
}
|
2443
2510
|
#endif
|
2444
2511
|
PQfreemem( pnotification );
|
@@ -2452,33 +2519,77 @@ pgconn_wait_for_notify(int argc, VALUE *argv, VALUE self)
|
|
2452
2519
|
|
2453
2520
|
/*
|
2454
2521
|
* call-seq:
|
2455
|
-
* conn.put_copy_data( buffer ) -> Boolean
|
2522
|
+
* conn.put_copy_data( buffer [, encoder] ) -> Boolean
|
2456
2523
|
*
|
2457
2524
|
* Transmits _buffer_ as copy data to the server.
|
2458
2525
|
* Returns true if the data was sent, false if it was
|
2459
2526
|
* not sent (false is only possible if the connection
|
2460
2527
|
* is in nonblocking mode, and this command would block).
|
2461
2528
|
*
|
2529
|
+
* encoder can be a PG::Coder derivation (typically PG::TextEncoder::CopyRow).
|
2530
|
+
* This encodes the received data fields from an Array of Strings. Optionally
|
2531
|
+
* the encoder can type cast the fields form various Ruby types in one step,
|
2532
|
+
* if PG::TextEncoder::CopyRow#type_map is set accordingly.
|
2533
|
+
*
|
2462
2534
|
* Raises an exception if an error occurs.
|
2463
2535
|
*
|
2464
2536
|
* See also #copy_data.
|
2465
2537
|
*
|
2466
2538
|
*/
|
2467
2539
|
static VALUE
|
2468
|
-
pgconn_put_copy_data(
|
2469
|
-
VALUE self, buffer;
|
2540
|
+
pgconn_put_copy_data(int argc, VALUE *argv, VALUE self)
|
2470
2541
|
{
|
2471
2542
|
int ret;
|
2472
|
-
|
2473
|
-
|
2543
|
+
int len;
|
2544
|
+
t_pg_connection *this = pg_get_connection_safe( self );
|
2545
|
+
VALUE value;
|
2546
|
+
VALUE buffer = Qnil;
|
2547
|
+
VALUE encoder;
|
2548
|
+
VALUE intermediate;
|
2549
|
+
t_pg_coder *p_coder = NULL;
|
2550
|
+
|
2551
|
+
rb_scan_args( argc, argv, "11", &value, &encoder );
|
2552
|
+
|
2553
|
+
if( NIL_P(encoder) ){
|
2554
|
+
if( NIL_P(this->encoder_for_put_copy_data) ){
|
2555
|
+
buffer = value;
|
2556
|
+
} else {
|
2557
|
+
p_coder = DATA_PTR( this->encoder_for_put_copy_data );
|
2558
|
+
}
|
2559
|
+
} else if( rb_obj_is_kind_of(encoder, rb_cPG_Coder) ) {
|
2560
|
+
Data_Get_Struct( encoder, t_pg_coder, p_coder );
|
2561
|
+
} else {
|
2562
|
+
rb_raise( rb_eTypeError, "wrong encoder type %s (expected some kind of PG::Coder)",
|
2563
|
+
rb_obj_classname( encoder ) );
|
2564
|
+
}
|
2565
|
+
|
2566
|
+
if( p_coder ){
|
2567
|
+
t_pg_coder_enc_func enc_func;
|
2568
|
+
|
2569
|
+
enc_func = pg_coder_enc_func( p_coder );
|
2570
|
+
len = enc_func( p_coder, value, NULL, &intermediate );
|
2571
|
+
|
2572
|
+
if( len == -1 ){
|
2573
|
+
/* The intermediate value is a String that can be used directly. */
|
2574
|
+
buffer = intermediate;
|
2575
|
+
} else {
|
2576
|
+
buffer = rb_str_new(NULL, len);
|
2577
|
+
len = enc_func( p_coder, value, RSTRING_PTR(buffer), &intermediate);
|
2578
|
+
rb_str_set_len( buffer, len );
|
2579
|
+
}
|
2580
|
+
}
|
2581
|
+
|
2474
2582
|
Check_Type(buffer, T_STRING);
|
2475
2583
|
|
2476
|
-
ret = gvl_PQputCopyData(
|
2584
|
+
ret = gvl_PQputCopyData(this->pgconn, RSTRING_PTR(buffer), RSTRING_LENINT(buffer));
|
2477
2585
|
if(ret == -1) {
|
2478
|
-
error = rb_exc_new2(rb_ePGerror, PQerrorMessage(
|
2586
|
+
VALUE error = rb_exc_new2(rb_ePGerror, PQerrorMessage(this->pgconn));
|
2479
2587
|
rb_iv_set(error, "@connection", self);
|
2480
2588
|
rb_exc_raise(error);
|
2481
2589
|
}
|
2590
|
+
RB_GC_GUARD(intermediate);
|
2591
|
+
RB_GC_GUARD(buffer);
|
2592
|
+
|
2482
2593
|
return (ret) ? Qtrue : Qfalse;
|
2483
2594
|
}
|
2484
2595
|
|
@@ -2508,7 +2619,7 @@ pgconn_put_copy_end(int argc, VALUE *argv, VALUE self)
|
|
2508
2619
|
if (rb_scan_args(argc, argv, "01", &str) == 0)
|
2509
2620
|
error_message = NULL;
|
2510
2621
|
else
|
2511
|
-
error_message =
|
2622
|
+
error_message = StringValueCStr(str);
|
2512
2623
|
|
2513
2624
|
ret = gvl_PQputCopyEnd(conn, error_message);
|
2514
2625
|
if(ret == -1) {
|
@@ -2521,12 +2632,17 @@ pgconn_put_copy_end(int argc, VALUE *argv, VALUE self)
|
|
2521
2632
|
|
2522
2633
|
/*
|
2523
2634
|
* call-seq:
|
2524
|
-
* conn.get_copy_data( [ async = false ] ) -> String
|
2635
|
+
* conn.get_copy_data( [ async = false [, decoder = nil ]] ) -> String
|
2525
2636
|
*
|
2526
2637
|
* Return a string containing one row of data, +nil+
|
2527
2638
|
* if the copy is done, or +false+ if the call would
|
2528
2639
|
* block (only possible if _async_ is true).
|
2529
2640
|
*
|
2641
|
+
* decoder can be a PG::Coder derivation (typically PG::TextDecoder::CopyRow).
|
2642
|
+
* This decodes the received data fields as Array of Strings. Optionally
|
2643
|
+
* the decoder can type cast the fields to various Ruby types in one step,
|
2644
|
+
* if PG::TextDecoder::CopyRow#type_map is set accordingly.
|
2645
|
+
*
|
2530
2646
|
* See also #copy_data.
|
2531
2647
|
*
|
2532
2648
|
*/
|
@@ -2535,20 +2651,29 @@ pgconn_get_copy_data(int argc, VALUE *argv, VALUE self )
|
|
2535
2651
|
{
|
2536
2652
|
VALUE async_in;
|
2537
2653
|
VALUE error;
|
2538
|
-
VALUE
|
2654
|
+
VALUE result;
|
2539
2655
|
int ret;
|
2540
|
-
int async;
|
2541
2656
|
char *buffer;
|
2542
|
-
|
2657
|
+
VALUE decoder;
|
2658
|
+
t_pg_coder *p_coder = NULL;
|
2659
|
+
t_pg_connection *this = pg_get_connection_safe( self );
|
2543
2660
|
|
2544
|
-
|
2545
|
-
async = 0;
|
2546
|
-
else
|
2547
|
-
async = (async_in == Qfalse || async_in == Qnil) ? 0 : 1;
|
2661
|
+
rb_scan_args(argc, argv, "02", &async_in, &decoder);
|
2548
2662
|
|
2549
|
-
|
2663
|
+
if( NIL_P(decoder) ){
|
2664
|
+
if( !NIL_P(this->decoder_for_get_copy_data) ){
|
2665
|
+
p_coder = DATA_PTR( this->decoder_for_get_copy_data );
|
2666
|
+
}
|
2667
|
+
} else if( rb_obj_is_kind_of(decoder, rb_cPG_Coder) ) {
|
2668
|
+
Data_Get_Struct( decoder, t_pg_coder, p_coder );
|
2669
|
+
} else {
|
2670
|
+
rb_raise( rb_eTypeError, "wrong decoder type %s (expected some kind of PG::Coder)",
|
2671
|
+
rb_obj_classname( decoder ) );
|
2672
|
+
}
|
2673
|
+
|
2674
|
+
ret = gvl_PQgetCopyData(this->pgconn, &buffer, RTEST(async_in));
|
2550
2675
|
if(ret == -2) { /* error */
|
2551
|
-
error = rb_exc_new2(rb_ePGerror, PQerrorMessage(
|
2676
|
+
error = rb_exc_new2(rb_ePGerror, PQerrorMessage(this->pgconn));
|
2552
2677
|
rb_iv_set(error, "@connection", self);
|
2553
2678
|
rb_exc_raise(error);
|
2554
2679
|
}
|
@@ -2558,9 +2683,16 @@ pgconn_get_copy_data(int argc, VALUE *argv, VALUE self )
|
|
2558
2683
|
if(ret == 0) { /* would block */
|
2559
2684
|
return Qfalse;
|
2560
2685
|
}
|
2561
|
-
|
2686
|
+
|
2687
|
+
if( p_coder ){
|
2688
|
+
t_pg_coder_dec_func dec_func = pg_coder_dec_func( p_coder, p_coder->format );
|
2689
|
+
result = dec_func( p_coder, buffer, ret, 0, 0, ENCODING_GET(self) );
|
2690
|
+
} else {
|
2691
|
+
result = rb_tainted_str_new(buffer, ret);
|
2692
|
+
}
|
2693
|
+
|
2562
2694
|
PQfreemem(buffer);
|
2563
|
-
return
|
2695
|
+
return result;
|
2564
2696
|
}
|
2565
2697
|
|
2566
2698
|
/*
|
@@ -2597,6 +2729,7 @@ pgconn_trace(VALUE self, VALUE stream)
|
|
2597
2729
|
FILE *new_fp;
|
2598
2730
|
int old_fd, new_fd;
|
2599
2731
|
VALUE new_file;
|
2732
|
+
t_pg_connection *this = pg_get_connection_safe( self );
|
2600
2733
|
|
2601
2734
|
if(rb_respond_to(stream,rb_intern("fileno")) == Qfalse)
|
2602
2735
|
rb_raise(rb_eArgError, "stream does not respond to method: fileno");
|
@@ -2619,9 +2752,9 @@ pgconn_trace(VALUE self, VALUE stream)
|
|
2619
2752
|
rb_raise(rb_eArgError, "stream is not writable");
|
2620
2753
|
|
2621
2754
|
new_file = rb_funcall(rb_cIO, rb_intern("new"), 1, INT2NUM(new_fd));
|
2622
|
-
|
2755
|
+
this->trace_stream = new_file;
|
2623
2756
|
|
2624
|
-
PQtrace(
|
2757
|
+
PQtrace(this->pgconn, new_fp);
|
2625
2758
|
return Qnil;
|
2626
2759
|
}
|
2627
2760
|
|
@@ -2634,11 +2767,11 @@ pgconn_trace(VALUE self, VALUE stream)
|
|
2634
2767
|
static VALUE
|
2635
2768
|
pgconn_untrace(VALUE self)
|
2636
2769
|
{
|
2637
|
-
|
2638
|
-
|
2639
|
-
|
2640
|
-
rb_funcall(trace_stream, rb_intern("close"), 0);
|
2641
|
-
|
2770
|
+
t_pg_connection *this = pg_get_connection_safe( self );
|
2771
|
+
|
2772
|
+
PQuntrace(this->pgconn);
|
2773
|
+
rb_funcall(this->trace_stream, rb_intern("close"), 0);
|
2774
|
+
this->trace_stream = Qnil;
|
2642
2775
|
return Qnil;
|
2643
2776
|
}
|
2644
2777
|
|
@@ -2648,19 +2781,16 @@ pgconn_untrace(VALUE self)
|
|
2648
2781
|
* currently-registered Ruby notice_receiver object.
|
2649
2782
|
*/
|
2650
2783
|
void
|
2651
|
-
notice_receiver_proxy(void *arg, const PGresult *
|
2784
|
+
notice_receiver_proxy(void *arg, const PGresult *pgresult)
|
2652
2785
|
{
|
2653
|
-
VALUE proc;
|
2654
2786
|
VALUE self = (VALUE)arg;
|
2787
|
+
t_pg_connection *this = pg_get_connection( self );
|
2655
2788
|
|
2656
|
-
if (
|
2657
|
-
VALUE
|
2658
|
-
|
2659
|
-
|
2660
|
-
|
2661
|
-
ENCODING_SET( val, rb_enc_to_index(enc) );
|
2662
|
-
#endif
|
2663
|
-
rb_funcall(proc, rb_intern("call"), 1, val);
|
2789
|
+
if (this->notice_receiver != Qnil) {
|
2790
|
+
VALUE result = pg_new_result_autoclear( (PGresult *)pgresult, self );
|
2791
|
+
|
2792
|
+
rb_funcall(this->notice_receiver, rb_intern("call"), 1, result);
|
2793
|
+
pg_result_clear( result );
|
2664
2794
|
}
|
2665
2795
|
return;
|
2666
2796
|
}
|
@@ -2698,7 +2828,7 @@ static VALUE
|
|
2698
2828
|
pgconn_set_notice_receiver(VALUE self)
|
2699
2829
|
{
|
2700
2830
|
VALUE proc, old_proc;
|
2701
|
-
|
2831
|
+
t_pg_connection *this = pg_get_connection_safe( self );
|
2702
2832
|
|
2703
2833
|
/* If default_notice_receiver is unset, assume that the current
|
2704
2834
|
* notice receiver is the default, and save it to a global variable.
|
@@ -2706,19 +2836,19 @@ pgconn_set_notice_receiver(VALUE self)
|
|
2706
2836
|
* always the same, so won't vary among connections.
|
2707
2837
|
*/
|
2708
2838
|
if(default_notice_receiver == NULL)
|
2709
|
-
default_notice_receiver = PQsetNoticeReceiver(
|
2839
|
+
default_notice_receiver = PQsetNoticeReceiver(this->pgconn, NULL, NULL);
|
2710
2840
|
|
2711
|
-
old_proc =
|
2841
|
+
old_proc = this->notice_receiver;
|
2712
2842
|
if( rb_block_given_p() ) {
|
2713
2843
|
proc = rb_block_proc();
|
2714
|
-
PQsetNoticeReceiver(
|
2844
|
+
PQsetNoticeReceiver(this->pgconn, gvl_notice_receiver_proxy, (void *)self);
|
2715
2845
|
} else {
|
2716
2846
|
/* if no block is given, set back to default */
|
2717
2847
|
proc = Qnil;
|
2718
|
-
PQsetNoticeReceiver(
|
2848
|
+
PQsetNoticeReceiver(this->pgconn, default_notice_receiver, NULL);
|
2719
2849
|
}
|
2720
2850
|
|
2721
|
-
|
2851
|
+
this->notice_receiver = proc;
|
2722
2852
|
return old_proc;
|
2723
2853
|
}
|
2724
2854
|
|
@@ -2730,17 +2860,13 @@ pgconn_set_notice_receiver(VALUE self)
|
|
2730
2860
|
void
|
2731
2861
|
notice_processor_proxy(void *arg, const char *message)
|
2732
2862
|
{
|
2733
|
-
VALUE proc;
|
2734
2863
|
VALUE self = (VALUE)arg;
|
2864
|
+
t_pg_connection *this = pg_get_connection( self );
|
2735
2865
|
|
2736
|
-
if (
|
2866
|
+
if (this->notice_receiver != Qnil) {
|
2737
2867
|
VALUE message_str = rb_tainted_str_new2(message);
|
2738
|
-
|
2739
|
-
|
2740
|
-
rb_encoding *enc = pg_conn_enc_get( conn );
|
2741
|
-
ENCODING_SET( message_str, rb_enc_to_index(enc) );
|
2742
|
-
#endif
|
2743
|
-
rb_funcall(proc, rb_intern("call"), 1, message_str);
|
2868
|
+
PG_ENCODING_SET_NOCHECK( message_str, ENCODING_GET(self) );
|
2869
|
+
rb_funcall(this->notice_receiver, rb_intern("call"), 1, message_str);
|
2744
2870
|
}
|
2745
2871
|
return;
|
2746
2872
|
}
|
@@ -2762,7 +2888,7 @@ static VALUE
|
|
2762
2888
|
pgconn_set_notice_processor(VALUE self)
|
2763
2889
|
{
|
2764
2890
|
VALUE proc, old_proc;
|
2765
|
-
|
2891
|
+
t_pg_connection *this = pg_get_connection_safe( self );
|
2766
2892
|
|
2767
2893
|
/* If default_notice_processor is unset, assume that the current
|
2768
2894
|
* notice processor is the default, and save it to a global variable.
|
@@ -2770,19 +2896,19 @@ pgconn_set_notice_processor(VALUE self)
|
|
2770
2896
|
* always the same, so won't vary among connections.
|
2771
2897
|
*/
|
2772
2898
|
if(default_notice_processor == NULL)
|
2773
|
-
default_notice_processor = PQsetNoticeProcessor(
|
2899
|
+
default_notice_processor = PQsetNoticeProcessor(this->pgconn, NULL, NULL);
|
2774
2900
|
|
2775
|
-
old_proc =
|
2901
|
+
old_proc = this->notice_receiver;
|
2776
2902
|
if( rb_block_given_p() ) {
|
2777
2903
|
proc = rb_block_proc();
|
2778
|
-
PQsetNoticeProcessor(
|
2904
|
+
PQsetNoticeProcessor(this->pgconn, gvl_notice_processor_proxy, (void *)self);
|
2779
2905
|
} else {
|
2780
2906
|
/* if no block is given, set back to default */
|
2781
2907
|
proc = Qnil;
|
2782
|
-
PQsetNoticeProcessor(
|
2908
|
+
PQsetNoticeProcessor(this->pgconn, default_notice_processor, NULL);
|
2783
2909
|
}
|
2784
2910
|
|
2785
|
-
|
2911
|
+
this->notice_receiver = proc;
|
2786
2912
|
return old_proc;
|
2787
2913
|
}
|
2788
2914
|
|
@@ -2814,9 +2940,12 @@ pgconn_set_client_encoding(VALUE self, VALUE str)
|
|
2814
2940
|
|
2815
2941
|
Check_Type(str, T_STRING);
|
2816
2942
|
|
2817
|
-
if ( (PQsetClientEncoding(conn,
|
2818
|
-
rb_raise(rb_ePGerror, "invalid encoding name: %s",
|
2943
|
+
if ( (PQsetClientEncoding(conn, StringValueCStr(str))) == -1 ) {
|
2944
|
+
rb_raise(rb_ePGerror, "invalid encoding name: %s",StringValueCStr(str));
|
2819
2945
|
}
|
2946
|
+
#ifdef M17N_SUPPORTED
|
2947
|
+
pgconn_set_internal_encoding_index( self );
|
2948
|
+
#endif
|
2820
2949
|
|
2821
2950
|
return Qnil;
|
2822
2951
|
}
|
@@ -2868,7 +2997,9 @@ pgconn_transaction(VALUE self)
|
|
2868
2997
|
/*
|
2869
2998
|
* call-seq:
|
2870
2999
|
* PG::Connection.quote_ident( str ) -> String
|
3000
|
+
* PG::Connection.quote_ident( array ) -> String
|
2871
3001
|
* conn.quote_ident( str ) -> String
|
3002
|
+
* conn.quote_ident( array ) -> String
|
2872
3003
|
*
|
2873
3004
|
* Returns a string that is safe for inclusion in a SQL query as an
|
2874
3005
|
* identifier. Note: this is not a quote function for values, but for
|
@@ -2885,45 +3016,22 @@ pgconn_transaction(VALUE self)
|
|
2885
3016
|
* Similarly, this function also protects against special characters,
|
2886
3017
|
* and other things that might allow SQL injection if the identifier
|
2887
3018
|
* comes from an untrusted source.
|
3019
|
+
*
|
3020
|
+
* If the parameter is an Array, then all it's values are separately quoted
|
3021
|
+
* and then joined by a "." character. This can be used for identifiers in
|
3022
|
+
* the form "schema"."table"."column" .
|
3023
|
+
*
|
3024
|
+
* This method is functional identical to the encoder PG::TextEncoder::Identifier .
|
3025
|
+
*
|
2888
3026
|
*/
|
2889
3027
|
static VALUE
|
2890
3028
|
pgconn_s_quote_ident(VALUE self, VALUE in_str)
|
2891
3029
|
{
|
2892
3030
|
VALUE ret;
|
2893
|
-
|
2894
|
-
/* result size at most NAMEDATALEN*2 plus surrounding
|
2895
|
-
* double-quotes. */
|
2896
|
-
char buffer[NAMEDATALEN*2+2];
|
2897
|
-
unsigned int i=0,j=0;
|
2898
|
-
#ifdef M17N_SUPPORTED
|
2899
|
-
rb_encoding* enc;
|
2900
|
-
#endif
|
2901
|
-
|
2902
|
-
UNUSED( self );
|
3031
|
+
pg_text_enc_identifier(NULL, in_str, NULL, &ret);
|
2903
3032
|
|
2904
|
-
if(strlen(str) >= NAMEDATALEN) {
|
2905
|
-
rb_raise(rb_eArgError,
|
2906
|
-
"Input string is longer than NAMEDATALEN-1 (%d)",
|
2907
|
-
NAMEDATALEN-1);
|
2908
|
-
}
|
2909
|
-
buffer[j++] = '"';
|
2910
|
-
for(i = 0; i < strlen(str) && str[i]; i++) {
|
2911
|
-
if(str[i] == '"')
|
2912
|
-
buffer[j++] = '"';
|
2913
|
-
buffer[j++] = str[i];
|
2914
|
-
}
|
2915
|
-
buffer[j++] = '"';
|
2916
|
-
ret = rb_str_new(buffer,j);
|
2917
3033
|
OBJ_INFECT(ret, in_str);
|
2918
|
-
|
2919
|
-
#ifdef M17N_SUPPORTED
|
2920
|
-
if ( rb_obj_class(self) == rb_cPGconn ) {
|
2921
|
-
enc = pg_conn_enc_get( pg_get_pgconn(self) );
|
2922
|
-
} else {
|
2923
|
-
enc = rb_enc_get(in_str);
|
2924
|
-
}
|
2925
|
-
rb_enc_associate(ret, enc);
|
2926
|
-
#endif
|
3034
|
+
PG_ENCODING_SET_NOCHECK(ret, ENCODING_GET( rb_obj_is_kind_of(self, rb_cPGconn) ? self : in_str ));
|
2927
3035
|
|
2928
3036
|
return ret;
|
2929
3037
|
}
|
@@ -3077,7 +3185,7 @@ pgconn_locreat(int argc, VALUE *argv, VALUE self)
|
|
3077
3185
|
if (lo_oid == 0)
|
3078
3186
|
rb_raise(rb_ePGerror, "lo_creat failed");
|
3079
3187
|
|
3080
|
-
return
|
3188
|
+
return UINT2NUM(lo_oid);
|
3081
3189
|
}
|
3082
3190
|
|
3083
3191
|
/*
|
@@ -3092,13 +3200,13 @@ pgconn_locreate(VALUE self, VALUE in_lo_oid)
|
|
3092
3200
|
{
|
3093
3201
|
Oid ret, lo_oid;
|
3094
3202
|
PGconn *conn = pg_get_pgconn(self);
|
3095
|
-
lo_oid =
|
3203
|
+
lo_oid = NUM2UINT(in_lo_oid);
|
3096
3204
|
|
3097
3205
|
ret = lo_create(conn, lo_oid);
|
3098
3206
|
if (ret == InvalidOid)
|
3099
3207
|
rb_raise(rb_ePGerror, "lo_create failed");
|
3100
3208
|
|
3101
|
-
return
|
3209
|
+
return UINT2NUM(ret);
|
3102
3210
|
}
|
3103
3211
|
|
3104
3212
|
/*
|
@@ -3118,11 +3226,11 @@ pgconn_loimport(VALUE self, VALUE filename)
|
|
3118
3226
|
|
3119
3227
|
Check_Type(filename, T_STRING);
|
3120
3228
|
|
3121
|
-
lo_oid = lo_import(conn,
|
3229
|
+
lo_oid = lo_import(conn, StringValueCStr(filename));
|
3122
3230
|
if (lo_oid == 0) {
|
3123
3231
|
rb_raise(rb_ePGerror, "%s", PQerrorMessage(conn));
|
3124
3232
|
}
|
3125
|
-
return
|
3233
|
+
return UINT2NUM(lo_oid);
|
3126
3234
|
}
|
3127
3235
|
|
3128
3236
|
/*
|
@@ -3135,15 +3243,12 @@ static VALUE
|
|
3135
3243
|
pgconn_loexport(VALUE self, VALUE lo_oid, VALUE filename)
|
3136
3244
|
{
|
3137
3245
|
PGconn *conn = pg_get_pgconn(self);
|
3138
|
-
|
3246
|
+
Oid oid;
|
3139
3247
|
Check_Type(filename, T_STRING);
|
3140
3248
|
|
3141
|
-
oid =
|
3142
|
-
if (oid < 0) {
|
3143
|
-
rb_raise(rb_ePGerror, "invalid large object oid %d",oid);
|
3144
|
-
}
|
3249
|
+
oid = NUM2UINT(lo_oid);
|
3145
3250
|
|
3146
|
-
if (lo_export(conn, oid,
|
3251
|
+
if (lo_export(conn, oid, StringValueCStr(filename)) < 0) {
|
3147
3252
|
rb_raise(rb_ePGerror, "%s", PQerrorMessage(conn));
|
3148
3253
|
}
|
3149
3254
|
return Qnil;
|
@@ -3168,7 +3273,7 @@ pgconn_loopen(int argc, VALUE *argv, VALUE self)
|
|
3168
3273
|
PGconn *conn = pg_get_pgconn(self);
|
3169
3274
|
|
3170
3275
|
rb_scan_args(argc, argv, "11", &selfid, &nmode);
|
3171
|
-
lo_oid =
|
3276
|
+
lo_oid = NUM2UINT(selfid);
|
3172
3277
|
if(NIL_P(nmode))
|
3173
3278
|
mode = INV_READ;
|
3174
3279
|
else
|
@@ -3335,10 +3440,7 @@ static VALUE
|
|
3335
3440
|
pgconn_lounlink(VALUE self, VALUE in_oid)
|
3336
3441
|
{
|
3337
3442
|
PGconn *conn = pg_get_pgconn(self);
|
3338
|
-
|
3339
|
-
|
3340
|
-
if (oid < 0)
|
3341
|
-
rb_raise(rb_ePGerror, "invalid oid %d",oid);
|
3443
|
+
Oid oid = NUM2UINT(in_oid);
|
3342
3444
|
|
3343
3445
|
if(lo_unlink(conn,oid) < 0)
|
3344
3446
|
rb_raise(rb_ePGerror,"lo_unlink failed");
|
@@ -3349,6 +3451,14 @@ pgconn_lounlink(VALUE self, VALUE in_oid)
|
|
3349
3451
|
|
3350
3452
|
#ifdef M17N_SUPPORTED
|
3351
3453
|
|
3454
|
+
void
|
3455
|
+
pgconn_set_internal_encoding_index( VALUE self )
|
3456
|
+
{
|
3457
|
+
PGconn *conn = pg_get_pgconn(self);
|
3458
|
+
rb_encoding *enc = pg_conn_enc_get( conn );
|
3459
|
+
PG_ENCODING_SET_NOCHECK( self, rb_enc_to_index(enc));
|
3460
|
+
}
|
3461
|
+
|
3352
3462
|
/*
|
3353
3463
|
* call-seq:
|
3354
3464
|
* conn.internal_encoding -> Encoding
|
@@ -3389,11 +3499,12 @@ static VALUE pgconn_external_encoding(VALUE self);
|
|
3389
3499
|
static VALUE
|
3390
3500
|
pgconn_internal_encoding_set(VALUE self, VALUE enc)
|
3391
3501
|
{
|
3502
|
+
VALUE enc_inspect;
|
3392
3503
|
if (NIL_P(enc)) {
|
3393
3504
|
pgconn_set_client_encoding( self, rb_usascii_str_new_cstr("SQL_ASCII") );
|
3394
3505
|
return enc;
|
3395
3506
|
}
|
3396
|
-
else if ( TYPE(enc) == T_STRING && strcasecmp("JOHAB",
|
3507
|
+
else if ( TYPE(enc) == T_STRING && strcasecmp("JOHAB", StringValueCStr(enc)) == 0 ) {
|
3397
3508
|
pgconn_set_client_encoding(self, rb_usascii_str_new_cstr("JOHAB"));
|
3398
3509
|
return enc;
|
3399
3510
|
}
|
@@ -3406,10 +3517,12 @@ pgconn_internal_encoding_set(VALUE self, VALUE enc)
|
|
3406
3517
|
rb_raise( rb_eEncCompatError, "incompatible character encodings: %s and %s",
|
3407
3518
|
rb_enc_name(rb_to_encoding(server_encoding)), name );
|
3408
3519
|
}
|
3520
|
+
pgconn_set_internal_encoding_index( self );
|
3409
3521
|
return enc;
|
3410
3522
|
}
|
3411
3523
|
|
3412
|
-
|
3524
|
+
enc_inspect = rb_inspect(enc);
|
3525
|
+
rb_raise( rb_ePGerror, "unknown encoding: %s", StringValueCStr(enc_inspect) );
|
3413
3526
|
|
3414
3527
|
return Qnil;
|
3415
3528
|
}
|
@@ -3426,21 +3539,18 @@ pgconn_internal_encoding_set(VALUE self, VALUE enc)
|
|
3426
3539
|
static VALUE
|
3427
3540
|
pgconn_external_encoding(VALUE self)
|
3428
3541
|
{
|
3429
|
-
|
3430
|
-
VALUE encoding = rb_iv_get( self, "@external_encoding" );
|
3542
|
+
t_pg_connection *this = pg_get_connection_safe( self );
|
3431
3543
|
rb_encoding *enc = NULL;
|
3432
3544
|
const char *pg_encname = NULL;
|
3433
3545
|
|
3434
3546
|
/* Use cached value if found */
|
3435
|
-
if ( RTEST(
|
3547
|
+
if ( RTEST(this->external_encoding) ) return this->external_encoding;
|
3436
3548
|
|
3437
|
-
pg_encname = PQparameterStatus(
|
3549
|
+
pg_encname = PQparameterStatus( this->pgconn, "server_encoding" );
|
3438
3550
|
enc = pg_get_pg_encname_as_rb_encoding( pg_encname );
|
3439
|
-
|
3440
|
-
|
3441
|
-
rb_iv_set( self, "@external_encoding", encoding );
|
3551
|
+
this->external_encoding = rb_enc_from_encoding( enc );
|
3442
3552
|
|
3443
|
-
return
|
3553
|
+
return this->external_encoding;
|
3444
3554
|
}
|
3445
3555
|
|
3446
3556
|
|
@@ -3465,8 +3575,10 @@ pgconn_set_default_encoding( VALUE self )
|
|
3465
3575
|
if ( PQsetClientEncoding(conn, encname) != 0 )
|
3466
3576
|
rb_warn( "Failed to set the default_internal encoding to %s: '%s'",
|
3467
3577
|
encname, PQerrorMessage(conn) );
|
3578
|
+
pgconn_set_internal_encoding_index( self );
|
3468
3579
|
return rb_enc_from_encoding( enc );
|
3469
3580
|
} else {
|
3581
|
+
pgconn_set_internal_encoding_index( self );
|
3470
3582
|
return Qnil;
|
3471
3583
|
}
|
3472
3584
|
}
|
@@ -3474,11 +3586,193 @@ pgconn_set_default_encoding( VALUE self )
|
|
3474
3586
|
|
3475
3587
|
#endif /* M17N_SUPPORTED */
|
3476
3588
|
|
3589
|
+
/*
|
3590
|
+
* call-seq:
|
3591
|
+
* res.type_map_for_queries = typemap
|
3592
|
+
*
|
3593
|
+
* Set the default TypeMap that is used for type casts of query bind parameters.
|
3594
|
+
*
|
3595
|
+
* +typemap+ must be a kind of PG::TypeMap .
|
3596
|
+
*
|
3597
|
+
*/
|
3598
|
+
static VALUE
|
3599
|
+
pgconn_type_map_for_queries_set(VALUE self, VALUE typemap)
|
3600
|
+
{
|
3601
|
+
t_pg_connection *this = pg_get_connection( self );
|
3602
|
+
|
3603
|
+
if ( !rb_obj_is_kind_of(typemap, rb_cTypeMap) ) {
|
3604
|
+
rb_raise( rb_eTypeError, "wrong argument type %s (expected kind of PG::TypeMap)",
|
3605
|
+
rb_obj_classname( typemap ) );
|
3606
|
+
}
|
3607
|
+
Check_Type(typemap, T_DATA);
|
3608
|
+
this->type_map_for_queries = typemap;
|
3609
|
+
|
3610
|
+
return typemap;
|
3611
|
+
}
|
3612
|
+
|
3613
|
+
/*
|
3614
|
+
* call-seq:
|
3615
|
+
* res.type_map_for_queries -> TypeMap
|
3616
|
+
*
|
3617
|
+
* Returns the default TypeMap that is currently set for type casts of query
|
3618
|
+
* bind parameters.
|
3619
|
+
*
|
3620
|
+
*/
|
3621
|
+
static VALUE
|
3622
|
+
pgconn_type_map_for_queries_get(VALUE self)
|
3623
|
+
{
|
3624
|
+
t_pg_connection *this = pg_get_connection( self );
|
3625
|
+
|
3626
|
+
return this->type_map_for_queries;
|
3627
|
+
}
|
3628
|
+
|
3629
|
+
/*
|
3630
|
+
* call-seq:
|
3631
|
+
* res.type_map_for_results = typemap
|
3632
|
+
*
|
3633
|
+
* Set the default TypeMap that is used for type casts of result values.
|
3634
|
+
*
|
3635
|
+
* +typemap+ must be a kind of PG::TypeMap .
|
3636
|
+
*
|
3637
|
+
*/
|
3638
|
+
static VALUE
|
3639
|
+
pgconn_type_map_for_results_set(VALUE self, VALUE typemap)
|
3640
|
+
{
|
3641
|
+
t_pg_connection *this = pg_get_connection( self );
|
3642
|
+
|
3643
|
+
if ( !rb_obj_is_kind_of(typemap, rb_cTypeMap) ) {
|
3644
|
+
rb_raise( rb_eTypeError, "wrong argument type %s (expected kind of PG::TypeMap)",
|
3645
|
+
rb_obj_classname( typemap ) );
|
3646
|
+
}
|
3647
|
+
Check_Type(typemap, T_DATA);
|
3648
|
+
this->type_map_for_results = typemap;
|
3649
|
+
|
3650
|
+
return typemap;
|
3651
|
+
}
|
3652
|
+
|
3653
|
+
/*
|
3654
|
+
* call-seq:
|
3655
|
+
* res.type_map_for_results -> TypeMap
|
3656
|
+
*
|
3657
|
+
* Returns the default TypeMap that is currently set for type casts of result values.
|
3658
|
+
*
|
3659
|
+
*/
|
3660
|
+
static VALUE
|
3661
|
+
pgconn_type_map_for_results_get(VALUE self)
|
3662
|
+
{
|
3663
|
+
t_pg_connection *this = pg_get_connection( self );
|
3664
|
+
|
3665
|
+
return this->type_map_for_results;
|
3666
|
+
}
|
3667
|
+
|
3668
|
+
|
3669
|
+
/*
|
3670
|
+
* call-seq:
|
3671
|
+
* res.encoder_for_put_copy_data = encoder
|
3672
|
+
*
|
3673
|
+
* Set the default coder that is used for type casting of parameters
|
3674
|
+
* to #put_copy_data .
|
3675
|
+
*
|
3676
|
+
* +encoder+ can be:
|
3677
|
+
* * a kind of PG::Coder
|
3678
|
+
* * +nil+ - disable type encoding, data must be a String.
|
3679
|
+
*
|
3680
|
+
*/
|
3681
|
+
static VALUE
|
3682
|
+
pgconn_encoder_for_put_copy_data_set(VALUE self, VALUE typemap)
|
3683
|
+
{
|
3684
|
+
t_pg_connection *this = pg_get_connection( self );
|
3685
|
+
|
3686
|
+
if( typemap != Qnil ){
|
3687
|
+
if ( !rb_obj_is_kind_of(typemap, rb_cPG_Coder) ) {
|
3688
|
+
rb_raise( rb_eTypeError, "wrong argument type %s (expected kind of PG::Coder)",
|
3689
|
+
rb_obj_classname( typemap ) );
|
3690
|
+
}
|
3691
|
+
Check_Type(typemap, T_DATA);
|
3692
|
+
}
|
3693
|
+
this->encoder_for_put_copy_data = typemap;
|
3694
|
+
|
3695
|
+
return typemap;
|
3696
|
+
}
|
3697
|
+
|
3698
|
+
/*
|
3699
|
+
* call-seq:
|
3700
|
+
* res.encoder_for_put_copy_data -> PG::Coder
|
3701
|
+
*
|
3702
|
+
* Returns the default coder object that is currently set for type casting of parameters
|
3703
|
+
* to #put_copy_data .
|
3704
|
+
*
|
3705
|
+
* Returns either:
|
3706
|
+
* * a kind of PG::Coder
|
3707
|
+
* * +nil+ - type encoding is disabled, returned data will be a String.
|
3708
|
+
*
|
3709
|
+
*/
|
3710
|
+
static VALUE
|
3711
|
+
pgconn_encoder_for_put_copy_data_get(VALUE self)
|
3712
|
+
{
|
3713
|
+
t_pg_connection *this = pg_get_connection( self );
|
3714
|
+
|
3715
|
+
return this->encoder_for_put_copy_data;
|
3716
|
+
}
|
3717
|
+
|
3718
|
+
/*
|
3719
|
+
* call-seq:
|
3720
|
+
* res.decoder_for_get_copy_data = decoder
|
3721
|
+
*
|
3722
|
+
* Set the default coder that is used for type casting of received data
|
3723
|
+
* by #get_copy_data .
|
3724
|
+
*
|
3725
|
+
* +decoder+ can be:
|
3726
|
+
* * a kind of PG::Coder
|
3727
|
+
* * +nil+ - disable type decoding, returned data will be a String.
|
3728
|
+
*
|
3729
|
+
*/
|
3730
|
+
static VALUE
|
3731
|
+
pgconn_decoder_for_get_copy_data_set(VALUE self, VALUE typemap)
|
3732
|
+
{
|
3733
|
+
t_pg_connection *this = pg_get_connection( self );
|
3734
|
+
|
3735
|
+
if( typemap != Qnil ){
|
3736
|
+
if ( !rb_obj_is_kind_of(typemap, rb_cPG_Coder) ) {
|
3737
|
+
rb_raise( rb_eTypeError, "wrong argument type %s (expected kind of PG::Coder)",
|
3738
|
+
rb_obj_classname( typemap ) );
|
3739
|
+
}
|
3740
|
+
Check_Type(typemap, T_DATA);
|
3741
|
+
}
|
3742
|
+
this->decoder_for_get_copy_data = typemap;
|
3743
|
+
|
3744
|
+
return typemap;
|
3745
|
+
}
|
3746
|
+
|
3747
|
+
/*
|
3748
|
+
* call-seq:
|
3749
|
+
* res.decoder_for_get_copy_data -> PG::Coder
|
3750
|
+
*
|
3751
|
+
* Returns the default coder object that is currently set for type casting of received
|
3752
|
+
* data by #get_copy_data .
|
3753
|
+
*
|
3754
|
+
* Returns either:
|
3755
|
+
* * a kind of PG::Coder
|
3756
|
+
* * +nil+ - type encoding is disabled, returned data will be a String.
|
3757
|
+
*
|
3758
|
+
*/
|
3759
|
+
static VALUE
|
3760
|
+
pgconn_decoder_for_get_copy_data_get(VALUE self)
|
3761
|
+
{
|
3762
|
+
t_pg_connection *this = pg_get_connection( self );
|
3763
|
+
|
3764
|
+
return this->decoder_for_get_copy_data;
|
3765
|
+
}
|
3477
3766
|
|
3478
3767
|
|
3479
3768
|
void
|
3480
3769
|
init_pg_connection()
|
3481
3770
|
{
|
3771
|
+
s_id_encode = rb_intern("encode");
|
3772
|
+
sym_type = ID2SYM(rb_intern("type"));
|
3773
|
+
sym_format = ID2SYM(rb_intern("format"));
|
3774
|
+
sym_value = ID2SYM(rb_intern("value"));
|
3775
|
+
|
3482
3776
|
rb_cPGconn = rb_define_class_under( rb_mPG, "Connection", rb_cObject );
|
3483
3777
|
rb_include_module(rb_cPGconn, rb_mPGconstants);
|
3484
3778
|
|
@@ -3518,6 +3812,9 @@ init_pg_connection()
|
|
3518
3812
|
rb_define_method(rb_cPGconn, "host", pgconn_host, 0);
|
3519
3813
|
rb_define_method(rb_cPGconn, "port", pgconn_port, 0);
|
3520
3814
|
rb_define_method(rb_cPGconn, "tty", pgconn_tty, 0);
|
3815
|
+
#ifdef HAVE_PQCONNINFO
|
3816
|
+
rb_define_method(rb_cPGconn, "conninfo", pgconn_conninfo, 0);
|
3817
|
+
#endif
|
3521
3818
|
rb_define_method(rb_cPGconn, "options", pgconn_options, 0);
|
3522
3819
|
rb_define_method(rb_cPGconn, "status", pgconn_status, 0);
|
3523
3820
|
rb_define_method(rb_cPGconn, "transaction_status", pgconn_transaction_status, 0);
|
@@ -3578,7 +3875,7 @@ init_pg_connection()
|
|
3578
3875
|
rb_define_method(rb_cPGconn, "notifies", pgconn_notifies, 0);
|
3579
3876
|
|
3580
3877
|
/****** PG::Connection INSTANCE METHODS: COPY ******/
|
3581
|
-
rb_define_method(rb_cPGconn, "put_copy_data", pgconn_put_copy_data, 1);
|
3878
|
+
rb_define_method(rb_cPGconn, "put_copy_data", pgconn_put_copy_data, -1);
|
3582
3879
|
rb_define_method(rb_cPGconn, "put_copy_end", pgconn_put_copy_end, -1);
|
3583
3880
|
rb_define_method(rb_cPGconn, "get_copy_data", pgconn_get_copy_data, -1);
|
3584
3881
|
|
@@ -3639,5 +3936,13 @@ init_pg_connection()
|
|
3639
3936
|
rb_define_method(rb_cPGconn, "set_default_encoding", pgconn_set_default_encoding, 0);
|
3640
3937
|
#endif /* M17N_SUPPORTED */
|
3641
3938
|
|
3939
|
+
rb_define_method(rb_cPGconn, "type_map_for_queries=", pgconn_type_map_for_queries_set, 1);
|
3940
|
+
rb_define_method(rb_cPGconn, "type_map_for_queries", pgconn_type_map_for_queries_get, 0);
|
3941
|
+
rb_define_method(rb_cPGconn, "type_map_for_results=", pgconn_type_map_for_results_set, 1);
|
3942
|
+
rb_define_method(rb_cPGconn, "type_map_for_results", pgconn_type_map_for_results_get, 0);
|
3943
|
+
rb_define_method(rb_cPGconn, "encoder_for_put_copy_data=", pgconn_encoder_for_put_copy_data_set, 1);
|
3944
|
+
rb_define_method(rb_cPGconn, "encoder_for_put_copy_data", pgconn_encoder_for_put_copy_data_get, 0);
|
3945
|
+
rb_define_method(rb_cPGconn, "decoder_for_get_copy_data=", pgconn_decoder_for_get_copy_data_set, 1);
|
3946
|
+
rb_define_method(rb_cPGconn, "decoder_for_get_copy_data", pgconn_decoder_for_get_copy_data_get, 0);
|
3642
3947
|
}
|
3643
3948
|
|