pg 0.17.1-x86-mingw32 → 0.18.0.pre20141017160319-x86-mingw32

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