pg 0.17.1 → 0.18.4

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