pg 0.18.0.pre20140820094244 → 0.18.0.pre20141017155815

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