pg 1.0.0 → 1.5.9

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 (126) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data/Gemfile +20 -0
  4. data/History.md +932 -0
  5. data/Manifest.txt +8 -3
  6. data/README-Windows.rdoc +4 -4
  7. data/README.ja.md +300 -0
  8. data/README.md +286 -0
  9. data/Rakefile +41 -138
  10. data/Rakefile.cross +71 -66
  11. data/certs/ged.pem +24 -0
  12. data/certs/kanis@comcard.de.pem +20 -0
  13. data/certs/larskanis-2022.pem +26 -0
  14. data/certs/larskanis-2023.pem +24 -0
  15. data/certs/larskanis-2024.pem +24 -0
  16. data/ext/errorcodes.def +84 -5
  17. data/ext/errorcodes.rb +1 -1
  18. data/ext/errorcodes.txt +23 -6
  19. data/ext/extconf.rb +109 -25
  20. data/ext/gvl_wrappers.c +4 -0
  21. data/ext/gvl_wrappers.h +23 -0
  22. data/ext/pg.c +213 -155
  23. data/ext/pg.h +89 -23
  24. data/ext/pg_binary_decoder.c +164 -16
  25. data/ext/pg_binary_encoder.c +238 -13
  26. data/ext/pg_coder.c +159 -35
  27. data/ext/pg_connection.c +1584 -967
  28. data/ext/pg_copy_coder.c +373 -43
  29. data/ext/pg_errors.c +1 -1
  30. data/ext/pg_record_coder.c +522 -0
  31. data/ext/pg_result.c +710 -217
  32. data/ext/pg_text_decoder.c +630 -43
  33. data/ext/pg_text_encoder.c +222 -72
  34. data/ext/pg_tuple.c +572 -0
  35. data/ext/pg_type_map.c +45 -11
  36. data/ext/pg_type_map_all_strings.c +21 -7
  37. data/ext/pg_type_map_by_class.c +59 -27
  38. data/ext/pg_type_map_by_column.c +80 -37
  39. data/ext/pg_type_map_by_mri_type.c +49 -20
  40. data/ext/pg_type_map_by_oid.c +62 -29
  41. data/ext/pg_type_map_in_ruby.c +56 -22
  42. data/ext/{util.c → pg_util.c} +12 -12
  43. data/ext/{util.h → pg_util.h} +2 -2
  44. data/lib/pg/basic_type_map_based_on_result.rb +67 -0
  45. data/lib/pg/basic_type_map_for_queries.rb +202 -0
  46. data/lib/pg/basic_type_map_for_results.rb +104 -0
  47. data/lib/pg/basic_type_registry.rb +311 -0
  48. data/lib/pg/binary_decoder/date.rb +9 -0
  49. data/lib/pg/binary_decoder/timestamp.rb +26 -0
  50. data/lib/pg/binary_encoder/timestamp.rb +20 -0
  51. data/lib/pg/coder.rb +36 -13
  52. data/lib/pg/connection.rb +769 -70
  53. data/lib/pg/exceptions.rb +22 -2
  54. data/lib/pg/result.rb +14 -2
  55. data/lib/pg/text_decoder/date.rb +21 -0
  56. data/lib/pg/text_decoder/inet.rb +9 -0
  57. data/lib/pg/text_decoder/json.rb +17 -0
  58. data/lib/pg/text_decoder/numeric.rb +9 -0
  59. data/lib/pg/text_decoder/timestamp.rb +30 -0
  60. data/lib/pg/text_encoder/date.rb +13 -0
  61. data/lib/pg/text_encoder/inet.rb +31 -0
  62. data/lib/pg/text_encoder/json.rb +17 -0
  63. data/lib/pg/text_encoder/numeric.rb +9 -0
  64. data/lib/pg/text_encoder/timestamp.rb +24 -0
  65. data/lib/pg/tuple.rb +30 -0
  66. data/lib/pg/type_map_by_column.rb +3 -2
  67. data/lib/pg/version.rb +4 -0
  68. data/lib/pg.rb +106 -39
  69. data/misc/openssl-pg-segfault.rb +31 -0
  70. data/misc/postgres/History.txt +9 -0
  71. data/misc/postgres/Manifest.txt +5 -0
  72. data/misc/postgres/README.txt +21 -0
  73. data/misc/postgres/Rakefile +21 -0
  74. data/misc/postgres/lib/postgres.rb +16 -0
  75. data/misc/ruby-pg/History.txt +9 -0
  76. data/misc/ruby-pg/Manifest.txt +5 -0
  77. data/misc/ruby-pg/README.txt +21 -0
  78. data/misc/ruby-pg/Rakefile +21 -0
  79. data/misc/ruby-pg/lib/ruby/pg.rb +16 -0
  80. data/pg.gemspec +36 -0
  81. data/rakelib/task_extension.rb +46 -0
  82. data/sample/array_insert.rb +20 -0
  83. data/sample/async_api.rb +102 -0
  84. data/sample/async_copyto.rb +39 -0
  85. data/sample/async_mixed.rb +56 -0
  86. data/sample/check_conn.rb +21 -0
  87. data/sample/copydata.rb +71 -0
  88. data/sample/copyfrom.rb +81 -0
  89. data/sample/copyto.rb +19 -0
  90. data/sample/cursor.rb +21 -0
  91. data/sample/disk_usage_report.rb +177 -0
  92. data/sample/issue-119.rb +94 -0
  93. data/sample/losample.rb +69 -0
  94. data/sample/minimal-testcase.rb +17 -0
  95. data/sample/notify_wait.rb +72 -0
  96. data/sample/pg_statistics.rb +285 -0
  97. data/sample/replication_monitor.rb +222 -0
  98. data/sample/test_binary_values.rb +33 -0
  99. data/sample/wal_shipper.rb +434 -0
  100. data/sample/warehouse_partitions.rb +311 -0
  101. data.tar.gz.sig +0 -0
  102. metadata +138 -223
  103. metadata.gz.sig +0 -0
  104. data/.gemtest +0 -0
  105. data/ChangeLog +0 -6595
  106. data/History.rdoc +0 -422
  107. data/README.ja.rdoc +0 -14
  108. data/README.rdoc +0 -167
  109. data/lib/pg/basic_type_mapping.rb +0 -426
  110. data/lib/pg/constants.rb +0 -11
  111. data/lib/pg/text_decoder.rb +0 -51
  112. data/lib/pg/text_encoder.rb +0 -35
  113. data/spec/data/expected_trace.out +0 -26
  114. data/spec/data/random_binary_data +0 -0
  115. data/spec/helpers.rb +0 -348
  116. data/spec/pg/basic_type_mapping_spec.rb +0 -305
  117. data/spec/pg/connection_spec.rb +0 -1719
  118. data/spec/pg/result_spec.rb +0 -456
  119. data/spec/pg/type_map_by_class_spec.rb +0 -138
  120. data/spec/pg/type_map_by_column_spec.rb +0 -222
  121. data/spec/pg/type_map_by_mri_type_spec.rb +0 -136
  122. data/spec/pg/type_map_by_oid_spec.rb +0 -149
  123. data/spec/pg/type_map_in_ruby_spec.rb +0 -164
  124. data/spec/pg/type_map_spec.rb +0 -22
  125. data/spec/pg/type_spec.rb +0 -777
  126. data/spec/pg_spec.rb +0 -50
@@ -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 c53f993a4254 2014/12/12 21:57:29 lars $
3
+ * $Id$
4
4
  *
5
5
  * This is the default typemap.
6
6
  *
@@ -8,6 +8,19 @@
8
8
 
9
9
  #include "pg.h"
10
10
 
11
+ static const rb_data_type_t pg_tmas_type = {
12
+ "PG::TypeMapAllStrings",
13
+ {
14
+ pg_typemap_mark,
15
+ RUBY_TYPED_DEFAULT_FREE,
16
+ pg_typemap_memsize,
17
+ pg_compact_callback(pg_typemap_compact),
18
+ },
19
+ &pg_typemap_type,
20
+ 0,
21
+ RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED | PG_RUBY_TYPED_FROZEN_SHAREABLE,
22
+ };
23
+
11
24
  VALUE rb_cTypeMapAllStrings;
12
25
  VALUE pg_typemap_all_strings;
13
26
 
@@ -33,9 +46,9 @@ pg_tmas_result_value( t_typemap *p_typemap, VALUE result, int tuple, int field )
33
46
  len = PQgetlength( p_result->pgresult, tuple, field );
34
47
 
35
48
  if ( 0 == PQfformat(p_result->pgresult, field) ) {
36
- ret = pg_text_dec_string(NULL, val, len, tuple, field, ENCODING_GET(result));
49
+ ret = pg_text_dec_string(NULL, val, len, tuple, field, p_result->enc_idx);
37
50
  } else {
38
- ret = pg_bin_dec_bytea(NULL, val, len, tuple, field, ENCODING_GET(result));
51
+ ret = pg_bin_dec_bytea(NULL, val, len, tuple, field, p_result->enc_idx);
39
52
  }
40
53
 
41
54
  return ret;
@@ -63,6 +76,7 @@ pg_tmas_fit_to_copy_get( VALUE self )
63
76
  static VALUE
64
77
  pg_tmas_typecast_copy_get( t_typemap *p_typemap, VALUE field_str, int fieldno, int format, int enc_idx )
65
78
  {
79
+ rb_str_modify(field_str);
66
80
  if( format == 0 ){
67
81
  PG_ENCODING_SET_NOCHECK( field_str, enc_idx );
68
82
  } else {
@@ -77,7 +91,7 @@ pg_tmas_s_allocate( VALUE klass )
77
91
  t_typemap *this;
78
92
  VALUE self;
79
93
 
80
- self = Data_Make_Struct( klass, t_typemap, NULL, -1, this );
94
+ self = TypedData_Make_Struct( klass, t_typemap, &pg_tmas_type, this );
81
95
 
82
96
  this->funcs.fit_to_result = pg_tmas_fit_to_result;
83
97
  this->funcs.fit_to_query = pg_tmas_fit_to_query;
@@ -91,7 +105,7 @@ pg_tmas_s_allocate( VALUE klass )
91
105
 
92
106
 
93
107
  void
94
- init_pg_type_map_all_strings()
108
+ init_pg_type_map_all_strings(void)
95
109
  {
96
110
  /*
97
111
  * Document-class: PG::TypeMapAllStrings < PG::TypeMap
@@ -99,7 +113,7 @@ init_pg_type_map_all_strings()
99
113
  * This type map casts all values received from the database server to Strings
100
114
  * and sends all values to the server after conversion to String by +#to_s+ .
101
115
  * 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
116
+ * and to PG::TextDecoder::String for text format respectively PG::BinaryDecoder::Bytea
103
117
  * for binary format received from the server.
104
118
  *
105
119
  * It is suitable for type casting query bind parameters, result values and
@@ -111,6 +125,6 @@ init_pg_type_map_all_strings()
111
125
  rb_cTypeMapAllStrings = rb_define_class_under( rb_mPG, "TypeMapAllStrings", rb_cTypeMap );
112
126
  rb_define_alloc_func( rb_cTypeMapAllStrings, pg_tmas_s_allocate );
113
127
 
114
- pg_typemap_all_strings = rb_funcall( rb_cTypeMapAllStrings, rb_intern("new"), 0 );
128
+ pg_typemap_all_strings = rb_obj_freeze( rb_funcall( rb_cTypeMapAllStrings, rb_intern("new"), 0 ));
115
129
  rb_gc_register_address( &pg_typemap_all_strings );
116
130
  }
@@ -1,6 +1,6 @@
1
1
  /*
2
2
  * pg_type_map_by_class.c - PG::TypeMapByClass class extension
3
- * $Id: pg_type_map_by_class.c,v eeb8a82c5328 2014/11/10 19:34:02 lars $
3
+ * $Id$
4
4
  *
5
5
  * This type map can be used to select value encoders based on the class
6
6
  * of the given value to be send.
@@ -10,7 +10,6 @@
10
10
  #include "pg.h"
11
11
 
12
12
  static VALUE rb_cTypeMapByClass;
13
- static ID s_id_ancestors;
14
13
 
15
14
  typedef struct {
16
15
  t_typemap typemap;
@@ -28,7 +27,7 @@ typedef struct {
28
27
  * We use 8 Bits of the klass object id as index to a 256 entry cache.
29
28
  * This avoids full lookups in most cases.
30
29
  */
31
- #define CACHE_LOOKUP(this, klass) ( &this->cache_row[(klass >> 8) & 0xff] )
30
+ #define CACHE_LOOKUP(this, klass) ( &this->cache_row[(((unsigned long)klass) >> 8) & 0xff] )
32
31
 
33
32
 
34
33
  static t_pg_coder *
@@ -48,7 +47,7 @@ pg_tmbk_lookup_klass(t_tmbk *this, VALUE klass, VALUE param_value)
48
47
 
49
48
  if( NIL_P(obj) ){
50
49
  int i;
51
- VALUE ancestors = rb_funcall( klass, s_id_ancestors, 0 );
50
+ VALUE ancestors = rb_mod_ancestors( klass );
52
51
 
53
52
  Check_Type( ancestors, T_ARRAY );
54
53
  /* Don't look at the first element, it's expected to equal klass. */
@@ -63,10 +62,10 @@ pg_tmbk_lookup_klass(t_tmbk *this, VALUE klass, VALUE param_value)
63
62
  if(NIL_P(obj)){
64
63
  p_coder = NULL;
65
64
  }else if(rb_obj_is_kind_of(obj, rb_cPG_Coder)){
66
- Data_Get_Struct(obj, t_pg_coder, p_coder);
65
+ TypedData_Get_Struct(obj, t_pg_coder, &pg_coder_type, p_coder);
67
66
  }else{
68
67
  if( RB_TYPE_P(obj, T_SYMBOL) ){
69
- /* A Proc object (or something that responds to #call). */
68
+ /* A Symbol: Call the method with this name. */
70
69
  obj = rb_funcall(this->self, SYM2ID(obj), 1, param_value);
71
70
  }else{
72
71
  /* A Proc object (or something that responds to #call). */
@@ -75,11 +74,9 @@ pg_tmbk_lookup_klass(t_tmbk *this, VALUE klass, VALUE param_value)
75
74
 
76
75
  if( NIL_P(obj) ){
77
76
  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
77
  }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 ));
78
+ /* Check retrieved coder type */
79
+ TypedData_Get_Struct(obj, t_pg_coder, &pg_coder_type, p_coder);
83
80
  }
84
81
 
85
82
  /* We can not cache coders retrieved by ruby code, because we can not anticipate
@@ -104,7 +101,7 @@ pg_tmbk_typecast_query_param( t_typemap *p_typemap, VALUE param_value, int field
104
101
  p_coder = pg_tmbk_lookup_klass( this, rb_obj_class(param_value), param_value );
105
102
 
106
103
  if( !p_coder ){
107
- t_typemap *default_tm = DATA_PTR( this->typemap.default_typemap );
104
+ t_typemap *default_tm = RTYPEDDATA_DATA( this->typemap.default_typemap );
108
105
  return default_tm->funcs.typecast_query_param( default_tm, param_value, field );
109
106
  }
110
107
 
@@ -114,42 +111,76 @@ pg_tmbk_typecast_query_param( t_typemap *p_typemap, VALUE param_value, int field
114
111
  static VALUE
115
112
  pg_tmbk_fit_to_query( VALUE self, VALUE params )
116
113
  {
117
- t_tmbk *this = (t_tmbk *)DATA_PTR(self);
114
+ t_tmbk *this = (t_tmbk *)RTYPEDDATA_DATA(self);
118
115
  /* 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 );
116
+ t_typemap *default_tm = RTYPEDDATA_DATA( this->typemap.default_typemap );
120
117
  default_tm->funcs.fit_to_query( this->typemap.default_typemap, params );
121
118
  return self;
122
119
  }
123
120
 
124
121
  static void
125
- pg_tmbk_mark( t_tmbk *this )
122
+ pg_tmbk_mark( void *_this )
123
+ {
124
+ t_tmbk *this = (t_tmbk *)_this;
125
+ pg_typemap_mark(&this->typemap);
126
+ rb_gc_mark_movable(this->klass_to_coder);
127
+ rb_gc_mark_movable(this->self);
128
+ }
129
+
130
+ static size_t
131
+ pg_tmbk_memsize( const void *_this )
126
132
  {
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. */
133
+ const t_tmbk *this = (const t_tmbk *)_this;
134
+ return sizeof(*this);
130
135
  }
131
136
 
137
+ static void
138
+ pg_tmbk_compact(void *ptr)
139
+ {
140
+ t_tmbk *this = (t_tmbk *)ptr;
141
+
142
+ pg_typemap_compact(&this->typemap);
143
+ pg_gc_location(this->klass_to_coder);
144
+ pg_gc_location(this->self);
145
+
146
+ /* Clear the cache, to be safe from changes of klass VALUE by GC.compact. */
147
+ memset(&this->cache_row, 0, sizeof(this->cache_row));
148
+ }
149
+
150
+ static const rb_data_type_t pg_tmbk_type = {
151
+ "PG::TypeMapByClass",
152
+ {
153
+ pg_tmbk_mark,
154
+ RUBY_TYPED_DEFAULT_FREE,
155
+ pg_tmbk_memsize,
156
+ pg_compact_callback(pg_tmbk_compact),
157
+ },
158
+ &pg_typemap_type,
159
+ 0,
160
+ RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED | PG_RUBY_TYPED_FROZEN_SHAREABLE,
161
+ };
162
+
132
163
  static VALUE
133
164
  pg_tmbk_s_allocate( VALUE klass )
134
165
  {
135
166
  t_tmbk *this;
136
167
  VALUE self;
137
168
 
138
- self = Data_Make_Struct( klass, t_tmbk, pg_tmbk_mark, -1, this );
169
+ self = TypedData_Make_Struct( klass, t_tmbk, &pg_tmbk_type, this );
139
170
  this->typemap.funcs.fit_to_result = pg_typemap_fit_to_result;
140
171
  this->typemap.funcs.fit_to_query = pg_tmbk_fit_to_query;
141
172
  this->typemap.funcs.fit_to_copy_get = pg_typemap_fit_to_copy_get;
142
173
  this->typemap.funcs.typecast_result_value = pg_typemap_result_value;
143
174
  this->typemap.funcs.typecast_query_param = pg_tmbk_typecast_query_param;
144
175
  this->typemap.funcs.typecast_copy_get = pg_typemap_typecast_copy_get;
145
- this->typemap.default_typemap = pg_typemap_all_strings;
176
+ RB_OBJ_WRITE(self, &this->typemap.default_typemap, pg_typemap_all_strings);
146
177
 
147
178
  /* We need to store self in the this-struct, because pg_tmbk_typecast_query_param(),
148
179
  * is called with the this-pointer only. */
149
180
  this->self = self;
150
- this->klass_to_coder = rb_hash_new();
181
+ RB_OBJ_WRITE(self, &this->klass_to_coder, rb_hash_new());
151
182
 
152
- /* The cache is properly initialized by Data_Make_Struct(). */
183
+ /* The cache is properly initialized by TypedData_Make_Struct(). */
153
184
 
154
185
  return self;
155
186
  }
@@ -172,7 +203,9 @@ pg_tmbk_s_allocate( VALUE klass )
172
203
  static VALUE
173
204
  pg_tmbk_aset( VALUE self, VALUE klass, VALUE coder )
174
205
  {
175
- t_tmbk *this = DATA_PTR( self );
206
+ t_tmbk *this = RTYPEDDATA_DATA( self );
207
+
208
+ rb_check_frozen(self);
176
209
 
177
210
  if(NIL_P(coder)){
178
211
  rb_hash_delete( this->klass_to_coder, klass );
@@ -196,7 +229,7 @@ pg_tmbk_aset( VALUE self, VALUE klass, VALUE coder )
196
229
  static VALUE
197
230
  pg_tmbk_aref( VALUE self, VALUE klass )
198
231
  {
199
- t_tmbk *this = DATA_PTR( self );
232
+ t_tmbk *this = RTYPEDDATA_DATA( self );
200
233
 
201
234
  return rb_hash_lookup(this->klass_to_coder, klass);
202
235
  }
@@ -210,16 +243,14 @@ pg_tmbk_aref( VALUE self, VALUE klass )
210
243
  static VALUE
211
244
  pg_tmbk_coders( VALUE self )
212
245
  {
213
- t_tmbk *this = DATA_PTR( self );
246
+ t_tmbk *this = RTYPEDDATA_DATA( self );
214
247
 
215
248
  return rb_obj_freeze(rb_hash_dup(this->klass_to_coder));
216
249
  }
217
250
 
218
251
  void
219
- init_pg_type_map_by_class()
252
+ init_pg_type_map_by_class(void)
220
253
  {
221
- s_id_ancestors = rb_intern("ancestors");
222
-
223
254
  /*
224
255
  * Document-class: PG::TypeMapByClass < PG::TypeMap
225
256
  *
@@ -235,5 +266,6 @@ init_pg_type_map_by_class()
235
266
  rb_define_method( rb_cTypeMapByClass, "[]=", pg_tmbk_aset, 2 );
236
267
  rb_define_method( rb_cTypeMapByClass, "[]", pg_tmbk_aref, 1 );
237
268
  rb_define_method( rb_cTypeMapByClass, "coders", pg_tmbk_coders, 0 );
269
+ /* rb_mDefaultTypeMappable = rb_define_module_under( rb_cTypeMap, "DefaultTypeMappable"); */
238
270
  rb_include_module( rb_cTypeMapByClass, rb_mDefaultTypeMappable );
239
271
  }
@@ -1,6 +1,6 @@
1
1
  /*
2
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 $
3
+ * $Id$
4
4
  *
5
5
  */
6
6
 
@@ -16,7 +16,7 @@ static VALUE
16
16
  pg_tmbc_fit_to_result( VALUE self, VALUE result )
17
17
  {
18
18
  int nfields;
19
- t_tmbc *this = DATA_PTR( self );
19
+ t_tmbc *this = RTYPEDDATA_DATA( self );
20
20
  t_typemap *default_tm;
21
21
  VALUE sub_typemap;
22
22
 
@@ -26,8 +26,8 @@ pg_tmbc_fit_to_result( VALUE self, VALUE result )
26
26
  nfields, this->nfields );
27
27
  }
28
28
 
29
- /* Ensure that the default type map fits equaly. */
30
- default_tm = DATA_PTR( this->typemap.default_typemap );
29
+ /* Ensure that the default type map fits equally. */
30
+ default_tm = RTYPEDDATA_DATA( this->typemap.default_typemap );
31
31
  sub_typemap = default_tm->funcs.fit_to_result( this->typemap.default_typemap, result );
32
32
 
33
33
  /* Did the default type return the same object ? */
@@ -42,7 +42,7 @@ pg_tmbc_fit_to_result( VALUE self, VALUE result )
42
42
 
43
43
  memcpy( p_new_typemap, this, struct_size );
44
44
  p_new_typemap->typemap.default_typemap = sub_typemap;
45
- DATA_PTR(new_typemap) = p_new_typemap;
45
+ RTYPEDDATA_DATA(new_typemap) = p_new_typemap;
46
46
  return new_typemap;
47
47
  }
48
48
  }
@@ -51,7 +51,7 @@ static VALUE
51
51
  pg_tmbc_fit_to_query( VALUE self, VALUE params )
52
52
  {
53
53
  int nfields;
54
- t_tmbc *this = DATA_PTR( self );
54
+ t_tmbc *this = RTYPEDDATA_DATA( self );
55
55
  t_typemap *default_tm;
56
56
 
57
57
  nfields = (int)RARRAY_LEN( params );
@@ -60,8 +60,8 @@ pg_tmbc_fit_to_query( VALUE self, VALUE params )
60
60
  nfields, this->nfields );
61
61
  }
62
62
 
63
- /* Ensure that the default type map fits equaly. */
64
- default_tm = DATA_PTR( this->typemap.default_typemap );
63
+ /* Ensure that the default type map fits equally. */
64
+ default_tm = RTYPEDDATA_DATA( this->typemap.default_typemap );
65
65
  default_tm->funcs.fit_to_query( this->typemap.default_typemap, params );
66
66
 
67
67
  return self;
@@ -70,10 +70,10 @@ pg_tmbc_fit_to_query( VALUE self, VALUE params )
70
70
  static int
71
71
  pg_tmbc_fit_to_copy_get( VALUE self )
72
72
  {
73
- t_tmbc *this = DATA_PTR( self );
73
+ t_tmbc *this = RTYPEDDATA_DATA( self );
74
74
 
75
- /* Ensure that the default type map fits equaly. */
76
- t_typemap *default_tm = DATA_PTR( this->typemap.default_typemap );
75
+ /* Ensure that the default type map fits equally. */
76
+ t_typemap *default_tm = RTYPEDDATA_DATA( this->typemap.default_typemap );
77
77
  default_tm->funcs.fit_to_copy_get( this->typemap.default_typemap );
78
78
 
79
79
  return this->nfields;
@@ -99,15 +99,15 @@ pg_tmbc_result_value( t_typemap *p_typemap, VALUE result, int tuple, int field )
99
99
  int len = PQgetlength( p_result->pgresult, tuple, field );
100
100
 
101
101
  if( p_coder->dec_func ){
102
- return p_coder->dec_func(p_coder, val, len, tuple, field, ENCODING_GET(result));
102
+ return p_coder->dec_func(p_coder, val, len, tuple, field, p_result->enc_idx);
103
103
  } else {
104
104
  t_pg_coder_dec_func dec_func;
105
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));
106
+ return dec_func(p_coder, val, len, tuple, field, p_result->enc_idx);
107
107
  }
108
108
  }
109
109
 
110
- default_tm = DATA_PTR( this->typemap.default_typemap );
110
+ default_tm = RTYPEDDATA_DATA( this->typemap.default_typemap );
111
111
  return default_tm->funcs.typecast_result_value( default_tm, result, tuple, field );
112
112
  }
113
113
 
@@ -120,7 +120,7 @@ pg_tmbc_typecast_query_param( t_typemap *p_typemap, VALUE param_value, int field
120
120
  t_pg_coder *p_coder = this->convs[field].cconv;
121
121
 
122
122
  if( !p_coder ){
123
- t_typemap *default_tm = DATA_PTR( this->typemap.default_typemap );
123
+ t_typemap *default_tm = RTYPEDDATA_DATA( this->typemap.default_typemap );
124
124
  return default_tm->funcs.typecast_query_param( default_tm, param_value, field );
125
125
  }
126
126
 
@@ -142,7 +142,7 @@ pg_tmbc_typecast_copy_get( t_typemap *p_typemap, VALUE field_str, int fieldno, i
142
142
  p_coder = this->convs[fieldno].cconv;
143
143
 
144
144
  if( !p_coder ){
145
- t_typemap *default_tm = DATA_PTR( this->typemap.default_typemap );
145
+ t_typemap *default_tm = RTYPEDDATA_DATA( this->typemap.default_typemap );
146
146
  return default_tm->funcs.typecast_copy_get( default_tm, field_str, fieldno, format, enc_idx );
147
147
  }
148
148
 
@@ -150,15 +150,17 @@ pg_tmbc_typecast_copy_get( t_typemap *p_typemap, VALUE field_str, int fieldno, i
150
150
 
151
151
  /* Is it a pure String conversion? Then we can directly send field_str to the user. */
152
152
  if( dec_func == pg_text_dec_string ){
153
+ rb_str_modify(field_str);
153
154
  PG_ENCODING_SET_NOCHECK( field_str, enc_idx );
154
155
  return field_str;
155
156
  }
156
157
  if( dec_func == pg_bin_dec_bytea ){
158
+ rb_str_modify(field_str);
157
159
  PG_ENCODING_SET_NOCHECK( field_str, rb_ascii8bit_encindex() );
158
160
  return field_str;
159
161
  }
160
162
 
161
- return dec_func( p_coder, RSTRING_PTR(field_str), RSTRING_LEN(field_str), 0, fieldno, enc_idx );
163
+ return dec_func( p_coder, RSTRING_PTR(field_str), RSTRING_LENINT(field_str), 0, fieldno, enc_idx );
162
164
  }
163
165
 
164
166
  const struct pg_typemap_funcs pg_tmbc_funcs = {
@@ -171,38 +173,77 @@ const struct pg_typemap_funcs pg_tmbc_funcs = {
171
173
  };
172
174
 
173
175
  static void
174
- pg_tmbc_mark( t_tmbc *this )
176
+ pg_tmbc_mark( void *_this )
175
177
  {
178
+ t_tmbc *this = (t_tmbc *)_this;
176
179
  int i;
177
180
 
178
181
  /* allocated but not initialized ? */
179
182
  if( this == (t_tmbc *)&pg_typemap_funcs ) return;
180
183
 
181
- rb_gc_mark(this->typemap.default_typemap);
184
+ pg_typemap_mark(&this->typemap);
182
185
  for( i=0; i<this->nfields; i++){
183
186
  t_pg_coder *p_coder = this->convs[i].cconv;
184
187
  if( p_coder )
185
- rb_gc_mark(p_coder->coder_obj);
188
+ rb_gc_mark_movable(p_coder->coder_obj);
189
+ }
190
+ }
191
+
192
+ static size_t
193
+ pg_tmbc_memsize( const void *_this )
194
+ {
195
+ const t_tmbc *this = (const t_tmbc *)_this;
196
+ return sizeof(t_tmbc) + sizeof(struct pg_tmbc_converter) * this->nfields;
197
+ }
198
+
199
+ static void
200
+ pg_tmbc_compact( void *_this )
201
+ {
202
+ t_tmbc *this = (t_tmbc *)_this;
203
+ int i;
204
+
205
+ /* allocated but not initialized ? */
206
+ if( this == (t_tmbc *)&pg_typemap_funcs ) return;
207
+
208
+ pg_typemap_compact(&this->typemap);
209
+ for( i=0; i<this->nfields; i++){
210
+ t_pg_coder *p_coder = this->convs[i].cconv;
211
+ if( p_coder )
212
+ pg_gc_location(p_coder->coder_obj);
186
213
  }
187
214
  }
188
215
 
189
216
  static void
190
- pg_tmbc_free( t_tmbc *this )
217
+ pg_tmbc_free( void *_this )
191
218
  {
219
+ t_tmbc *this = (t_tmbc *)_this;
192
220
  /* allocated but not initialized ? */
193
221
  if( this == (t_tmbc *)&pg_typemap_funcs ) return;
194
222
  xfree( this );
195
223
  }
196
224
 
225
+ static const rb_data_type_t pg_tmbc_type = {
226
+ "PG::TypeMapByColumn",
227
+ {
228
+ pg_tmbc_mark,
229
+ pg_tmbc_free,
230
+ pg_tmbc_memsize,
231
+ pg_compact_callback(pg_tmbc_compact),
232
+ },
233
+ &pg_typemap_type,
234
+ 0,
235
+ RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED | PG_RUBY_TYPED_FROZEN_SHAREABLE,
236
+ };
237
+
197
238
  static VALUE
198
239
  pg_tmbc_s_allocate( VALUE klass )
199
240
  {
200
241
  /* 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 );
242
+ return TypedData_Wrap_Struct( klass, &pg_tmbc_type, (t_tmbc *)&pg_typemap_funcs );
202
243
  }
203
244
 
204
245
  VALUE
205
- pg_tmbc_allocate()
246
+ pg_tmbc_allocate(void)
206
247
  {
207
248
  return pg_tmbc_s_allocate(rb_cTypeMapByColumn);
208
249
  }
@@ -221,19 +262,19 @@ pg_tmbc_allocate()
221
262
  static VALUE
222
263
  pg_tmbc_init(VALUE self, VALUE conv_ary)
223
264
  {
224
- int i;
265
+ long i;
225
266
  t_tmbc *this;
226
267
  int conv_ary_len;
227
268
 
228
- Check_Type(self, T_DATA);
269
+ rb_check_frozen(self);
229
270
  Check_Type(conv_ary, T_ARRAY);
230
- conv_ary_len = RARRAY_LEN(conv_ary);
271
+ conv_ary_len = RARRAY_LENINT(conv_ary);
231
272
  this = xmalloc(sizeof(t_tmbc) + sizeof(struct pg_tmbc_converter) * conv_ary_len);
232
273
  /* Set nfields to 0 at first, so that GC mark function doesn't access uninitialized memory. */
233
274
  this->nfields = 0;
234
275
  this->typemap.funcs = pg_tmbc_funcs;
235
- this->typemap.default_typemap = pg_typemap_all_strings;
236
- DATA_PTR(self) = this;
276
+ RB_OBJ_WRITE(self, &this->typemap.default_typemap, pg_typemap_all_strings);
277
+ RTYPEDDATA_DATA(self) = this;
237
278
 
238
279
  for(i=0; i<conv_ary_len; i++)
239
280
  {
@@ -242,11 +283,12 @@ pg_tmbc_init(VALUE self, VALUE conv_ary)
242
283
  if( obj == Qnil ){
243
284
  /* no type cast */
244
285
  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
286
  } 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 ));
287
+ t_pg_coder *p_coder;
288
+ /* Check argument type and store the coder pointer */
289
+ TypedData_Get_Struct(obj, t_pg_coder, &pg_coder_type, p_coder);
290
+ RB_OBJ_WRITTEN(self, Qnil, p_coder->coder_obj);
291
+ this->convs[i].cconv = p_coder;
250
292
  }
251
293
  }
252
294
 
@@ -266,7 +308,7 @@ static VALUE
266
308
  pg_tmbc_coders(VALUE self)
267
309
  {
268
310
  int i;
269
- t_tmbc *this = DATA_PTR( self );
311
+ t_tmbc *this = RTYPEDDATA_DATA( self );
270
312
  VALUE ary_coders = rb_ary_new();
271
313
 
272
314
  for( i=0; i<this->nfields; i++){
@@ -282,7 +324,7 @@ pg_tmbc_coders(VALUE self)
282
324
  }
283
325
 
284
326
  void
285
- init_pg_type_map_by_column()
327
+ init_pg_type_map_by_column(void)
286
328
  {
287
329
  s_id_decode = rb_intern("decode");
288
330
  s_id_encode = rb_intern("encode");
@@ -292,13 +334,13 @@ init_pg_type_map_by_column()
292
334
  *
293
335
  * This type map casts values by a coder assigned per field/column.
294
336
  *
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
337
+ * Each PG::TypeMapByColumn has a fixed list of either encoders or decoders,
338
+ * that is defined at TypeMapByColumn.new . A type map with encoders is usable for type casting
297
339
  * query bind parameters and COPY data for PG::Connection#put_copy_data .
298
340
  * A type map with decoders is usable for type casting of result values and
299
341
  * COPY data from PG::Connection#get_copy_data .
300
342
  *
301
- * PG::TypeMapByColumns are in particular useful in conjunction with prepared statements,
343
+ * PG::TypeMapByColumn objects are in particular useful in conjunction with prepared statements,
302
344
  * since they can be cached alongside with the statement handle.
303
345
  *
304
346
  * This type map strategy is also used internally by PG::TypeMapByOid, when the
@@ -308,5 +350,6 @@ init_pg_type_map_by_column()
308
350
  rb_define_alloc_func( rb_cTypeMapByColumn, pg_tmbc_s_allocate );
309
351
  rb_define_method( rb_cTypeMapByColumn, "initialize", pg_tmbc_init, 1 );
310
352
  rb_define_method( rb_cTypeMapByColumn, "coders", pg_tmbc_coders, 0 );
353
+ /* rb_mDefaultTypeMappable = rb_define_module_under( rb_cTypeMap, "DefaultTypeMappable"); */
311
354
  rb_include_module( rb_cTypeMapByColumn, rb_mDefaultTypeMappable );
312
355
  }