pg 1.1.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (77) hide show
  1. checksums.yaml +7 -0
  2. checksums.yaml.gz.sig +3 -0
  3. data.tar.gz.sig +0 -0
  4. data/.gemtest +0 -0
  5. data/BSDL +22 -0
  6. data/ChangeLog +6595 -0
  7. data/Contributors.rdoc +46 -0
  8. data/History.rdoc +492 -0
  9. data/LICENSE +56 -0
  10. data/Manifest.txt +72 -0
  11. data/POSTGRES +23 -0
  12. data/README-OS_X.rdoc +68 -0
  13. data/README-Windows.rdoc +56 -0
  14. data/README.ja.rdoc +14 -0
  15. data/README.rdoc +178 -0
  16. data/Rakefile +215 -0
  17. data/Rakefile.cross +298 -0
  18. data/ext/errorcodes.def +968 -0
  19. data/ext/errorcodes.rb +45 -0
  20. data/ext/errorcodes.txt +478 -0
  21. data/ext/extconf.rb +94 -0
  22. data/ext/gvl_wrappers.c +17 -0
  23. data/ext/gvl_wrappers.h +241 -0
  24. data/ext/pg.c +640 -0
  25. data/ext/pg.h +365 -0
  26. data/ext/pg_binary_decoder.c +229 -0
  27. data/ext/pg_binary_encoder.c +162 -0
  28. data/ext/pg_coder.c +549 -0
  29. data/ext/pg_connection.c +4252 -0
  30. data/ext/pg_copy_coder.c +596 -0
  31. data/ext/pg_errors.c +95 -0
  32. data/ext/pg_result.c +1501 -0
  33. data/ext/pg_text_decoder.c +981 -0
  34. data/ext/pg_text_encoder.c +682 -0
  35. data/ext/pg_tuple.c +541 -0
  36. data/ext/pg_type_map.c +166 -0
  37. data/ext/pg_type_map_all_strings.c +116 -0
  38. data/ext/pg_type_map_by_class.c +239 -0
  39. data/ext/pg_type_map_by_column.c +312 -0
  40. data/ext/pg_type_map_by_mri_type.c +284 -0
  41. data/ext/pg_type_map_by_oid.c +355 -0
  42. data/ext/pg_type_map_in_ruby.c +299 -0
  43. data/ext/util.c +149 -0
  44. data/ext/util.h +65 -0
  45. data/ext/vc/pg.sln +26 -0
  46. data/ext/vc/pg_18/pg.vcproj +216 -0
  47. data/ext/vc/pg_19/pg_19.vcproj +209 -0
  48. data/lib/pg.rb +74 -0
  49. data/lib/pg/basic_type_mapping.rb +459 -0
  50. data/lib/pg/binary_decoder.rb +22 -0
  51. data/lib/pg/coder.rb +83 -0
  52. data/lib/pg/connection.rb +291 -0
  53. data/lib/pg/constants.rb +11 -0
  54. data/lib/pg/exceptions.rb +11 -0
  55. data/lib/pg/result.rb +31 -0
  56. data/lib/pg/text_decoder.rb +47 -0
  57. data/lib/pg/text_encoder.rb +69 -0
  58. data/lib/pg/tuple.rb +30 -0
  59. data/lib/pg/type_map_by_column.rb +15 -0
  60. data/spec/data/expected_trace.out +26 -0
  61. data/spec/data/random_binary_data +0 -0
  62. data/spec/helpers.rb +380 -0
  63. data/spec/pg/basic_type_mapping_spec.rb +508 -0
  64. data/spec/pg/connection_spec.rb +1872 -0
  65. data/spec/pg/connection_sync_spec.rb +41 -0
  66. data/spec/pg/result_spec.rb +491 -0
  67. data/spec/pg/tuple_spec.rb +280 -0
  68. data/spec/pg/type_map_by_class_spec.rb +138 -0
  69. data/spec/pg/type_map_by_column_spec.rb +222 -0
  70. data/spec/pg/type_map_by_mri_type_spec.rb +136 -0
  71. data/spec/pg/type_map_by_oid_spec.rb +149 -0
  72. data/spec/pg/type_map_in_ruby_spec.rb +164 -0
  73. data/spec/pg/type_map_spec.rb +22 -0
  74. data/spec/pg/type_spec.rb +949 -0
  75. data/spec/pg_spec.rb +50 -0
  76. metadata +322 -0
  77. metadata.gz.sig +0 -0
@@ -0,0 +1,312 @@
1
+ /*
2
+ * pg_column_map.c - PG::ColumnMap class extension
3
+ * $Id: pg_type_map_by_column.c,v fcf731d3dff7 2015/09/08 12:25:06 jfali $
4
+ *
5
+ */
6
+
7
+ #include "pg.h"
8
+
9
+ static VALUE rb_cTypeMapByColumn;
10
+ static ID s_id_decode;
11
+ static ID s_id_encode;
12
+
13
+ static VALUE pg_tmbc_s_allocate( VALUE klass );
14
+
15
+ static VALUE
16
+ pg_tmbc_fit_to_result( VALUE self, VALUE result )
17
+ {
18
+ int nfields;
19
+ t_tmbc *this = DATA_PTR( self );
20
+ t_typemap *default_tm;
21
+ VALUE sub_typemap;
22
+
23
+ nfields = PQnfields( pgresult_get(result) );
24
+ if ( this->nfields != nfields ) {
25
+ rb_raise( rb_eArgError, "number of result fields (%d) does not match number of mapped columns (%d)",
26
+ nfields, this->nfields );
27
+ }
28
+
29
+ /* Ensure that the default type map fits equaly. */
30
+ default_tm = DATA_PTR( this->typemap.default_typemap );
31
+ sub_typemap = default_tm->funcs.fit_to_result( this->typemap.default_typemap, result );
32
+
33
+ /* Did the default type return the same object ? */
34
+ if( sub_typemap == this->typemap.default_typemap ){
35
+ return self;
36
+ } else {
37
+ /* Our default type map built a new object, so we need to propagate it
38
+ * and build a copy of this type map and set it as default there.. */
39
+ VALUE new_typemap = pg_tmbc_s_allocate( rb_cTypeMapByColumn );
40
+ size_t struct_size = sizeof(t_tmbc) + sizeof(struct pg_tmbc_converter) * nfields;
41
+ t_tmbc *p_new_typemap = (t_tmbc *)xmalloc(struct_size);
42
+
43
+ memcpy( p_new_typemap, this, struct_size );
44
+ p_new_typemap->typemap.default_typemap = sub_typemap;
45
+ DATA_PTR(new_typemap) = p_new_typemap;
46
+ return new_typemap;
47
+ }
48
+ }
49
+
50
+ static VALUE
51
+ pg_tmbc_fit_to_query( VALUE self, VALUE params )
52
+ {
53
+ int nfields;
54
+ t_tmbc *this = DATA_PTR( self );
55
+ t_typemap *default_tm;
56
+
57
+ nfields = (int)RARRAY_LEN( params );
58
+ if ( this->nfields != nfields ) {
59
+ rb_raise( rb_eArgError, "number of result fields (%d) does not match number of mapped columns (%d)",
60
+ nfields, this->nfields );
61
+ }
62
+
63
+ /* Ensure that the default type map fits equaly. */
64
+ default_tm = DATA_PTR( this->typemap.default_typemap );
65
+ default_tm->funcs.fit_to_query( this->typemap.default_typemap, params );
66
+
67
+ return self;
68
+ }
69
+
70
+ static int
71
+ pg_tmbc_fit_to_copy_get( VALUE self )
72
+ {
73
+ t_tmbc *this = DATA_PTR( self );
74
+
75
+ /* Ensure that the default type map fits equaly. */
76
+ t_typemap *default_tm = DATA_PTR( this->typemap.default_typemap );
77
+ default_tm->funcs.fit_to_copy_get( this->typemap.default_typemap );
78
+
79
+ return this->nfields;
80
+ }
81
+
82
+
83
+ VALUE
84
+ pg_tmbc_result_value( t_typemap *p_typemap, VALUE result, int tuple, int field )
85
+ {
86
+ t_pg_coder *p_coder = NULL;
87
+ t_pg_result *p_result = pgresult_get_this(result);
88
+ t_tmbc *this = (t_tmbc *) p_typemap;
89
+ t_typemap *default_tm;
90
+
91
+ if (PQgetisnull(p_result->pgresult, tuple, field)) {
92
+ return Qnil;
93
+ }
94
+
95
+ p_coder = this->convs[field].cconv;
96
+
97
+ if( p_coder ){
98
+ char * val = PQgetvalue( p_result->pgresult, tuple, field );
99
+ int len = PQgetlength( p_result->pgresult, tuple, field );
100
+
101
+ if( p_coder->dec_func ){
102
+ return p_coder->dec_func(p_coder, val, len, tuple, field, ENCODING_GET(result));
103
+ } else {
104
+ t_pg_coder_dec_func dec_func;
105
+ dec_func = pg_coder_dec_func( p_coder, PQfformat(p_result->pgresult, field) );
106
+ return dec_func(p_coder, val, len, tuple, field, ENCODING_GET(result));
107
+ }
108
+ }
109
+
110
+ default_tm = DATA_PTR( this->typemap.default_typemap );
111
+ return default_tm->funcs.typecast_result_value( default_tm, result, tuple, field );
112
+ }
113
+
114
+ static t_pg_coder *
115
+ pg_tmbc_typecast_query_param( t_typemap *p_typemap, VALUE param_value, int field )
116
+ {
117
+ t_tmbc *this = (t_tmbc *) p_typemap;
118
+
119
+ /* Number of fields were already checked in pg_tmbc_fit_to_query() */
120
+ t_pg_coder *p_coder = this->convs[field].cconv;
121
+
122
+ if( !p_coder ){
123
+ t_typemap *default_tm = DATA_PTR( this->typemap.default_typemap );
124
+ return default_tm->funcs.typecast_query_param( default_tm, param_value, field );
125
+ }
126
+
127
+ return p_coder;
128
+ }
129
+
130
+ static VALUE
131
+ pg_tmbc_typecast_copy_get( t_typemap *p_typemap, VALUE field_str, int fieldno, int format, int enc_idx )
132
+ {
133
+ t_tmbc *this = (t_tmbc *) p_typemap;
134
+ t_pg_coder *p_coder;
135
+ t_pg_coder_dec_func dec_func;
136
+
137
+ if ( fieldno >= this->nfields || fieldno < 0 ) {
138
+ rb_raise( rb_eArgError, "number of copy fields (%d) exceeds number of mapped columns (%d)",
139
+ fieldno, this->nfields );
140
+ }
141
+
142
+ p_coder = this->convs[fieldno].cconv;
143
+
144
+ if( !p_coder ){
145
+ t_typemap *default_tm = DATA_PTR( this->typemap.default_typemap );
146
+ return default_tm->funcs.typecast_copy_get( default_tm, field_str, fieldno, format, enc_idx );
147
+ }
148
+
149
+ dec_func = pg_coder_dec_func( p_coder, format );
150
+
151
+ /* Is it a pure String conversion? Then we can directly send field_str to the user. */
152
+ if( dec_func == pg_text_dec_string ){
153
+ PG_ENCODING_SET_NOCHECK( field_str, enc_idx );
154
+ return field_str;
155
+ }
156
+ if( dec_func == pg_bin_dec_bytea ){
157
+ PG_ENCODING_SET_NOCHECK( field_str, rb_ascii8bit_encindex() );
158
+ return field_str;
159
+ }
160
+
161
+ return dec_func( p_coder, RSTRING_PTR(field_str), RSTRING_LEN(field_str), 0, fieldno, enc_idx );
162
+ }
163
+
164
+ const struct pg_typemap_funcs pg_tmbc_funcs = {
165
+ pg_tmbc_fit_to_result,
166
+ pg_tmbc_fit_to_query,
167
+ pg_tmbc_fit_to_copy_get,
168
+ pg_tmbc_result_value,
169
+ pg_tmbc_typecast_query_param,
170
+ pg_tmbc_typecast_copy_get
171
+ };
172
+
173
+ static void
174
+ pg_tmbc_mark( t_tmbc *this )
175
+ {
176
+ int i;
177
+
178
+ /* allocated but not initialized ? */
179
+ if( this == (t_tmbc *)&pg_typemap_funcs ) return;
180
+
181
+ rb_gc_mark(this->typemap.default_typemap);
182
+ for( i=0; i<this->nfields; i++){
183
+ t_pg_coder *p_coder = this->convs[i].cconv;
184
+ if( p_coder )
185
+ rb_gc_mark(p_coder->coder_obj);
186
+ }
187
+ }
188
+
189
+ static void
190
+ pg_tmbc_free( t_tmbc *this )
191
+ {
192
+ /* allocated but not initialized ? */
193
+ if( this == (t_tmbc *)&pg_typemap_funcs ) return;
194
+ xfree( this );
195
+ }
196
+
197
+ static VALUE
198
+ pg_tmbc_s_allocate( VALUE klass )
199
+ {
200
+ /* Use pg_typemap_funcs as interim struct until #initialize is called. */
201
+ return Data_Wrap_Struct( klass, pg_tmbc_mark, pg_tmbc_free, (t_tmbc *)&pg_typemap_funcs );
202
+ }
203
+
204
+ VALUE
205
+ pg_tmbc_allocate()
206
+ {
207
+ return pg_tmbc_s_allocate(rb_cTypeMapByColumn);
208
+ }
209
+
210
+ /*
211
+ * call-seq:
212
+ * PG::TypeMapByColumn.new( coders )
213
+ *
214
+ * Builds a new type map and assigns a list of coders for the given column.
215
+ * +coders+ must be an Array of PG::Coder objects or +nil+ values.
216
+ * The length of the Array corresponds to
217
+ * the number of columns or bind parameters this type map is usable for.
218
+ *
219
+ * A +nil+ value will forward the given field to the #default_type_map .
220
+ */
221
+ static VALUE
222
+ pg_tmbc_init(VALUE self, VALUE conv_ary)
223
+ {
224
+ int i;
225
+ t_tmbc *this;
226
+ int conv_ary_len;
227
+
228
+ Check_Type(self, T_DATA);
229
+ Check_Type(conv_ary, T_ARRAY);
230
+ conv_ary_len = RARRAY_LEN(conv_ary);
231
+ this = xmalloc(sizeof(t_tmbc) + sizeof(struct pg_tmbc_converter) * conv_ary_len);
232
+ /* Set nfields to 0 at first, so that GC mark function doesn't access uninitialized memory. */
233
+ this->nfields = 0;
234
+ this->typemap.funcs = pg_tmbc_funcs;
235
+ this->typemap.default_typemap = pg_typemap_all_strings;
236
+ DATA_PTR(self) = this;
237
+
238
+ for(i=0; i<conv_ary_len; i++)
239
+ {
240
+ VALUE obj = rb_ary_entry(conv_ary, i);
241
+
242
+ if( obj == Qnil ){
243
+ /* no type cast */
244
+ this->convs[i].cconv = NULL;
245
+ } else if( rb_obj_is_kind_of(obj, rb_cPG_Coder) ){
246
+ Data_Get_Struct(obj, t_pg_coder, this->convs[i].cconv);
247
+ } else {
248
+ rb_raise(rb_eArgError, "argument %d has invalid type %s (should be nil or some kind of PG::Coder)",
249
+ i+1, rb_obj_classname( obj ));
250
+ }
251
+ }
252
+
253
+ this->nfields = conv_ary_len;
254
+
255
+ return self;
256
+ }
257
+
258
+ /*
259
+ * call-seq:
260
+ * typemap.coders -> Array
261
+ *
262
+ * Array of PG::Coder objects. The length of the Array corresponds to
263
+ * the number of columns or bind parameters this type map is usable for.
264
+ */
265
+ static VALUE
266
+ pg_tmbc_coders(VALUE self)
267
+ {
268
+ int i;
269
+ t_tmbc *this = DATA_PTR( self );
270
+ VALUE ary_coders = rb_ary_new();
271
+
272
+ for( i=0; i<this->nfields; i++){
273
+ t_pg_coder *conv = this->convs[i].cconv;
274
+ if( conv ) {
275
+ rb_ary_push( ary_coders, conv->coder_obj );
276
+ } else {
277
+ rb_ary_push( ary_coders, Qnil );
278
+ }
279
+ }
280
+
281
+ return rb_obj_freeze(ary_coders);
282
+ }
283
+
284
+ void
285
+ init_pg_type_map_by_column()
286
+ {
287
+ s_id_decode = rb_intern("decode");
288
+ s_id_encode = rb_intern("encode");
289
+
290
+ /*
291
+ * Document-class: PG::TypeMapByColumn < PG::TypeMap
292
+ *
293
+ * This type map casts values by a coder assigned per field/column.
294
+ *
295
+ * Each PG:TypeMapByColumn has a fixed list of either encoders or decoders,
296
+ * that is defined at #new . A type map with encoders is usable for type casting
297
+ * query bind parameters and COPY data for PG::Connection#put_copy_data .
298
+ * A type map with decoders is usable for type casting of result values and
299
+ * COPY data from PG::Connection#get_copy_data .
300
+ *
301
+ * PG::TypeMapByColumns are in particular useful in conjunction with prepared statements,
302
+ * since they can be cached alongside with the statement handle.
303
+ *
304
+ * This type map strategy is also used internally by PG::TypeMapByOid, when the
305
+ * number of rows of a result set exceeds a given limit.
306
+ */
307
+ rb_cTypeMapByColumn = rb_define_class_under( rb_mPG, "TypeMapByColumn", rb_cTypeMap );
308
+ rb_define_alloc_func( rb_cTypeMapByColumn, pg_tmbc_s_allocate );
309
+ rb_define_method( rb_cTypeMapByColumn, "initialize", pg_tmbc_init, 1 );
310
+ rb_define_method( rb_cTypeMapByColumn, "coders", pg_tmbc_coders, 0 );
311
+ rb_include_module( rb_cTypeMapByColumn, rb_mDefaultTypeMappable );
312
+ }
@@ -0,0 +1,284 @@
1
+ /*
2
+ * pg_type_map_by_mri_type.c - PG::TypeMapByMriType class extension
3
+ * $Id: pg_type_map_by_mri_type.c,v 1269b8ad77b8 2015/02/06 16:38:23 lars $
4
+ *
5
+ * This type map can be used to select value encoders based on the MRI-internal
6
+ * value type code.
7
+ *
8
+ */
9
+
10
+ #include "pg.h"
11
+
12
+ static VALUE rb_cTypeMapByMriType;
13
+
14
+ #define FOR_EACH_MRI_TYPE(func) \
15
+ func(T_FIXNUM) \
16
+ func(T_TRUE) \
17
+ func(T_FALSE) \
18
+ func(T_FLOAT) \
19
+ func(T_BIGNUM) \
20
+ func(T_COMPLEX) \
21
+ func(T_RATIONAL) \
22
+ func(T_ARRAY) \
23
+ func(T_STRING) \
24
+ func(T_SYMBOL) \
25
+ func(T_OBJECT) \
26
+ func(T_CLASS) \
27
+ func(T_MODULE) \
28
+ func(T_REGEXP) \
29
+ func(T_HASH) \
30
+ func(T_STRUCT) \
31
+ func(T_FILE) \
32
+ func(T_DATA)
33
+
34
+ #define DECLARE_CODER(type) \
35
+ t_pg_coder *coder_##type; \
36
+ VALUE ask_##type; \
37
+ VALUE coder_obj_##type;
38
+
39
+ typedef struct {
40
+ t_typemap typemap;
41
+ struct pg_tmbmt_converter {
42
+ FOR_EACH_MRI_TYPE( DECLARE_CODER )
43
+ } coders;
44
+ } t_tmbmt;
45
+
46
+
47
+ #define CASE_AND_GET(type) \
48
+ case type: \
49
+ p_coder = this->coders.coder_##type; \
50
+ ask_for_coder = this->coders.ask_##type; \
51
+ break;
52
+
53
+ static t_pg_coder *
54
+ pg_tmbmt_typecast_query_param( t_typemap *p_typemap, VALUE param_value, int field )
55
+ {
56
+ t_tmbmt *this = (t_tmbmt *)p_typemap;
57
+ t_pg_coder *p_coder;
58
+ VALUE ask_for_coder;
59
+
60
+ switch(TYPE(param_value)){
61
+ FOR_EACH_MRI_TYPE( CASE_AND_GET )
62
+ default:
63
+ /* unknown MRI type */
64
+ p_coder = NULL;
65
+ ask_for_coder = Qnil;
66
+ }
67
+
68
+ if( !NIL_P(ask_for_coder) ){
69
+ /* No static Coder object, but proc/method given to ask for the Coder to use. */
70
+ VALUE obj;
71
+
72
+ obj = rb_funcall(ask_for_coder, rb_intern("call"), 1, param_value);
73
+
74
+ if( rb_obj_is_kind_of(obj, rb_cPG_Coder) ){
75
+ Data_Get_Struct(obj, t_pg_coder, p_coder);
76
+ }else{
77
+ rb_raise(rb_eTypeError, "argument %d has invalid type %s (should be nil or some kind of PG::Coder)",
78
+ field+1, rb_obj_classname( obj ));
79
+ }
80
+ }
81
+
82
+ if( !p_coder ){
83
+ t_typemap *default_tm = DATA_PTR( this->typemap.default_typemap );
84
+ return default_tm->funcs.typecast_query_param( default_tm, param_value, field );
85
+ }
86
+
87
+ return p_coder;
88
+ }
89
+
90
+ static VALUE
91
+ pg_tmbmt_fit_to_query( VALUE self, VALUE params )
92
+ {
93
+ t_tmbmt *this = (t_tmbmt *)DATA_PTR(self);
94
+ /* Nothing to check at this typemap, but ensure that the default type map fits. */
95
+ t_typemap *default_tm = DATA_PTR( this->typemap.default_typemap );
96
+ default_tm->funcs.fit_to_query( this->typemap.default_typemap, params );
97
+ return self;
98
+ }
99
+
100
+ #define GC_MARK_AS_USED(type) \
101
+ rb_gc_mark( this->coders.ask_##type ); \
102
+ rb_gc_mark( this->coders.coder_obj_##type );
103
+
104
+ static void
105
+ pg_tmbmt_mark( t_tmbmt *this )
106
+ {
107
+ rb_gc_mark(this->typemap.default_typemap);
108
+ FOR_EACH_MRI_TYPE( GC_MARK_AS_USED );
109
+ }
110
+
111
+ #define INIT_VARIABLES(type) \
112
+ this->coders.coder_##type = NULL; \
113
+ this->coders.ask_##type = Qnil; \
114
+ this->coders.coder_obj_##type = Qnil;
115
+
116
+ static VALUE
117
+ pg_tmbmt_s_allocate( VALUE klass )
118
+ {
119
+ t_tmbmt *this;
120
+ VALUE self;
121
+
122
+ self = Data_Make_Struct( klass, t_tmbmt, pg_tmbmt_mark, -1, this );
123
+ this->typemap.funcs.fit_to_result = pg_typemap_fit_to_result;
124
+ this->typemap.funcs.fit_to_query = pg_tmbmt_fit_to_query;
125
+ this->typemap.funcs.fit_to_copy_get = pg_typemap_fit_to_copy_get;
126
+ this->typemap.funcs.typecast_result_value = pg_typemap_result_value;
127
+ this->typemap.funcs.typecast_query_param = pg_tmbmt_typecast_query_param;
128
+ this->typemap.funcs.typecast_copy_get = pg_typemap_typecast_copy_get;
129
+ this->typemap.default_typemap = pg_typemap_all_strings;
130
+
131
+ FOR_EACH_MRI_TYPE( INIT_VARIABLES );
132
+
133
+ return self;
134
+ }
135
+
136
+ #define COMPARE_AND_ASSIGN(type) \
137
+ else if(!strcmp(p_mri_type, #type)){ \
138
+ this->coders.coder_obj_##type = coder; \
139
+ if(NIL_P(coder)){ \
140
+ this->coders.coder_##type = NULL; \
141
+ this->coders.ask_##type = Qnil; \
142
+ }else if(rb_obj_is_kind_of(coder, rb_cPG_Coder)){ \
143
+ Data_Get_Struct(coder, t_pg_coder, this->coders.coder_##type); \
144
+ this->coders.ask_##type = Qnil; \
145
+ }else if(RB_TYPE_P(coder, T_SYMBOL)){ \
146
+ this->coders.coder_##type = NULL; \
147
+ this->coders.ask_##type = rb_obj_method( self, coder ); \
148
+ }else{ \
149
+ this->coders.coder_##type = NULL; \
150
+ this->coders.ask_##type = coder; \
151
+ } \
152
+ }
153
+
154
+ /*
155
+ * call-seq:
156
+ * typemap.[mri_type] = coder
157
+ *
158
+ * Assigns a new PG::Coder object to the type map. The encoder
159
+ * is registered for type casts of the given +mri_type+ .
160
+ *
161
+ * +coder+ can be one of the following:
162
+ * * +nil+ - Values are forwarded to the #default_type_map .
163
+ * * a PG::Coder - Values are encoded by the given encoder
164
+ * * a Symbol - The method of this type map (or a derivation) that is called for each value to sent.
165
+ * It must return a PG::Coder.
166
+ * * a Proc - The Proc object is called for each value. It must return a PG::Coder.
167
+ *
168
+ * +mri_type+ must be one of the following strings:
169
+ * * +T_FIXNUM+
170
+ * * +T_TRUE+
171
+ * * +T_FALSE+
172
+ * * +T_FLOAT+
173
+ * * +T_BIGNUM+
174
+ * * +T_COMPLEX+
175
+ * * +T_RATIONAL+
176
+ * * +T_ARRAY+
177
+ * * +T_STRING+
178
+ * * +T_SYMBOL+
179
+ * * +T_OBJECT+
180
+ * * +T_CLASS+
181
+ * * +T_MODULE+
182
+ * * +T_REGEXP+
183
+ * * +T_HASH+
184
+ * * +T_STRUCT+
185
+ * * +T_FILE+
186
+ * * +T_DATA+
187
+ */
188
+ static VALUE
189
+ pg_tmbmt_aset( VALUE self, VALUE mri_type, VALUE coder )
190
+ {
191
+ t_tmbmt *this = DATA_PTR( self );
192
+ char *p_mri_type;
193
+
194
+ p_mri_type = StringValueCStr(mri_type);
195
+
196
+ if(0){}
197
+ FOR_EACH_MRI_TYPE( COMPARE_AND_ASSIGN )
198
+ else{
199
+ VALUE mri_type_inspect = rb_inspect( mri_type );
200
+ rb_raise(rb_eArgError, "unknown mri_type %s", StringValueCStr(mri_type_inspect));
201
+ }
202
+
203
+ return self;
204
+ }
205
+
206
+ #define COMPARE_AND_GET(type) \
207
+ else if(!strcmp(p_mri_type, #type)){ \
208
+ coder = this->coders.coder_obj_##type; \
209
+ }
210
+
211
+ /*
212
+ * call-seq:
213
+ * typemap.[mri_type] -> coder
214
+ *
215
+ * Returns the encoder object for the given +mri_type+
216
+ *
217
+ * See #[]= for allowed +mri_type+ .
218
+ */
219
+ static VALUE
220
+ pg_tmbmt_aref( VALUE self, VALUE mri_type )
221
+ {
222
+ VALUE coder;
223
+ t_tmbmt *this = DATA_PTR( self );
224
+ char *p_mri_type;
225
+
226
+ p_mri_type = StringValueCStr(mri_type);
227
+
228
+ if(0){}
229
+ FOR_EACH_MRI_TYPE( COMPARE_AND_GET )
230
+ else{
231
+ VALUE mri_type_inspect = rb_inspect( mri_type );
232
+ rb_raise(rb_eArgError, "unknown mri_type %s", StringValueCStr(mri_type_inspect));
233
+ }
234
+
235
+ return coder;
236
+ }
237
+
238
+ #define ADD_TO_HASH(type) \
239
+ rb_hash_aset( hash_coders, rb_obj_freeze(rb_str_new2(#type)), this->coders.coder_obj_##type );
240
+
241
+
242
+ /*
243
+ * call-seq:
244
+ * typemap.coders -> Hash
245
+ *
246
+ * Returns all mri types and their assigned encoder object.
247
+ */
248
+ static VALUE
249
+ pg_tmbmt_coders( VALUE self )
250
+ {
251
+ t_tmbmt *this = DATA_PTR( self );
252
+ VALUE hash_coders = rb_hash_new();
253
+
254
+ FOR_EACH_MRI_TYPE( ADD_TO_HASH );
255
+
256
+ return rb_obj_freeze(hash_coders);
257
+ }
258
+
259
+ void
260
+ init_pg_type_map_by_mri_type()
261
+ {
262
+ /*
263
+ * Document-class: PG::TypeMapByMriType < PG::TypeMap
264
+ *
265
+ * This type map casts values based on the Ruby object type code of the given value
266
+ * to be sent.
267
+ *
268
+ * This type map is usable for type casting query bind parameters and COPY data
269
+ * for PG::Connection#put_copy_data . Therefore only encoders might be assigned by
270
+ * the #[]= method.
271
+ *
272
+ * _Note_ : This type map is not portable across Ruby implementations and is less flexible
273
+ * than PG::TypeMapByClass.
274
+ * It is kept only for performance comparisons, but PG::TypeMapByClass proved to be equally
275
+ * fast in almost all cases.
276
+ *
277
+ */
278
+ rb_cTypeMapByMriType = rb_define_class_under( rb_mPG, "TypeMapByMriType", rb_cTypeMap );
279
+ rb_define_alloc_func( rb_cTypeMapByMriType, pg_tmbmt_s_allocate );
280
+ rb_define_method( rb_cTypeMapByMriType, "[]=", pg_tmbmt_aset, 2 );
281
+ rb_define_method( rb_cTypeMapByMriType, "[]", pg_tmbmt_aref, 1 );
282
+ rb_define_method( rb_cTypeMapByMriType, "coders", pg_tmbmt_coders, 0 );
283
+ rb_include_module( rb_cTypeMapByMriType, rb_mDefaultTypeMappable );
284
+ }