pg 0.17.1-x86-mingw32 → 0.18.0.pre20141017160319-x86-mingw32
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.tar.gz.sig +0 -0
- data/ChangeLog +1885 -169
- data/History.rdoc +6 -0
- data/Manifest.txt +25 -1
- data/README.rdoc +47 -0
- data/Rakefile +21 -12
- data/Rakefile.cross +39 -33
- data/ext/extconf.rb +27 -26
- data/ext/pg.c +73 -19
- data/ext/pg.h +194 -6
- data/ext/pg_binary_decoder.c +160 -0
- data/ext/pg_binary_encoder.c +160 -0
- data/ext/pg_coder.c +473 -0
- data/ext/pg_connection.c +872 -534
- data/ext/pg_copy_coder.c +557 -0
- data/ext/pg_result.c +266 -111
- data/ext/pg_text_decoder.c +424 -0
- data/ext/pg_text_encoder.c +631 -0
- data/ext/pg_type_map.c +113 -0
- data/ext/pg_type_map_all_strings.c +113 -0
- data/ext/pg_type_map_by_column.c +254 -0
- data/ext/pg_type_map_by_mri_type.c +266 -0
- data/ext/pg_type_map_by_oid.c +341 -0
- data/ext/util.c +149 -0
- data/ext/util.h +65 -0
- data/lib/1.9/pg_ext.so +0 -0
- data/lib/2.0/pg_ext.so +0 -0
- data/lib/2.1/pg_ext.so +0 -0
- data/lib/i386-mingw32/libpq.dll +0 -0
- data/lib/pg.rb +11 -1
- data/lib/pg/basic_type_mapping.rb +377 -0
- data/lib/pg/coder.rb +74 -0
- data/lib/pg/connection.rb +43 -1
- data/lib/pg/result.rb +13 -3
- data/lib/pg/text_decoder.rb +42 -0
- data/lib/pg/text_encoder.rb +27 -0
- data/lib/pg/type_map_by_column.rb +15 -0
- data/spec/{lib/helpers.rb → helpers.rb} +95 -35
- data/spec/pg/basic_type_mapping_spec.rb +251 -0
- data/spec/pg/connection_spec.rb +416 -214
- data/spec/pg/result_spec.rb +146 -116
- data/spec/pg/type_map_by_column_spec.rb +135 -0
- data/spec/pg/type_map_by_mri_type_spec.rb +122 -0
- data/spec/pg/type_map_by_oid_spec.rb +133 -0
- data/spec/pg/type_map_spec.rb +39 -0
- data/spec/pg/type_spec.rb +649 -0
- data/spec/pg_spec.rb +10 -18
- metadata +130 -52
- metadata.gz.sig +0 -0
- data/lib/1.8/pg_ext.so +0 -0
data/ext/pg_connection.c
CHANGED
@@ -6,16 +6,21 @@
|
|
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,58 @@ 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.
|
36
69
|
*/
|
37
70
|
PGconn *
|
38
71
|
pg_get_pgconn( VALUE self )
|
39
72
|
{
|
40
|
-
|
73
|
+
t_pg_connection *this;
|
74
|
+
Data_Get_Struct( self, t_pg_connection, this);
|
41
75
|
|
42
|
-
if ( !
|
76
|
+
if ( !this->pgconn )
|
43
77
|
rb_raise( rb_eConnectionBad, "connection is closed" );
|
44
78
|
|
45
|
-
return
|
79
|
+
return this->pgconn;
|
46
80
|
}
|
47
81
|
|
48
82
|
|
83
|
+
|
49
84
|
/*
|
50
85
|
* Close the associated socket IO object if there is one.
|
51
86
|
*/
|
52
87
|
void
|
53
88
|
pgconn_close_socket_io( VALUE self )
|
54
89
|
{
|
55
|
-
|
90
|
+
t_pg_connection *this = pg_get_connection( self );
|
91
|
+
VALUE socket_io = this->socket_io;
|
56
92
|
|
57
93
|
if ( RTEST(socket_io) ) {
|
58
94
|
#if defined(_WIN32) && defined(HAVE_RB_W32_WRAP_IO_HANDLE)
|
@@ -64,28 +100,59 @@ pgconn_close_socket_io( VALUE self )
|
|
64
100
|
rb_funcall( socket_io, rb_intern("close"), 0 );
|
65
101
|
}
|
66
102
|
|
67
|
-
|
103
|
+
this->socket_io = Qnil;
|
68
104
|
}
|
69
105
|
|
70
106
|
|
71
107
|
/*
|
72
|
-
*
|
108
|
+
* Create a Ruby Array of Hashes out of a PGconninfoOptions array.
|
73
109
|
*/
|
110
|
+
static VALUE
|
111
|
+
pgconn_make_conninfo_array( const PQconninfoOption *options )
|
112
|
+
{
|
113
|
+
VALUE ary = rb_ary_new();
|
114
|
+
VALUE hash;
|
115
|
+
int i = 0;
|
74
116
|
|
75
|
-
|
76
|
-
* Object validity checker. Returns the data pointer.
|
77
|
-
*/
|
78
|
-
static PGconn *
|
79
|
-
pgconn_check( VALUE self ) {
|
117
|
+
if (!options) return Qnil;
|
80
118
|
|
81
|
-
|
119
|
+
for(i = 0; options[i].keyword != NULL; i++) {
|
120
|
+
hash = rb_hash_new();
|
121
|
+
if(options[i].keyword)
|
122
|
+
rb_hash_aset(hash, ID2SYM(rb_intern("keyword")), rb_str_new2(options[i].keyword));
|
123
|
+
if(options[i].envvar)
|
124
|
+
rb_hash_aset(hash, ID2SYM(rb_intern("envvar")), rb_str_new2(options[i].envvar));
|
125
|
+
if(options[i].compiled)
|
126
|
+
rb_hash_aset(hash, ID2SYM(rb_intern("compiled")), rb_str_new2(options[i].compiled));
|
127
|
+
if(options[i].val)
|
128
|
+
rb_hash_aset(hash, ID2SYM(rb_intern("val")), rb_str_new2(options[i].val));
|
129
|
+
if(options[i].label)
|
130
|
+
rb_hash_aset(hash, ID2SYM(rb_intern("label")), rb_str_new2(options[i].label));
|
131
|
+
if(options[i].dispchar)
|
132
|
+
rb_hash_aset(hash, ID2SYM(rb_intern("dispchar")), rb_str_new2(options[i].dispchar));
|
133
|
+
rb_hash_aset(hash, ID2SYM(rb_intern("dispsize")), INT2NUM(options[i].dispsize));
|
134
|
+
rb_ary_push(ary, hash);
|
135
|
+
}
|
136
|
+
|
137
|
+
return ary;
|
138
|
+
}
|
82
139
|
|
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
140
|
|
88
|
-
|
141
|
+
/*
|
142
|
+
* GC Mark function
|
143
|
+
*/
|
144
|
+
static void
|
145
|
+
pgconn_gc_mark( t_pg_connection *this )
|
146
|
+
{
|
147
|
+
rb_gc_mark( this->socket_io );
|
148
|
+
rb_gc_mark( this->notice_receiver );
|
149
|
+
rb_gc_mark( this->notice_processor );
|
150
|
+
rb_gc_mark( this->type_map_for_queries );
|
151
|
+
rb_gc_mark( this->type_map_for_results );
|
152
|
+
rb_gc_mark( this->trace_stream );
|
153
|
+
rb_gc_mark( this->external_encoding );
|
154
|
+
rb_gc_mark( this->encoder_for_put_copy_data );
|
155
|
+
rb_gc_mark( this->decoder_for_get_copy_data );
|
89
156
|
}
|
90
157
|
|
91
158
|
|
@@ -93,10 +160,12 @@ pgconn_check( VALUE self ) {
|
|
93
160
|
* GC Free function
|
94
161
|
*/
|
95
162
|
static void
|
96
|
-
pgconn_gc_free(
|
163
|
+
pgconn_gc_free( t_pg_connection *this )
|
97
164
|
{
|
98
|
-
if (
|
99
|
-
PQfinish(
|
165
|
+
if (this->pgconn != NULL)
|
166
|
+
PQfinish( this->pgconn );
|
167
|
+
|
168
|
+
xfree(this);
|
100
169
|
}
|
101
170
|
|
102
171
|
|
@@ -113,10 +182,20 @@ pgconn_gc_free( PGconn *conn )
|
|
113
182
|
static VALUE
|
114
183
|
pgconn_s_allocate( VALUE klass )
|
115
184
|
{
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
185
|
+
t_pg_connection *this;
|
186
|
+
VALUE self = Data_Make_Struct( klass, t_pg_connection, pgconn_gc_mark, pgconn_gc_free, this );
|
187
|
+
|
188
|
+
this->pgconn = NULL;
|
189
|
+
this->socket_io = Qnil;
|
190
|
+
this->notice_receiver = Qnil;
|
191
|
+
this->notice_processor = Qnil;
|
192
|
+
this->type_map_for_queries = Qnil;
|
193
|
+
this->type_map_for_results = Qnil;
|
194
|
+
this->encoder_for_put_copy_data = Qnil;
|
195
|
+
this->decoder_for_get_copy_data = Qnil;
|
196
|
+
this->trace_stream = Qnil;
|
197
|
+
this->external_encoding = Qnil;
|
198
|
+
|
120
199
|
return self;
|
121
200
|
}
|
122
201
|
|
@@ -181,21 +260,19 @@ pgconn_s_allocate( VALUE klass )
|
|
181
260
|
static VALUE
|
182
261
|
pgconn_init(int argc, VALUE *argv, VALUE self)
|
183
262
|
{
|
184
|
-
|
263
|
+
t_pg_connection *this;
|
185
264
|
VALUE conninfo;
|
186
265
|
VALUE error;
|
187
266
|
|
267
|
+
this = pg_get_connection( self );
|
188
268
|
conninfo = rb_funcall2( rb_cPGconn, rb_intern("parse_connect_args"), argc, argv );
|
189
|
-
|
269
|
+
this->pgconn = gvl_PQconnectdb(StringValueCStr(conninfo));
|
190
270
|
|
191
|
-
if(
|
271
|
+
if(this->pgconn == NULL)
|
192
272
|
rb_raise(rb_ePGerror, "PQconnectdb() unable to allocate structure");
|
193
273
|
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
if (PQstatus(conn) == CONNECTION_BAD) {
|
198
|
-
error = rb_exc_new2(rb_eConnectionBad, PQerrorMessage(conn));
|
274
|
+
if (PQstatus(this->pgconn) == CONNECTION_BAD) {
|
275
|
+
error = rb_exc_new2(rb_eConnectionBad, PQerrorMessage(this->pgconn));
|
199
276
|
rb_iv_set(error, "@connection", self);
|
200
277
|
rb_exc_raise(error);
|
201
278
|
}
|
@@ -229,27 +306,25 @@ pgconn_init(int argc, VALUE *argv, VALUE self)
|
|
229
306
|
static VALUE
|
230
307
|
pgconn_s_connect_start( int argc, VALUE *argv, VALUE klass )
|
231
308
|
{
|
232
|
-
PGconn *conn = NULL;
|
233
309
|
VALUE rb_conn;
|
234
310
|
VALUE conninfo;
|
235
311
|
VALUE error;
|
312
|
+
t_pg_connection *this;
|
236
313
|
|
237
314
|
/*
|
238
315
|
* PG::Connection.connect_start must act as both alloc() and initialize()
|
239
316
|
* because it is not invoked by calling new().
|
240
317
|
*/
|
241
318
|
rb_conn = pgconn_s_allocate( klass );
|
319
|
+
this = pg_get_connection( rb_conn );
|
242
320
|
conninfo = rb_funcall2( klass, rb_intern("parse_connect_args"), argc, argv );
|
243
|
-
|
321
|
+
this->pgconn = gvl_PQconnectStart( StringValueCStr(conninfo) );
|
244
322
|
|
245
|
-
if(
|
323
|
+
if( this->pgconn == NULL )
|
246
324
|
rb_raise(rb_ePGerror, "PQconnectStart() unable to allocate structure");
|
247
325
|
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
if ( PQstatus(conn) == CONNECTION_BAD ) {
|
252
|
-
error = rb_exc_new2(rb_eConnectionBad, PQerrorMessage(conn));
|
326
|
+
if ( PQstatus(this->pgconn) == CONNECTION_BAD ) {
|
327
|
+
error = rb_exc_new2(rb_eConnectionBad, PQerrorMessage(this->pgconn));
|
253
328
|
rb_iv_set(error, "@connection", rb_conn);
|
254
329
|
rb_exc_raise(error);
|
255
330
|
}
|
@@ -286,7 +361,7 @@ pgconn_s_ping( int argc, VALUE *argv, VALUE klass )
|
|
286
361
|
VALUE conninfo;
|
287
362
|
|
288
363
|
conninfo = rb_funcall2( klass, rb_intern("parse_connect_args"), argc, argv );
|
289
|
-
ping = PQping(
|
364
|
+
ping = PQping( StringValueCStr(conninfo) );
|
290
365
|
|
291
366
|
return INT2FIX((int)ping);
|
292
367
|
}
|
@@ -319,31 +394,13 @@ static VALUE
|
|
319
394
|
pgconn_s_conndefaults(VALUE self)
|
320
395
|
{
|
321
396
|
PQconninfoOption *options = PQconndefaults();
|
322
|
-
VALUE
|
323
|
-
|
324
|
-
|
397
|
+
VALUE array = pgconn_make_conninfo_array( options );
|
398
|
+
|
399
|
+
PQconninfoFree(options);
|
325
400
|
|
326
401
|
UNUSED( self );
|
327
402
|
|
328
|
-
|
329
|
-
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;
|
403
|
+
return array;
|
347
404
|
}
|
348
405
|
|
349
406
|
|
@@ -369,7 +426,7 @@ pgconn_s_encrypt_password(VALUE self, VALUE password, VALUE username)
|
|
369
426
|
Check_Type(password, T_STRING);
|
370
427
|
Check_Type(username, T_STRING);
|
371
428
|
|
372
|
-
encrypted = PQencryptPassword(
|
429
|
+
encrypted = PQencryptPassword(StringValueCStr(password), StringValueCStr(username));
|
373
430
|
rval = rb_str_new2( encrypted );
|
374
431
|
PQfreemem( encrypted );
|
375
432
|
|
@@ -435,9 +492,11 @@ pgconn_connect_poll(VALUE self)
|
|
435
492
|
static VALUE
|
436
493
|
pgconn_finish( VALUE self )
|
437
494
|
{
|
495
|
+
t_pg_connection *this = pg_get_connection_safe( self );
|
496
|
+
|
438
497
|
pgconn_close_socket_io( self );
|
439
|
-
PQfinish(
|
440
|
-
|
498
|
+
PQfinish( this->pgconn );
|
499
|
+
this->pgconn = NULL;
|
441
500
|
return Qnil;
|
442
501
|
}
|
443
502
|
|
@@ -451,7 +510,8 @@ pgconn_finish( VALUE self )
|
|
451
510
|
static VALUE
|
452
511
|
pgconn_finished_p( VALUE self )
|
453
512
|
{
|
454
|
-
|
513
|
+
t_pg_connection *this = pg_get_connection( self );
|
514
|
+
if ( this->pgconn ) return Qfalse;
|
455
515
|
return Qtrue;
|
456
516
|
}
|
457
517
|
|
@@ -604,6 +664,29 @@ pgconn_options(VALUE self)
|
|
604
664
|
return rb_tainted_str_new2(options);
|
605
665
|
}
|
606
666
|
|
667
|
+
|
668
|
+
#ifdef HAVE_PQCONNINFO
|
669
|
+
/*
|
670
|
+
* call-seq:
|
671
|
+
* conn.conninfo -> hash
|
672
|
+
*
|
673
|
+
* Returns the connection options used by a live connection.
|
674
|
+
*
|
675
|
+
*/
|
676
|
+
static VALUE
|
677
|
+
pgconn_conninfo( VALUE self )
|
678
|
+
{
|
679
|
+
PGconn *conn = pg_get_pgconn(self);
|
680
|
+
PQconninfoOption *options = PQconninfo( conn );
|
681
|
+
VALUE array = pgconn_make_conninfo_array( options );
|
682
|
+
|
683
|
+
PQconninfoFree(options);
|
684
|
+
|
685
|
+
return array;
|
686
|
+
}
|
687
|
+
#endif
|
688
|
+
|
689
|
+
|
607
690
|
/*
|
608
691
|
* call-seq:
|
609
692
|
* conn.status()
|
@@ -654,7 +737,7 @@ pgconn_transaction_status(VALUE self)
|
|
654
737
|
static VALUE
|
655
738
|
pgconn_parameter_status(VALUE self, VALUE param_name)
|
656
739
|
{
|
657
|
-
const char *ret = PQparameterStatus(pg_get_pgconn(self),
|
740
|
+
const char *ret = PQparameterStatus(pg_get_pgconn(self), StringValueCStr(param_name));
|
658
741
|
if(ret == NULL)
|
659
742
|
return Qnil;
|
660
743
|
else
|
@@ -753,10 +836,11 @@ pgconn_socket_io(VALUE self)
|
|
753
836
|
int sd;
|
754
837
|
int ruby_sd;
|
755
838
|
ID id_autoclose = rb_intern("autoclose=");
|
756
|
-
|
839
|
+
t_pg_connection *this = pg_get_connection_safe( self );
|
840
|
+
VALUE socket_io = this->socket_io;
|
757
841
|
|
758
842
|
if ( !RTEST(socket_io) ) {
|
759
|
-
if( (sd = PQsocket(
|
843
|
+
if( (sd = PQsocket(this->pgconn)) < 0)
|
760
844
|
rb_raise(rb_eConnectionBad, "PQsocket() can't get socket descriptor");
|
761
845
|
|
762
846
|
#ifdef _WIN32
|
@@ -772,7 +856,7 @@ pgconn_socket_io(VALUE self)
|
|
772
856
|
rb_funcall( socket_io, id_autoclose, 1, Qfalse );
|
773
857
|
}
|
774
858
|
|
775
|
-
|
859
|
+
this->socket_io = socket_io;
|
776
860
|
}
|
777
861
|
|
778
862
|
return socket_io;
|
@@ -861,7 +945,7 @@ pgconn_exec(int argc, VALUE *argv, VALUE self)
|
|
861
945
|
if ( argc == 1 ) {
|
862
946
|
Check_Type(argv[0], T_STRING);
|
863
947
|
|
864
|
-
result = gvl_PQexec(conn,
|
948
|
+
result = gvl_PQexec(conn, StringValueCStr(argv[0]));
|
865
949
|
rb_pgresult = pg_new_result(result, self);
|
866
950
|
pg_result_check(rb_pgresult);
|
867
951
|
if (rb_block_given_p()) {
|
@@ -878,10 +962,262 @@ pgconn_exec(int argc, VALUE *argv, VALUE self)
|
|
878
962
|
}
|
879
963
|
|
880
964
|
|
965
|
+
struct linked_typecast_data {
|
966
|
+
struct linked_typecast_data *next;
|
967
|
+
char data[0];
|
968
|
+
};
|
969
|
+
|
970
|
+
/* This struct is allocated on the stack for all query execution functions. */
|
971
|
+
struct query_params_data {
|
972
|
+
|
973
|
+
/*
|
974
|
+
* Filled by caller
|
975
|
+
*/
|
976
|
+
|
977
|
+
/* Is the query function to execute one with types array? */
|
978
|
+
int with_types;
|
979
|
+
/* Array of query params from user space */
|
980
|
+
VALUE params;
|
981
|
+
/* The typemap given from user space */
|
982
|
+
VALUE typemap;
|
983
|
+
|
984
|
+
/*
|
985
|
+
* Filled by alloc_query_params()
|
986
|
+
*/
|
987
|
+
|
988
|
+
/* Wraps the pointer of allocated memory, if function parameters dont't
|
989
|
+
* fit in the memory_pool below.
|
990
|
+
*/
|
991
|
+
VALUE heap_pool;
|
992
|
+
|
993
|
+
/* Pointer to the value string pointers (either within memory_pool or heap_pool).
|
994
|
+
* The value strings itself are either directly within RString memory or,
|
995
|
+
* in case of type casted values, within memory_pool or typecast_heap_chain.
|
996
|
+
*/
|
997
|
+
char **values;
|
998
|
+
/* Pointer to the param lengths (either within memory_pool or heap_pool) */
|
999
|
+
int *lengths;
|
1000
|
+
/* Pointer to the format codes (either within memory_pool or heap_pool) */
|
1001
|
+
int *formats;
|
1002
|
+
/* Pointer to the OID types (either within memory_pool or heap_pool) */
|
1003
|
+
Oid *types;
|
1004
|
+
|
1005
|
+
/* This array takes the string values for the timeframe of the query,
|
1006
|
+
* if param value convertion is required
|
1007
|
+
*/
|
1008
|
+
VALUE gc_array;
|
1009
|
+
|
1010
|
+
/* Wraps a single linked list of allocated memory chunks for type casted params.
|
1011
|
+
* Used when the memory_pool is to small.
|
1012
|
+
*/
|
1013
|
+
VALUE typecast_heap_chain;
|
1014
|
+
|
1015
|
+
/* This memory pool is used to place above query function parameters on it. */
|
1016
|
+
char memory_pool[QUERYDATA_BUFFER_SIZE];
|
1017
|
+
};
|
1018
|
+
|
1019
|
+
static void
|
1020
|
+
free_typecast_heap_chain(struct linked_typecast_data *chain_entry)
|
1021
|
+
{
|
1022
|
+
while(chain_entry){
|
1023
|
+
struct linked_typecast_data *next = chain_entry->next;
|
1024
|
+
xfree(chain_entry);
|
1025
|
+
chain_entry = next;
|
1026
|
+
}
|
1027
|
+
}
|
1028
|
+
|
1029
|
+
static char *
|
1030
|
+
alloc_typecast_buf( VALUE *typecast_heap_chain, int len )
|
1031
|
+
{
|
1032
|
+
/* Allocate a new memory chunk from heap */
|
1033
|
+
struct linked_typecast_data *allocated =
|
1034
|
+
(struct linked_typecast_data *)xmalloc(sizeof(struct linked_typecast_data) + len);
|
1035
|
+
|
1036
|
+
/* Did we already wrap a memory chain per T_DATA object? */
|
1037
|
+
if( NIL_P( *typecast_heap_chain ) ){
|
1038
|
+
/* Leave free'ing of the buffer chain to the GC, when paramsData has left the stack */
|
1039
|
+
*typecast_heap_chain = Data_Wrap_Struct( rb_cObject, NULL, free_typecast_heap_chain, allocated );
|
1040
|
+
allocated->next = NULL;
|
1041
|
+
} else {
|
1042
|
+
/* Append to the chain */
|
1043
|
+
allocated->next = DATA_PTR( *typecast_heap_chain );
|
1044
|
+
DATA_PTR( *typecast_heap_chain ) = allocated;
|
1045
|
+
}
|
1046
|
+
|
1047
|
+
return &allocated->data[0];
|
1048
|
+
}
|
1049
|
+
|
1050
|
+
|
1051
|
+
static int
|
1052
|
+
alloc_query_params1(struct query_params_data *paramsData)
|
1053
|
+
{
|
1054
|
+
VALUE param_value;
|
1055
|
+
t_typemap *p_typemap;
|
1056
|
+
int nParams;
|
1057
|
+
int i=0;
|
1058
|
+
t_pg_coder *conv;
|
1059
|
+
unsigned int required_pool_size;
|
1060
|
+
char *memory_pool;
|
1061
|
+
|
1062
|
+
Data_Get_Struct( paramsData->typemap, t_typemap, p_typemap);
|
1063
|
+
|
1064
|
+
nParams = (int)RARRAY_LEN(paramsData->params);
|
1065
|
+
|
1066
|
+
required_pool_size = nParams * (
|
1067
|
+
sizeof(char *) +
|
1068
|
+
sizeof(int) +
|
1069
|
+
sizeof(int) +
|
1070
|
+
(paramsData->with_types ? sizeof(Oid) : 0));
|
1071
|
+
|
1072
|
+
if( sizeof(paramsData->memory_pool) < required_pool_size ){
|
1073
|
+
/* Allocate one combined memory pool for all possible function parameters */
|
1074
|
+
memory_pool = (char*)xmalloc( required_pool_size );
|
1075
|
+
/* Leave free'ing of the buffer to the GC, when paramsData has left the stack */
|
1076
|
+
paramsData->heap_pool = Data_Wrap_Struct( rb_cObject, NULL, -1, memory_pool );
|
1077
|
+
required_pool_size = 0;
|
1078
|
+
}else{
|
1079
|
+
/* Use stack memory for function parameters */
|
1080
|
+
memory_pool = paramsData->memory_pool;
|
1081
|
+
}
|
1082
|
+
|
1083
|
+
paramsData->values = (char **)memory_pool;
|
1084
|
+
paramsData->lengths = (int *)((char*)paramsData->values + sizeof(char *) * nParams);
|
1085
|
+
paramsData->formats = (int *)((char*)paramsData->lengths + sizeof(int) * nParams);
|
1086
|
+
paramsData->types = (Oid *)((char*)paramsData->formats + sizeof(int) * nParams);
|
1087
|
+
|
1088
|
+
{
|
1089
|
+
char *typecast_buf = paramsData->memory_pool + required_pool_size;
|
1090
|
+
|
1091
|
+
for ( i = 0; i < nParams; i++ ) {
|
1092
|
+
param_value = rb_ary_entry(paramsData->params, i);
|
1093
|
+
|
1094
|
+
paramsData->formats[i] = 0;
|
1095
|
+
if( paramsData->with_types )
|
1096
|
+
paramsData->types[i] = 0;
|
1097
|
+
|
1098
|
+
/* Let the given typemap select a coder for this param */
|
1099
|
+
conv = p_typemap->typecast_query_param(paramsData->typemap, param_value, i);
|
1100
|
+
|
1101
|
+
/* Using a coder object for the param_value? Then set it's format code and oid. */
|
1102
|
+
if( conv ){
|
1103
|
+
paramsData->formats[i] = conv->format;
|
1104
|
+
if( paramsData->with_types )
|
1105
|
+
paramsData->types[i] = conv->oid;
|
1106
|
+
} else {
|
1107
|
+
/* No coder, but got we a hash form for the query param?
|
1108
|
+
* Then take format code and oid from there. */
|
1109
|
+
if (TYPE(param_value) == T_HASH) {
|
1110
|
+
VALUE format_value = rb_hash_aref(param_value, sym_format);
|
1111
|
+
if( !NIL_P(format_value) )
|
1112
|
+
paramsData->formats[i] = NUM2INT(format_value);
|
1113
|
+
if( paramsData->with_types ){
|
1114
|
+
VALUE type_value = rb_hash_aref(param_value, sym_type);
|
1115
|
+
if( !NIL_P(type_value) )
|
1116
|
+
paramsData->types[i] = NUM2UINT(type_value);
|
1117
|
+
}
|
1118
|
+
param_value = rb_hash_aref(param_value, sym_value);
|
1119
|
+
}
|
1120
|
+
}
|
1121
|
+
|
1122
|
+
if( NIL_P(param_value) ){
|
1123
|
+
paramsData->values[i] = NULL;
|
1124
|
+
paramsData->lengths[i] = 0;
|
1125
|
+
} else {
|
1126
|
+
t_pg_coder_enc_func enc_func = pg_coder_enc_func( conv );
|
1127
|
+
VALUE intermediate;
|
1128
|
+
|
1129
|
+
/* 1st pass for retiving the required memory space */
|
1130
|
+
int len = enc_func(conv, param_value, NULL, &intermediate);
|
1131
|
+
|
1132
|
+
if( len == -1 ){
|
1133
|
+
/* The intermediate value is a String that can be used directly. */
|
1134
|
+
|
1135
|
+
/* Ensure that the String object is zero terminated as expected by libpq. */
|
1136
|
+
if( paramsData->formats[i] == 0 )
|
1137
|
+
StringValueCStr(intermediate);
|
1138
|
+
/* In case a new string object was generated, make sure it doesn't get freed by the GC */
|
1139
|
+
if( intermediate != param_value )
|
1140
|
+
rb_ary_push(paramsData->gc_array, intermediate);
|
1141
|
+
paramsData->values[i] = RSTRING_PTR(intermediate);
|
1142
|
+
paramsData->lengths[i] = RSTRING_LENINT(intermediate);
|
1143
|
+
|
1144
|
+
} else {
|
1145
|
+
/* Is the stack memory pool too small to take the type casted value? */
|
1146
|
+
if( sizeof(paramsData->memory_pool) < required_pool_size + len + 1){
|
1147
|
+
typecast_buf = alloc_typecast_buf( ¶msData->typecast_heap_chain, len + 1 );
|
1148
|
+
}
|
1149
|
+
|
1150
|
+
/* 2nd pass for writing the data to prepared buffer */
|
1151
|
+
len = enc_func(conv, param_value, typecast_buf, &intermediate);
|
1152
|
+
paramsData->values[i] = typecast_buf;
|
1153
|
+
if( paramsData->formats[i] == 0 ){
|
1154
|
+
/* text format strings must be zero terminated and lengths are ignored */
|
1155
|
+
typecast_buf[len] = 0;
|
1156
|
+
typecast_buf += len + 1;
|
1157
|
+
required_pool_size += len + 1;
|
1158
|
+
} else {
|
1159
|
+
paramsData->lengths[i] = len;
|
1160
|
+
typecast_buf += len;
|
1161
|
+
required_pool_size += len;
|
1162
|
+
}
|
1163
|
+
}
|
1164
|
+
|
1165
|
+
RB_GC_GUARD(intermediate);
|
1166
|
+
}
|
1167
|
+
}
|
1168
|
+
}
|
1169
|
+
|
1170
|
+
return nParams;
|
1171
|
+
}
|
1172
|
+
|
1173
|
+
static void
|
1174
|
+
free_query_params(struct query_params_data *paramsData)
|
1175
|
+
{
|
1176
|
+
/* currently nothing to free */
|
1177
|
+
}
|
1178
|
+
|
1179
|
+
static int
|
1180
|
+
alloc_query_params(struct query_params_data *paramsData)
|
1181
|
+
{
|
1182
|
+
int nParams;
|
1183
|
+
Check_Type(paramsData->params, T_ARRAY);
|
1184
|
+
|
1185
|
+
if( NIL_P(paramsData->typemap) ){
|
1186
|
+
/* We don't need to call fit_to_query for pg_default_typemap. It does nothing. */
|
1187
|
+
paramsData->typemap = pg_default_typemap;
|
1188
|
+
} else {
|
1189
|
+
t_typemap *p_typemap = DATA_PTR( paramsData->typemap );
|
1190
|
+
paramsData->typemap = p_typemap->fit_to_query( paramsData->typemap, paramsData->params );
|
1191
|
+
}
|
1192
|
+
|
1193
|
+
paramsData->heap_pool = Qnil;
|
1194
|
+
paramsData->typecast_heap_chain = Qnil;
|
1195
|
+
paramsData->gc_array = rb_ary_new();
|
1196
|
+
|
1197
|
+
nParams = alloc_query_params1(paramsData);
|
1198
|
+
return nParams;
|
1199
|
+
}
|
1200
|
+
|
1201
|
+
void
|
1202
|
+
pgconn_query_assign_typemap( VALUE self, struct query_params_data *paramsData )
|
1203
|
+
{
|
1204
|
+
if(NIL_P(paramsData->typemap)){
|
1205
|
+
/* Use default typemap for queries. It's type is checked when assigned. */
|
1206
|
+
paramsData->typemap = pg_get_connection(self)->type_map_for_queries;
|
1207
|
+
}else{
|
1208
|
+
/* Check type of method param */
|
1209
|
+
if ( !rb_obj_is_kind_of(paramsData->typemap, rb_cTypeMap) ) {
|
1210
|
+
rb_raise( rb_eTypeError, "wrong argument type %s (expected kind of PG::TypeMap)",
|
1211
|
+
rb_obj_classname( paramsData->typemap ) );
|
1212
|
+
}
|
1213
|
+
Check_Type( paramsData->typemap, T_DATA );
|
1214
|
+
}
|
1215
|
+
}
|
1216
|
+
|
881
1217
|
/*
|
882
1218
|
* call-seq:
|
883
|
-
* conn.exec_params(sql, params[, result_format ] ) -> PG::Result
|
884
|
-
* conn.exec_params(sql, params[, result_format ] ) {|pg_result| block }
|
1219
|
+
* conn.exec_params(sql, params[, result_format[, type_map]] ) -> PG::Result
|
1220
|
+
* conn.exec_params(sql, params[, result_format[, type_map]] ) {|pg_result| block }
|
885
1221
|
*
|
886
1222
|
* Sends SQL query request specified by +sql+ to PostgreSQL using placeholders
|
887
1223
|
* for parameters.
|
@@ -911,6 +1247,12 @@ pgconn_exec(int argc, VALUE *argv, VALUE self)
|
|
911
1247
|
* The optional +result_format+ should be 0 for text results, 1
|
912
1248
|
* for binary.
|
913
1249
|
*
|
1250
|
+
* type_map can be a PG::TypeMap derivation (such as PG::BasicTypeMapForQueries).
|
1251
|
+
* This will type cast the params form various Ruby types before transmission
|
1252
|
+
* based on the encoders defined by the type map. When a type encoder is used
|
1253
|
+
* the format and oid of a given bind parameter are retrieved from the encoder
|
1254
|
+
* instead out of the hash form described above.
|
1255
|
+
*
|
914
1256
|
* If the optional code block is given, it will be passed <i>result</i> as an argument,
|
915
1257
|
* and the PG::Result object will automatically be cleared when the block terminates.
|
916
1258
|
* In this instance, <code>conn.exec</code> returns the value of the block.
|
@@ -921,102 +1263,30 @@ pgconn_exec_params( int argc, VALUE *argv, VALUE self )
|
|
921
1263
|
PGconn *conn = pg_get_pgconn(self);
|
922
1264
|
PGresult *result = NULL;
|
923
1265
|
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;
|
1266
|
+
VALUE command, in_res_fmt;
|
930
1267
|
int nParams;
|
931
|
-
Oid *paramTypes;
|
932
|
-
char ** paramValues;
|
933
|
-
int *paramLengths;
|
934
|
-
int *paramFormats;
|
935
1268
|
int resultFormat;
|
1269
|
+
struct query_params_data paramsData;
|
936
1270
|
|
937
|
-
rb_scan_args(argc, argv, "
|
1271
|
+
rb_scan_args(argc, argv, "13", &command, ¶msData.params, &in_res_fmt, ¶msData.typemap);
|
1272
|
+
paramsData.with_types = 1;
|
938
1273
|
|
939
1274
|
/*
|
940
1275
|
* Handle the edge-case where the caller is coming from #exec, but passed an explict +nil+
|
941
1276
|
* for the second parameter.
|
942
1277
|
*/
|
943
|
-
if ( NIL_P(params) ) {
|
1278
|
+
if ( NIL_P(paramsData.params) ) {
|
944
1279
|
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
1280
|
}
|
1281
|
+
pgconn_query_assign_typemap( self, ¶msData );
|
955
1282
|
|
956
|
-
|
957
|
-
|
1283
|
+
resultFormat = NIL_P(in_res_fmt) ? 0 : NUM2INT(in_res_fmt);
|
1284
|
+
nParams = alloc_query_params( ¶msData );
|
958
1285
|
|
959
|
-
|
960
|
-
|
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
|
-
}
|
1286
|
+
result = gvl_PQexecParams(conn, StringValueCStr(command), nParams, paramsData.types,
|
1287
|
+
(const char * const *)paramsData.values, paramsData.lengths, paramsData.formats, resultFormat);
|
1004
1288
|
|
1005
|
-
|
1006
|
-
paramFormats[i] = 0;
|
1007
|
-
else
|
1008
|
-
paramFormats[i] = NUM2INT(param_format);
|
1009
|
-
}
|
1010
|
-
|
1011
|
-
result = gvl_PQexecParams(conn, StringValuePtr(command), nParams, paramTypes,
|
1012
|
-
(const char * const *)paramValues, paramLengths, paramFormats, resultFormat);
|
1013
|
-
|
1014
|
-
rb_gc_unregister_address(&gc_array);
|
1015
|
-
|
1016
|
-
xfree(paramTypes);
|
1017
|
-
xfree(paramValues);
|
1018
|
-
xfree(paramLengths);
|
1019
|
-
xfree(paramFormats);
|
1289
|
+
free_query_params( ¶msData );
|
1020
1290
|
|
1021
1291
|
rb_pgresult = pg_new_result(result, self);
|
1022
1292
|
pg_result_check(rb_pgresult);
|
@@ -1070,14 +1340,13 @@ pgconn_prepare(int argc, VALUE *argv, VALUE self)
|
|
1070
1340
|
paramTypes = ALLOC_N(Oid, nParams);
|
1071
1341
|
for(i = 0; i < nParams; i++) {
|
1072
1342
|
param = rb_ary_entry(in_paramtypes, i);
|
1073
|
-
Check_Type(param, T_FIXNUM);
|
1074
1343
|
if(param == Qnil)
|
1075
1344
|
paramTypes[i] = 0;
|
1076
1345
|
else
|
1077
|
-
paramTypes[i] =
|
1346
|
+
paramTypes[i] = NUM2UINT(param);
|
1078
1347
|
}
|
1079
1348
|
}
|
1080
|
-
result = gvl_PQprepare(conn,
|
1349
|
+
result = gvl_PQprepare(conn, StringValueCStr(name), StringValueCStr(command),
|
1081
1350
|
nParams, paramTypes);
|
1082
1351
|
|
1083
1352
|
xfree(paramTypes);
|
@@ -1089,8 +1358,8 @@ pgconn_prepare(int argc, VALUE *argv, VALUE self)
|
|
1089
1358
|
|
1090
1359
|
/*
|
1091
1360
|
* 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 }
|
1361
|
+
* conn.exec_prepared(statement_name [, params, result_format[, type_map]] ) -> PG::Result
|
1362
|
+
* conn.exec_prepared(statement_name [, params, result_format[, type_map]] ) {|pg_result| block }
|
1094
1363
|
*
|
1095
1364
|
* Execute prepared named statement specified by _statement_name_.
|
1096
1365
|
* Returns a PG::Result instance on success.
|
@@ -1112,6 +1381,12 @@ pgconn_prepare(int argc, VALUE *argv, VALUE self)
|
|
1112
1381
|
* The optional +result_format+ should be 0 for text results, 1
|
1113
1382
|
* for binary.
|
1114
1383
|
*
|
1384
|
+
* type_map can be a PG::TypeMap derivation (such as PG::BasicTypeMapForQueries).
|
1385
|
+
* This will type cast the params form various Ruby types before transmission
|
1386
|
+
* based on the encoders defined by the type map. When a type encoder is used
|
1387
|
+
* the format and oid of a given bind parameter are retrieved from the encoder
|
1388
|
+
* instead out of the hash form described above.
|
1389
|
+
*
|
1115
1390
|
* If the optional code block is given, it will be passed <i>result</i> as an argument,
|
1116
1391
|
* and the PG::Result object will automatically be cleared when the block terminates.
|
1117
1392
|
* In this instance, <code>conn.exec_prepared</code> returns the value of the block.
|
@@ -1122,89 +1397,28 @@ pgconn_exec_prepared(int argc, VALUE *argv, VALUE self)
|
|
1122
1397
|
PGconn *conn = pg_get_pgconn(self);
|
1123
1398
|
PGresult *result = NULL;
|
1124
1399
|
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;
|
1400
|
+
VALUE name, in_res_fmt;
|
1131
1401
|
int nParams;
|
1132
|
-
char ** paramValues;
|
1133
|
-
int *paramLengths;
|
1134
|
-
int *paramFormats;
|
1135
1402
|
int resultFormat;
|
1403
|
+
struct query_params_data paramsData;
|
1136
1404
|
|
1137
|
-
|
1138
|
-
|
1405
|
+
rb_scan_args(argc, argv, "13", &name, ¶msData.params, &in_res_fmt, ¶msData.typemap);
|
1406
|
+
paramsData.with_types = 0;
|
1139
1407
|
Check_Type(name, T_STRING);
|
1140
1408
|
|
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);
|
1409
|
+
if(NIL_P(paramsData.params)) {
|
1410
|
+
paramsData.params = rb_ary_new2(0);
|
1154
1411
|
}
|
1412
|
+
pgconn_query_assign_typemap( self, ¶msData );
|
1155
1413
|
|
1156
|
-
|
1157
|
-
|
1158
|
-
sym_value = ID2SYM(rb_intern("value"));
|
1159
|
-
sym_format = ID2SYM(rb_intern("format"));
|
1160
|
-
nParams = (int)RARRAY_LEN(params);
|
1161
|
-
paramValues = ALLOC_N(char *, nParams);
|
1162
|
-
paramLengths = ALLOC_N(int, nParams);
|
1163
|
-
paramFormats = ALLOC_N(int, nParams);
|
1164
|
-
for(i = 0; i < nParams; i++) {
|
1165
|
-
param = rb_ary_entry(params, i);
|
1166
|
-
if (TYPE(param) == T_HASH) {
|
1167
|
-
param_value_tmp = rb_hash_aref(param, sym_value);
|
1168
|
-
if(param_value_tmp == Qnil)
|
1169
|
-
param_value = param_value_tmp;
|
1170
|
-
else
|
1171
|
-
param_value = rb_obj_as_string(param_value_tmp);
|
1172
|
-
param_format = rb_hash_aref(param, sym_format);
|
1173
|
-
}
|
1174
|
-
else {
|
1175
|
-
if(param == Qnil)
|
1176
|
-
param_value = param;
|
1177
|
-
else
|
1178
|
-
param_value = rb_obj_as_string(param);
|
1179
|
-
param_format = INT2NUM(0);
|
1180
|
-
}
|
1181
|
-
if(param_value == Qnil) {
|
1182
|
-
paramValues[i] = NULL;
|
1183
|
-
paramLengths[i] = 0;
|
1184
|
-
}
|
1185
|
-
else {
|
1186
|
-
Check_Type(param_value, T_STRING);
|
1187
|
-
/* make sure param_value doesn't get freed by the GC */
|
1188
|
-
rb_ary_push(gc_array, param_value);
|
1189
|
-
paramValues[i] = StringValuePtr(param_value);
|
1190
|
-
paramLengths[i] = (int)RSTRING_LEN(param_value);
|
1191
|
-
}
|
1192
|
-
|
1193
|
-
if(param_format == Qnil)
|
1194
|
-
paramFormats[i] = 0;
|
1195
|
-
else
|
1196
|
-
paramFormats[i] = NUM2INT(param_format);
|
1197
|
-
}
|
1414
|
+
resultFormat = NIL_P(in_res_fmt) ? 0 : NUM2INT(in_res_fmt);
|
1415
|
+
nParams = alloc_query_params( ¶msData );
|
1198
1416
|
|
1199
|
-
result = gvl_PQexecPrepared(conn,
|
1200
|
-
(const char * const *)
|
1417
|
+
result = gvl_PQexecPrepared(conn, StringValueCStr(name), nParams,
|
1418
|
+
(const char * const *)paramsData.values, paramsData.lengths, paramsData.formats,
|
1201
1419
|
resultFormat);
|
1202
1420
|
|
1203
|
-
|
1204
|
-
|
1205
|
-
xfree(paramValues);
|
1206
|
-
xfree(paramLengths);
|
1207
|
-
xfree(paramFormats);
|
1421
|
+
free_query_params( ¶msData );
|
1208
1422
|
|
1209
1423
|
rb_pgresult = pg_new_result(result, self);
|
1210
1424
|
pg_result_check(rb_pgresult);
|
@@ -1234,7 +1448,7 @@ pgconn_describe_prepared(VALUE self, VALUE stmt_name)
|
|
1234
1448
|
}
|
1235
1449
|
else {
|
1236
1450
|
Check_Type(stmt_name, T_STRING);
|
1237
|
-
stmt =
|
1451
|
+
stmt = StringValueCStr(stmt_name);
|
1238
1452
|
}
|
1239
1453
|
result = gvl_PQdescribePrepared(conn, stmt);
|
1240
1454
|
rb_pgresult = pg_new_result(result, self);
|
@@ -1262,7 +1476,7 @@ pgconn_describe_portal(self, stmt_name)
|
|
1262
1476
|
}
|
1263
1477
|
else {
|
1264
1478
|
Check_Type(stmt_name, T_STRING);
|
1265
|
-
stmt =
|
1479
|
+
stmt = StringValueCStr(stmt_name);
|
1266
1480
|
}
|
1267
1481
|
result = gvl_PQdescribePortal(conn, stmt);
|
1268
1482
|
rb_pgresult = pg_new_result(result, self);
|
@@ -1324,9 +1538,6 @@ pgconn_s_escape(VALUE self, VALUE string)
|
|
1324
1538
|
size_t size;
|
1325
1539
|
int error;
|
1326
1540
|
VALUE result;
|
1327
|
-
#ifdef M17N_SUPPORTED
|
1328
|
-
rb_encoding* enc;
|
1329
|
-
#endif
|
1330
1541
|
|
1331
1542
|
Check_Type(string, T_STRING);
|
1332
1543
|
|
@@ -1339,20 +1550,12 @@ pgconn_s_escape(VALUE self, VALUE string)
|
|
1339
1550
|
rb_raise(rb_ePGerror, "%s", PQerrorMessage(pg_get_pgconn(self)));
|
1340
1551
|
}
|
1341
1552
|
} else {
|
1342
|
-
size = PQescapeString(escaped, RSTRING_PTR(string), (
|
1553
|
+
size = PQescapeString(escaped, RSTRING_PTR(string), RSTRING_LENINT(string));
|
1343
1554
|
}
|
1344
1555
|
result = rb_str_new(escaped, size);
|
1345
1556
|
xfree(escaped);
|
1346
1557
|
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
|
1558
|
+
PG_ENCODING_SET_NOCHECK(result, ENCODING_GET( rb_obj_class(self) == rb_cPGconn ? self : string ));
|
1356
1559
|
|
1357
1560
|
return result;
|
1358
1561
|
}
|
@@ -1424,7 +1627,7 @@ pgconn_s_unescape_bytea(VALUE self, VALUE str)
|
|
1424
1627
|
UNUSED( self );
|
1425
1628
|
|
1426
1629
|
Check_Type(str, T_STRING);
|
1427
|
-
from = (unsigned char*)
|
1630
|
+
from = (unsigned char*)StringValueCStr(str);
|
1428
1631
|
|
1429
1632
|
to = PQunescapeBytea(from, &to_len);
|
1430
1633
|
|
@@ -1462,10 +1665,7 @@ pgconn_escape_literal(VALUE self, VALUE string)
|
|
1462
1665
|
result = rb_str_new2(escaped);
|
1463
1666
|
PQfreemem(escaped);
|
1464
1667
|
OBJ_INFECT(result, string);
|
1465
|
-
|
1466
|
-
#ifdef M17N_SUPPORTED
|
1467
|
-
rb_enc_associate(result, pg_conn_enc_get( pg_get_pgconn(self) ));
|
1468
|
-
#endif
|
1668
|
+
PG_ENCODING_SET_NOCHECK(result, ENCODING_GET(self));
|
1469
1669
|
|
1470
1670
|
return result;
|
1471
1671
|
}
|
@@ -1502,10 +1702,7 @@ pgconn_escape_identifier(VALUE self, VALUE string)
|
|
1502
1702
|
result = rb_str_new2(escaped);
|
1503
1703
|
PQfreemem(escaped);
|
1504
1704
|
OBJ_INFECT(result, string);
|
1505
|
-
|
1506
|
-
#ifdef M17N_SUPPORTED
|
1507
|
-
rb_enc_associate(result, pg_conn_enc_get( pg_get_pgconn(self) ));
|
1508
|
-
#endif
|
1705
|
+
PG_ENCODING_SET_NOCHECK(result, ENCODING_GET(self));
|
1509
1706
|
|
1510
1707
|
return result;
|
1511
1708
|
}
|
@@ -1522,7 +1719,7 @@ pgconn_escape_identifier(VALUE self, VALUE string)
|
|
1522
1719
|
* Then call Connection#get_result repeatedly, until it returns nil.
|
1523
1720
|
*
|
1524
1721
|
* Each (but the last) received Result has exactly one row and a
|
1525
|
-
* Result#result_status of PGRES_SINGLE_TUPLE. The last
|
1722
|
+
* Result#result_status of PGRES_SINGLE_TUPLE. The last Result has
|
1526
1723
|
* zero rows and is used to indicate a successful execution of the query.
|
1527
1724
|
* All of these Result objects will contain the same row description data
|
1528
1725
|
* (column names, types, etc) that an ordinary Result object for the query
|
@@ -1568,7 +1765,7 @@ pgconn_set_single_row_mode(VALUE self)
|
|
1568
1765
|
|
1569
1766
|
/*
|
1570
1767
|
* call-seq:
|
1571
|
-
* conn.send_query(sql [, params, result_format ] ) -> nil
|
1768
|
+
* conn.send_query(sql [, params, result_format[, type_map ]] ) -> nil
|
1572
1769
|
*
|
1573
1770
|
* Sends SQL query request specified by _sql_ to PostgreSQL for
|
1574
1771
|
* asynchronous processing, and immediately returns.
|
@@ -1596,32 +1793,32 @@ pgconn_set_single_row_mode(VALUE self)
|
|
1596
1793
|
*
|
1597
1794
|
* The optional +result_format+ should be 0 for text results, 1
|
1598
1795
|
* for binary.
|
1796
|
+
*
|
1797
|
+
* type_map can be a PG::TypeMap derivation (such as PG::BasicTypeMapForQueries).
|
1798
|
+
* This will type cast the params form various Ruby types before transmission
|
1799
|
+
* based on the encoders defined by the type map. When a type encoder is used
|
1800
|
+
* the format and oid of a given bind parameter are retrieved from the encoder
|
1801
|
+
* instead out of the hash form described above.
|
1802
|
+
*
|
1599
1803
|
*/
|
1600
1804
|
static VALUE
|
1601
1805
|
pgconn_send_query(int argc, VALUE *argv, VALUE self)
|
1602
1806
|
{
|
1603
1807
|
PGconn *conn = pg_get_pgconn(self);
|
1604
1808
|
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;
|
1809
|
+
VALUE command, in_res_fmt;
|
1610
1810
|
VALUE error;
|
1611
|
-
int i=0;
|
1612
1811
|
int nParams;
|
1613
|
-
Oid *paramTypes;
|
1614
|
-
char ** paramValues;
|
1615
|
-
int *paramLengths;
|
1616
|
-
int *paramFormats;
|
1617
1812
|
int resultFormat;
|
1813
|
+
struct query_params_data paramsData;
|
1618
1814
|
|
1619
|
-
rb_scan_args(argc, argv, "
|
1815
|
+
rb_scan_args(argc, argv, "13", &command, ¶msData.params, &in_res_fmt, ¶msData.typemap);
|
1816
|
+
paramsData.with_types = 1;
|
1620
1817
|
Check_Type(command, T_STRING);
|
1621
1818
|
|
1622
1819
|
/* If called with no parameters, use PQsendQuery */
|
1623
|
-
if(NIL_P(params)) {
|
1624
|
-
if(gvl_PQsendQuery(conn,
|
1820
|
+
if(NIL_P(paramsData.params)) {
|
1821
|
+
if(gvl_PQsendQuery(conn,StringValueCStr(command)) == 0) {
|
1625
1822
|
error = rb_exc_new2(rb_eUnableToSend, PQerrorMessage(conn));
|
1626
1823
|
rb_iv_set(error, "@connection", self);
|
1627
1824
|
rb_exc_raise(error);
|
@@ -1632,77 +1829,15 @@ pgconn_send_query(int argc, VALUE *argv, VALUE self)
|
|
1632
1829
|
/* If called with parameters, and optionally result_format,
|
1633
1830
|
* use PQsendQueryParams
|
1634
1831
|
*/
|
1635
|
-
Check_Type(params, T_ARRAY);
|
1636
1832
|
|
1637
|
-
|
1638
|
-
|
1639
|
-
|
1640
|
-
else {
|
1641
|
-
resultFormat = NUM2INT(in_res_fmt);
|
1642
|
-
}
|
1833
|
+
pgconn_query_assign_typemap( self, ¶msData );
|
1834
|
+
resultFormat = NIL_P(in_res_fmt) ? 0 : NUM2INT(in_res_fmt);
|
1835
|
+
nParams = alloc_query_params( ¶msData );
|
1643
1836
|
|
1644
|
-
|
1645
|
-
|
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
|
-
|
1691
|
-
if(param_format == Qnil)
|
1692
|
-
paramFormats[i] = 0;
|
1693
|
-
else
|
1694
|
-
paramFormats[i] = NUM2INT(param_format);
|
1695
|
-
}
|
1837
|
+
result = gvl_PQsendQueryParams(conn, StringValueCStr(command), nParams, paramsData.types,
|
1838
|
+
(const char * const *)paramsData.values, paramsData.lengths, paramsData.formats, resultFormat);
|
1696
1839
|
|
1697
|
-
|
1698
|
-
(const char * const *)paramValues, paramLengths, paramFormats, resultFormat);
|
1699
|
-
|
1700
|
-
rb_gc_unregister_address(&gc_array);
|
1701
|
-
|
1702
|
-
xfree(paramTypes);
|
1703
|
-
xfree(paramValues);
|
1704
|
-
xfree(paramLengths);
|
1705
|
-
xfree(paramFormats);
|
1840
|
+
free_query_params( ¶msData );
|
1706
1841
|
|
1707
1842
|
if(result == 0) {
|
1708
1843
|
error = rb_exc_new2(rb_eUnableToSend, PQerrorMessage(conn));
|
@@ -1754,14 +1889,13 @@ pgconn_send_prepare(int argc, VALUE *argv, VALUE self)
|
|
1754
1889
|
paramTypes = ALLOC_N(Oid, nParams);
|
1755
1890
|
for(i = 0; i < nParams; i++) {
|
1756
1891
|
param = rb_ary_entry(in_paramtypes, i);
|
1757
|
-
Check_Type(param, T_FIXNUM);
|
1758
1892
|
if(param == Qnil)
|
1759
1893
|
paramTypes[i] = 0;
|
1760
1894
|
else
|
1761
|
-
paramTypes[i] =
|
1895
|
+
paramTypes[i] = NUM2UINT(param);
|
1762
1896
|
}
|
1763
1897
|
}
|
1764
|
-
result = gvl_PQsendPrepare(conn,
|
1898
|
+
result = gvl_PQsendPrepare(conn, StringValueCStr(name), StringValueCStr(command),
|
1765
1899
|
nParams, paramTypes);
|
1766
1900
|
|
1767
1901
|
xfree(paramTypes);
|
@@ -1776,7 +1910,7 @@ pgconn_send_prepare(int argc, VALUE *argv, VALUE self)
|
|
1776
1910
|
|
1777
1911
|
/*
|
1778
1912
|
* call-seq:
|
1779
|
-
* conn.send_query_prepared( statement_name [, params, result_format ] )
|
1913
|
+
* conn.send_query_prepared( statement_name [, params, result_format[, type_map ]] )
|
1780
1914
|
* -> nil
|
1781
1915
|
*
|
1782
1916
|
* Execute prepared named statement specified by _statement_name_
|
@@ -1798,96 +1932,43 @@ pgconn_send_prepare(int argc, VALUE *argv, VALUE self)
|
|
1798
1932
|
*
|
1799
1933
|
* The optional +result_format+ should be 0 for text results, 1
|
1800
1934
|
* for binary.
|
1935
|
+
*
|
1936
|
+
* type_map can be a PG::TypeMap derivation (such as PG::BasicTypeMapForQueries).
|
1937
|
+
* This will type cast the params form various Ruby types before transmission
|
1938
|
+
* based on the encoders defined by the type map. When a type encoder is used
|
1939
|
+
* the format and oid of a given bind parameter are retrieved from the encoder
|
1940
|
+
* instead out of the hash form described above.
|
1941
|
+
*
|
1801
1942
|
*/
|
1802
1943
|
static VALUE
|
1803
1944
|
pgconn_send_query_prepared(int argc, VALUE *argv, VALUE self)
|
1804
1945
|
{
|
1805
1946
|
PGconn *conn = pg_get_pgconn(self);
|
1806
1947
|
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;
|
1948
|
+
VALUE name, in_res_fmt;
|
1812
1949
|
VALUE error;
|
1813
|
-
int i = 0;
|
1814
1950
|
int nParams;
|
1815
|
-
char ** paramValues;
|
1816
|
-
int *paramLengths;
|
1817
|
-
int *paramFormats;
|
1818
1951
|
int resultFormat;
|
1952
|
+
struct query_params_data paramsData;
|
1819
1953
|
|
1820
|
-
rb_scan_args(argc, argv, "
|
1954
|
+
rb_scan_args(argc, argv, "13", &name, ¶msData.params, &in_res_fmt, ¶msData.typemap);
|
1955
|
+
paramsData.with_types = 0;
|
1821
1956
|
Check_Type(name, T_STRING);
|
1822
1957
|
|
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)) {
|
1958
|
+
if(NIL_P(paramsData.params)) {
|
1959
|
+
paramsData.params = rb_ary_new2(0);
|
1832
1960
|
resultFormat = 0;
|
1833
1961
|
}
|
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
|
-
}
|
1962
|
+
pgconn_query_assign_typemap( self, ¶msData );
|
1875
1963
|
|
1876
|
-
|
1877
|
-
|
1878
|
-
else
|
1879
|
-
paramFormats[i] = NUM2INT(param_format);
|
1880
|
-
}
|
1964
|
+
resultFormat = NIL_P(in_res_fmt) ? 0 : NUM2INT(in_res_fmt);
|
1965
|
+
nParams = alloc_query_params( ¶msData );
|
1881
1966
|
|
1882
|
-
result = gvl_PQsendQueryPrepared(conn,
|
1883
|
-
(const char * const *)
|
1967
|
+
result = gvl_PQsendQueryPrepared(conn, StringValueCStr(name), nParams,
|
1968
|
+
(const char * const *)paramsData.values, paramsData.lengths, paramsData.formats,
|
1884
1969
|
resultFormat);
|
1885
1970
|
|
1886
|
-
|
1887
|
-
|
1888
|
-
xfree(paramValues);
|
1889
|
-
xfree(paramLengths);
|
1890
|
-
xfree(paramFormats);
|
1971
|
+
free_query_params( ¶msData );
|
1891
1972
|
|
1892
1973
|
if(result == 0) {
|
1893
1974
|
error = rb_exc_new2(rb_eUnableToSend, PQerrorMessage(conn));
|
@@ -1910,7 +1991,7 @@ pgconn_send_describe_prepared(VALUE self, VALUE stmt_name)
|
|
1910
1991
|
VALUE error;
|
1911
1992
|
PGconn *conn = pg_get_pgconn(self);
|
1912
1993
|
/* returns 0 on failure */
|
1913
|
-
if(gvl_PQsendDescribePrepared(conn,
|
1994
|
+
if(gvl_PQsendDescribePrepared(conn,StringValueCStr(stmt_name)) == 0) {
|
1914
1995
|
error = rb_exc_new2(rb_eUnableToSend, PQerrorMessage(conn));
|
1915
1996
|
rb_iv_set(error, "@connection", self);
|
1916
1997
|
rb_exc_raise(error);
|
@@ -1932,7 +2013,7 @@ pgconn_send_describe_portal(VALUE self, VALUE portal)
|
|
1932
2013
|
VALUE error;
|
1933
2014
|
PGconn *conn = pg_get_pgconn(self);
|
1934
2015
|
/* returns 0 on failure */
|
1935
|
-
if(gvl_PQsendDescribePortal(conn,
|
2016
|
+
if(gvl_PQsendDescribePortal(conn,StringValueCStr(portal)) == 0) {
|
1936
2017
|
error = rb_exc_new2(rb_eUnableToSend, PQerrorMessage(conn));
|
1937
2018
|
rb_iv_set(error, "@connection", self);
|
1938
2019
|
rb_exc_raise(error);
|
@@ -2157,10 +2238,8 @@ pgconn_notifies(VALUE self)
|
|
2157
2238
|
relname = rb_tainted_str_new2(notification->relname);
|
2158
2239
|
be_pid = INT2NUM(notification->be_pid);
|
2159
2240
|
extra = rb_tainted_str_new2(notification->extra);
|
2160
|
-
|
2161
|
-
|
2162
|
-
ENCODING_SET( extra, rb_enc_to_index(pg_conn_enc_get( conn )) );
|
2163
|
-
#endif
|
2241
|
+
PG_ENCODING_SET_NOCHECK( relname, ENCODING_GET(self) );
|
2242
|
+
PG_ENCODING_SET_NOCHECK( extra, ENCODING_GET(self) );
|
2164
2243
|
|
2165
2244
|
rb_hash_aset(hash, sym_relname, relname);
|
2166
2245
|
rb_hash_aset(hash, sym_be_pid, be_pid);
|
@@ -2429,16 +2508,12 @@ pgconn_wait_for_notify(int argc, VALUE *argv, VALUE self)
|
|
2429
2508
|
if ( !pnotification ) return Qnil;
|
2430
2509
|
|
2431
2510
|
relname = rb_tainted_str_new2( pnotification->relname );
|
2432
|
-
|
2433
|
-
ENCODING_SET( relname, rb_enc_to_index(pg_conn_enc_get( conn )) );
|
2434
|
-
#endif
|
2511
|
+
PG_ENCODING_SET_NOCHECK( relname, ENCODING_GET(self) );
|
2435
2512
|
be_pid = INT2NUM( pnotification->be_pid );
|
2436
2513
|
#ifdef HAVE_ST_NOTIFY_EXTRA
|
2437
2514
|
if ( *pnotification->extra ) {
|
2438
2515
|
extra = rb_tainted_str_new2( pnotification->extra );
|
2439
|
-
|
2440
|
-
ENCODING_SET( extra, rb_enc_to_index(pg_conn_enc_get( conn )) );
|
2441
|
-
#endif
|
2516
|
+
PG_ENCODING_SET_NOCHECK( extra, ENCODING_GET(self) );
|
2442
2517
|
}
|
2443
2518
|
#endif
|
2444
2519
|
PQfreemem( pnotification );
|
@@ -2452,33 +2527,77 @@ pgconn_wait_for_notify(int argc, VALUE *argv, VALUE self)
|
|
2452
2527
|
|
2453
2528
|
/*
|
2454
2529
|
* call-seq:
|
2455
|
-
* conn.put_copy_data( buffer ) -> Boolean
|
2530
|
+
* conn.put_copy_data( buffer [, encoder] ) -> Boolean
|
2456
2531
|
*
|
2457
2532
|
* Transmits _buffer_ as copy data to the server.
|
2458
2533
|
* Returns true if the data was sent, false if it was
|
2459
2534
|
* not sent (false is only possible if the connection
|
2460
2535
|
* is in nonblocking mode, and this command would block).
|
2461
2536
|
*
|
2537
|
+
* encoder can be a PG::Coder derivation (typically PG::TestEncoder::CopyRow).
|
2538
|
+
* This encodes the received data fields from an Array of Strings. Optionally
|
2539
|
+
* the encoder can type cast the fields form various Ruby types in one step,
|
2540
|
+
* if PG::TestEncoder::CopyRow#type_map is set accordingly.
|
2541
|
+
*
|
2462
2542
|
* Raises an exception if an error occurs.
|
2463
2543
|
*
|
2464
2544
|
* See also #copy_data.
|
2465
2545
|
*
|
2466
2546
|
*/
|
2467
2547
|
static VALUE
|
2468
|
-
pgconn_put_copy_data(
|
2469
|
-
VALUE self, buffer;
|
2548
|
+
pgconn_put_copy_data(int argc, VALUE *argv, VALUE self)
|
2470
2549
|
{
|
2471
2550
|
int ret;
|
2472
|
-
|
2473
|
-
|
2551
|
+
int len;
|
2552
|
+
t_pg_connection *this = pg_get_connection_safe( self );
|
2553
|
+
VALUE value;
|
2554
|
+
VALUE buffer = Qnil;
|
2555
|
+
VALUE encoder;
|
2556
|
+
VALUE intermediate;
|
2557
|
+
t_pg_coder *p_coder = NULL;
|
2558
|
+
|
2559
|
+
rb_scan_args( argc, argv, "11", &value, &encoder );
|
2560
|
+
|
2561
|
+
if( NIL_P(encoder) ){
|
2562
|
+
if( NIL_P(this->encoder_for_put_copy_data) ){
|
2563
|
+
buffer = value;
|
2564
|
+
} else {
|
2565
|
+
p_coder = DATA_PTR( this->encoder_for_put_copy_data );
|
2566
|
+
}
|
2567
|
+
} else if( rb_obj_is_kind_of(encoder, rb_cPG_Coder) ) {
|
2568
|
+
Data_Get_Struct( encoder, t_pg_coder, p_coder );
|
2569
|
+
} else {
|
2570
|
+
rb_raise( rb_eTypeError, "wrong encoder type %s (expected some kind of PG::Coder)",
|
2571
|
+
rb_obj_classname( encoder ) );
|
2572
|
+
}
|
2573
|
+
|
2574
|
+
if( p_coder ){
|
2575
|
+
t_pg_coder_enc_func enc_func;
|
2576
|
+
|
2577
|
+
enc_func = pg_coder_enc_func( p_coder );
|
2578
|
+
len = enc_func( p_coder, value, NULL, &intermediate );
|
2579
|
+
|
2580
|
+
if( len == -1 ){
|
2581
|
+
/* The intermediate value is a String that can be used directly. */
|
2582
|
+
buffer = intermediate;
|
2583
|
+
} else {
|
2584
|
+
buffer = rb_str_new(NULL, len);
|
2585
|
+
len = enc_func( p_coder, value, RSTRING_PTR(buffer), &intermediate);
|
2586
|
+
rb_str_set_len( buffer, len );
|
2587
|
+
}
|
2588
|
+
}
|
2589
|
+
|
2474
2590
|
Check_Type(buffer, T_STRING);
|
2475
2591
|
|
2476
|
-
ret = gvl_PQputCopyData(
|
2592
|
+
ret = gvl_PQputCopyData(this->pgconn, RSTRING_PTR(buffer), RSTRING_LENINT(buffer));
|
2477
2593
|
if(ret == -1) {
|
2478
|
-
error = rb_exc_new2(rb_ePGerror, PQerrorMessage(
|
2594
|
+
VALUE error = rb_exc_new2(rb_ePGerror, PQerrorMessage(this->pgconn));
|
2479
2595
|
rb_iv_set(error, "@connection", self);
|
2480
2596
|
rb_exc_raise(error);
|
2481
2597
|
}
|
2598
|
+
RB_GC_GUARD(intermediate);
|
2599
|
+
RB_GC_GUARD(buffer);
|
2600
|
+
|
2482
2601
|
return (ret) ? Qtrue : Qfalse;
|
2483
2602
|
}
|
2484
2603
|
|
@@ -2508,7 +2627,7 @@ pgconn_put_copy_end(int argc, VALUE *argv, VALUE self)
|
|
2508
2627
|
if (rb_scan_args(argc, argv, "01", &str) == 0)
|
2509
2628
|
error_message = NULL;
|
2510
2629
|
else
|
2511
|
-
error_message =
|
2630
|
+
error_message = StringValueCStr(str);
|
2512
2631
|
|
2513
2632
|
ret = gvl_PQputCopyEnd(conn, error_message);
|
2514
2633
|
if(ret == -1) {
|
@@ -2521,12 +2640,17 @@ pgconn_put_copy_end(int argc, VALUE *argv, VALUE self)
|
|
2521
2640
|
|
2522
2641
|
/*
|
2523
2642
|
* call-seq:
|
2524
|
-
* conn.get_copy_data( [ async = false ] ) -> String
|
2643
|
+
* conn.get_copy_data( [ async = false [, decoder = nil ]] ) -> String
|
2525
2644
|
*
|
2526
2645
|
* Return a string containing one row of data, +nil+
|
2527
2646
|
* if the copy is done, or +false+ if the call would
|
2528
2647
|
* block (only possible if _async_ is true).
|
2529
2648
|
*
|
2649
|
+
* decoder can be a PG::Coder derivation (typically PG::TestDecoder::CopyRow).
|
2650
|
+
* This decodes the received data fields as Array of Strings. Optionally
|
2651
|
+
* the decoder can type cast the fields to various Ruby types in one step,
|
2652
|
+
* if PG::TestDecoder::CopyRow#type_map is set accordingly.
|
2653
|
+
*
|
2530
2654
|
* See also #copy_data.
|
2531
2655
|
*
|
2532
2656
|
*/
|
@@ -2535,20 +2659,29 @@ pgconn_get_copy_data(int argc, VALUE *argv, VALUE self )
|
|
2535
2659
|
{
|
2536
2660
|
VALUE async_in;
|
2537
2661
|
VALUE error;
|
2538
|
-
VALUE
|
2662
|
+
VALUE result;
|
2539
2663
|
int ret;
|
2540
|
-
int async;
|
2541
2664
|
char *buffer;
|
2542
|
-
|
2665
|
+
VALUE decoder;
|
2666
|
+
t_pg_coder *p_coder = NULL;
|
2667
|
+
t_pg_connection *this = pg_get_connection_safe( self );
|
2543
2668
|
|
2544
|
-
|
2545
|
-
|
2546
|
-
|
2547
|
-
|
2669
|
+
rb_scan_args(argc, argv, "02", &async_in, &decoder);
|
2670
|
+
|
2671
|
+
if( NIL_P(decoder) ){
|
2672
|
+
if( !NIL_P(this->decoder_for_get_copy_data) ){
|
2673
|
+
p_coder = DATA_PTR( this->decoder_for_get_copy_data );
|
2674
|
+
}
|
2675
|
+
} else if( rb_obj_is_kind_of(decoder, rb_cPG_Coder) ) {
|
2676
|
+
Data_Get_Struct( decoder, t_pg_coder, p_coder );
|
2677
|
+
} else {
|
2678
|
+
rb_raise( rb_eTypeError, "wrong decoder type %s (expected some kind of PG::Coder)",
|
2679
|
+
rb_obj_classname( decoder ) );
|
2680
|
+
}
|
2548
2681
|
|
2549
|
-
ret = gvl_PQgetCopyData(
|
2682
|
+
ret = gvl_PQgetCopyData(this->pgconn, &buffer, RTEST(async_in));
|
2550
2683
|
if(ret == -2) { /* error */
|
2551
|
-
error = rb_exc_new2(rb_ePGerror, PQerrorMessage(
|
2684
|
+
error = rb_exc_new2(rb_ePGerror, PQerrorMessage(this->pgconn));
|
2552
2685
|
rb_iv_set(error, "@connection", self);
|
2553
2686
|
rb_exc_raise(error);
|
2554
2687
|
}
|
@@ -2558,9 +2691,16 @@ pgconn_get_copy_data(int argc, VALUE *argv, VALUE self )
|
|
2558
2691
|
if(ret == 0) { /* would block */
|
2559
2692
|
return Qfalse;
|
2560
2693
|
}
|
2561
|
-
|
2694
|
+
|
2695
|
+
if( p_coder ){
|
2696
|
+
t_pg_coder_dec_func dec_func = pg_coder_dec_func( p_coder, p_coder->format );
|
2697
|
+
result = dec_func( p_coder, buffer, ret, 0, 0, ENCODING_GET(self) );
|
2698
|
+
} else {
|
2699
|
+
result = rb_tainted_str_new(buffer, ret);
|
2700
|
+
}
|
2701
|
+
|
2562
2702
|
PQfreemem(buffer);
|
2563
|
-
return
|
2703
|
+
return result;
|
2564
2704
|
}
|
2565
2705
|
|
2566
2706
|
/*
|
@@ -2597,6 +2737,7 @@ pgconn_trace(VALUE self, VALUE stream)
|
|
2597
2737
|
FILE *new_fp;
|
2598
2738
|
int old_fd, new_fd;
|
2599
2739
|
VALUE new_file;
|
2740
|
+
t_pg_connection *this = pg_get_connection_safe( self );
|
2600
2741
|
|
2601
2742
|
if(rb_respond_to(stream,rb_intern("fileno")) == Qfalse)
|
2602
2743
|
rb_raise(rb_eArgError, "stream does not respond to method: fileno");
|
@@ -2619,9 +2760,9 @@ pgconn_trace(VALUE self, VALUE stream)
|
|
2619
2760
|
rb_raise(rb_eArgError, "stream is not writable");
|
2620
2761
|
|
2621
2762
|
new_file = rb_funcall(rb_cIO, rb_intern("new"), 1, INT2NUM(new_fd));
|
2622
|
-
|
2763
|
+
this->trace_stream = new_file;
|
2623
2764
|
|
2624
|
-
PQtrace(
|
2765
|
+
PQtrace(this->pgconn, new_fp);
|
2625
2766
|
return Qnil;
|
2626
2767
|
}
|
2627
2768
|
|
@@ -2634,11 +2775,11 @@ pgconn_trace(VALUE self, VALUE stream)
|
|
2634
2775
|
static VALUE
|
2635
2776
|
pgconn_untrace(VALUE self)
|
2636
2777
|
{
|
2637
|
-
|
2638
|
-
|
2639
|
-
|
2640
|
-
rb_funcall(trace_stream, rb_intern("close"), 0);
|
2641
|
-
|
2778
|
+
t_pg_connection *this = pg_get_connection_safe( self );
|
2779
|
+
|
2780
|
+
PQuntrace(this->pgconn);
|
2781
|
+
rb_funcall(this->trace_stream, rb_intern("close"), 0);
|
2782
|
+
this->trace_stream = Qnil;
|
2642
2783
|
return Qnil;
|
2643
2784
|
}
|
2644
2785
|
|
@@ -2648,19 +2789,16 @@ pgconn_untrace(VALUE self)
|
|
2648
2789
|
* currently-registered Ruby notice_receiver object.
|
2649
2790
|
*/
|
2650
2791
|
void
|
2651
|
-
notice_receiver_proxy(void *arg, const PGresult *
|
2792
|
+
notice_receiver_proxy(void *arg, const PGresult *pgresult)
|
2652
2793
|
{
|
2653
|
-
VALUE proc;
|
2654
2794
|
VALUE self = (VALUE)arg;
|
2795
|
+
t_pg_connection *this = pg_get_connection( self );
|
2655
2796
|
|
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);
|
2797
|
+
if (this->notice_receiver != Qnil) {
|
2798
|
+
VALUE result = pg_new_result_autoclear( (PGresult *)pgresult, self );
|
2799
|
+
|
2800
|
+
rb_funcall(this->notice_receiver, rb_intern("call"), 1, result);
|
2801
|
+
pg_result_clear( result );
|
2664
2802
|
}
|
2665
2803
|
return;
|
2666
2804
|
}
|
@@ -2698,7 +2836,7 @@ static VALUE
|
|
2698
2836
|
pgconn_set_notice_receiver(VALUE self)
|
2699
2837
|
{
|
2700
2838
|
VALUE proc, old_proc;
|
2701
|
-
|
2839
|
+
t_pg_connection *this = pg_get_connection_safe( self );
|
2702
2840
|
|
2703
2841
|
/* If default_notice_receiver is unset, assume that the current
|
2704
2842
|
* notice receiver is the default, and save it to a global variable.
|
@@ -2706,19 +2844,19 @@ pgconn_set_notice_receiver(VALUE self)
|
|
2706
2844
|
* always the same, so won't vary among connections.
|
2707
2845
|
*/
|
2708
2846
|
if(default_notice_receiver == NULL)
|
2709
|
-
default_notice_receiver = PQsetNoticeReceiver(
|
2847
|
+
default_notice_receiver = PQsetNoticeReceiver(this->pgconn, NULL, NULL);
|
2710
2848
|
|
2711
|
-
old_proc =
|
2849
|
+
old_proc = this->notice_receiver;
|
2712
2850
|
if( rb_block_given_p() ) {
|
2713
2851
|
proc = rb_block_proc();
|
2714
|
-
PQsetNoticeReceiver(
|
2852
|
+
PQsetNoticeReceiver(this->pgconn, gvl_notice_receiver_proxy, (void *)self);
|
2715
2853
|
} else {
|
2716
2854
|
/* if no block is given, set back to default */
|
2717
2855
|
proc = Qnil;
|
2718
|
-
PQsetNoticeReceiver(
|
2856
|
+
PQsetNoticeReceiver(this->pgconn, default_notice_receiver, NULL);
|
2719
2857
|
}
|
2720
2858
|
|
2721
|
-
|
2859
|
+
this->notice_receiver = proc;
|
2722
2860
|
return old_proc;
|
2723
2861
|
}
|
2724
2862
|
|
@@ -2730,17 +2868,13 @@ pgconn_set_notice_receiver(VALUE self)
|
|
2730
2868
|
void
|
2731
2869
|
notice_processor_proxy(void *arg, const char *message)
|
2732
2870
|
{
|
2733
|
-
VALUE proc;
|
2734
2871
|
VALUE self = (VALUE)arg;
|
2872
|
+
t_pg_connection *this = pg_get_connection( self );
|
2735
2873
|
|
2736
|
-
if (
|
2874
|
+
if (this->notice_receiver != Qnil) {
|
2737
2875
|
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);
|
2876
|
+
PG_ENCODING_SET_NOCHECK( message_str, ENCODING_GET(self) );
|
2877
|
+
rb_funcall(this->notice_receiver, rb_intern("call"), 1, message_str);
|
2744
2878
|
}
|
2745
2879
|
return;
|
2746
2880
|
}
|
@@ -2762,7 +2896,7 @@ static VALUE
|
|
2762
2896
|
pgconn_set_notice_processor(VALUE self)
|
2763
2897
|
{
|
2764
2898
|
VALUE proc, old_proc;
|
2765
|
-
|
2899
|
+
t_pg_connection *this = pg_get_connection_safe( self );
|
2766
2900
|
|
2767
2901
|
/* If default_notice_processor is unset, assume that the current
|
2768
2902
|
* notice processor is the default, and save it to a global variable.
|
@@ -2770,19 +2904,19 @@ pgconn_set_notice_processor(VALUE self)
|
|
2770
2904
|
* always the same, so won't vary among connections.
|
2771
2905
|
*/
|
2772
2906
|
if(default_notice_processor == NULL)
|
2773
|
-
default_notice_processor = PQsetNoticeProcessor(
|
2907
|
+
default_notice_processor = PQsetNoticeProcessor(this->pgconn, NULL, NULL);
|
2774
2908
|
|
2775
|
-
old_proc =
|
2909
|
+
old_proc = this->notice_receiver;
|
2776
2910
|
if( rb_block_given_p() ) {
|
2777
2911
|
proc = rb_block_proc();
|
2778
|
-
PQsetNoticeProcessor(
|
2912
|
+
PQsetNoticeProcessor(this->pgconn, gvl_notice_processor_proxy, (void *)self);
|
2779
2913
|
} else {
|
2780
2914
|
/* if no block is given, set back to default */
|
2781
2915
|
proc = Qnil;
|
2782
|
-
PQsetNoticeProcessor(
|
2916
|
+
PQsetNoticeProcessor(this->pgconn, default_notice_processor, NULL);
|
2783
2917
|
}
|
2784
2918
|
|
2785
|
-
|
2919
|
+
this->notice_receiver = proc;
|
2786
2920
|
return old_proc;
|
2787
2921
|
}
|
2788
2922
|
|
@@ -2814,9 +2948,12 @@ pgconn_set_client_encoding(VALUE self, VALUE str)
|
|
2814
2948
|
|
2815
2949
|
Check_Type(str, T_STRING);
|
2816
2950
|
|
2817
|
-
if ( (PQsetClientEncoding(conn,
|
2818
|
-
rb_raise(rb_ePGerror, "invalid encoding name: %s",
|
2951
|
+
if ( (PQsetClientEncoding(conn, StringValueCStr(str))) == -1 ) {
|
2952
|
+
rb_raise(rb_ePGerror, "invalid encoding name: %s",StringValueCStr(str));
|
2819
2953
|
}
|
2954
|
+
#ifdef M17N_SUPPORTED
|
2955
|
+
pgconn_set_internal_encoding_index( self );
|
2956
|
+
#endif
|
2820
2957
|
|
2821
2958
|
return Qnil;
|
2822
2959
|
}
|
@@ -2895,19 +3032,15 @@ pgconn_s_quote_ident(VALUE self, VALUE in_str)
|
|
2895
3032
|
* double-quotes. */
|
2896
3033
|
char buffer[NAMEDATALEN*2+2];
|
2897
3034
|
unsigned int i=0,j=0;
|
2898
|
-
|
2899
|
-
rb_encoding* enc;
|
2900
|
-
#endif
|
3035
|
+
unsigned int str_len = RSTRING_LENINT(in_str);
|
2901
3036
|
|
2902
|
-
|
2903
|
-
|
2904
|
-
if(strlen(str) >= NAMEDATALEN) {
|
3037
|
+
if(str_len >= NAMEDATALEN) {
|
2905
3038
|
rb_raise(rb_eArgError,
|
2906
3039
|
"Input string is longer than NAMEDATALEN-1 (%d)",
|
2907
3040
|
NAMEDATALEN-1);
|
2908
3041
|
}
|
2909
3042
|
buffer[j++] = '"';
|
2910
|
-
for(i = 0; i <
|
3043
|
+
for(i = 0; i < str_len && str[i]; i++) {
|
2911
3044
|
if(str[i] == '"')
|
2912
3045
|
buffer[j++] = '"';
|
2913
3046
|
buffer[j++] = str[i];
|
@@ -2915,15 +3048,7 @@ pgconn_s_quote_ident(VALUE self, VALUE in_str)
|
|
2915
3048
|
buffer[j++] = '"';
|
2916
3049
|
ret = rb_str_new(buffer,j);
|
2917
3050
|
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
|
3051
|
+
PG_ENCODING_SET_NOCHECK(ret, ENCODING_GET( rb_obj_class(self) == rb_cPGconn ? self : in_str ));
|
2927
3052
|
|
2928
3053
|
return ret;
|
2929
3054
|
}
|
@@ -3077,7 +3202,7 @@ pgconn_locreat(int argc, VALUE *argv, VALUE self)
|
|
3077
3202
|
if (lo_oid == 0)
|
3078
3203
|
rb_raise(rb_ePGerror, "lo_creat failed");
|
3079
3204
|
|
3080
|
-
return
|
3205
|
+
return UINT2NUM(lo_oid);
|
3081
3206
|
}
|
3082
3207
|
|
3083
3208
|
/*
|
@@ -3092,13 +3217,13 @@ pgconn_locreate(VALUE self, VALUE in_lo_oid)
|
|
3092
3217
|
{
|
3093
3218
|
Oid ret, lo_oid;
|
3094
3219
|
PGconn *conn = pg_get_pgconn(self);
|
3095
|
-
lo_oid =
|
3220
|
+
lo_oid = NUM2UINT(in_lo_oid);
|
3096
3221
|
|
3097
3222
|
ret = lo_create(conn, lo_oid);
|
3098
3223
|
if (ret == InvalidOid)
|
3099
3224
|
rb_raise(rb_ePGerror, "lo_create failed");
|
3100
3225
|
|
3101
|
-
return
|
3226
|
+
return UINT2NUM(ret);
|
3102
3227
|
}
|
3103
3228
|
|
3104
3229
|
/*
|
@@ -3118,11 +3243,11 @@ pgconn_loimport(VALUE self, VALUE filename)
|
|
3118
3243
|
|
3119
3244
|
Check_Type(filename, T_STRING);
|
3120
3245
|
|
3121
|
-
lo_oid = lo_import(conn,
|
3246
|
+
lo_oid = lo_import(conn, StringValueCStr(filename));
|
3122
3247
|
if (lo_oid == 0) {
|
3123
3248
|
rb_raise(rb_ePGerror, "%s", PQerrorMessage(conn));
|
3124
3249
|
}
|
3125
|
-
return
|
3250
|
+
return UINT2NUM(lo_oid);
|
3126
3251
|
}
|
3127
3252
|
|
3128
3253
|
/*
|
@@ -3135,15 +3260,12 @@ static VALUE
|
|
3135
3260
|
pgconn_loexport(VALUE self, VALUE lo_oid, VALUE filename)
|
3136
3261
|
{
|
3137
3262
|
PGconn *conn = pg_get_pgconn(self);
|
3138
|
-
|
3263
|
+
Oid oid;
|
3139
3264
|
Check_Type(filename, T_STRING);
|
3140
3265
|
|
3141
|
-
oid =
|
3142
|
-
if (oid < 0) {
|
3143
|
-
rb_raise(rb_ePGerror, "invalid large object oid %d",oid);
|
3144
|
-
}
|
3266
|
+
oid = NUM2UINT(lo_oid);
|
3145
3267
|
|
3146
|
-
if (lo_export(conn, oid,
|
3268
|
+
if (lo_export(conn, oid, StringValueCStr(filename)) < 0) {
|
3147
3269
|
rb_raise(rb_ePGerror, "%s", PQerrorMessage(conn));
|
3148
3270
|
}
|
3149
3271
|
return Qnil;
|
@@ -3168,7 +3290,7 @@ pgconn_loopen(int argc, VALUE *argv, VALUE self)
|
|
3168
3290
|
PGconn *conn = pg_get_pgconn(self);
|
3169
3291
|
|
3170
3292
|
rb_scan_args(argc, argv, "11", &selfid, &nmode);
|
3171
|
-
lo_oid =
|
3293
|
+
lo_oid = NUM2UINT(selfid);
|
3172
3294
|
if(NIL_P(nmode))
|
3173
3295
|
mode = INV_READ;
|
3174
3296
|
else
|
@@ -3335,10 +3457,7 @@ static VALUE
|
|
3335
3457
|
pgconn_lounlink(VALUE self, VALUE in_oid)
|
3336
3458
|
{
|
3337
3459
|
PGconn *conn = pg_get_pgconn(self);
|
3338
|
-
|
3339
|
-
|
3340
|
-
if (oid < 0)
|
3341
|
-
rb_raise(rb_ePGerror, "invalid oid %d",oid);
|
3460
|
+
Oid oid = NUM2UINT(in_oid);
|
3342
3461
|
|
3343
3462
|
if(lo_unlink(conn,oid) < 0)
|
3344
3463
|
rb_raise(rb_ePGerror,"lo_unlink failed");
|
@@ -3349,6 +3468,14 @@ pgconn_lounlink(VALUE self, VALUE in_oid)
|
|
3349
3468
|
|
3350
3469
|
#ifdef M17N_SUPPORTED
|
3351
3470
|
|
3471
|
+
void
|
3472
|
+
pgconn_set_internal_encoding_index( VALUE self )
|
3473
|
+
{
|
3474
|
+
PGconn *conn = pg_get_pgconn(self);
|
3475
|
+
rb_encoding *enc = pg_conn_enc_get( conn );
|
3476
|
+
PG_ENCODING_SET_NOCHECK( self, rb_enc_to_index(enc));
|
3477
|
+
}
|
3478
|
+
|
3352
3479
|
/*
|
3353
3480
|
* call-seq:
|
3354
3481
|
* conn.internal_encoding -> Encoding
|
@@ -3389,11 +3516,12 @@ static VALUE pgconn_external_encoding(VALUE self);
|
|
3389
3516
|
static VALUE
|
3390
3517
|
pgconn_internal_encoding_set(VALUE self, VALUE enc)
|
3391
3518
|
{
|
3519
|
+
VALUE enc_inspect;
|
3392
3520
|
if (NIL_P(enc)) {
|
3393
3521
|
pgconn_set_client_encoding( self, rb_usascii_str_new_cstr("SQL_ASCII") );
|
3394
3522
|
return enc;
|
3395
3523
|
}
|
3396
|
-
else if ( TYPE(enc) == T_STRING && strcasecmp("JOHAB",
|
3524
|
+
else if ( TYPE(enc) == T_STRING && strcasecmp("JOHAB", StringValueCStr(enc)) == 0 ) {
|
3397
3525
|
pgconn_set_client_encoding(self, rb_usascii_str_new_cstr("JOHAB"));
|
3398
3526
|
return enc;
|
3399
3527
|
}
|
@@ -3406,10 +3534,12 @@ pgconn_internal_encoding_set(VALUE self, VALUE enc)
|
|
3406
3534
|
rb_raise( rb_eEncCompatError, "incompatible character encodings: %s and %s",
|
3407
3535
|
rb_enc_name(rb_to_encoding(server_encoding)), name );
|
3408
3536
|
}
|
3537
|
+
pgconn_set_internal_encoding_index( self );
|
3409
3538
|
return enc;
|
3410
3539
|
}
|
3411
3540
|
|
3412
|
-
|
3541
|
+
enc_inspect = rb_inspect(enc);
|
3542
|
+
rb_raise( rb_ePGerror, "unknown encoding: %s", StringValueCStr(enc_inspect) );
|
3413
3543
|
|
3414
3544
|
return Qnil;
|
3415
3545
|
}
|
@@ -3426,21 +3556,18 @@ pgconn_internal_encoding_set(VALUE self, VALUE enc)
|
|
3426
3556
|
static VALUE
|
3427
3557
|
pgconn_external_encoding(VALUE self)
|
3428
3558
|
{
|
3429
|
-
|
3430
|
-
VALUE encoding = rb_iv_get( self, "@external_encoding" );
|
3559
|
+
t_pg_connection *this = pg_get_connection_safe( self );
|
3431
3560
|
rb_encoding *enc = NULL;
|
3432
3561
|
const char *pg_encname = NULL;
|
3433
3562
|
|
3434
3563
|
/* Use cached value if found */
|
3435
|
-
if ( RTEST(
|
3564
|
+
if ( RTEST(this->external_encoding) ) return this->external_encoding;
|
3436
3565
|
|
3437
|
-
pg_encname = PQparameterStatus(
|
3566
|
+
pg_encname = PQparameterStatus( this->pgconn, "server_encoding" );
|
3438
3567
|
enc = pg_get_pg_encname_as_rb_encoding( pg_encname );
|
3439
|
-
|
3440
|
-
|
3441
|
-
rb_iv_set( self, "@external_encoding", encoding );
|
3568
|
+
this->external_encoding = rb_enc_from_encoding( enc );
|
3442
3569
|
|
3443
|
-
return
|
3570
|
+
return this->external_encoding;
|
3444
3571
|
}
|
3445
3572
|
|
3446
3573
|
|
@@ -3465,8 +3592,10 @@ pgconn_set_default_encoding( VALUE self )
|
|
3465
3592
|
if ( PQsetClientEncoding(conn, encname) != 0 )
|
3466
3593
|
rb_warn( "Failed to set the default_internal encoding to %s: '%s'",
|
3467
3594
|
encname, PQerrorMessage(conn) );
|
3595
|
+
pgconn_set_internal_encoding_index( self );
|
3468
3596
|
return rb_enc_from_encoding( enc );
|
3469
3597
|
} else {
|
3598
|
+
pgconn_set_internal_encoding_index( self );
|
3470
3599
|
return Qnil;
|
3471
3600
|
}
|
3472
3601
|
}
|
@@ -3474,11 +3603,209 @@ pgconn_set_default_encoding( VALUE self )
|
|
3474
3603
|
|
3475
3604
|
#endif /* M17N_SUPPORTED */
|
3476
3605
|
|
3606
|
+
/*
|
3607
|
+
* call-seq:
|
3608
|
+
* res.type_map_for_queries = typemap
|
3609
|
+
*
|
3610
|
+
* Set the default TypeMap that is used for type casts of query bind parameters.
|
3611
|
+
*
|
3612
|
+
* +typemap+ can be:
|
3613
|
+
* * a kind of PG::TypeMap
|
3614
|
+
* * +nil+ - to type cast all query params by #to_str.
|
3615
|
+
*
|
3616
|
+
*/
|
3617
|
+
static VALUE
|
3618
|
+
pgconn_type_map_for_queries_set(VALUE self, VALUE typemap)
|
3619
|
+
{
|
3620
|
+
t_pg_connection *this = pg_get_connection( self );
|
3621
|
+
|
3622
|
+
if( typemap != Qnil ){
|
3623
|
+
if ( !rb_obj_is_kind_of(typemap, rb_cTypeMap) ) {
|
3624
|
+
rb_raise( rb_eTypeError, "wrong argument type %s (expected kind of PG::TypeMap)",
|
3625
|
+
rb_obj_classname( typemap ) );
|
3626
|
+
}
|
3627
|
+
Check_Type(typemap, T_DATA);
|
3628
|
+
}
|
3629
|
+
this->type_map_for_queries = typemap;
|
3630
|
+
|
3631
|
+
return typemap;
|
3632
|
+
}
|
3633
|
+
|
3634
|
+
/*
|
3635
|
+
* call-seq:
|
3636
|
+
* res.type_map_for_queries -> TypeMap
|
3637
|
+
*
|
3638
|
+
* Returns the default TypeMap that is currently set for type casts of query
|
3639
|
+
* bind parameters.
|
3640
|
+
*
|
3641
|
+
* Returns either:
|
3642
|
+
* * a kind of PG::TypeMap or
|
3643
|
+
* * +nil+ - when no type map is set.
|
3644
|
+
*
|
3645
|
+
*/
|
3646
|
+
static VALUE
|
3647
|
+
pgconn_type_map_for_queries_get(VALUE self)
|
3648
|
+
{
|
3649
|
+
t_pg_connection *this = pg_get_connection( self );
|
3650
|
+
|
3651
|
+
return this->type_map_for_queries;
|
3652
|
+
}
|
3653
|
+
|
3654
|
+
/*
|
3655
|
+
* call-seq:
|
3656
|
+
* res.type_map_for_results = typemap
|
3657
|
+
*
|
3658
|
+
* Set the default TypeMap that is used for type casts of result values.
|
3659
|
+
*
|
3660
|
+
* +typemap+ can be:
|
3661
|
+
* * a kind of PG::TypeMap
|
3662
|
+
* * +nil+ - to type cast all result values to String.
|
3663
|
+
*
|
3664
|
+
*/
|
3665
|
+
static VALUE
|
3666
|
+
pgconn_type_map_for_results_set(VALUE self, VALUE typemap)
|
3667
|
+
{
|
3668
|
+
t_pg_connection *this = pg_get_connection( self );
|
3669
|
+
|
3670
|
+
if( typemap != Qnil ){
|
3671
|
+
if ( !rb_obj_is_kind_of(typemap, rb_cTypeMap) ) {
|
3672
|
+
rb_raise( rb_eTypeError, "wrong argument type %s (expected kind of PG::TypeMap)",
|
3673
|
+
rb_obj_classname( typemap ) );
|
3674
|
+
}
|
3675
|
+
Check_Type(typemap, T_DATA);
|
3676
|
+
}
|
3677
|
+
this->type_map_for_results = typemap;
|
3678
|
+
|
3679
|
+
return typemap;
|
3680
|
+
}
|
3681
|
+
|
3682
|
+
/*
|
3683
|
+
* call-seq:
|
3684
|
+
* res.type_map_for_results -> TypeMap
|
3685
|
+
*
|
3686
|
+
* Returns the default TypeMap that is currently set for type casts of result values.
|
3687
|
+
*
|
3688
|
+
* Returns either:
|
3689
|
+
* * a kind of PG::TypeMap or
|
3690
|
+
* * +nil+ - when no type map is set.
|
3691
|
+
*
|
3692
|
+
*/
|
3693
|
+
static VALUE
|
3694
|
+
pgconn_type_map_for_results_get(VALUE self)
|
3695
|
+
{
|
3696
|
+
t_pg_connection *this = pg_get_connection( self );
|
3697
|
+
|
3698
|
+
return this->type_map_for_results;
|
3699
|
+
}
|
3700
|
+
|
3701
|
+
|
3702
|
+
/*
|
3703
|
+
* call-seq:
|
3704
|
+
* res.encoder_for_put_copy_data = encoder
|
3705
|
+
*
|
3706
|
+
* Set the default coder that is used for type casting of parameters
|
3707
|
+
* to #put_copy_data .
|
3708
|
+
*
|
3709
|
+
* +encoder+ can be:
|
3710
|
+
* * a kind of PG::Coder
|
3711
|
+
* * +nil+ - disable type encoding, data must be a String.
|
3712
|
+
*
|
3713
|
+
*/
|
3714
|
+
static VALUE
|
3715
|
+
pgconn_encoder_for_put_copy_data_set(VALUE self, VALUE typemap)
|
3716
|
+
{
|
3717
|
+
t_pg_connection *this = pg_get_connection( self );
|
3718
|
+
|
3719
|
+
if( typemap != Qnil ){
|
3720
|
+
if ( !rb_obj_is_kind_of(typemap, rb_cPG_Coder) ) {
|
3721
|
+
rb_raise( rb_eTypeError, "wrong argument type %s (expected kind of PG::Coder)",
|
3722
|
+
rb_obj_classname( typemap ) );
|
3723
|
+
}
|
3724
|
+
Check_Type(typemap, T_DATA);
|
3725
|
+
}
|
3726
|
+
this->encoder_for_put_copy_data = typemap;
|
3727
|
+
|
3728
|
+
return typemap;
|
3729
|
+
}
|
3730
|
+
|
3731
|
+
/*
|
3732
|
+
* call-seq:
|
3733
|
+
* res.encoder_for_put_copy_data -> PG::Coder
|
3734
|
+
*
|
3735
|
+
* Returns the default coder object that is currently set for type casting of parameters
|
3736
|
+
* to #put_copy_data .
|
3737
|
+
*
|
3738
|
+
* Returns either:
|
3739
|
+
* * a kind of PG::Coder
|
3740
|
+
* * +nil+ - type encoding is disabled, returned data will be a String.
|
3741
|
+
*
|
3742
|
+
*/
|
3743
|
+
static VALUE
|
3744
|
+
pgconn_encoder_for_put_copy_data_get(VALUE self)
|
3745
|
+
{
|
3746
|
+
t_pg_connection *this = pg_get_connection( self );
|
3747
|
+
|
3748
|
+
return this->encoder_for_put_copy_data;
|
3749
|
+
}
|
3750
|
+
|
3751
|
+
/*
|
3752
|
+
* call-seq:
|
3753
|
+
* res.decoder_for_get_copy_data = decoder
|
3754
|
+
*
|
3755
|
+
* Set the default coder that is used for type casting of received data
|
3756
|
+
* by #get_copy_data .
|
3757
|
+
*
|
3758
|
+
* +decoder+ can be:
|
3759
|
+
* * a kind of PG::Coder
|
3760
|
+
* * +nil+ - disable type decoding, returned data will be a String.
|
3761
|
+
*
|
3762
|
+
*/
|
3763
|
+
static VALUE
|
3764
|
+
pgconn_decoder_for_get_copy_data_set(VALUE self, VALUE typemap)
|
3765
|
+
{
|
3766
|
+
t_pg_connection *this = pg_get_connection( self );
|
3767
|
+
|
3768
|
+
if( typemap != Qnil ){
|
3769
|
+
if ( !rb_obj_is_kind_of(typemap, rb_cPG_Coder) ) {
|
3770
|
+
rb_raise( rb_eTypeError, "wrong argument type %s (expected kind of PG::Coder)",
|
3771
|
+
rb_obj_classname( typemap ) );
|
3772
|
+
}
|
3773
|
+
Check_Type(typemap, T_DATA);
|
3774
|
+
}
|
3775
|
+
this->decoder_for_get_copy_data = typemap;
|
3776
|
+
|
3777
|
+
return typemap;
|
3778
|
+
}
|
3779
|
+
|
3780
|
+
/*
|
3781
|
+
* call-seq:
|
3782
|
+
* res.decoder_for_get_copy_data -> PG::Coder
|
3783
|
+
*
|
3784
|
+
* Returns the default coder object that is currently set for type casting of received
|
3785
|
+
* data by #get_copy_data .
|
3786
|
+
*
|
3787
|
+
* Returns either:
|
3788
|
+
* * a kind of PG::Coder
|
3789
|
+
* * +nil+ - type encoding is disabled, returned data will be a String.
|
3790
|
+
*
|
3791
|
+
*/
|
3792
|
+
static VALUE
|
3793
|
+
pgconn_decoder_for_get_copy_data_get(VALUE self)
|
3794
|
+
{
|
3795
|
+
t_pg_connection *this = pg_get_connection( self );
|
3796
|
+
|
3797
|
+
return this->decoder_for_get_copy_data;
|
3798
|
+
}
|
3477
3799
|
|
3478
3800
|
|
3479
3801
|
void
|
3480
3802
|
init_pg_connection()
|
3481
3803
|
{
|
3804
|
+
s_id_encode = rb_intern("encode");
|
3805
|
+
sym_type = ID2SYM(rb_intern("type"));
|
3806
|
+
sym_format = ID2SYM(rb_intern("format"));
|
3807
|
+
sym_value = ID2SYM(rb_intern("value"));
|
3808
|
+
|
3482
3809
|
rb_cPGconn = rb_define_class_under( rb_mPG, "Connection", rb_cObject );
|
3483
3810
|
rb_include_module(rb_cPGconn, rb_mPGconstants);
|
3484
3811
|
|
@@ -3518,6 +3845,9 @@ init_pg_connection()
|
|
3518
3845
|
rb_define_method(rb_cPGconn, "host", pgconn_host, 0);
|
3519
3846
|
rb_define_method(rb_cPGconn, "port", pgconn_port, 0);
|
3520
3847
|
rb_define_method(rb_cPGconn, "tty", pgconn_tty, 0);
|
3848
|
+
#ifdef HAVE_PQCONNINFO
|
3849
|
+
rb_define_method(rb_cPGconn, "conninfo", pgconn_conninfo, 0);
|
3850
|
+
#endif
|
3521
3851
|
rb_define_method(rb_cPGconn, "options", pgconn_options, 0);
|
3522
3852
|
rb_define_method(rb_cPGconn, "status", pgconn_status, 0);
|
3523
3853
|
rb_define_method(rb_cPGconn, "transaction_status", pgconn_transaction_status, 0);
|
@@ -3578,7 +3908,7 @@ init_pg_connection()
|
|
3578
3908
|
rb_define_method(rb_cPGconn, "notifies", pgconn_notifies, 0);
|
3579
3909
|
|
3580
3910
|
/****** PG::Connection INSTANCE METHODS: COPY ******/
|
3581
|
-
rb_define_method(rb_cPGconn, "put_copy_data", pgconn_put_copy_data, 1);
|
3911
|
+
rb_define_method(rb_cPGconn, "put_copy_data", pgconn_put_copy_data, -1);
|
3582
3912
|
rb_define_method(rb_cPGconn, "put_copy_end", pgconn_put_copy_end, -1);
|
3583
3913
|
rb_define_method(rb_cPGconn, "get_copy_data", pgconn_get_copy_data, -1);
|
3584
3914
|
|
@@ -3639,5 +3969,13 @@ init_pg_connection()
|
|
3639
3969
|
rb_define_method(rb_cPGconn, "set_default_encoding", pgconn_set_default_encoding, 0);
|
3640
3970
|
#endif /* M17N_SUPPORTED */
|
3641
3971
|
|
3972
|
+
rb_define_method(rb_cPGconn, "type_map_for_queries=", pgconn_type_map_for_queries_set, 1);
|
3973
|
+
rb_define_method(rb_cPGconn, "type_map_for_queries", pgconn_type_map_for_queries_get, 0);
|
3974
|
+
rb_define_method(rb_cPGconn, "type_map_for_results=", pgconn_type_map_for_results_set, 1);
|
3975
|
+
rb_define_method(rb_cPGconn, "type_map_for_results", pgconn_type_map_for_results_get, 0);
|
3976
|
+
rb_define_method(rb_cPGconn, "encoder_for_put_copy_data=", pgconn_encoder_for_put_copy_data_set, 1);
|
3977
|
+
rb_define_method(rb_cPGconn, "encoder_for_put_copy_data", pgconn_encoder_for_put_copy_data_get, 0);
|
3978
|
+
rb_define_method(rb_cPGconn, "decoder_for_get_copy_data=", pgconn_decoder_for_get_copy_data_set, 1);
|
3979
|
+
rb_define_method(rb_cPGconn, "decoder_for_get_copy_data", pgconn_decoder_for_get_copy_data_get, 0);
|
3642
3980
|
}
|
3643
3981
|
|