pg 0.18.0.pre20140820094244 → 0.18.0.pre20141017155815
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 +1573 -2
- data/History.rdoc +3 -11
- data/Manifest.txt +24 -0
- data/README.rdoc +51 -4
- data/Rakefile +20 -14
- data/Rakefile.cross +39 -32
- data/ext/extconf.rb +27 -26
- data/ext/pg.c +75 -21
- 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 +454 -0
- data/ext/pg_connection.c +815 -518
- data/ext/pg_copy_coder.c +557 -0
- data/ext/pg_result.c +258 -103
- data/ext/pg_text_decoder.c +424 -0
- data/ext/pg_text_encoder.c +608 -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 +121 -0
- data/ext/util.h +63 -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 +38 -5
- 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/helpers.rb +9 -1
- data/spec/pg/basic_type_mapping_spec.rb +251 -0
- data/spec/pg/connection_spec.rb +232 -13
- data/spec/pg/result_spec.rb +52 -0
- 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 +620 -0
- metadata +40 -4
- 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 57d770944b5d 2014/10/09 20:20:11 lars $
|
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,29 +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
|
|
49
83
|
|
50
|
-
|
51
84
|
/*
|
52
85
|
* Close the associated socket IO object if there is one.
|
53
86
|
*/
|
54
87
|
void
|
55
88
|
pgconn_close_socket_io( VALUE self )
|
56
89
|
{
|
57
|
-
|
90
|
+
t_pg_connection *this = pg_get_connection( self );
|
91
|
+
VALUE socket_io = this->socket_io;
|
58
92
|
|
59
93
|
if ( RTEST(socket_io) ) {
|
60
94
|
#if defined(_WIN32) && defined(HAVE_RB_W32_WRAP_IO_HANDLE)
|
@@ -66,7 +100,7 @@ pgconn_close_socket_io( VALUE self )
|
|
66
100
|
rb_funcall( socket_io, rb_intern("close"), 0 );
|
67
101
|
}
|
68
102
|
|
69
|
-
|
103
|
+
this->socket_io = Qnil;
|
70
104
|
}
|
71
105
|
|
72
106
|
|
@@ -105,23 +139,20 @@ pgconn_make_conninfo_array( const PQconninfoOption *options )
|
|
105
139
|
|
106
140
|
|
107
141
|
/*
|
108
|
-
*
|
109
|
-
*/
|
110
|
-
|
111
|
-
/*
|
112
|
-
* Object validity checker. Returns the data pointer.
|
142
|
+
* GC Mark function
|
113
143
|
*/
|
114
|
-
static
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
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 );
|
125
156
|
}
|
126
157
|
|
127
158
|
|
@@ -129,10 +160,12 @@ pgconn_check( VALUE self ) {
|
|
129
160
|
* GC Free function
|
130
161
|
*/
|
131
162
|
static void
|
132
|
-
pgconn_gc_free(
|
163
|
+
pgconn_gc_free( t_pg_connection *this )
|
133
164
|
{
|
134
|
-
if (
|
135
|
-
PQfinish(
|
165
|
+
if (this->pgconn != NULL)
|
166
|
+
PQfinish( this->pgconn );
|
167
|
+
|
168
|
+
xfree(this);
|
136
169
|
}
|
137
170
|
|
138
171
|
|
@@ -149,10 +182,20 @@ pgconn_gc_free( PGconn *conn )
|
|
149
182
|
static VALUE
|
150
183
|
pgconn_s_allocate( VALUE klass )
|
151
184
|
{
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
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
|
+
|
156
199
|
return self;
|
157
200
|
}
|
158
201
|
|
@@ -217,21 +260,19 @@ pgconn_s_allocate( VALUE klass )
|
|
217
260
|
static VALUE
|
218
261
|
pgconn_init(int argc, VALUE *argv, VALUE self)
|
219
262
|
{
|
220
|
-
|
263
|
+
t_pg_connection *this;
|
221
264
|
VALUE conninfo;
|
222
265
|
VALUE error;
|
223
266
|
|
267
|
+
this = pg_get_connection( self );
|
224
268
|
conninfo = rb_funcall2( rb_cPGconn, rb_intern("parse_connect_args"), argc, argv );
|
225
|
-
|
269
|
+
this->pgconn = gvl_PQconnectdb(StringValueCStr(conninfo));
|
226
270
|
|
227
|
-
if(
|
271
|
+
if(this->pgconn == NULL)
|
228
272
|
rb_raise(rb_ePGerror, "PQconnectdb() unable to allocate structure");
|
229
273
|
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
if (PQstatus(conn) == CONNECTION_BAD) {
|
234
|
-
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));
|
235
276
|
rb_iv_set(error, "@connection", self);
|
236
277
|
rb_exc_raise(error);
|
237
278
|
}
|
@@ -265,27 +306,25 @@ pgconn_init(int argc, VALUE *argv, VALUE self)
|
|
265
306
|
static VALUE
|
266
307
|
pgconn_s_connect_start( int argc, VALUE *argv, VALUE klass )
|
267
308
|
{
|
268
|
-
PGconn *conn = NULL;
|
269
309
|
VALUE rb_conn;
|
270
310
|
VALUE conninfo;
|
271
311
|
VALUE error;
|
312
|
+
t_pg_connection *this;
|
272
313
|
|
273
314
|
/*
|
274
315
|
* PG::Connection.connect_start must act as both alloc() and initialize()
|
275
316
|
* because it is not invoked by calling new().
|
276
317
|
*/
|
277
318
|
rb_conn = pgconn_s_allocate( klass );
|
319
|
+
this = pg_get_connection( rb_conn );
|
278
320
|
conninfo = rb_funcall2( klass, rb_intern("parse_connect_args"), argc, argv );
|
279
|
-
|
321
|
+
this->pgconn = gvl_PQconnectStart( StringValueCStr(conninfo) );
|
280
322
|
|
281
|
-
if(
|
323
|
+
if( this->pgconn == NULL )
|
282
324
|
rb_raise(rb_ePGerror, "PQconnectStart() unable to allocate structure");
|
283
325
|
|
284
|
-
|
285
|
-
|
286
|
-
|
287
|
-
if ( PQstatus(conn) == CONNECTION_BAD ) {
|
288
|
-
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));
|
289
328
|
rb_iv_set(error, "@connection", rb_conn);
|
290
329
|
rb_exc_raise(error);
|
291
330
|
}
|
@@ -322,7 +361,7 @@ pgconn_s_ping( int argc, VALUE *argv, VALUE klass )
|
|
322
361
|
VALUE conninfo;
|
323
362
|
|
324
363
|
conninfo = rb_funcall2( klass, rb_intern("parse_connect_args"), argc, argv );
|
325
|
-
ping = PQping(
|
364
|
+
ping = PQping( StringValueCStr(conninfo) );
|
326
365
|
|
327
366
|
return INT2FIX((int)ping);
|
328
367
|
}
|
@@ -387,7 +426,7 @@ pgconn_s_encrypt_password(VALUE self, VALUE password, VALUE username)
|
|
387
426
|
Check_Type(password, T_STRING);
|
388
427
|
Check_Type(username, T_STRING);
|
389
428
|
|
390
|
-
encrypted = PQencryptPassword(
|
429
|
+
encrypted = PQencryptPassword(StringValueCStr(password), StringValueCStr(username));
|
391
430
|
rval = rb_str_new2( encrypted );
|
392
431
|
PQfreemem( encrypted );
|
393
432
|
|
@@ -453,9 +492,11 @@ pgconn_connect_poll(VALUE self)
|
|
453
492
|
static VALUE
|
454
493
|
pgconn_finish( VALUE self )
|
455
494
|
{
|
495
|
+
t_pg_connection *this = pg_get_connection_safe( self );
|
496
|
+
|
456
497
|
pgconn_close_socket_io( self );
|
457
|
-
PQfinish(
|
458
|
-
|
498
|
+
PQfinish( this->pgconn );
|
499
|
+
this->pgconn = NULL;
|
459
500
|
return Qnil;
|
460
501
|
}
|
461
502
|
|
@@ -469,7 +510,8 @@ pgconn_finish( VALUE self )
|
|
469
510
|
static VALUE
|
470
511
|
pgconn_finished_p( VALUE self )
|
471
512
|
{
|
472
|
-
|
513
|
+
t_pg_connection *this = pg_get_connection( self );
|
514
|
+
if ( this->pgconn ) return Qfalse;
|
473
515
|
return Qtrue;
|
474
516
|
}
|
475
517
|
|
@@ -623,6 +665,7 @@ pgconn_options(VALUE self)
|
|
623
665
|
}
|
624
666
|
|
625
667
|
|
668
|
+
#ifdef HAVE_PQCONNINFO
|
626
669
|
/*
|
627
670
|
* call-seq:
|
628
671
|
* conn.conninfo -> hash
|
@@ -641,7 +684,7 @@ pgconn_conninfo( VALUE self )
|
|
641
684
|
|
642
685
|
return array;
|
643
686
|
}
|
644
|
-
|
687
|
+
#endif
|
645
688
|
|
646
689
|
|
647
690
|
/*
|
@@ -694,7 +737,7 @@ pgconn_transaction_status(VALUE self)
|
|
694
737
|
static VALUE
|
695
738
|
pgconn_parameter_status(VALUE self, VALUE param_name)
|
696
739
|
{
|
697
|
-
const char *ret = PQparameterStatus(pg_get_pgconn(self),
|
740
|
+
const char *ret = PQparameterStatus(pg_get_pgconn(self), StringValueCStr(param_name));
|
698
741
|
if(ret == NULL)
|
699
742
|
return Qnil;
|
700
743
|
else
|
@@ -793,10 +836,11 @@ pgconn_socket_io(VALUE self)
|
|
793
836
|
int sd;
|
794
837
|
int ruby_sd;
|
795
838
|
ID id_autoclose = rb_intern("autoclose=");
|
796
|
-
|
839
|
+
t_pg_connection *this = pg_get_connection_safe( self );
|
840
|
+
VALUE socket_io = this->socket_io;
|
797
841
|
|
798
842
|
if ( !RTEST(socket_io) ) {
|
799
|
-
if( (sd = PQsocket(
|
843
|
+
if( (sd = PQsocket(this->pgconn)) < 0)
|
800
844
|
rb_raise(rb_eConnectionBad, "PQsocket() can't get socket descriptor");
|
801
845
|
|
802
846
|
#ifdef _WIN32
|
@@ -812,7 +856,7 @@ pgconn_socket_io(VALUE self)
|
|
812
856
|
rb_funcall( socket_io, id_autoclose, 1, Qfalse );
|
813
857
|
}
|
814
858
|
|
815
|
-
|
859
|
+
this->socket_io = socket_io;
|
816
860
|
}
|
817
861
|
|
818
862
|
return socket_io;
|
@@ -901,7 +945,7 @@ pgconn_exec(int argc, VALUE *argv, VALUE self)
|
|
901
945
|
if ( argc == 1 ) {
|
902
946
|
Check_Type(argv[0], T_STRING);
|
903
947
|
|
904
|
-
result = gvl_PQexec(conn,
|
948
|
+
result = gvl_PQexec(conn, StringValueCStr(argv[0]));
|
905
949
|
rb_pgresult = pg_new_result(result, self);
|
906
950
|
pg_result_check(rb_pgresult);
|
907
951
|
if (rb_block_given_p()) {
|
@@ -918,10 +962,262 @@ pgconn_exec(int argc, VALUE *argv, VALUE self)
|
|
918
962
|
}
|
919
963
|
|
920
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
|
+
|
921
1217
|
/*
|
922
1218
|
* call-seq:
|
923
|
-
* conn.exec_params(sql, params[, result_format ] ) -> PG::Result
|
924
|
-
* 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 }
|
925
1221
|
*
|
926
1222
|
* Sends SQL query request specified by +sql+ to PostgreSQL using placeholders
|
927
1223
|
* for parameters.
|
@@ -951,6 +1247,12 @@ pgconn_exec(int argc, VALUE *argv, VALUE self)
|
|
951
1247
|
* The optional +result_format+ should be 0 for text results, 1
|
952
1248
|
* for binary.
|
953
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
|
+
*
|
954
1256
|
* If the optional code block is given, it will be passed <i>result</i> as an argument,
|
955
1257
|
* and the PG::Result object will automatically be cleared when the block terminates.
|
956
1258
|
* In this instance, <code>conn.exec</code> returns the value of the block.
|
@@ -961,102 +1263,30 @@ pgconn_exec_params( int argc, VALUE *argv, VALUE self )
|
|
961
1263
|
PGconn *conn = pg_get_pgconn(self);
|
962
1264
|
PGresult *result = NULL;
|
963
1265
|
VALUE rb_pgresult;
|
964
|
-
VALUE command,
|
965
|
-
VALUE param, param_type, param_value, param_format;
|
966
|
-
VALUE param_value_tmp;
|
967
|
-
VALUE sym_type, sym_value, sym_format;
|
968
|
-
VALUE gc_array;
|
969
|
-
int i=0;
|
1266
|
+
VALUE command, in_res_fmt;
|
970
1267
|
int nParams;
|
971
|
-
Oid *paramTypes;
|
972
|
-
char ** paramValues;
|
973
|
-
int *paramLengths;
|
974
|
-
int *paramFormats;
|
975
1268
|
int resultFormat;
|
1269
|
+
struct query_params_data paramsData;
|
976
1270
|
|
977
|
-
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;
|
978
1273
|
|
979
1274
|
/*
|
980
1275
|
* Handle the edge-case where the caller is coming from #exec, but passed an explict +nil+
|
981
1276
|
* for the second parameter.
|
982
1277
|
*/
|
983
|
-
if ( NIL_P(params) ) {
|
1278
|
+
if ( NIL_P(paramsData.params) ) {
|
984
1279
|
return pgconn_exec( 1, argv, self );
|
985
|
-
}
|
986
|
-
|
987
|
-
Check_Type(params, T_ARRAY);
|
988
|
-
|
989
|
-
if ( NIL_P(in_res_fmt) ) {
|
990
|
-
resultFormat = 0;
|
991
|
-
}
|
992
|
-
else {
|
993
|
-
resultFormat = NUM2INT(in_res_fmt);
|
994
1280
|
}
|
1281
|
+
pgconn_query_assign_typemap( self, ¶msData );
|
995
1282
|
|
996
|
-
|
997
|
-
|
1283
|
+
resultFormat = NIL_P(in_res_fmt) ? 0 : NUM2INT(in_res_fmt);
|
1284
|
+
nParams = alloc_query_params( ¶msData );
|
998
1285
|
|
999
|
-
|
1000
|
-
|
1001
|
-
sym_format = ID2SYM(rb_intern("format"));
|
1002
|
-
nParams = (int)RARRAY_LEN(params);
|
1003
|
-
paramTypes = ALLOC_N(Oid, nParams);
|
1004
|
-
paramValues = ALLOC_N(char *, nParams);
|
1005
|
-
paramLengths = ALLOC_N(int, nParams);
|
1006
|
-
paramFormats = ALLOC_N(int, nParams);
|
1007
|
-
|
1008
|
-
for ( i = 0; i < nParams; i++ ) {
|
1009
|
-
param = rb_ary_entry(params, i);
|
1010
|
-
if (TYPE(param) == T_HASH) {
|
1011
|
-
param_type = rb_hash_aref(param, sym_type);
|
1012
|
-
param_value_tmp = rb_hash_aref(param, sym_value);
|
1013
|
-
if(param_value_tmp == Qnil)
|
1014
|
-
param_value = param_value_tmp;
|
1015
|
-
else
|
1016
|
-
param_value = rb_obj_as_string(param_value_tmp);
|
1017
|
-
param_format = rb_hash_aref(param, sym_format);
|
1018
|
-
}
|
1019
|
-
else {
|
1020
|
-
param_type = Qnil;
|
1021
|
-
if(param == Qnil)
|
1022
|
-
param_value = param;
|
1023
|
-
else
|
1024
|
-
param_value = rb_obj_as_string(param);
|
1025
|
-
param_format = Qnil;
|
1026
|
-
}
|
1286
|
+
result = gvl_PQexecParams(conn, StringValueCStr(command), nParams, paramsData.types,
|
1287
|
+
(const char * const *)paramsData.values, paramsData.lengths, paramsData.formats, resultFormat);
|
1027
1288
|
|
1028
|
-
|
1029
|
-
paramTypes[i] = 0;
|
1030
|
-
else
|
1031
|
-
paramTypes[i] = NUM2INT(param_type);
|
1032
|
-
|
1033
|
-
if(param_value == Qnil) {
|
1034
|
-
paramValues[i] = NULL;
|
1035
|
-
paramLengths[i] = 0;
|
1036
|
-
}
|
1037
|
-
else {
|
1038
|
-
Check_Type(param_value, T_STRING);
|
1039
|
-
/* make sure param_value doesn't get freed by the GC */
|
1040
|
-
rb_ary_push(gc_array, param_value);
|
1041
|
-
paramValues[i] = StringValuePtr(param_value);
|
1042
|
-
paramLengths[i] = (int)RSTRING_LEN(param_value);
|
1043
|
-
}
|
1044
|
-
|
1045
|
-
if(param_format == Qnil)
|
1046
|
-
paramFormats[i] = 0;
|
1047
|
-
else
|
1048
|
-
paramFormats[i] = NUM2INT(param_format);
|
1049
|
-
}
|
1050
|
-
|
1051
|
-
result = gvl_PQexecParams(conn, StringValuePtr(command), nParams, paramTypes,
|
1052
|
-
(const char * const *)paramValues, paramLengths, paramFormats, resultFormat);
|
1053
|
-
|
1054
|
-
rb_gc_unregister_address(&gc_array);
|
1055
|
-
|
1056
|
-
xfree(paramTypes);
|
1057
|
-
xfree(paramValues);
|
1058
|
-
xfree(paramLengths);
|
1059
|
-
xfree(paramFormats);
|
1289
|
+
free_query_params( ¶msData );
|
1060
1290
|
|
1061
1291
|
rb_pgresult = pg_new_result(result, self);
|
1062
1292
|
pg_result_check(rb_pgresult);
|
@@ -1110,14 +1340,13 @@ pgconn_prepare(int argc, VALUE *argv, VALUE self)
|
|
1110
1340
|
paramTypes = ALLOC_N(Oid, nParams);
|
1111
1341
|
for(i = 0; i < nParams; i++) {
|
1112
1342
|
param = rb_ary_entry(in_paramtypes, i);
|
1113
|
-
Check_Type(param, T_FIXNUM);
|
1114
1343
|
if(param == Qnil)
|
1115
1344
|
paramTypes[i] = 0;
|
1116
1345
|
else
|
1117
|
-
paramTypes[i] =
|
1346
|
+
paramTypes[i] = NUM2UINT(param);
|
1118
1347
|
}
|
1119
1348
|
}
|
1120
|
-
result = gvl_PQprepare(conn,
|
1349
|
+
result = gvl_PQprepare(conn, StringValueCStr(name), StringValueCStr(command),
|
1121
1350
|
nParams, paramTypes);
|
1122
1351
|
|
1123
1352
|
xfree(paramTypes);
|
@@ -1129,8 +1358,8 @@ pgconn_prepare(int argc, VALUE *argv, VALUE self)
|
|
1129
1358
|
|
1130
1359
|
/*
|
1131
1360
|
* call-seq:
|
1132
|
-
* conn.exec_prepared(statement_name [, params, result_format ] ) -> PG::Result
|
1133
|
-
* 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 }
|
1134
1363
|
*
|
1135
1364
|
* Execute prepared named statement specified by _statement_name_.
|
1136
1365
|
* Returns a PG::Result instance on success.
|
@@ -1152,6 +1381,12 @@ pgconn_prepare(int argc, VALUE *argv, VALUE self)
|
|
1152
1381
|
* The optional +result_format+ should be 0 for text results, 1
|
1153
1382
|
* for binary.
|
1154
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
|
+
*
|
1155
1390
|
* If the optional code block is given, it will be passed <i>result</i> as an argument,
|
1156
1391
|
* and the PG::Result object will automatically be cleared when the block terminates.
|
1157
1392
|
* In this instance, <code>conn.exec_prepared</code> returns the value of the block.
|
@@ -1162,89 +1397,28 @@ pgconn_exec_prepared(int argc, VALUE *argv, VALUE self)
|
|
1162
1397
|
PGconn *conn = pg_get_pgconn(self);
|
1163
1398
|
PGresult *result = NULL;
|
1164
1399
|
VALUE rb_pgresult;
|
1165
|
-
VALUE name,
|
1166
|
-
VALUE param, param_value, param_format;
|
1167
|
-
VALUE param_value_tmp;
|
1168
|
-
VALUE sym_value, sym_format;
|
1169
|
-
VALUE gc_array;
|
1170
|
-
int i = 0;
|
1400
|
+
VALUE name, in_res_fmt;
|
1171
1401
|
int nParams;
|
1172
|
-
char ** paramValues;
|
1173
|
-
int *paramLengths;
|
1174
|
-
int *paramFormats;
|
1175
1402
|
int resultFormat;
|
1403
|
+
struct query_params_data paramsData;
|
1176
1404
|
|
1177
|
-
|
1178
|
-
|
1405
|
+
rb_scan_args(argc, argv, "13", &name, ¶msData.params, &in_res_fmt, ¶msData.typemap);
|
1406
|
+
paramsData.with_types = 0;
|
1179
1407
|
Check_Type(name, T_STRING);
|
1180
1408
|
|
1181
|
-
if(NIL_P(params)) {
|
1182
|
-
params = rb_ary_new2(0);
|
1183
|
-
resultFormat = 0;
|
1184
|
-
}
|
1185
|
-
else {
|
1186
|
-
Check_Type(params, T_ARRAY);
|
1409
|
+
if(NIL_P(paramsData.params)) {
|
1410
|
+
paramsData.params = rb_ary_new2(0);
|
1187
1411
|
}
|
1412
|
+
pgconn_query_assign_typemap( self, ¶msData );
|
1188
1413
|
|
1189
|
-
|
1190
|
-
|
1191
|
-
}
|
1192
|
-
else {
|
1193
|
-
resultFormat = NUM2INT(in_res_fmt);
|
1194
|
-
}
|
1414
|
+
resultFormat = NIL_P(in_res_fmt) ? 0 : NUM2INT(in_res_fmt);
|
1415
|
+
nParams = alloc_query_params( ¶msData );
|
1195
1416
|
|
1196
|
-
|
1197
|
-
|
1198
|
-
sym_value = ID2SYM(rb_intern("value"));
|
1199
|
-
sym_format = ID2SYM(rb_intern("format"));
|
1200
|
-
nParams = (int)RARRAY_LEN(params);
|
1201
|
-
paramValues = ALLOC_N(char *, nParams);
|
1202
|
-
paramLengths = ALLOC_N(int, nParams);
|
1203
|
-
paramFormats = ALLOC_N(int, nParams);
|
1204
|
-
for(i = 0; i < nParams; i++) {
|
1205
|
-
param = rb_ary_entry(params, i);
|
1206
|
-
if (TYPE(param) == T_HASH) {
|
1207
|
-
param_value_tmp = rb_hash_aref(param, sym_value);
|
1208
|
-
if(param_value_tmp == Qnil)
|
1209
|
-
param_value = param_value_tmp;
|
1210
|
-
else
|
1211
|
-
param_value = rb_obj_as_string(param_value_tmp);
|
1212
|
-
param_format = rb_hash_aref(param, sym_format);
|
1213
|
-
}
|
1214
|
-
else {
|
1215
|
-
if(param == Qnil)
|
1216
|
-
param_value = param;
|
1217
|
-
else
|
1218
|
-
param_value = rb_obj_as_string(param);
|
1219
|
-
param_format = INT2NUM(0);
|
1220
|
-
}
|
1221
|
-
if(param_value == Qnil) {
|
1222
|
-
paramValues[i] = NULL;
|
1223
|
-
paramLengths[i] = 0;
|
1224
|
-
}
|
1225
|
-
else {
|
1226
|
-
Check_Type(param_value, T_STRING);
|
1227
|
-
/* make sure param_value doesn't get freed by the GC */
|
1228
|
-
rb_ary_push(gc_array, param_value);
|
1229
|
-
paramValues[i] = StringValuePtr(param_value);
|
1230
|
-
paramLengths[i] = (int)RSTRING_LEN(param_value);
|
1231
|
-
}
|
1232
|
-
|
1233
|
-
if(param_format == Qnil)
|
1234
|
-
paramFormats[i] = 0;
|
1235
|
-
else
|
1236
|
-
paramFormats[i] = NUM2INT(param_format);
|
1237
|
-
}
|
1238
|
-
|
1239
|
-
result = gvl_PQexecPrepared(conn, StringValuePtr(name), nParams,
|
1240
|
-
(const char * const *)paramValues, paramLengths, paramFormats,
|
1417
|
+
result = gvl_PQexecPrepared(conn, StringValueCStr(name), nParams,
|
1418
|
+
(const char * const *)paramsData.values, paramsData.lengths, paramsData.formats,
|
1241
1419
|
resultFormat);
|
1242
1420
|
|
1243
|
-
|
1244
|
-
|
1245
|
-
xfree(paramValues);
|
1246
|
-
xfree(paramLengths);
|
1247
|
-
xfree(paramFormats);
|
1421
|
+
free_query_params( ¶msData );
|
1248
1422
|
|
1249
1423
|
rb_pgresult = pg_new_result(result, self);
|
1250
1424
|
pg_result_check(rb_pgresult);
|
@@ -1274,7 +1448,7 @@ pgconn_describe_prepared(VALUE self, VALUE stmt_name)
|
|
1274
1448
|
}
|
1275
1449
|
else {
|
1276
1450
|
Check_Type(stmt_name, T_STRING);
|
1277
|
-
stmt =
|
1451
|
+
stmt = StringValueCStr(stmt_name);
|
1278
1452
|
}
|
1279
1453
|
result = gvl_PQdescribePrepared(conn, stmt);
|
1280
1454
|
rb_pgresult = pg_new_result(result, self);
|
@@ -1302,7 +1476,7 @@ pgconn_describe_portal(self, stmt_name)
|
|
1302
1476
|
}
|
1303
1477
|
else {
|
1304
1478
|
Check_Type(stmt_name, T_STRING);
|
1305
|
-
stmt =
|
1479
|
+
stmt = StringValueCStr(stmt_name);
|
1306
1480
|
}
|
1307
1481
|
result = gvl_PQdescribePortal(conn, stmt);
|
1308
1482
|
rb_pgresult = pg_new_result(result, self);
|
@@ -1364,9 +1538,6 @@ pgconn_s_escape(VALUE self, VALUE string)
|
|
1364
1538
|
size_t size;
|
1365
1539
|
int error;
|
1366
1540
|
VALUE result;
|
1367
|
-
#ifdef M17N_SUPPORTED
|
1368
|
-
rb_encoding* enc;
|
1369
|
-
#endif
|
1370
1541
|
|
1371
1542
|
Check_Type(string, T_STRING);
|
1372
1543
|
|
@@ -1379,20 +1550,12 @@ pgconn_s_escape(VALUE self, VALUE string)
|
|
1379
1550
|
rb_raise(rb_ePGerror, "%s", PQerrorMessage(pg_get_pgconn(self)));
|
1380
1551
|
}
|
1381
1552
|
} else {
|
1382
|
-
size = PQescapeString(escaped, RSTRING_PTR(string), (
|
1553
|
+
size = PQescapeString(escaped, RSTRING_PTR(string), RSTRING_LENINT(string));
|
1383
1554
|
}
|
1384
1555
|
result = rb_str_new(escaped, size);
|
1385
1556
|
xfree(escaped);
|
1386
1557
|
OBJ_INFECT(result, string);
|
1387
|
-
|
1388
|
-
#ifdef M17N_SUPPORTED
|
1389
|
-
if ( rb_obj_class(self) == rb_cPGconn ) {
|
1390
|
-
enc = pg_conn_enc_get( pg_get_pgconn(self) );
|
1391
|
-
} else {
|
1392
|
-
enc = rb_enc_get(string);
|
1393
|
-
}
|
1394
|
-
rb_enc_associate(result, enc);
|
1395
|
-
#endif
|
1558
|
+
PG_ENCODING_SET_NOCHECK(result, ENCODING_GET( rb_obj_class(self) == rb_cPGconn ? self : string ));
|
1396
1559
|
|
1397
1560
|
return result;
|
1398
1561
|
}
|
@@ -1464,7 +1627,7 @@ pgconn_s_unescape_bytea(VALUE self, VALUE str)
|
|
1464
1627
|
UNUSED( self );
|
1465
1628
|
|
1466
1629
|
Check_Type(str, T_STRING);
|
1467
|
-
from = (unsigned char*)
|
1630
|
+
from = (unsigned char*)StringValueCStr(str);
|
1468
1631
|
|
1469
1632
|
to = PQunescapeBytea(from, &to_len);
|
1470
1633
|
|
@@ -1502,10 +1665,7 @@ pgconn_escape_literal(VALUE self, VALUE string)
|
|
1502
1665
|
result = rb_str_new2(escaped);
|
1503
1666
|
PQfreemem(escaped);
|
1504
1667
|
OBJ_INFECT(result, string);
|
1505
|
-
|
1506
|
-
#ifdef M17N_SUPPORTED
|
1507
|
-
rb_enc_associate(result, pg_conn_enc_get( pg_get_pgconn(self) ));
|
1508
|
-
#endif
|
1668
|
+
PG_ENCODING_SET_NOCHECK(result, ENCODING_GET(self));
|
1509
1669
|
|
1510
1670
|
return result;
|
1511
1671
|
}
|
@@ -1542,10 +1702,7 @@ pgconn_escape_identifier(VALUE self, VALUE string)
|
|
1542
1702
|
result = rb_str_new2(escaped);
|
1543
1703
|
PQfreemem(escaped);
|
1544
1704
|
OBJ_INFECT(result, string);
|
1545
|
-
|
1546
|
-
#ifdef M17N_SUPPORTED
|
1547
|
-
rb_enc_associate(result, pg_conn_enc_get( pg_get_pgconn(self) ));
|
1548
|
-
#endif
|
1705
|
+
PG_ENCODING_SET_NOCHECK(result, ENCODING_GET(self));
|
1549
1706
|
|
1550
1707
|
return result;
|
1551
1708
|
}
|
@@ -1608,7 +1765,7 @@ pgconn_set_single_row_mode(VALUE self)
|
|
1608
1765
|
|
1609
1766
|
/*
|
1610
1767
|
* call-seq:
|
1611
|
-
* conn.send_query(sql [, params, result_format ] ) -> nil
|
1768
|
+
* conn.send_query(sql [, params, result_format[, type_map ]] ) -> nil
|
1612
1769
|
*
|
1613
1770
|
* Sends SQL query request specified by _sql_ to PostgreSQL for
|
1614
1771
|
* asynchronous processing, and immediately returns.
|
@@ -1636,32 +1793,32 @@ pgconn_set_single_row_mode(VALUE self)
|
|
1636
1793
|
*
|
1637
1794
|
* The optional +result_format+ should be 0 for text results, 1
|
1638
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
|
+
*
|
1639
1803
|
*/
|
1640
1804
|
static VALUE
|
1641
1805
|
pgconn_send_query(int argc, VALUE *argv, VALUE self)
|
1642
1806
|
{
|
1643
1807
|
PGconn *conn = pg_get_pgconn(self);
|
1644
1808
|
int result;
|
1645
|
-
VALUE command,
|
1646
|
-
VALUE param, param_type, param_value, param_format;
|
1647
|
-
VALUE param_value_tmp;
|
1648
|
-
VALUE sym_type, sym_value, sym_format;
|
1649
|
-
VALUE gc_array;
|
1809
|
+
VALUE command, in_res_fmt;
|
1650
1810
|
VALUE error;
|
1651
|
-
int i=0;
|
1652
1811
|
int nParams;
|
1653
|
-
Oid *paramTypes;
|
1654
|
-
char ** paramValues;
|
1655
|
-
int *paramLengths;
|
1656
|
-
int *paramFormats;
|
1657
1812
|
int resultFormat;
|
1813
|
+
struct query_params_data paramsData;
|
1658
1814
|
|
1659
|
-
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;
|
1660
1817
|
Check_Type(command, T_STRING);
|
1661
1818
|
|
1662
1819
|
/* If called with no parameters, use PQsendQuery */
|
1663
|
-
if(NIL_P(params)) {
|
1664
|
-
if(gvl_PQsendQuery(conn,
|
1820
|
+
if(NIL_P(paramsData.params)) {
|
1821
|
+
if(gvl_PQsendQuery(conn,StringValueCStr(command)) == 0) {
|
1665
1822
|
error = rb_exc_new2(rb_eUnableToSend, PQerrorMessage(conn));
|
1666
1823
|
rb_iv_set(error, "@connection", self);
|
1667
1824
|
rb_exc_raise(error);
|
@@ -1672,77 +1829,15 @@ pgconn_send_query(int argc, VALUE *argv, VALUE self)
|
|
1672
1829
|
/* If called with parameters, and optionally result_format,
|
1673
1830
|
* use PQsendQueryParams
|
1674
1831
|
*/
|
1675
|
-
Check_Type(params, T_ARRAY);
|
1676
|
-
|
1677
|
-
if(NIL_P(in_res_fmt)) {
|
1678
|
-
resultFormat = 0;
|
1679
|
-
}
|
1680
|
-
else {
|
1681
|
-
resultFormat = NUM2INT(in_res_fmt);
|
1682
|
-
}
|
1683
|
-
|
1684
|
-
gc_array = rb_ary_new();
|
1685
|
-
rb_gc_register_address(&gc_array);
|
1686
|
-
sym_type = ID2SYM(rb_intern("type"));
|
1687
|
-
sym_value = ID2SYM(rb_intern("value"));
|
1688
|
-
sym_format = ID2SYM(rb_intern("format"));
|
1689
|
-
nParams = (int)RARRAY_LEN(params);
|
1690
|
-
paramTypes = ALLOC_N(Oid, nParams);
|
1691
|
-
paramValues = ALLOC_N(char *, nParams);
|
1692
|
-
paramLengths = ALLOC_N(int, nParams);
|
1693
|
-
paramFormats = ALLOC_N(int, nParams);
|
1694
|
-
for(i = 0; i < nParams; i++) {
|
1695
|
-
param = rb_ary_entry(params, i);
|
1696
|
-
if (TYPE(param) == T_HASH) {
|
1697
|
-
param_type = rb_hash_aref(param, sym_type);
|
1698
|
-
param_value_tmp = rb_hash_aref(param, sym_value);
|
1699
|
-
if(param_value_tmp == Qnil)
|
1700
|
-
param_value = param_value_tmp;
|
1701
|
-
else
|
1702
|
-
param_value = rb_obj_as_string(param_value_tmp);
|
1703
|
-
param_format = rb_hash_aref(param, sym_format);
|
1704
|
-
}
|
1705
|
-
else {
|
1706
|
-
param_type = INT2NUM(0);
|
1707
|
-
if(param == Qnil)
|
1708
|
-
param_value = param;
|
1709
|
-
else
|
1710
|
-
param_value = rb_obj_as_string(param);
|
1711
|
-
param_format = INT2NUM(0);
|
1712
|
-
}
|
1713
|
-
|
1714
|
-
if(param_type == Qnil)
|
1715
|
-
paramTypes[i] = 0;
|
1716
|
-
else
|
1717
|
-
paramTypes[i] = NUM2INT(param_type);
|
1718
|
-
|
1719
|
-
if(param_value == Qnil) {
|
1720
|
-
paramValues[i] = NULL;
|
1721
|
-
paramLengths[i] = 0;
|
1722
|
-
}
|
1723
|
-
else {
|
1724
|
-
Check_Type(param_value, T_STRING);
|
1725
|
-
/* make sure param_value doesn't get freed by the GC */
|
1726
|
-
rb_ary_push(gc_array, param_value);
|
1727
|
-
paramValues[i] = StringValuePtr(param_value);
|
1728
|
-
paramLengths[i] = (int)RSTRING_LEN(param_value);
|
1729
|
-
}
|
1730
|
-
|
1731
|
-
if(param_format == Qnil)
|
1732
|
-
paramFormats[i] = 0;
|
1733
|
-
else
|
1734
|
-
paramFormats[i] = NUM2INT(param_format);
|
1735
|
-
}
|
1736
1832
|
|
1737
|
-
|
1738
|
-
|
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 );
|
1739
1836
|
|
1740
|
-
|
1837
|
+
result = gvl_PQsendQueryParams(conn, StringValueCStr(command), nParams, paramsData.types,
|
1838
|
+
(const char * const *)paramsData.values, paramsData.lengths, paramsData.formats, resultFormat);
|
1741
1839
|
|
1742
|
-
|
1743
|
-
xfree(paramValues);
|
1744
|
-
xfree(paramLengths);
|
1745
|
-
xfree(paramFormats);
|
1840
|
+
free_query_params( ¶msData );
|
1746
1841
|
|
1747
1842
|
if(result == 0) {
|
1748
1843
|
error = rb_exc_new2(rb_eUnableToSend, PQerrorMessage(conn));
|
@@ -1794,14 +1889,13 @@ pgconn_send_prepare(int argc, VALUE *argv, VALUE self)
|
|
1794
1889
|
paramTypes = ALLOC_N(Oid, nParams);
|
1795
1890
|
for(i = 0; i < nParams; i++) {
|
1796
1891
|
param = rb_ary_entry(in_paramtypes, i);
|
1797
|
-
Check_Type(param, T_FIXNUM);
|
1798
1892
|
if(param == Qnil)
|
1799
1893
|
paramTypes[i] = 0;
|
1800
1894
|
else
|
1801
|
-
paramTypes[i] =
|
1895
|
+
paramTypes[i] = NUM2UINT(param);
|
1802
1896
|
}
|
1803
1897
|
}
|
1804
|
-
result = gvl_PQsendPrepare(conn,
|
1898
|
+
result = gvl_PQsendPrepare(conn, StringValueCStr(name), StringValueCStr(command),
|
1805
1899
|
nParams, paramTypes);
|
1806
1900
|
|
1807
1901
|
xfree(paramTypes);
|
@@ -1816,7 +1910,7 @@ pgconn_send_prepare(int argc, VALUE *argv, VALUE self)
|
|
1816
1910
|
|
1817
1911
|
/*
|
1818
1912
|
* call-seq:
|
1819
|
-
* conn.send_query_prepared( statement_name [, params, result_format ] )
|
1913
|
+
* conn.send_query_prepared( statement_name [, params, result_format[, type_map ]] )
|
1820
1914
|
* -> nil
|
1821
1915
|
*
|
1822
1916
|
* Execute prepared named statement specified by _statement_name_
|
@@ -1838,96 +1932,43 @@ pgconn_send_prepare(int argc, VALUE *argv, VALUE self)
|
|
1838
1932
|
*
|
1839
1933
|
* The optional +result_format+ should be 0 for text results, 1
|
1840
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
|
+
*
|
1841
1942
|
*/
|
1842
1943
|
static VALUE
|
1843
1944
|
pgconn_send_query_prepared(int argc, VALUE *argv, VALUE self)
|
1844
1945
|
{
|
1845
1946
|
PGconn *conn = pg_get_pgconn(self);
|
1846
1947
|
int result;
|
1847
|
-
VALUE name,
|
1848
|
-
VALUE param, param_value, param_format;
|
1849
|
-
VALUE param_value_tmp;
|
1850
|
-
VALUE sym_value, sym_format;
|
1851
|
-
VALUE gc_array;
|
1948
|
+
VALUE name, in_res_fmt;
|
1852
1949
|
VALUE error;
|
1853
|
-
int i = 0;
|
1854
1950
|
int nParams;
|
1855
|
-
char ** paramValues;
|
1856
|
-
int *paramLengths;
|
1857
|
-
int *paramFormats;
|
1858
1951
|
int resultFormat;
|
1952
|
+
struct query_params_data paramsData;
|
1859
1953
|
|
1860
|
-
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;
|
1861
1956
|
Check_Type(name, T_STRING);
|
1862
1957
|
|
1863
|
-
if(NIL_P(params)) {
|
1864
|
-
params = rb_ary_new2(0);
|
1958
|
+
if(NIL_P(paramsData.params)) {
|
1959
|
+
paramsData.params = rb_ary_new2(0);
|
1865
1960
|
resultFormat = 0;
|
1866
1961
|
}
|
1867
|
-
|
1868
|
-
Check_Type(params, T_ARRAY);
|
1869
|
-
}
|
1962
|
+
pgconn_query_assign_typemap( self, ¶msData );
|
1870
1963
|
|
1871
|
-
|
1872
|
-
|
1873
|
-
}
|
1874
|
-
else {
|
1875
|
-
resultFormat = NUM2INT(in_res_fmt);
|
1876
|
-
}
|
1964
|
+
resultFormat = NIL_P(in_res_fmt) ? 0 : NUM2INT(in_res_fmt);
|
1965
|
+
nParams = alloc_query_params( ¶msData );
|
1877
1966
|
|
1878
|
-
|
1879
|
-
|
1880
|
-
sym_value = ID2SYM(rb_intern("value"));
|
1881
|
-
sym_format = ID2SYM(rb_intern("format"));
|
1882
|
-
nParams = (int)RARRAY_LEN(params);
|
1883
|
-
paramValues = ALLOC_N(char *, nParams);
|
1884
|
-
paramLengths = ALLOC_N(int, nParams);
|
1885
|
-
paramFormats = ALLOC_N(int, nParams);
|
1886
|
-
for(i = 0; i < nParams; i++) {
|
1887
|
-
param = rb_ary_entry(params, i);
|
1888
|
-
if (TYPE(param) == T_HASH) {
|
1889
|
-
param_value_tmp = rb_hash_aref(param, sym_value);
|
1890
|
-
if(param_value_tmp == Qnil)
|
1891
|
-
param_value = param_value_tmp;
|
1892
|
-
else
|
1893
|
-
param_value = rb_obj_as_string(param_value_tmp);
|
1894
|
-
param_format = rb_hash_aref(param, sym_format);
|
1895
|
-
}
|
1896
|
-
else {
|
1897
|
-
if(param == Qnil)
|
1898
|
-
param_value = param;
|
1899
|
-
else
|
1900
|
-
param_value = rb_obj_as_string(param);
|
1901
|
-
param_format = INT2NUM(0);
|
1902
|
-
}
|
1903
|
-
|
1904
|
-
if(param_value == Qnil) {
|
1905
|
-
paramValues[i] = NULL;
|
1906
|
-
paramLengths[i] = 0;
|
1907
|
-
}
|
1908
|
-
else {
|
1909
|
-
Check_Type(param_value, T_STRING);
|
1910
|
-
/* make sure param_value doesn't get freed by the GC */
|
1911
|
-
rb_ary_push(gc_array, param_value);
|
1912
|
-
paramValues[i] = StringValuePtr(param_value);
|
1913
|
-
paramLengths[i] = (int)RSTRING_LEN(param_value);
|
1914
|
-
}
|
1915
|
-
|
1916
|
-
if(param_format == Qnil)
|
1917
|
-
paramFormats[i] = 0;
|
1918
|
-
else
|
1919
|
-
paramFormats[i] = NUM2INT(param_format);
|
1920
|
-
}
|
1921
|
-
|
1922
|
-
result = gvl_PQsendQueryPrepared(conn, StringValuePtr(name), nParams,
|
1923
|
-
(const char * const *)paramValues, paramLengths, paramFormats,
|
1967
|
+
result = gvl_PQsendQueryPrepared(conn, StringValueCStr(name), nParams,
|
1968
|
+
(const char * const *)paramsData.values, paramsData.lengths, paramsData.formats,
|
1924
1969
|
resultFormat);
|
1925
1970
|
|
1926
|
-
|
1927
|
-
|
1928
|
-
xfree(paramValues);
|
1929
|
-
xfree(paramLengths);
|
1930
|
-
xfree(paramFormats);
|
1971
|
+
free_query_params( ¶msData );
|
1931
1972
|
|
1932
1973
|
if(result == 0) {
|
1933
1974
|
error = rb_exc_new2(rb_eUnableToSend, PQerrorMessage(conn));
|
@@ -1950,7 +1991,7 @@ pgconn_send_describe_prepared(VALUE self, VALUE stmt_name)
|
|
1950
1991
|
VALUE error;
|
1951
1992
|
PGconn *conn = pg_get_pgconn(self);
|
1952
1993
|
/* returns 0 on failure */
|
1953
|
-
if(gvl_PQsendDescribePrepared(conn,
|
1994
|
+
if(gvl_PQsendDescribePrepared(conn,StringValueCStr(stmt_name)) == 0) {
|
1954
1995
|
error = rb_exc_new2(rb_eUnableToSend, PQerrorMessage(conn));
|
1955
1996
|
rb_iv_set(error, "@connection", self);
|
1956
1997
|
rb_exc_raise(error);
|
@@ -1972,7 +2013,7 @@ pgconn_send_describe_portal(VALUE self, VALUE portal)
|
|
1972
2013
|
VALUE error;
|
1973
2014
|
PGconn *conn = pg_get_pgconn(self);
|
1974
2015
|
/* returns 0 on failure */
|
1975
|
-
if(gvl_PQsendDescribePortal(conn,
|
2016
|
+
if(gvl_PQsendDescribePortal(conn,StringValueCStr(portal)) == 0) {
|
1976
2017
|
error = rb_exc_new2(rb_eUnableToSend, PQerrorMessage(conn));
|
1977
2018
|
rb_iv_set(error, "@connection", self);
|
1978
2019
|
rb_exc_raise(error);
|
@@ -2197,10 +2238,8 @@ pgconn_notifies(VALUE self)
|
|
2197
2238
|
relname = rb_tainted_str_new2(notification->relname);
|
2198
2239
|
be_pid = INT2NUM(notification->be_pid);
|
2199
2240
|
extra = rb_tainted_str_new2(notification->extra);
|
2200
|
-
|
2201
|
-
|
2202
|
-
ENCODING_SET( extra, rb_enc_to_index(pg_conn_enc_get( conn )) );
|
2203
|
-
#endif
|
2241
|
+
PG_ENCODING_SET_NOCHECK( relname, ENCODING_GET(self) );
|
2242
|
+
PG_ENCODING_SET_NOCHECK( extra, ENCODING_GET(self) );
|
2204
2243
|
|
2205
2244
|
rb_hash_aset(hash, sym_relname, relname);
|
2206
2245
|
rb_hash_aset(hash, sym_be_pid, be_pid);
|
@@ -2469,16 +2508,12 @@ pgconn_wait_for_notify(int argc, VALUE *argv, VALUE self)
|
|
2469
2508
|
if ( !pnotification ) return Qnil;
|
2470
2509
|
|
2471
2510
|
relname = rb_tainted_str_new2( pnotification->relname );
|
2472
|
-
|
2473
|
-
ENCODING_SET( relname, rb_enc_to_index(pg_conn_enc_get( conn )) );
|
2474
|
-
#endif
|
2511
|
+
PG_ENCODING_SET_NOCHECK( relname, ENCODING_GET(self) );
|
2475
2512
|
be_pid = INT2NUM( pnotification->be_pid );
|
2476
2513
|
#ifdef HAVE_ST_NOTIFY_EXTRA
|
2477
2514
|
if ( *pnotification->extra ) {
|
2478
2515
|
extra = rb_tainted_str_new2( pnotification->extra );
|
2479
|
-
|
2480
|
-
ENCODING_SET( extra, rb_enc_to_index(pg_conn_enc_get( conn )) );
|
2481
|
-
#endif
|
2516
|
+
PG_ENCODING_SET_NOCHECK( extra, ENCODING_GET(self) );
|
2482
2517
|
}
|
2483
2518
|
#endif
|
2484
2519
|
PQfreemem( pnotification );
|
@@ -2492,33 +2527,77 @@ pgconn_wait_for_notify(int argc, VALUE *argv, VALUE self)
|
|
2492
2527
|
|
2493
2528
|
/*
|
2494
2529
|
* call-seq:
|
2495
|
-
* conn.put_copy_data( buffer ) -> Boolean
|
2530
|
+
* conn.put_copy_data( buffer [, encoder] ) -> Boolean
|
2496
2531
|
*
|
2497
2532
|
* Transmits _buffer_ as copy data to the server.
|
2498
2533
|
* Returns true if the data was sent, false if it was
|
2499
2534
|
* not sent (false is only possible if the connection
|
2500
2535
|
* is in nonblocking mode, and this command would block).
|
2501
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
|
+
*
|
2502
2542
|
* Raises an exception if an error occurs.
|
2503
2543
|
*
|
2504
2544
|
* See also #copy_data.
|
2505
2545
|
*
|
2506
2546
|
*/
|
2507
2547
|
static VALUE
|
2508
|
-
pgconn_put_copy_data(
|
2509
|
-
VALUE self, buffer;
|
2548
|
+
pgconn_put_copy_data(int argc, VALUE *argv, VALUE self)
|
2510
2549
|
{
|
2511
2550
|
int ret;
|
2512
|
-
|
2513
|
-
|
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
|
+
|
2514
2590
|
Check_Type(buffer, T_STRING);
|
2515
2591
|
|
2516
|
-
ret = gvl_PQputCopyData(
|
2592
|
+
ret = gvl_PQputCopyData(this->pgconn, RSTRING_PTR(buffer), RSTRING_LENINT(buffer));
|
2517
2593
|
if(ret == -1) {
|
2518
|
-
error = rb_exc_new2(rb_ePGerror, PQerrorMessage(
|
2594
|
+
VALUE error = rb_exc_new2(rb_ePGerror, PQerrorMessage(this->pgconn));
|
2519
2595
|
rb_iv_set(error, "@connection", self);
|
2520
2596
|
rb_exc_raise(error);
|
2521
2597
|
}
|
2598
|
+
RB_GC_GUARD(intermediate);
|
2599
|
+
RB_GC_GUARD(buffer);
|
2600
|
+
|
2522
2601
|
return (ret) ? Qtrue : Qfalse;
|
2523
2602
|
}
|
2524
2603
|
|
@@ -2548,7 +2627,7 @@ pgconn_put_copy_end(int argc, VALUE *argv, VALUE self)
|
|
2548
2627
|
if (rb_scan_args(argc, argv, "01", &str) == 0)
|
2549
2628
|
error_message = NULL;
|
2550
2629
|
else
|
2551
|
-
error_message =
|
2630
|
+
error_message = StringValueCStr(str);
|
2552
2631
|
|
2553
2632
|
ret = gvl_PQputCopyEnd(conn, error_message);
|
2554
2633
|
if(ret == -1) {
|
@@ -2561,12 +2640,17 @@ pgconn_put_copy_end(int argc, VALUE *argv, VALUE self)
|
|
2561
2640
|
|
2562
2641
|
/*
|
2563
2642
|
* call-seq:
|
2564
|
-
* conn.get_copy_data( [ async = false ] ) -> String
|
2643
|
+
* conn.get_copy_data( [ async = false [, decoder = nil ]] ) -> String
|
2565
2644
|
*
|
2566
2645
|
* Return a string containing one row of data, +nil+
|
2567
2646
|
* if the copy is done, or +false+ if the call would
|
2568
2647
|
* block (only possible if _async_ is true).
|
2569
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
|
+
*
|
2570
2654
|
* See also #copy_data.
|
2571
2655
|
*
|
2572
2656
|
*/
|
@@ -2575,20 +2659,29 @@ pgconn_get_copy_data(int argc, VALUE *argv, VALUE self )
|
|
2575
2659
|
{
|
2576
2660
|
VALUE async_in;
|
2577
2661
|
VALUE error;
|
2578
|
-
VALUE
|
2662
|
+
VALUE result;
|
2579
2663
|
int ret;
|
2580
|
-
int async;
|
2581
2664
|
char *buffer;
|
2582
|
-
|
2665
|
+
VALUE decoder;
|
2666
|
+
t_pg_coder *p_coder = NULL;
|
2667
|
+
t_pg_connection *this = pg_get_connection_safe( self );
|
2583
2668
|
|
2584
|
-
|
2585
|
-
async = 0;
|
2586
|
-
else
|
2587
|
-
async = (async_in == Qfalse || async_in == Qnil) ? 0 : 1;
|
2669
|
+
rb_scan_args(argc, argv, "02", &async_in, &decoder);
|
2588
2670
|
|
2589
|
-
|
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
|
+
}
|
2681
|
+
|
2682
|
+
ret = gvl_PQgetCopyData(this->pgconn, &buffer, RTEST(async_in));
|
2590
2683
|
if(ret == -2) { /* error */
|
2591
|
-
error = rb_exc_new2(rb_ePGerror, PQerrorMessage(
|
2684
|
+
error = rb_exc_new2(rb_ePGerror, PQerrorMessage(this->pgconn));
|
2592
2685
|
rb_iv_set(error, "@connection", self);
|
2593
2686
|
rb_exc_raise(error);
|
2594
2687
|
}
|
@@ -2598,9 +2691,16 @@ pgconn_get_copy_data(int argc, VALUE *argv, VALUE self )
|
|
2598
2691
|
if(ret == 0) { /* would block */
|
2599
2692
|
return Qfalse;
|
2600
2693
|
}
|
2601
|
-
|
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
|
+
|
2602
2702
|
PQfreemem(buffer);
|
2603
|
-
return
|
2703
|
+
return result;
|
2604
2704
|
}
|
2605
2705
|
|
2606
2706
|
/*
|
@@ -2637,6 +2737,7 @@ pgconn_trace(VALUE self, VALUE stream)
|
|
2637
2737
|
FILE *new_fp;
|
2638
2738
|
int old_fd, new_fd;
|
2639
2739
|
VALUE new_file;
|
2740
|
+
t_pg_connection *this = pg_get_connection_safe( self );
|
2640
2741
|
|
2641
2742
|
if(rb_respond_to(stream,rb_intern("fileno")) == Qfalse)
|
2642
2743
|
rb_raise(rb_eArgError, "stream does not respond to method: fileno");
|
@@ -2659,9 +2760,9 @@ pgconn_trace(VALUE self, VALUE stream)
|
|
2659
2760
|
rb_raise(rb_eArgError, "stream is not writable");
|
2660
2761
|
|
2661
2762
|
new_file = rb_funcall(rb_cIO, rb_intern("new"), 1, INT2NUM(new_fd));
|
2662
|
-
|
2763
|
+
this->trace_stream = new_file;
|
2663
2764
|
|
2664
|
-
PQtrace(
|
2765
|
+
PQtrace(this->pgconn, new_fp);
|
2665
2766
|
return Qnil;
|
2666
2767
|
}
|
2667
2768
|
|
@@ -2674,11 +2775,11 @@ pgconn_trace(VALUE self, VALUE stream)
|
|
2674
2775
|
static VALUE
|
2675
2776
|
pgconn_untrace(VALUE self)
|
2676
2777
|
{
|
2677
|
-
|
2678
|
-
|
2679
|
-
|
2680
|
-
rb_funcall(trace_stream, rb_intern("close"), 0);
|
2681
|
-
|
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;
|
2682
2783
|
return Qnil;
|
2683
2784
|
}
|
2684
2785
|
|
@@ -2688,19 +2789,16 @@ pgconn_untrace(VALUE self)
|
|
2688
2789
|
* currently-registered Ruby notice_receiver object.
|
2689
2790
|
*/
|
2690
2791
|
void
|
2691
|
-
notice_receiver_proxy(void *arg, const PGresult *
|
2792
|
+
notice_receiver_proxy(void *arg, const PGresult *pgresult)
|
2692
2793
|
{
|
2693
|
-
VALUE proc;
|
2694
2794
|
VALUE self = (VALUE)arg;
|
2795
|
+
t_pg_connection *this = pg_get_connection( self );
|
2695
2796
|
|
2696
|
-
if (
|
2697
|
-
VALUE
|
2698
|
-
|
2699
|
-
|
2700
|
-
|
2701
|
-
ENCODING_SET( val, rb_enc_to_index(enc) );
|
2702
|
-
#endif
|
2703
|
-
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 );
|
2704
2802
|
}
|
2705
2803
|
return;
|
2706
2804
|
}
|
@@ -2738,7 +2836,7 @@ static VALUE
|
|
2738
2836
|
pgconn_set_notice_receiver(VALUE self)
|
2739
2837
|
{
|
2740
2838
|
VALUE proc, old_proc;
|
2741
|
-
|
2839
|
+
t_pg_connection *this = pg_get_connection_safe( self );
|
2742
2840
|
|
2743
2841
|
/* If default_notice_receiver is unset, assume that the current
|
2744
2842
|
* notice receiver is the default, and save it to a global variable.
|
@@ -2746,19 +2844,19 @@ pgconn_set_notice_receiver(VALUE self)
|
|
2746
2844
|
* always the same, so won't vary among connections.
|
2747
2845
|
*/
|
2748
2846
|
if(default_notice_receiver == NULL)
|
2749
|
-
default_notice_receiver = PQsetNoticeReceiver(
|
2847
|
+
default_notice_receiver = PQsetNoticeReceiver(this->pgconn, NULL, NULL);
|
2750
2848
|
|
2751
|
-
old_proc =
|
2849
|
+
old_proc = this->notice_receiver;
|
2752
2850
|
if( rb_block_given_p() ) {
|
2753
2851
|
proc = rb_block_proc();
|
2754
|
-
PQsetNoticeReceiver(
|
2852
|
+
PQsetNoticeReceiver(this->pgconn, gvl_notice_receiver_proxy, (void *)self);
|
2755
2853
|
} else {
|
2756
2854
|
/* if no block is given, set back to default */
|
2757
2855
|
proc = Qnil;
|
2758
|
-
PQsetNoticeReceiver(
|
2856
|
+
PQsetNoticeReceiver(this->pgconn, default_notice_receiver, NULL);
|
2759
2857
|
}
|
2760
2858
|
|
2761
|
-
|
2859
|
+
this->notice_receiver = proc;
|
2762
2860
|
return old_proc;
|
2763
2861
|
}
|
2764
2862
|
|
@@ -2770,17 +2868,13 @@ pgconn_set_notice_receiver(VALUE self)
|
|
2770
2868
|
void
|
2771
2869
|
notice_processor_proxy(void *arg, const char *message)
|
2772
2870
|
{
|
2773
|
-
VALUE proc;
|
2774
2871
|
VALUE self = (VALUE)arg;
|
2872
|
+
t_pg_connection *this = pg_get_connection( self );
|
2775
2873
|
|
2776
|
-
if (
|
2874
|
+
if (this->notice_receiver != Qnil) {
|
2777
2875
|
VALUE message_str = rb_tainted_str_new2(message);
|
2778
|
-
|
2779
|
-
|
2780
|
-
rb_encoding *enc = pg_conn_enc_get( conn );
|
2781
|
-
ENCODING_SET( message_str, rb_enc_to_index(enc) );
|
2782
|
-
#endif
|
2783
|
-
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);
|
2784
2878
|
}
|
2785
2879
|
return;
|
2786
2880
|
}
|
@@ -2802,7 +2896,7 @@ static VALUE
|
|
2802
2896
|
pgconn_set_notice_processor(VALUE self)
|
2803
2897
|
{
|
2804
2898
|
VALUE proc, old_proc;
|
2805
|
-
|
2899
|
+
t_pg_connection *this = pg_get_connection_safe( self );
|
2806
2900
|
|
2807
2901
|
/* If default_notice_processor is unset, assume that the current
|
2808
2902
|
* notice processor is the default, and save it to a global variable.
|
@@ -2810,19 +2904,19 @@ pgconn_set_notice_processor(VALUE self)
|
|
2810
2904
|
* always the same, so won't vary among connections.
|
2811
2905
|
*/
|
2812
2906
|
if(default_notice_processor == NULL)
|
2813
|
-
default_notice_processor = PQsetNoticeProcessor(
|
2907
|
+
default_notice_processor = PQsetNoticeProcessor(this->pgconn, NULL, NULL);
|
2814
2908
|
|
2815
|
-
old_proc =
|
2909
|
+
old_proc = this->notice_receiver;
|
2816
2910
|
if( rb_block_given_p() ) {
|
2817
2911
|
proc = rb_block_proc();
|
2818
|
-
PQsetNoticeProcessor(
|
2912
|
+
PQsetNoticeProcessor(this->pgconn, gvl_notice_processor_proxy, (void *)self);
|
2819
2913
|
} else {
|
2820
2914
|
/* if no block is given, set back to default */
|
2821
2915
|
proc = Qnil;
|
2822
|
-
PQsetNoticeProcessor(
|
2916
|
+
PQsetNoticeProcessor(this->pgconn, default_notice_processor, NULL);
|
2823
2917
|
}
|
2824
2918
|
|
2825
|
-
|
2919
|
+
this->notice_receiver = proc;
|
2826
2920
|
return old_proc;
|
2827
2921
|
}
|
2828
2922
|
|
@@ -2854,9 +2948,12 @@ pgconn_set_client_encoding(VALUE self, VALUE str)
|
|
2854
2948
|
|
2855
2949
|
Check_Type(str, T_STRING);
|
2856
2950
|
|
2857
|
-
if ( (PQsetClientEncoding(conn,
|
2858
|
-
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));
|
2859
2953
|
}
|
2954
|
+
#ifdef M17N_SUPPORTED
|
2955
|
+
pgconn_set_internal_encoding_index( self );
|
2956
|
+
#endif
|
2860
2957
|
|
2861
2958
|
return Qnil;
|
2862
2959
|
}
|
@@ -2935,19 +3032,15 @@ pgconn_s_quote_ident(VALUE self, VALUE in_str)
|
|
2935
3032
|
* double-quotes. */
|
2936
3033
|
char buffer[NAMEDATALEN*2+2];
|
2937
3034
|
unsigned int i=0,j=0;
|
2938
|
-
|
2939
|
-
rb_encoding* enc;
|
2940
|
-
#endif
|
2941
|
-
|
2942
|
-
UNUSED( self );
|
3035
|
+
unsigned int str_len = RSTRING_LENINT(in_str);
|
2943
3036
|
|
2944
|
-
if(
|
3037
|
+
if(str_len >= NAMEDATALEN) {
|
2945
3038
|
rb_raise(rb_eArgError,
|
2946
3039
|
"Input string is longer than NAMEDATALEN-1 (%d)",
|
2947
3040
|
NAMEDATALEN-1);
|
2948
3041
|
}
|
2949
3042
|
buffer[j++] = '"';
|
2950
|
-
for(i = 0; i <
|
3043
|
+
for(i = 0; i < str_len && str[i]; i++) {
|
2951
3044
|
if(str[i] == '"')
|
2952
3045
|
buffer[j++] = '"';
|
2953
3046
|
buffer[j++] = str[i];
|
@@ -2955,15 +3048,7 @@ pgconn_s_quote_ident(VALUE self, VALUE in_str)
|
|
2955
3048
|
buffer[j++] = '"';
|
2956
3049
|
ret = rb_str_new(buffer,j);
|
2957
3050
|
OBJ_INFECT(ret, in_str);
|
2958
|
-
|
2959
|
-
#ifdef M17N_SUPPORTED
|
2960
|
-
if ( rb_obj_class(self) == rb_cPGconn ) {
|
2961
|
-
enc = pg_conn_enc_get( pg_get_pgconn(self) );
|
2962
|
-
} else {
|
2963
|
-
enc = rb_enc_get(in_str);
|
2964
|
-
}
|
2965
|
-
rb_enc_associate(ret, enc);
|
2966
|
-
#endif
|
3051
|
+
PG_ENCODING_SET_NOCHECK(ret, ENCODING_GET( rb_obj_class(self) == rb_cPGconn ? self : in_str ));
|
2967
3052
|
|
2968
3053
|
return ret;
|
2969
3054
|
}
|
@@ -3117,7 +3202,7 @@ pgconn_locreat(int argc, VALUE *argv, VALUE self)
|
|
3117
3202
|
if (lo_oid == 0)
|
3118
3203
|
rb_raise(rb_ePGerror, "lo_creat failed");
|
3119
3204
|
|
3120
|
-
return
|
3205
|
+
return UINT2NUM(lo_oid);
|
3121
3206
|
}
|
3122
3207
|
|
3123
3208
|
/*
|
@@ -3132,13 +3217,13 @@ pgconn_locreate(VALUE self, VALUE in_lo_oid)
|
|
3132
3217
|
{
|
3133
3218
|
Oid ret, lo_oid;
|
3134
3219
|
PGconn *conn = pg_get_pgconn(self);
|
3135
|
-
lo_oid =
|
3220
|
+
lo_oid = NUM2UINT(in_lo_oid);
|
3136
3221
|
|
3137
3222
|
ret = lo_create(conn, lo_oid);
|
3138
3223
|
if (ret == InvalidOid)
|
3139
3224
|
rb_raise(rb_ePGerror, "lo_create failed");
|
3140
3225
|
|
3141
|
-
return
|
3226
|
+
return UINT2NUM(ret);
|
3142
3227
|
}
|
3143
3228
|
|
3144
3229
|
/*
|
@@ -3158,11 +3243,11 @@ pgconn_loimport(VALUE self, VALUE filename)
|
|
3158
3243
|
|
3159
3244
|
Check_Type(filename, T_STRING);
|
3160
3245
|
|
3161
|
-
lo_oid = lo_import(conn,
|
3246
|
+
lo_oid = lo_import(conn, StringValueCStr(filename));
|
3162
3247
|
if (lo_oid == 0) {
|
3163
3248
|
rb_raise(rb_ePGerror, "%s", PQerrorMessage(conn));
|
3164
3249
|
}
|
3165
|
-
return
|
3250
|
+
return UINT2NUM(lo_oid);
|
3166
3251
|
}
|
3167
3252
|
|
3168
3253
|
/*
|
@@ -3175,15 +3260,12 @@ static VALUE
|
|
3175
3260
|
pgconn_loexport(VALUE self, VALUE lo_oid, VALUE filename)
|
3176
3261
|
{
|
3177
3262
|
PGconn *conn = pg_get_pgconn(self);
|
3178
|
-
|
3263
|
+
Oid oid;
|
3179
3264
|
Check_Type(filename, T_STRING);
|
3180
3265
|
|
3181
|
-
oid =
|
3182
|
-
if (oid < 0) {
|
3183
|
-
rb_raise(rb_ePGerror, "invalid large object oid %d",oid);
|
3184
|
-
}
|
3266
|
+
oid = NUM2UINT(lo_oid);
|
3185
3267
|
|
3186
|
-
if (lo_export(conn, oid,
|
3268
|
+
if (lo_export(conn, oid, StringValueCStr(filename)) < 0) {
|
3187
3269
|
rb_raise(rb_ePGerror, "%s", PQerrorMessage(conn));
|
3188
3270
|
}
|
3189
3271
|
return Qnil;
|
@@ -3208,7 +3290,7 @@ pgconn_loopen(int argc, VALUE *argv, VALUE self)
|
|
3208
3290
|
PGconn *conn = pg_get_pgconn(self);
|
3209
3291
|
|
3210
3292
|
rb_scan_args(argc, argv, "11", &selfid, &nmode);
|
3211
|
-
lo_oid =
|
3293
|
+
lo_oid = NUM2UINT(selfid);
|
3212
3294
|
if(NIL_P(nmode))
|
3213
3295
|
mode = INV_READ;
|
3214
3296
|
else
|
@@ -3375,10 +3457,7 @@ static VALUE
|
|
3375
3457
|
pgconn_lounlink(VALUE self, VALUE in_oid)
|
3376
3458
|
{
|
3377
3459
|
PGconn *conn = pg_get_pgconn(self);
|
3378
|
-
|
3379
|
-
|
3380
|
-
if (oid < 0)
|
3381
|
-
rb_raise(rb_ePGerror, "invalid oid %d",oid);
|
3460
|
+
Oid oid = NUM2UINT(in_oid);
|
3382
3461
|
|
3383
3462
|
if(lo_unlink(conn,oid) < 0)
|
3384
3463
|
rb_raise(rb_ePGerror,"lo_unlink failed");
|
@@ -3389,6 +3468,14 @@ pgconn_lounlink(VALUE self, VALUE in_oid)
|
|
3389
3468
|
|
3390
3469
|
#ifdef M17N_SUPPORTED
|
3391
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
|
+
|
3392
3479
|
/*
|
3393
3480
|
* call-seq:
|
3394
3481
|
* conn.internal_encoding -> Encoding
|
@@ -3429,11 +3516,12 @@ static VALUE pgconn_external_encoding(VALUE self);
|
|
3429
3516
|
static VALUE
|
3430
3517
|
pgconn_internal_encoding_set(VALUE self, VALUE enc)
|
3431
3518
|
{
|
3519
|
+
VALUE enc_inspect;
|
3432
3520
|
if (NIL_P(enc)) {
|
3433
3521
|
pgconn_set_client_encoding( self, rb_usascii_str_new_cstr("SQL_ASCII") );
|
3434
3522
|
return enc;
|
3435
3523
|
}
|
3436
|
-
else if ( TYPE(enc) == T_STRING && strcasecmp("JOHAB",
|
3524
|
+
else if ( TYPE(enc) == T_STRING && strcasecmp("JOHAB", StringValueCStr(enc)) == 0 ) {
|
3437
3525
|
pgconn_set_client_encoding(self, rb_usascii_str_new_cstr("JOHAB"));
|
3438
3526
|
return enc;
|
3439
3527
|
}
|
@@ -3446,10 +3534,12 @@ pgconn_internal_encoding_set(VALUE self, VALUE enc)
|
|
3446
3534
|
rb_raise( rb_eEncCompatError, "incompatible character encodings: %s and %s",
|
3447
3535
|
rb_enc_name(rb_to_encoding(server_encoding)), name );
|
3448
3536
|
}
|
3537
|
+
pgconn_set_internal_encoding_index( self );
|
3449
3538
|
return enc;
|
3450
3539
|
}
|
3451
3540
|
|
3452
|
-
|
3541
|
+
enc_inspect = rb_inspect(enc);
|
3542
|
+
rb_raise( rb_ePGerror, "unknown encoding: %s", StringValueCStr(enc_inspect) );
|
3453
3543
|
|
3454
3544
|
return Qnil;
|
3455
3545
|
}
|
@@ -3466,21 +3556,18 @@ pgconn_internal_encoding_set(VALUE self, VALUE enc)
|
|
3466
3556
|
static VALUE
|
3467
3557
|
pgconn_external_encoding(VALUE self)
|
3468
3558
|
{
|
3469
|
-
|
3470
|
-
VALUE encoding = rb_iv_get( self, "@external_encoding" );
|
3559
|
+
t_pg_connection *this = pg_get_connection_safe( self );
|
3471
3560
|
rb_encoding *enc = NULL;
|
3472
3561
|
const char *pg_encname = NULL;
|
3473
3562
|
|
3474
3563
|
/* Use cached value if found */
|
3475
|
-
if ( RTEST(
|
3564
|
+
if ( RTEST(this->external_encoding) ) return this->external_encoding;
|
3476
3565
|
|
3477
|
-
pg_encname = PQparameterStatus(
|
3566
|
+
pg_encname = PQparameterStatus( this->pgconn, "server_encoding" );
|
3478
3567
|
enc = pg_get_pg_encname_as_rb_encoding( pg_encname );
|
3479
|
-
|
3568
|
+
this->external_encoding = rb_enc_from_encoding( enc );
|
3480
3569
|
|
3481
|
-
|
3482
|
-
|
3483
|
-
return encoding;
|
3570
|
+
return this->external_encoding;
|
3484
3571
|
}
|
3485
3572
|
|
3486
3573
|
|
@@ -3505,8 +3592,10 @@ pgconn_set_default_encoding( VALUE self )
|
|
3505
3592
|
if ( PQsetClientEncoding(conn, encname) != 0 )
|
3506
3593
|
rb_warn( "Failed to set the default_internal encoding to %s: '%s'",
|
3507
3594
|
encname, PQerrorMessage(conn) );
|
3595
|
+
pgconn_set_internal_encoding_index( self );
|
3508
3596
|
return rb_enc_from_encoding( enc );
|
3509
3597
|
} else {
|
3598
|
+
pgconn_set_internal_encoding_index( self );
|
3510
3599
|
return Qnil;
|
3511
3600
|
}
|
3512
3601
|
}
|
@@ -3514,11 +3603,209 @@ pgconn_set_default_encoding( VALUE self )
|
|
3514
3603
|
|
3515
3604
|
#endif /* M17N_SUPPORTED */
|
3516
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
|
+
}
|
3517
3799
|
|
3518
3800
|
|
3519
3801
|
void
|
3520
3802
|
init_pg_connection()
|
3521
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
|
+
|
3522
3809
|
rb_cPGconn = rb_define_class_under( rb_mPG, "Connection", rb_cObject );
|
3523
3810
|
rb_include_module(rb_cPGconn, rb_mPGconstants);
|
3524
3811
|
|
@@ -3558,7 +3845,9 @@ init_pg_connection()
|
|
3558
3845
|
rb_define_method(rb_cPGconn, "host", pgconn_host, 0);
|
3559
3846
|
rb_define_method(rb_cPGconn, "port", pgconn_port, 0);
|
3560
3847
|
rb_define_method(rb_cPGconn, "tty", pgconn_tty, 0);
|
3848
|
+
#ifdef HAVE_PQCONNINFO
|
3561
3849
|
rb_define_method(rb_cPGconn, "conninfo", pgconn_conninfo, 0);
|
3850
|
+
#endif
|
3562
3851
|
rb_define_method(rb_cPGconn, "options", pgconn_options, 0);
|
3563
3852
|
rb_define_method(rb_cPGconn, "status", pgconn_status, 0);
|
3564
3853
|
rb_define_method(rb_cPGconn, "transaction_status", pgconn_transaction_status, 0);
|
@@ -3619,7 +3908,7 @@ init_pg_connection()
|
|
3619
3908
|
rb_define_method(rb_cPGconn, "notifies", pgconn_notifies, 0);
|
3620
3909
|
|
3621
3910
|
/****** PG::Connection INSTANCE METHODS: COPY ******/
|
3622
|
-
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);
|
3623
3912
|
rb_define_method(rb_cPGconn, "put_copy_end", pgconn_put_copy_end, -1);
|
3624
3913
|
rb_define_method(rb_cPGconn, "get_copy_data", pgconn_get_copy_data, -1);
|
3625
3914
|
|
@@ -3680,5 +3969,13 @@ init_pg_connection()
|
|
3680
3969
|
rb_define_method(rb_cPGconn, "set_default_encoding", pgconn_set_default_encoding, 0);
|
3681
3970
|
#endif /* M17N_SUPPORTED */
|
3682
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);
|
3683
3980
|
}
|
3684
3981
|
|