pg 0.18.0.pre20141017160319 → 0.18.0.pre20141117110243

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.
@@ -1,6 +1,6 @@
1
1
  /*
2
2
  * pg_text_decoder.c - PG::TextDecoder module
3
- * $Id: pg_text_decoder.c,v e64618a44912 2014/10/05 19:56:05 lars $
3
+ * $Id$
4
4
  *
5
5
  */
6
6
 
@@ -1,6 +1,6 @@
1
1
  /*
2
2
  * pg_text_encoder.c - PG::TextEncoder module
3
- * $Id: pg_text_encoder.c,v a4725dfca9e4 2014/10/15 19:50:56 lars $
3
+ * $Id$
4
4
  *
5
5
  */
6
6
 
@@ -42,6 +42,7 @@
42
42
  #include "pg.h"
43
43
  #include "util.h"
44
44
  #include <inttypes.h>
45
+ #include <math.h>
45
46
 
46
47
  VALUE rb_mPG_TextEncoder;
47
48
  static ID s_id_encode;
@@ -246,6 +247,46 @@ pg_text_enc_float(t_pg_coder *conv, VALUE value, char *out, VALUE *intermediate)
246
247
  }
247
248
  }
248
249
 
250
+ static const char hextab[] = {
251
+ '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'
252
+ };
253
+
254
+ /*
255
+ * Document-class: PG::TextEncoder::Bytea < PG::SimpleEncoder
256
+ *
257
+ * This is an encoder class for the PostgreSQL bytea type for server version 9.0
258
+ * or newer.
259
+ *
260
+ * The binary String is converted to hexadecimal representation for transmission
261
+ * in text format. For query bind parameters it is recommended to use
262
+ * PG::BinaryEncoder::Bytea instead, in order to decrease network traffic and
263
+ * CPU usage.
264
+ *
265
+ */
266
+ static int
267
+ pg_text_enc_bytea(t_pg_coder *conv, VALUE value, char *out, VALUE *intermediate)
268
+ {
269
+ if(out){
270
+ size_t strlen = RSTRING_LEN(*intermediate);
271
+ char *iptr = RSTRING_PTR(*intermediate);
272
+ char *eptr = iptr + strlen;
273
+ char *optr = out;
274
+ *optr++ = '\\';
275
+ *optr++ = 'x';
276
+
277
+ for( ; iptr < eptr; iptr++ ){
278
+ unsigned char c = *iptr;
279
+ *optr++ = hextab[c >> 4];
280
+ *optr++ = hextab[c & 0xf];
281
+ }
282
+ return optr - out;
283
+ }else{
284
+ *intermediate = rb_obj_as_string(value);
285
+ /* The output starts with "\x" and each character is converted to hex. */
286
+ return 2 + RSTRING_LEN(*intermediate) * 2;
287
+ }
288
+ }
289
+
249
290
  typedef int (*t_quote_func)( void *_this, char *p_in, int strlen, char *p_out );
250
291
 
251
292
  static int
@@ -619,6 +660,8 @@ init_pg_text_encoder()
619
660
  pg_define_coder( "Float", pg_text_enc_float, rb_cPG_SimpleEncoder, rb_mPG_TextEncoder );
620
661
  /* dummy = rb_define_class_under( rb_mPG_TextEncoder, "String", rb_cPG_SimpleEncoder ); */
621
662
  pg_define_coder( "String", pg_coder_enc_to_s, rb_cPG_SimpleEncoder, rb_mPG_TextEncoder );
663
+ /* dummy = rb_define_class_under( rb_mPG_TextEncoder, "Bytea", rb_cPG_SimpleEncoder ); */
664
+ pg_define_coder( "Bytea", pg_text_enc_bytea, rb_cPG_SimpleEncoder, rb_mPG_TextEncoder );
622
665
 
623
666
  /* dummy = rb_define_class_under( rb_mPG_TextEncoder, "Array", rb_cPG_CompositeEncoder ); */
624
667
  pg_define_coder( "Array", pg_text_enc_array, rb_cPG_CompositeEncoder, rb_mPG_TextEncoder );
@@ -1,12 +1,13 @@
1
1
  /*
2
2
  * pg_column_map.c - PG::ColumnMap class extension
3
- * $Id: pg_type_map.c,v 4227fdc5f0ac 2014/10/07 17:42:09 lars $
3
+ * $Id$
4
4
  *
5
5
  */
6
6
 
7
7
  #include "pg.h"
8
8
 
9
9
  VALUE rb_cTypeMap;
10
+ VALUE rb_mDefaultTypeMappable;
10
11
  static ID s_id_fit_to_query;
11
12
  static ID s_id_fit_to_result;
12
13
 
@@ -27,31 +28,40 @@ pg_typemap_fit_to_query( VALUE self, VALUE params )
27
28
  int
28
29
  pg_typemap_fit_to_copy_get( VALUE self )
29
30
  {
30
- rb_raise( rb_eNotImpError, "type map %s is not suitable to map copy_get_data results", rb_obj_classname(self) );
31
+ rb_raise( rb_eNotImpError, "type map %s is not suitable to map get_copy_data results", rb_obj_classname(self) );
31
32
  return Qnil;
32
33
  }
33
34
 
34
35
  VALUE
35
- pg_typemap_result_value(VALUE self, int tuple, int field)
36
+ pg_typemap_result_value( t_typemap *p_typemap, VALUE result, int tuple, int field )
36
37
  {
37
38
  rb_raise( rb_eNotImpError, "type map is not suitable to map result values" );
38
39
  return Qnil;
39
40
  }
40
41
 
41
42
  t_pg_coder *
42
- pg_typemap_typecast_query_param(VALUE self, VALUE param_value, int field)
43
+ pg_typemap_typecast_query_param( t_typemap *p_typemap, VALUE param_value, int field )
43
44
  {
44
- rb_raise( rb_eNotImpError, "type map %s is not suitable to map query params", rb_obj_classname(self) );
45
+ rb_raise( rb_eNotImpError, "type map is not suitable to map query params" );
45
46
  return NULL;
46
47
  }
47
48
 
48
49
  VALUE
49
50
  pg_typemap_typecast_copy_get( t_typemap *p_typemap, VALUE field_str, int fieldno, int format, int enc_idx )
50
51
  {
51
- rb_raise( rb_eNotImpError, "type map is not suitable to map copy_get_data results" );
52
+ rb_raise( rb_eNotImpError, "type map is not suitable to map get_copy_data results" );
52
53
  return Qnil;
53
54
  }
54
55
 
56
+ const struct pg_typemap_funcs pg_typemap_funcs = {
57
+ .fit_to_result = pg_typemap_fit_to_result,
58
+ .fit_to_query = pg_typemap_fit_to_query,
59
+ .fit_to_copy_get = pg_typemap_fit_to_copy_get,
60
+ .typecast_result_value = pg_typemap_result_value,
61
+ .typecast_query_param = pg_typemap_typecast_query_param,
62
+ .typecast_copy_get = pg_typemap_typecast_copy_get
63
+ };
64
+
55
65
  static VALUE
56
66
  pg_typemap_s_allocate( VALUE klass )
57
67
  {
@@ -59,12 +69,7 @@ pg_typemap_s_allocate( VALUE klass )
59
69
  t_typemap *this;
60
70
 
61
71
  self = Data_Make_Struct( klass, t_typemap, NULL, -1, this );
62
- this->fit_to_result = pg_typemap_fit_to_result;
63
- this->fit_to_query = pg_typemap_fit_to_query;
64
- this->fit_to_copy_get = pg_typemap_fit_to_copy_get;
65
- this->typecast_result_value = pg_typemap_result_value;
66
- this->typecast_query_param = pg_typemap_typecast_query_param;
67
- this->typecast_copy_get = pg_typemap_typecast_copy_get;
72
+ this->funcs = pg_typemap_funcs;
68
73
 
69
74
  return self;
70
75
  }
@@ -79,7 +84,7 @@ pg_typemap_fit_to_result_ext( VALUE self, VALUE result )
79
84
  rb_obj_classname( result ) );
80
85
  }
81
86
 
82
- return this->fit_to_result( self, result );
87
+ return this->funcs.fit_to_result( self, result );
83
88
  }
84
89
 
85
90
  static VALUE
@@ -89,7 +94,68 @@ pg_typemap_fit_to_query_ext( VALUE self, VALUE params )
89
94
 
90
95
  Check_Type( params, T_ARRAY);
91
96
 
92
- return this->fit_to_query( self, params );
97
+ return this->funcs.fit_to_query( self, params );
98
+ }
99
+
100
+ /*
101
+ * call-seq:
102
+ * res.default_type_map = typemap
103
+ *
104
+ * Set the default TypeMap that is used for values that could not be
105
+ * casted by this type map.
106
+ *
107
+ * +typemap+ must be a kind of PG::TypeMap
108
+ *
109
+ */
110
+ static VALUE
111
+ pg_typemap_default_type_map_set(VALUE self, VALUE typemap)
112
+ {
113
+ t_typemap *this = DATA_PTR( self );
114
+
115
+ if ( !rb_obj_is_kind_of(typemap, rb_cTypeMap) ) {
116
+ rb_raise( rb_eTypeError, "wrong argument type %s (expected kind of PG::TypeMap)",
117
+ rb_obj_classname( typemap ) );
118
+ }
119
+ Check_Type(typemap, T_DATA);
120
+ this->default_typemap = typemap;
121
+
122
+ return typemap;
123
+ }
124
+
125
+ /*
126
+ * call-seq:
127
+ * res.default_type_map -> TypeMap
128
+ *
129
+ * Returns the default TypeMap that is currently set for values that could not be
130
+ * casted by this type map.
131
+ *
132
+ * Returns a kind of PG::TypeMap.
133
+ *
134
+ */
135
+ static VALUE
136
+ pg_typemap_default_type_map_get(VALUE self)
137
+ {
138
+ t_typemap *this = DATA_PTR( self );
139
+
140
+ return this->default_typemap;
141
+ }
142
+
143
+ /*
144
+ * call-seq:
145
+ * res.with_default_type_map( typemap )
146
+ *
147
+ * Set the default TypeMap that is used for values that could not be
148
+ * casted by this type map.
149
+ *
150
+ * +typemap+ must be a kind of PG::TypeMap
151
+ *
152
+ * Returns self.
153
+ */
154
+ static VALUE
155
+ pg_typemap_with_default_type_map(VALUE self, VALUE typemap)
156
+ {
157
+ pg_typemap_default_type_map_set( self, typemap );
158
+ return self;
93
159
  }
94
160
 
95
161
  void
@@ -110,4 +176,9 @@ init_pg_type_map()
110
176
  rb_define_alloc_func( rb_cTypeMap, pg_typemap_s_allocate );
111
177
  rb_define_method( rb_cTypeMap, "fit_to_result", pg_typemap_fit_to_result_ext, 1 );
112
178
  rb_define_method( rb_cTypeMap, "fit_to_query", pg_typemap_fit_to_query_ext, 1 );
179
+
180
+ rb_mDefaultTypeMappable = rb_define_module_under( rb_cTypeMap, "DefaultTypeMappable");
181
+ rb_define_method( rb_mDefaultTypeMappable, "default_type_map=", pg_typemap_default_type_map_set, 1 );
182
+ rb_define_method( rb_mDefaultTypeMappable, "default_type_map", pg_typemap_default_type_map_get, 0 );
183
+ rb_define_method( rb_mDefaultTypeMappable, "with_default_type_map", pg_typemap_with_default_type_map, 1 );
113
184
  }
@@ -1,6 +1,6 @@
1
1
  /*
2
2
  * pg_type_map_all_strings.c - PG::TypeMapAllStrings class extension
3
- * $Id: pg_type_map_all_strings.c,v 4227fdc5f0ac 2014/10/07 17:42:09 lars $
3
+ * $Id$
4
4
  *
5
5
  * This is the default typemap.
6
6
  *
@@ -9,7 +9,7 @@
9
9
  #include "pg.h"
10
10
 
11
11
  VALUE rb_cTypeMapAllStrings;
12
- VALUE pg_default_typemap;
12
+ VALUE pg_typemap_all_strings;
13
13
 
14
14
  static VALUE
15
15
  pg_tmas_fit_to_result( VALUE self, VALUE result )
@@ -18,7 +18,7 @@ pg_tmas_fit_to_result( VALUE self, VALUE result )
18
18
  }
19
19
 
20
20
  static VALUE
21
- pg_tmas_result_value(VALUE result, int tuple, int field)
21
+ pg_tmas_result_value( t_typemap *p_typemap, VALUE result, int tuple, int field )
22
22
  {
23
23
  VALUE ret;
24
24
  char * val;
@@ -48,7 +48,7 @@ pg_tmas_fit_to_query( VALUE self, VALUE params )
48
48
  }
49
49
 
50
50
  static t_pg_coder *
51
- pg_tmas_typecast_query_param(VALUE self, VALUE param_value, int field)
51
+ pg_tmas_typecast_query_param( t_typemap *p_typemap, VALUE param_value, int field )
52
52
  {
53
53
  return NULL;
54
54
  }
@@ -79,12 +79,12 @@ pg_tmas_s_allocate( VALUE klass )
79
79
 
80
80
  self = Data_Make_Struct( klass, t_typemap, NULL, -1, this );
81
81
 
82
- this->fit_to_result = pg_tmas_fit_to_result;
83
- this->fit_to_query = pg_tmas_fit_to_query;
84
- this->fit_to_copy_get = pg_tmas_fit_to_copy_get;
85
- this->typecast_result_value = pg_tmas_result_value;
86
- this->typecast_query_param = pg_tmas_typecast_query_param;
87
- this->typecast_copy_get = pg_tmas_typecast_copy_get;
82
+ this->funcs.fit_to_result = pg_tmas_fit_to_result;
83
+ this->funcs.fit_to_query = pg_tmas_fit_to_query;
84
+ this->funcs.fit_to_copy_get = pg_tmas_fit_to_copy_get;
85
+ this->funcs.typecast_result_value = pg_tmas_result_value;
86
+ this->funcs.typecast_query_param = pg_tmas_typecast_query_param;
87
+ this->funcs.typecast_copy_get = pg_tmas_typecast_copy_get;
88
88
 
89
89
  return self;
90
90
  }
@@ -98,16 +98,19 @@ init_pg_type_map_all_strings()
98
98
  *
99
99
  * This type map casts all values received from the database server to Strings
100
100
  * and sends all values to the server after conversion to String by +#to_str+ .
101
+ * That means, it is hard coded to PG::TextEncoder::String for value encoding
102
+ * and to PG::TextDecoder::String for text format respectivly PG::BinaryDecoder::Bytea
103
+ * for binary format received from the server.
101
104
  *
102
105
  * It is suitable for type casting query bind parameters, result values and
103
106
  * COPY IN/OUT data.
104
107
  *
105
- * This is the default type map. It is used when type_map is not set or set to +nil+.
108
+ * This is the default type map for each PG::Connection .
106
109
  *
107
110
  */
108
111
  rb_cTypeMapAllStrings = rb_define_class_under( rb_mPG, "TypeMapAllStrings", rb_cTypeMap );
109
112
  rb_define_alloc_func( rb_cTypeMapAllStrings, pg_tmas_s_allocate );
110
113
 
111
- pg_default_typemap = rb_funcall( rb_cTypeMapAllStrings, rb_intern("new"), 0 );
112
- rb_gc_register_address( &pg_default_typemap );
114
+ pg_typemap_all_strings = rb_funcall( rb_cTypeMapAllStrings, rb_intern("new"), 0 );
115
+ rb_gc_register_address( &pg_typemap_all_strings );
113
116
  }
@@ -0,0 +1,239 @@
1
+ /*
2
+ * pg_type_map_by_class.c - PG::TypeMapByClass class extension
3
+ * $Id$
4
+ *
5
+ * This type map can be used to select value encoders based on the class
6
+ * of the given value to be send.
7
+ *
8
+ */
9
+
10
+ #include "pg.h"
11
+
12
+ static VALUE rb_cTypeMapByClass;
13
+ static ID s_id_ancestors;
14
+
15
+ typedef struct {
16
+ t_typemap typemap;
17
+
18
+ VALUE klass_to_coder;
19
+ VALUE self;
20
+
21
+ struct pg_tmbk_coder_cache_entry {
22
+ VALUE klass;
23
+ t_pg_coder *p_coder;
24
+ } cache_row[0x100];
25
+ } t_tmbk;
26
+
27
+ /*
28
+ * We use 8 Bits of the klass object id as index to a 256 entry cache.
29
+ * This avoids full lookups in most cases.
30
+ */
31
+ #define CACHE_LOOKUP(this, klass) ( &this->cache_row[(klass >> 8) & 0xff] )
32
+
33
+
34
+ static t_pg_coder *
35
+ pg_tmbk_lookup_klass(t_tmbk *this, VALUE klass, VALUE param_value)
36
+ {
37
+ t_pg_coder *p_coder;
38
+ struct pg_tmbk_coder_cache_entry *p_ce;
39
+
40
+ p_ce = CACHE_LOOKUP(this, klass);
41
+
42
+ /* Is the cache entry for the expected klass? */
43
+ if( p_ce->klass == klass ) {
44
+ p_coder = p_ce->p_coder;
45
+ } else {
46
+ /* No, then do a full lookup based on the ancestors. */
47
+ VALUE obj = rb_hash_lookup( this->klass_to_coder, klass );
48
+
49
+ if( NIL_P(obj) ){
50
+ int i;
51
+ VALUE ancestors = rb_funcall( klass, s_id_ancestors, 0 );
52
+
53
+ Check_Type( ancestors, T_ARRAY );
54
+ /* Don't look at the first element, it's expected to equal klass. */
55
+ for( i=1; i<RARRAY_LEN(ancestors); i++ ){
56
+ obj = rb_hash_lookup( this->klass_to_coder, rb_ary_entry( ancestors, i) );
57
+
58
+ if( !NIL_P(obj) )
59
+ break;
60
+ }
61
+ }
62
+
63
+ if(NIL_P(obj)){
64
+ p_coder = NULL;
65
+ }else if(rb_obj_is_kind_of(obj, rb_cPG_Coder)){
66
+ Data_Get_Struct(obj, t_pg_coder, p_coder);
67
+ }else{
68
+ if( RB_TYPE_P(obj, T_SYMBOL) ){
69
+ /* A Proc object (or something that responds to #call). */
70
+ obj = rb_funcall(this->self, SYM2ID(obj), 1, param_value);
71
+ }else{
72
+ /* A Proc object (or something that responds to #call). */
73
+ obj = rb_funcall(obj, rb_intern("call"), 1, param_value);
74
+ }
75
+
76
+ if( NIL_P(obj) ){
77
+ p_coder = NULL;
78
+ }else if( rb_obj_is_kind_of(obj, rb_cPG_Coder) ){
79
+ Data_Get_Struct(obj, t_pg_coder, p_coder);
80
+ }else{
81
+ rb_raise(rb_eTypeError, "argument has invalid type %s (should be nil or some kind of PG::Coder)",
82
+ rb_obj_classname( obj ));
83
+ }
84
+
85
+ /* We can not cache coders retrieved by ruby code, because we can not anticipate
86
+ * the returned Coder object. */
87
+ return p_coder;
88
+ }
89
+
90
+ /* Write the retrieved coder to the cache */
91
+ p_ce->klass = klass;
92
+ p_ce->p_coder = p_coder;
93
+ }
94
+ return p_coder;
95
+ }
96
+
97
+
98
+ static t_pg_coder *
99
+ pg_tmbk_typecast_query_param( t_typemap *p_typemap, VALUE param_value, int field )
100
+ {
101
+ t_tmbk *this = (t_tmbk *)p_typemap;
102
+ t_pg_coder *p_coder;
103
+
104
+ p_coder = pg_tmbk_lookup_klass( this, rb_obj_class(param_value), param_value );
105
+
106
+ if( !p_coder ){
107
+ t_typemap *default_tm = DATA_PTR( this->typemap.default_typemap );
108
+ return default_tm->funcs.typecast_query_param( default_tm, param_value, field );
109
+ }
110
+
111
+ return p_coder;
112
+ }
113
+
114
+ static VALUE
115
+ pg_tmbk_fit_to_query( VALUE self, VALUE params )
116
+ {
117
+ t_tmbk *this = (t_tmbk *)DATA_PTR(self);
118
+ /* Nothing to check at this typemap, but ensure that the default type map fits. */
119
+ t_typemap *default_tm = DATA_PTR( this->typemap.default_typemap );
120
+ default_tm->funcs.fit_to_query( this->typemap.default_typemap, params );
121
+ return self;
122
+ }
123
+
124
+ static void
125
+ pg_tmbk_mark( t_tmbk *this )
126
+ {
127
+ rb_gc_mark(this->typemap.default_typemap);
128
+ rb_gc_mark(this->klass_to_coder);
129
+ /* All coders are in the Hash, so no need to mark the cache. */
130
+ }
131
+
132
+ static VALUE
133
+ pg_tmbk_s_allocate( VALUE klass )
134
+ {
135
+ t_tmbk *this;
136
+ VALUE self;
137
+
138
+ self = Data_Make_Struct( klass, t_tmbk, pg_tmbk_mark, -1, this );
139
+ this->typemap.funcs.fit_to_result = pg_typemap_fit_to_result;
140
+ this->typemap.funcs.fit_to_query = pg_tmbk_fit_to_query;
141
+ this->typemap.funcs.fit_to_copy_get = pg_typemap_fit_to_copy_get;
142
+ this->typemap.funcs.typecast_result_value = pg_typemap_result_value;
143
+ this->typemap.funcs.typecast_query_param = pg_tmbk_typecast_query_param;
144
+ this->typemap.funcs.typecast_copy_get = pg_typemap_typecast_copy_get;
145
+ this->typemap.default_typemap = pg_typemap_all_strings;
146
+
147
+ /* We need to store self in the this-struct, because pg_tmbk_typecast_query_param(),
148
+ * is called with the this-pointer only. */
149
+ this->self = self;
150
+ this->klass_to_coder = rb_hash_new();
151
+
152
+ /* The cache is properly initialized by Data_Make_Struct(). */
153
+
154
+ return self;
155
+ }
156
+
157
+ /*
158
+ * call-seq:
159
+ * typemap.[class] = coder
160
+ *
161
+ * Assigns a new PG::Coder object to the type map. The encoder
162
+ * is chosen for all values that are a kind of the given +class+ .
163
+ *
164
+ * +coder+ can be one of the following:
165
+ * * +nil+ - Values are forwarded to the #default_type_map .
166
+ * * a PG::Coder - Values are encoded by the given encoder
167
+ * * a Symbol - The method of this type map (or a derivation) that is called for each value to sent.
168
+ * It must return a PG::Coder or +nil+ .
169
+ * * a Proc - The Proc object is called for each value. It must return a PG::Coder or +nil+ .
170
+ *
171
+ */
172
+ static VALUE
173
+ pg_tmbk_aset( VALUE self, VALUE klass, VALUE coder )
174
+ {
175
+ t_tmbk *this = DATA_PTR( self );
176
+
177
+ if(NIL_P(coder)){
178
+ rb_hash_delete( this->klass_to_coder, klass );
179
+ }else{
180
+ rb_hash_aset( this->klass_to_coder, klass, coder );
181
+ }
182
+
183
+ /* The cache lookup key can be a derivation of the klass.
184
+ * So we can not expire the cache selectively. */
185
+ memset( &this->cache_row, 0, sizeof(this->cache_row) );
186
+
187
+ return coder;
188
+ }
189
+
190
+ /*
191
+ * call-seq:
192
+ * typemap.[class] -> coder
193
+ *
194
+ * Returns the encoder object for the given +class+
195
+ */
196
+ static VALUE
197
+ pg_tmbk_aref( VALUE self, VALUE klass )
198
+ {
199
+ t_tmbk *this = DATA_PTR( self );
200
+
201
+ return rb_hash_lookup(this->klass_to_coder, klass);
202
+ }
203
+
204
+ /*
205
+ * call-seq:
206
+ * typemap.coders -> Hash
207
+ *
208
+ * Returns all classes and their assigned encoder object.
209
+ */
210
+ static VALUE
211
+ pg_tmbk_coders( VALUE self )
212
+ {
213
+ t_tmbk *this = DATA_PTR( self );
214
+
215
+ return rb_obj_freeze(rb_hash_dup(this->klass_to_coder));
216
+ }
217
+
218
+ void
219
+ init_pg_type_map_by_class()
220
+ {
221
+ s_id_ancestors = rb_intern("ancestors");
222
+
223
+ /*
224
+ * Document-class: PG::TypeMapByClass < PG::TypeMap
225
+ *
226
+ * This type map casts values based on the class or the ancestors of the given value
227
+ * to be sent.
228
+ *
229
+ * This type map is usable for type casting query bind parameters and COPY data
230
+ * for PG::Connection#put_copy_data . Therefore only encoders might be assigned by
231
+ * the #[]= method.
232
+ */
233
+ rb_cTypeMapByClass = rb_define_class_under( rb_mPG, "TypeMapByClass", rb_cTypeMap );
234
+ rb_define_alloc_func( rb_cTypeMapByClass, pg_tmbk_s_allocate );
235
+ rb_define_method( rb_cTypeMapByClass, "[]=", pg_tmbk_aset, 2 );
236
+ rb_define_method( rb_cTypeMapByClass, "[]", pg_tmbk_aref, 1 );
237
+ rb_define_method( rb_cTypeMapByClass, "coders", pg_tmbk_coders, 0 );
238
+ rb_include_module( rb_cTypeMapByClass, rb_mDefaultTypeMappable );
239
+ }