pg 0.15.1 → 1.2.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (86) hide show
  1. checksums.yaml +5 -5
  2. checksums.yaml.gz.sig +0 -0
  3. data.tar.gz.sig +0 -0
  4. data/BSDL +2 -2
  5. data/ChangeLog +0 -3022
  6. data/History.rdoc +370 -4
  7. data/Manifest.txt +39 -19
  8. data/README-Windows.rdoc +17 -28
  9. data/README.ja.rdoc +1 -2
  10. data/README.rdoc +113 -14
  11. data/Rakefile +97 -36
  12. data/Rakefile.cross +109 -83
  13. data/ext/errorcodes.def +1032 -0
  14. data/ext/errorcodes.rb +45 -0
  15. data/ext/errorcodes.txt +494 -0
  16. data/ext/extconf.rb +55 -52
  17. data/ext/gvl_wrappers.c +4 -0
  18. data/ext/gvl_wrappers.h +94 -38
  19. data/ext/pg.c +273 -121
  20. data/ext/pg.h +292 -50
  21. data/ext/pg_binary_decoder.c +229 -0
  22. data/ext/pg_binary_encoder.c +163 -0
  23. data/ext/pg_coder.c +561 -0
  24. data/ext/pg_connection.c +1811 -1051
  25. data/ext/pg_copy_coder.c +599 -0
  26. data/ext/pg_errors.c +95 -0
  27. data/ext/pg_record_coder.c +491 -0
  28. data/ext/pg_result.c +917 -203
  29. data/ext/pg_text_decoder.c +987 -0
  30. data/ext/pg_text_encoder.c +814 -0
  31. data/ext/pg_tuple.c +549 -0
  32. data/ext/pg_type_map.c +166 -0
  33. data/ext/pg_type_map_all_strings.c +116 -0
  34. data/ext/pg_type_map_by_class.c +244 -0
  35. data/ext/pg_type_map_by_column.c +313 -0
  36. data/ext/pg_type_map_by_mri_type.c +284 -0
  37. data/ext/pg_type_map_by_oid.c +356 -0
  38. data/ext/pg_type_map_in_ruby.c +299 -0
  39. data/ext/pg_util.c +149 -0
  40. data/ext/pg_util.h +65 -0
  41. data/lib/pg.rb +31 -9
  42. data/lib/pg/basic_type_mapping.rb +522 -0
  43. data/lib/pg/binary_decoder.rb +23 -0
  44. data/lib/pg/coder.rb +104 -0
  45. data/lib/pg/connection.rb +235 -30
  46. data/lib/pg/constants.rb +2 -1
  47. data/lib/pg/exceptions.rb +2 -1
  48. data/lib/pg/result.rb +33 -6
  49. data/lib/pg/text_decoder.rb +46 -0
  50. data/lib/pg/text_encoder.rb +59 -0
  51. data/lib/pg/tuple.rb +30 -0
  52. data/lib/pg/type_map_by_column.rb +16 -0
  53. data/spec/{lib/helpers.rb → helpers.rb} +154 -52
  54. data/spec/pg/basic_type_mapping_spec.rb +630 -0
  55. data/spec/pg/connection_spec.rb +1352 -426
  56. data/spec/pg/connection_sync_spec.rb +41 -0
  57. data/spec/pg/result_spec.rb +508 -105
  58. data/spec/pg/tuple_spec.rb +333 -0
  59. data/spec/pg/type_map_by_class_spec.rb +138 -0
  60. data/spec/pg/type_map_by_column_spec.rb +226 -0
  61. data/spec/pg/type_map_by_mri_type_spec.rb +136 -0
  62. data/spec/pg/type_map_by_oid_spec.rb +149 -0
  63. data/spec/pg/type_map_in_ruby_spec.rb +164 -0
  64. data/spec/pg/type_map_spec.rb +22 -0
  65. data/spec/pg/type_spec.rb +1123 -0
  66. data/spec/pg_spec.rb +35 -16
  67. metadata +163 -84
  68. metadata.gz.sig +0 -0
  69. data/sample/array_insert.rb +0 -20
  70. data/sample/async_api.rb +0 -106
  71. data/sample/async_copyto.rb +0 -39
  72. data/sample/async_mixed.rb +0 -56
  73. data/sample/check_conn.rb +0 -21
  74. data/sample/copyfrom.rb +0 -81
  75. data/sample/copyto.rb +0 -19
  76. data/sample/cursor.rb +0 -21
  77. data/sample/disk_usage_report.rb +0 -186
  78. data/sample/issue-119.rb +0 -94
  79. data/sample/losample.rb +0 -69
  80. data/sample/minimal-testcase.rb +0 -17
  81. data/sample/notify_wait.rb +0 -72
  82. data/sample/pg_statistics.rb +0 -294
  83. data/sample/replication_monitor.rb +0 -231
  84. data/sample/test_binary_values.rb +0 -33
  85. data/sample/wal_shipper.rb +0 -434
  86. data/sample/warehouse_partitions.rb +0 -320
data/ext/pg_type_map.c ADDED
@@ -0,0 +1,166 @@
1
+ /*
2
+ * pg_column_map.c - PG::ColumnMap class extension
3
+ * $Id$
4
+ *
5
+ */
6
+
7
+ #include "pg.h"
8
+
9
+ VALUE rb_cTypeMap;
10
+ VALUE rb_mDefaultTypeMappable;
11
+ static ID s_id_fit_to_query;
12
+ static ID s_id_fit_to_result;
13
+
14
+ NORETURN( VALUE
15
+ pg_typemap_fit_to_result( VALUE self, VALUE result ));
16
+ NORETURN( VALUE
17
+ pg_typemap_fit_to_query( VALUE self, VALUE params ));
18
+ NORETURN( int
19
+ pg_typemap_fit_to_copy_get( VALUE self ));
20
+ NORETURN( VALUE
21
+ pg_typemap_result_value( t_typemap *p_typemap, VALUE result, int tuple, int field ));
22
+ NORETURN( t_pg_coder *
23
+ pg_typemap_typecast_query_param( t_typemap *p_typemap, VALUE param_value, int field ));
24
+ NORETURN( VALUE
25
+ pg_typemap_typecast_copy_get( t_typemap *p_typemap, VALUE field_str, int fieldno, int format, int enc_idx ));
26
+
27
+ VALUE
28
+ pg_typemap_fit_to_result( VALUE self, VALUE result )
29
+ {
30
+ rb_raise( rb_eNotImpError, "type map %s is not suitable to map result values", rb_obj_classname(self) );
31
+ }
32
+
33
+ VALUE
34
+ pg_typemap_fit_to_query( VALUE self, VALUE params )
35
+ {
36
+ rb_raise( rb_eNotImpError, "type map %s is not suitable to map query params", rb_obj_classname(self) );
37
+ }
38
+
39
+ int
40
+ pg_typemap_fit_to_copy_get( VALUE self )
41
+ {
42
+ rb_raise( rb_eNotImpError, "type map %s is not suitable to map get_copy_data results", rb_obj_classname(self) );
43
+ }
44
+
45
+ VALUE
46
+ pg_typemap_result_value( t_typemap *p_typemap, VALUE result, int tuple, int field )
47
+ {
48
+ rb_raise( rb_eNotImpError, "type map is not suitable to map result values" );
49
+ }
50
+
51
+ t_pg_coder *
52
+ pg_typemap_typecast_query_param( t_typemap *p_typemap, VALUE param_value, int field )
53
+ {
54
+ rb_raise( rb_eNotImpError, "type map is not suitable to map query params" );
55
+ }
56
+
57
+ VALUE
58
+ pg_typemap_typecast_copy_get( t_typemap *p_typemap, VALUE field_str, int fieldno, int format, int enc_idx )
59
+ {
60
+ rb_raise( rb_eNotImpError, "type map is not suitable to map get_copy_data results" );
61
+ }
62
+
63
+ const struct pg_typemap_funcs pg_typemap_funcs = {
64
+ pg_typemap_fit_to_result,
65
+ pg_typemap_fit_to_query,
66
+ pg_typemap_fit_to_copy_get,
67
+ pg_typemap_result_value,
68
+ pg_typemap_typecast_query_param,
69
+ pg_typemap_typecast_copy_get
70
+ };
71
+
72
+ static VALUE
73
+ pg_typemap_s_allocate( VALUE klass )
74
+ {
75
+ VALUE self;
76
+ t_typemap *this;
77
+
78
+ self = Data_Make_Struct( klass, t_typemap, NULL, -1, this );
79
+ this->funcs = pg_typemap_funcs;
80
+
81
+ return self;
82
+ }
83
+
84
+ /*
85
+ * call-seq:
86
+ * res.default_type_map = typemap
87
+ *
88
+ * Set the default TypeMap that is used for values that could not be
89
+ * casted by this type map.
90
+ *
91
+ * +typemap+ must be a kind of PG::TypeMap
92
+ *
93
+ */
94
+ static VALUE
95
+ pg_typemap_default_type_map_set(VALUE self, VALUE typemap)
96
+ {
97
+ t_typemap *this = DATA_PTR( self );
98
+
99
+ if ( !rb_obj_is_kind_of(typemap, rb_cTypeMap) ) {
100
+ rb_raise( rb_eTypeError, "wrong argument type %s (expected kind of PG::TypeMap)",
101
+ rb_obj_classname( typemap ) );
102
+ }
103
+ Check_Type(typemap, T_DATA);
104
+ this->default_typemap = typemap;
105
+
106
+ return typemap;
107
+ }
108
+
109
+ /*
110
+ * call-seq:
111
+ * res.default_type_map -> TypeMap
112
+ *
113
+ * Returns the default TypeMap that is currently set for values that could not be
114
+ * casted by this type map.
115
+ *
116
+ * Returns a kind of PG::TypeMap.
117
+ *
118
+ */
119
+ static VALUE
120
+ pg_typemap_default_type_map_get(VALUE self)
121
+ {
122
+ t_typemap *this = DATA_PTR( self );
123
+
124
+ return this->default_typemap;
125
+ }
126
+
127
+ /*
128
+ * call-seq:
129
+ * res.with_default_type_map( typemap )
130
+ *
131
+ * Set the default TypeMap that is used for values that could not be
132
+ * casted by this type map.
133
+ *
134
+ * +typemap+ must be a kind of PG::TypeMap
135
+ *
136
+ * Returns self.
137
+ */
138
+ static VALUE
139
+ pg_typemap_with_default_type_map(VALUE self, VALUE typemap)
140
+ {
141
+ pg_typemap_default_type_map_set( self, typemap );
142
+ return self;
143
+ }
144
+
145
+ void
146
+ init_pg_type_map()
147
+ {
148
+ s_id_fit_to_query = rb_intern("fit_to_query");
149
+ s_id_fit_to_result = rb_intern("fit_to_result");
150
+
151
+ /*
152
+ * Document-class: PG::TypeMap < Object
153
+ *
154
+ * This is the base class for type maps.
155
+ * See derived classes for implementations of different type cast strategies
156
+ * ( PG::TypeMapByColumn, PG::TypeMapByOid ).
157
+ *
158
+ */
159
+ rb_cTypeMap = rb_define_class_under( rb_mPG, "TypeMap", rb_cObject );
160
+ rb_define_alloc_func( rb_cTypeMap, pg_typemap_s_allocate );
161
+
162
+ rb_mDefaultTypeMappable = rb_define_module_under( rb_cTypeMap, "DefaultTypeMappable");
163
+ rb_define_method( rb_mDefaultTypeMappable, "default_type_map=", pg_typemap_default_type_map_set, 1 );
164
+ rb_define_method( rb_mDefaultTypeMappable, "default_type_map", pg_typemap_default_type_map_get, 0 );
165
+ rb_define_method( rb_mDefaultTypeMappable, "with_default_type_map", pg_typemap_with_default_type_map, 1 );
166
+ }
@@ -0,0 +1,116 @@
1
+ /*
2
+ * pg_type_map_all_strings.c - PG::TypeMapAllStrings class extension
3
+ * $Id$
4
+ *
5
+ * This is the default typemap.
6
+ *
7
+ */
8
+
9
+ #include "pg.h"
10
+
11
+ VALUE rb_cTypeMapAllStrings;
12
+ VALUE pg_typemap_all_strings;
13
+
14
+ static VALUE
15
+ pg_tmas_fit_to_result( VALUE self, VALUE result )
16
+ {
17
+ return self;
18
+ }
19
+
20
+ static VALUE
21
+ pg_tmas_result_value( t_typemap *p_typemap, VALUE result, int tuple, int field )
22
+ {
23
+ VALUE ret;
24
+ char * val;
25
+ int len;
26
+ t_pg_result *p_result = pgresult_get_this(result);
27
+
28
+ if (PQgetisnull(p_result->pgresult, tuple, field)) {
29
+ return Qnil;
30
+ }
31
+
32
+ val = PQgetvalue( p_result->pgresult, tuple, field );
33
+ len = PQgetlength( p_result->pgresult, tuple, field );
34
+
35
+ if ( 0 == PQfformat(p_result->pgresult, field) ) {
36
+ ret = pg_text_dec_string(NULL, val, len, tuple, field, p_result->enc_idx);
37
+ } else {
38
+ ret = pg_bin_dec_bytea(NULL, val, len, tuple, field, p_result->enc_idx);
39
+ }
40
+
41
+ return ret;
42
+ }
43
+
44
+ static VALUE
45
+ pg_tmas_fit_to_query( VALUE self, VALUE params )
46
+ {
47
+ return self;
48
+ }
49
+
50
+ static t_pg_coder *
51
+ pg_tmas_typecast_query_param( t_typemap *p_typemap, VALUE param_value, int field )
52
+ {
53
+ return NULL;
54
+ }
55
+
56
+ static int
57
+ pg_tmas_fit_to_copy_get( VALUE self )
58
+ {
59
+ /* We can not predict the number of columns for copy */
60
+ return 0;
61
+ }
62
+
63
+ static VALUE
64
+ pg_tmas_typecast_copy_get( t_typemap *p_typemap, VALUE field_str, int fieldno, int format, int enc_idx )
65
+ {
66
+ if( format == 0 ){
67
+ PG_ENCODING_SET_NOCHECK( field_str, enc_idx );
68
+ } else {
69
+ PG_ENCODING_SET_NOCHECK( field_str, rb_ascii8bit_encindex() );
70
+ }
71
+ return field_str;
72
+ }
73
+
74
+ static VALUE
75
+ pg_tmas_s_allocate( VALUE klass )
76
+ {
77
+ t_typemap *this;
78
+ VALUE self;
79
+
80
+ self = Data_Make_Struct( klass, t_typemap, NULL, -1, this );
81
+
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
+
89
+ return self;
90
+ }
91
+
92
+
93
+ void
94
+ init_pg_type_map_all_strings()
95
+ {
96
+ /*
97
+ * Document-class: PG::TypeMapAllStrings < PG::TypeMap
98
+ *
99
+ * This type map casts all values received from the database server to Strings
100
+ * and sends all values to the server after conversion to String by +#to_s+ .
101
+ * That means, it is hard coded to PG::TextEncoder::String for value encoding
102
+ * and to PG::TextDecoder::String for text format respectively PG::BinaryDecoder::Bytea
103
+ * for binary format received from the server.
104
+ *
105
+ * It is suitable for type casting query bind parameters, result values and
106
+ * COPY IN/OUT data.
107
+ *
108
+ * This is the default type map for each PG::Connection .
109
+ *
110
+ */
111
+ rb_cTypeMapAllStrings = rb_define_class_under( rb_mPG, "TypeMapAllStrings", rb_cTypeMap );
112
+ rb_define_alloc_func( rb_cTypeMapAllStrings, pg_tmas_s_allocate );
113
+
114
+ pg_typemap_all_strings = rb_funcall( rb_cTypeMapAllStrings, rb_intern("new"), 0 );
115
+ rb_gc_register_address( &pg_typemap_all_strings );
116
+ }
@@ -0,0 +1,244 @@
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[(((unsigned long)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 Symbol: Call the method with this name. */
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
+ rb_gc_mark(this->self);
130
+ /* Clear the cache, to be safe from changes of klass VALUE by GC.compact.
131
+ * TODO: Move cache clearing to compactation callback provided by Ruby-2.7+.
132
+ */
133
+ memset(&this->cache_row, 0, sizeof(this->cache_row));
134
+ }
135
+
136
+ static VALUE
137
+ pg_tmbk_s_allocate( VALUE klass )
138
+ {
139
+ t_tmbk *this;
140
+ VALUE self;
141
+
142
+ self = Data_Make_Struct( klass, t_tmbk, pg_tmbk_mark, -1, this );
143
+ this->typemap.funcs.fit_to_result = pg_typemap_fit_to_result;
144
+ this->typemap.funcs.fit_to_query = pg_tmbk_fit_to_query;
145
+ this->typemap.funcs.fit_to_copy_get = pg_typemap_fit_to_copy_get;
146
+ this->typemap.funcs.typecast_result_value = pg_typemap_result_value;
147
+ this->typemap.funcs.typecast_query_param = pg_tmbk_typecast_query_param;
148
+ this->typemap.funcs.typecast_copy_get = pg_typemap_typecast_copy_get;
149
+ this->typemap.default_typemap = pg_typemap_all_strings;
150
+
151
+ /* We need to store self in the this-struct, because pg_tmbk_typecast_query_param(),
152
+ * is called with the this-pointer only. */
153
+ this->self = self;
154
+ this->klass_to_coder = rb_hash_new();
155
+
156
+ /* The cache is properly initialized by Data_Make_Struct(). */
157
+
158
+ return self;
159
+ }
160
+
161
+ /*
162
+ * call-seq:
163
+ * typemap.[class] = coder
164
+ *
165
+ * Assigns a new PG::Coder object to the type map. The encoder
166
+ * is chosen for all values that are a kind of the given +class+ .
167
+ *
168
+ * +coder+ can be one of the following:
169
+ * * +nil+ - Values are forwarded to the #default_type_map .
170
+ * * a PG::Coder - Values are encoded by the given encoder
171
+ * * a Symbol - The method of this type map (or a derivation) that is called for each value to sent.
172
+ * It must return a PG::Coder or +nil+ .
173
+ * * a Proc - The Proc object is called for each value. It must return a PG::Coder or +nil+ .
174
+ *
175
+ */
176
+ static VALUE
177
+ pg_tmbk_aset( VALUE self, VALUE klass, VALUE coder )
178
+ {
179
+ t_tmbk *this = DATA_PTR( self );
180
+
181
+ if(NIL_P(coder)){
182
+ rb_hash_delete( this->klass_to_coder, klass );
183
+ }else{
184
+ rb_hash_aset( this->klass_to_coder, klass, coder );
185
+ }
186
+
187
+ /* The cache lookup key can be a derivation of the klass.
188
+ * So we can not expire the cache selectively. */
189
+ memset( &this->cache_row, 0, sizeof(this->cache_row) );
190
+
191
+ return coder;
192
+ }
193
+
194
+ /*
195
+ * call-seq:
196
+ * typemap.[class] -> coder
197
+ *
198
+ * Returns the encoder object for the given +class+
199
+ */
200
+ static VALUE
201
+ pg_tmbk_aref( VALUE self, VALUE klass )
202
+ {
203
+ t_tmbk *this = DATA_PTR( self );
204
+
205
+ return rb_hash_lookup(this->klass_to_coder, klass);
206
+ }
207
+
208
+ /*
209
+ * call-seq:
210
+ * typemap.coders -> Hash
211
+ *
212
+ * Returns all classes and their assigned encoder object.
213
+ */
214
+ static VALUE
215
+ pg_tmbk_coders( VALUE self )
216
+ {
217
+ t_tmbk *this = DATA_PTR( self );
218
+
219
+ return rb_obj_freeze(rb_hash_dup(this->klass_to_coder));
220
+ }
221
+
222
+ void
223
+ init_pg_type_map_by_class()
224
+ {
225
+ s_id_ancestors = rb_intern("ancestors");
226
+
227
+ /*
228
+ * Document-class: PG::TypeMapByClass < PG::TypeMap
229
+ *
230
+ * This type map casts values based on the class or the ancestors of the given value
231
+ * to be sent.
232
+ *
233
+ * This type map is usable for type casting query bind parameters and COPY data
234
+ * for PG::Connection#put_copy_data . Therefore only encoders might be assigned by
235
+ * the #[]= method.
236
+ */
237
+ rb_cTypeMapByClass = rb_define_class_under( rb_mPG, "TypeMapByClass", rb_cTypeMap );
238
+ rb_define_alloc_func( rb_cTypeMapByClass, pg_tmbk_s_allocate );
239
+ rb_define_method( rb_cTypeMapByClass, "[]=", pg_tmbk_aset, 2 );
240
+ rb_define_method( rb_cTypeMapByClass, "[]", pg_tmbk_aref, 1 );
241
+ rb_define_method( rb_cTypeMapByClass, "coders", pg_tmbk_coders, 0 );
242
+ /* rb_mDefaultTypeMappable = rb_define_module_under( rb_cTypeMap, "DefaultTypeMappable"); */
243
+ rb_include_module( rb_cTypeMapByClass, rb_mDefaultTypeMappable );
244
+ }