pg 1.2.3 → 1.4.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (107) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data/.appveyor.yml +36 -0
  4. data/.gems +6 -0
  5. data/.github/workflows/binary-gems.yml +86 -0
  6. data/.github/workflows/source-gem.yml +129 -0
  7. data/.gitignore +13 -0
  8. data/.hgsigs +34 -0
  9. data/.hgtags +41 -0
  10. data/.irbrc +23 -0
  11. data/.pryrc +23 -0
  12. data/.tm_properties +21 -0
  13. data/.travis.yml +49 -0
  14. data/Gemfile +14 -0
  15. data/History.rdoc +199 -7
  16. data/Manifest.txt +0 -1
  17. data/README.rdoc +7 -6
  18. data/Rakefile +27 -138
  19. data/Rakefile.cross +8 -5
  20. data/certs/ged.pem +24 -0
  21. data/certs/larskanis-2022.pem +26 -0
  22. data/ext/errorcodes.def +8 -0
  23. data/ext/errorcodes.rb +0 -0
  24. data/ext/errorcodes.txt +3 -1
  25. data/ext/extconf.rb +100 -25
  26. data/ext/gvl_wrappers.c +4 -0
  27. data/ext/gvl_wrappers.h +23 -0
  28. data/ext/pg.c +59 -28
  29. data/ext/pg.h +19 -1
  30. data/ext/pg_coder.c +82 -28
  31. data/ext/pg_connection.c +855 -654
  32. data/ext/pg_copy_coder.c +45 -16
  33. data/ext/pg_record_coder.c +45 -15
  34. data/ext/pg_result.c +79 -42
  35. data/ext/pg_text_decoder.c +1 -1
  36. data/ext/pg_text_encoder.c +6 -6
  37. data/ext/pg_tuple.c +49 -29
  38. data/ext/pg_type_map.c +41 -8
  39. data/ext/pg_type_map_all_strings.c +15 -1
  40. data/ext/pg_type_map_by_class.c +49 -24
  41. data/ext/pg_type_map_by_column.c +66 -28
  42. data/ext/pg_type_map_by_mri_type.c +47 -18
  43. data/ext/pg_type_map_by_oid.c +52 -23
  44. data/ext/pg_type_map_in_ruby.c +50 -19
  45. data/ext/pg_util.c +2 -2
  46. data/lib/pg/basic_type_map_based_on_result.rb +47 -0
  47. data/lib/pg/basic_type_map_for_queries.rb +193 -0
  48. data/lib/pg/basic_type_map_for_results.rb +81 -0
  49. data/lib/pg/basic_type_registry.rb +301 -0
  50. data/lib/pg/coder.rb +1 -1
  51. data/lib/pg/connection.rb +668 -70
  52. data/lib/pg/exceptions.rb +7 -1
  53. data/lib/pg/version.rb +4 -0
  54. data/lib/pg.rb +47 -32
  55. data/misc/openssl-pg-segfault.rb +31 -0
  56. data/misc/postgres/History.txt +9 -0
  57. data/misc/postgres/Manifest.txt +5 -0
  58. data/misc/postgres/README.txt +21 -0
  59. data/misc/postgres/Rakefile +21 -0
  60. data/misc/postgres/lib/postgres.rb +16 -0
  61. data/misc/ruby-pg/History.txt +9 -0
  62. data/misc/ruby-pg/Manifest.txt +5 -0
  63. data/misc/ruby-pg/README.txt +21 -0
  64. data/misc/ruby-pg/Rakefile +21 -0
  65. data/misc/ruby-pg/lib/ruby/pg.rb +16 -0
  66. data/pg.gemspec +32 -0
  67. data/rakelib/task_extension.rb +46 -0
  68. data/sample/array_insert.rb +20 -0
  69. data/sample/async_api.rb +102 -0
  70. data/sample/async_copyto.rb +39 -0
  71. data/sample/async_mixed.rb +56 -0
  72. data/sample/check_conn.rb +21 -0
  73. data/sample/copydata.rb +71 -0
  74. data/sample/copyfrom.rb +81 -0
  75. data/sample/copyto.rb +19 -0
  76. data/sample/cursor.rb +21 -0
  77. data/sample/disk_usage_report.rb +177 -0
  78. data/sample/issue-119.rb +94 -0
  79. data/sample/losample.rb +69 -0
  80. data/sample/minimal-testcase.rb +17 -0
  81. data/sample/notify_wait.rb +72 -0
  82. data/sample/pg_statistics.rb +285 -0
  83. data/sample/replication_monitor.rb +222 -0
  84. data/sample/test_binary_values.rb +33 -0
  85. data/sample/wal_shipper.rb +434 -0
  86. data/sample/warehouse_partitions.rb +311 -0
  87. data.tar.gz.sig +0 -0
  88. metadata +87 -224
  89. metadata.gz.sig +0 -0
  90. data/ChangeLog +0 -0
  91. data/lib/pg/basic_type_mapping.rb +0 -522
  92. data/spec/data/expected_trace.out +0 -26
  93. data/spec/data/random_binary_data +0 -0
  94. data/spec/helpers.rb +0 -380
  95. data/spec/pg/basic_type_mapping_spec.rb +0 -630
  96. data/spec/pg/connection_spec.rb +0 -1949
  97. data/spec/pg/connection_sync_spec.rb +0 -41
  98. data/spec/pg/result_spec.rb +0 -681
  99. data/spec/pg/tuple_spec.rb +0 -333
  100. data/spec/pg/type_map_by_class_spec.rb +0 -138
  101. data/spec/pg/type_map_by_column_spec.rb +0 -226
  102. data/spec/pg/type_map_by_mri_type_spec.rb +0 -136
  103. data/spec/pg/type_map_by_oid_spec.rb +0 -149
  104. data/spec/pg/type_map_in_ruby_spec.rb +0 -164
  105. data/spec/pg/type_map_spec.rb +0 -22
  106. data/spec/pg/type_spec.rb +0 -1123
  107. data/spec/pg_spec.rb +0 -50
data/ext/pg_tuple.c CHANGED
@@ -52,57 +52,83 @@ typedef struct {
52
52
  VALUE values[0];
53
53
  } t_pg_tuple;
54
54
 
55
- static inline VALUE
56
- pg_tuple_get_field_names( t_pg_tuple *this )
55
+ static inline VALUE *
56
+ pg_tuple_get_field_names_ptr( t_pg_tuple *this )
57
57
  {
58
58
  if( this->num_fields != (int)RHASH_SIZE(this->field_map) ){
59
- return this->values[this->num_fields];
59
+ return &this->values[this->num_fields];
60
60
  } else {
61
- return Qfalse;
61
+ static VALUE f = Qfalse;
62
+ return &f;
63
+ }
64
+ }
65
+
66
+ static inline VALUE
67
+ pg_tuple_get_field_names( t_pg_tuple *this )
68
+ {
69
+ return *pg_tuple_get_field_names_ptr(this);
70
+ }
71
+
72
+ static void
73
+ pg_tuple_gc_mark( void *_this )
74
+ {
75
+ t_pg_tuple *this = (t_pg_tuple *)_this;
76
+ int i;
77
+
78
+ if( !this ) return;
79
+ rb_gc_mark_movable( this->result );
80
+ rb_gc_mark_movable( this->typemap );
81
+ rb_gc_mark_movable( this->field_map );
82
+
83
+ for( i = 0; i < this->num_fields; i++ ){
84
+ rb_gc_mark_movable( this->values[i] );
62
85
  }
86
+ rb_gc_mark_movable( pg_tuple_get_field_names(this) );
63
87
  }
64
88
 
65
89
  static void
66
- pg_tuple_gc_mark( t_pg_tuple *this )
90
+ pg_tuple_gc_compact( void *_this )
67
91
  {
92
+ t_pg_tuple *this = (t_pg_tuple *)_this;
68
93
  int i;
69
94
 
70
95
  if( !this ) return;
71
- rb_gc_mark( this->result );
72
- rb_gc_mark( this->typemap );
73
- rb_gc_mark( this->field_map );
96
+ pg_gc_location( this->result );
97
+ pg_gc_location( this->typemap );
98
+ pg_gc_location( this->field_map );
74
99
 
75
100
  for( i = 0; i < this->num_fields; i++ ){
76
- rb_gc_mark( this->values[i] );
101
+ pg_gc_location( this->values[i] );
77
102
  }
78
- rb_gc_mark( pg_tuple_get_field_names(this) );
103
+ pg_gc_location( *pg_tuple_get_field_names_ptr(this) );
79
104
  }
80
105
 
81
106
  static void
82
- pg_tuple_gc_free( t_pg_tuple *this )
107
+ pg_tuple_gc_free( void *_this )
83
108
  {
109
+ t_pg_tuple *this = (t_pg_tuple *)_this;
84
110
  if( !this ) return;
85
111
  xfree(this);
86
112
  }
87
113
 
88
114
  static size_t
89
- pg_tuple_memsize( t_pg_tuple *this )
115
+ pg_tuple_memsize( const void *_this )
90
116
  {
117
+ const t_pg_tuple *this = (const t_pg_tuple *)_this;
91
118
  if( this==NULL ) return 0;
92
119
  return sizeof(*this) + sizeof(*this->values) * this->num_fields;
93
120
  }
94
121
 
95
122
  static const rb_data_type_t pg_tuple_type = {
96
- "pg",
123
+ "PG::Tuple",
97
124
  {
98
- (void (*)(void*))pg_tuple_gc_mark,
99
- (void (*)(void*))pg_tuple_gc_free,
100
- (size_t (*)(const void *))pg_tuple_memsize,
125
+ pg_tuple_gc_mark,
126
+ pg_tuple_gc_free,
127
+ pg_tuple_memsize,
128
+ pg_compact_callback(pg_tuple_gc_compact),
101
129
  },
102
130
  0, 0,
103
- #ifdef RUBY_TYPED_FREE_IMMEDIATELY
104
131
  RUBY_TYPED_FREE_IMMEDIATELY,
105
- #endif
106
132
  };
107
133
 
108
134
  /*
@@ -172,7 +198,7 @@ pg_tuple_materialize_field(t_pg_tuple *this, int col)
172
198
  VALUE value = this->values[col];
173
199
 
174
200
  if( value == Qundef ){
175
- t_typemap *p_typemap = DATA_PTR( this->typemap );
201
+ t_typemap *p_typemap = RTYPEDDATA_DATA( this->typemap );
176
202
 
177
203
  pgresult_get(this->result); /* make sure we have a valid PGresult object */
178
204
  value = p_typemap->funcs.typecast_result_value(p_typemap, this->result, this->row_num, col);
@@ -445,10 +471,7 @@ pg_tuple_dump(VALUE self)
445
471
  values = rb_ary_new4(this->num_fields, &this->values[0]);
446
472
  a = rb_ary_new3(2, field_names, values);
447
473
 
448
- if (FL_TEST(self, FL_EXIVAR)) {
449
- rb_copy_generic_ivar(a, self);
450
- FL_SET(a, FL_EXIVAR);
451
- }
474
+ rb_copy_generic_ivar(a, self);
452
475
 
453
476
  return a;
454
477
  }
@@ -479,9 +502,9 @@ pg_tuple_load(VALUE self, VALUE a)
479
502
  rb_obj_freeze(field_names);
480
503
  values = RARRAY_AREF(a, 1);
481
504
  Check_Type(values, T_ARRAY);
482
- num_fields = RARRAY_LEN(values);
505
+ num_fields = RARRAY_LENINT(values);
483
506
 
484
- if (RARRAY_LEN(field_names) != num_fields)
507
+ if (RARRAY_LENINT(field_names) != num_fields)
485
508
  rb_raise(rb_eTypeError, "different number of fields and values");
486
509
 
487
510
  field_map = rb_hash_new();
@@ -516,10 +539,7 @@ pg_tuple_load(VALUE self, VALUE a)
516
539
 
517
540
  RTYPEDDATA_DATA(self) = this;
518
541
 
519
- if (FL_TEST(a, FL_EXIVAR)) {
520
- rb_copy_generic_ivar(self, a);
521
- FL_SET(self, FL_EXIVAR);
522
- }
542
+ rb_copy_generic_ivar(self, a);
523
543
 
524
544
  return self;
525
545
  }
data/ext/pg_type_map.c CHANGED
@@ -6,6 +6,40 @@
6
6
 
7
7
  #include "pg.h"
8
8
 
9
+ void
10
+ pg_typemap_mark( void *_this )
11
+ {
12
+ t_typemap *this = (t_typemap *)_this;
13
+ rb_gc_mark_movable(this->default_typemap);
14
+ }
15
+
16
+ size_t
17
+ pg_typemap_memsize( const void *_this )
18
+ {
19
+ t_typemap *this = (t_typemap *)_this;
20
+ return sizeof(*this);
21
+ }
22
+
23
+ void
24
+ pg_typemap_compact( void *_this )
25
+ {
26
+ t_typemap *this = (t_typemap *)_this;
27
+ pg_gc_location(this->default_typemap);
28
+ }
29
+
30
+ const rb_data_type_t pg_typemap_type = {
31
+ "PG::TypeMap",
32
+ {
33
+ pg_typemap_mark,
34
+ RUBY_TYPED_DEFAULT_FREE,
35
+ pg_typemap_memsize,
36
+ pg_compact_callback(pg_typemap_compact),
37
+ },
38
+ 0,
39
+ 0,
40
+ RUBY_TYPED_FREE_IMMEDIATELY,
41
+ };
42
+
9
43
  VALUE rb_cTypeMap;
10
44
  VALUE rb_mDefaultTypeMappable;
11
45
  static ID s_id_fit_to_query;
@@ -75,7 +109,7 @@ pg_typemap_s_allocate( VALUE klass )
75
109
  VALUE self;
76
110
  t_typemap *this;
77
111
 
78
- self = Data_Make_Struct( klass, t_typemap, NULL, -1, this );
112
+ self = TypedData_Make_Struct( klass, t_typemap, &pg_typemap_type, this );
79
113
  this->funcs = pg_typemap_funcs;
80
114
 
81
115
  return self;
@@ -94,13 +128,12 @@ pg_typemap_s_allocate( VALUE klass )
94
128
  static VALUE
95
129
  pg_typemap_default_type_map_set(VALUE self, VALUE typemap)
96
130
  {
97
- t_typemap *this = DATA_PTR( self );
131
+ t_typemap *this = RTYPEDDATA_DATA( self );
132
+ t_typemap *tm;
133
+ UNUSED(tm);
98
134
 
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);
135
+ /* Check type of method param */
136
+ TypedData_Get_Struct(typemap, t_typemap, &pg_typemap_type, tm);
104
137
  this->default_typemap = typemap;
105
138
 
106
139
  return typemap;
@@ -119,7 +152,7 @@ pg_typemap_default_type_map_set(VALUE self, VALUE typemap)
119
152
  static VALUE
120
153
  pg_typemap_default_type_map_get(VALUE self)
121
154
  {
122
- t_typemap *this = DATA_PTR( self );
155
+ t_typemap *this = RTYPEDDATA_DATA( self );
123
156
 
124
157
  return this->default_typemap;
125
158
  }
@@ -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,
22
+ };
23
+
11
24
  VALUE rb_cTypeMapAllStrings;
12
25
  VALUE pg_typemap_all_strings;
13
26
 
@@ -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;
@@ -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;
@@ -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,7 +62,7 @@ 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
68
  /* A Symbol: Call the method with this name. */
@@ -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,32 +111,62 @@ 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 )
126
123
  {
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
- */
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 )
132
+ {
133
+ const t_tmbk *this = (const t_tmbk *)_this;
134
+ return sizeof(*this);
135
+ }
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. */
133
147
  memset(&this->cache_row, 0, sizeof(this->cache_row));
134
148
  }
135
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,
161
+ };
162
+
136
163
  static VALUE
137
164
  pg_tmbk_s_allocate( VALUE klass )
138
165
  {
139
166
  t_tmbk *this;
140
167
  VALUE self;
141
168
 
142
- self = Data_Make_Struct( klass, t_tmbk, pg_tmbk_mark, -1, this );
169
+ self = TypedData_Make_Struct( klass, t_tmbk, &pg_tmbk_type, this );
143
170
  this->typemap.funcs.fit_to_result = pg_typemap_fit_to_result;
144
171
  this->typemap.funcs.fit_to_query = pg_tmbk_fit_to_query;
145
172
  this->typemap.funcs.fit_to_copy_get = pg_typemap_fit_to_copy_get;
@@ -153,7 +180,7 @@ pg_tmbk_s_allocate( VALUE klass )
153
180
  this->self = self;
154
181
  this->klass_to_coder = rb_hash_new();
155
182
 
156
- /* The cache is properly initialized by Data_Make_Struct(). */
183
+ /* The cache is properly initialized by TypedData_Make_Struct(). */
157
184
 
158
185
  return self;
159
186
  }
@@ -176,7 +203,7 @@ pg_tmbk_s_allocate( VALUE klass )
176
203
  static VALUE
177
204
  pg_tmbk_aset( VALUE self, VALUE klass, VALUE coder )
178
205
  {
179
- t_tmbk *this = DATA_PTR( self );
206
+ t_tmbk *this = RTYPEDDATA_DATA( self );
180
207
 
181
208
  if(NIL_P(coder)){
182
209
  rb_hash_delete( this->klass_to_coder, klass );
@@ -200,7 +227,7 @@ pg_tmbk_aset( VALUE self, VALUE klass, VALUE coder )
200
227
  static VALUE
201
228
  pg_tmbk_aref( VALUE self, VALUE klass )
202
229
  {
203
- t_tmbk *this = DATA_PTR( self );
230
+ t_tmbk *this = RTYPEDDATA_DATA( self );
204
231
 
205
232
  return rb_hash_lookup(this->klass_to_coder, klass);
206
233
  }
@@ -214,7 +241,7 @@ pg_tmbk_aref( VALUE self, VALUE klass )
214
241
  static VALUE
215
242
  pg_tmbk_coders( VALUE self )
216
243
  {
217
- t_tmbk *this = DATA_PTR( self );
244
+ t_tmbk *this = RTYPEDDATA_DATA( self );
218
245
 
219
246
  return rb_obj_freeze(rb_hash_dup(this->klass_to_coder));
220
247
  }
@@ -222,8 +249,6 @@ pg_tmbk_coders( VALUE self )
222
249
  void
223
250
  init_pg_type_map_by_class()
224
251
  {
225
- s_id_ancestors = rb_intern("ancestors");
226
-
227
252
  /*
228
253
  * Document-class: PG::TypeMapByClass < PG::TypeMap
229
254
  *
@@ -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;
@@ -107,7 +107,7 @@ pg_tmbc_result_value( t_typemap *p_typemap, VALUE result, int tuple, int field )
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,34 +173,73 @@ 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,
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
@@ -221,19 +262,18 @@ 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);
229
269
  Check_Type(conv_ary, T_ARRAY);
230
- conv_ary_len = RARRAY_LEN(conv_ary);
270
+ conv_ary_len = RARRAY_LENINT(conv_ary);
231
271
  this = xmalloc(sizeof(t_tmbc) + sizeof(struct pg_tmbc_converter) * conv_ary_len);
232
272
  /* Set nfields to 0 at first, so that GC mark function doesn't access uninitialized memory. */
233
273
  this->nfields = 0;
234
274
  this->typemap.funcs = pg_tmbc_funcs;
235
275
  this->typemap.default_typemap = pg_typemap_all_strings;
236
- DATA_PTR(self) = this;
276
+ RTYPEDDATA_DATA(self) = this;
237
277
 
238
278
  for(i=0; i<conv_ary_len; i++)
239
279
  {
@@ -242,11 +282,9 @@ pg_tmbc_init(VALUE self, VALUE conv_ary)
242
282
  if( obj == Qnil ){
243
283
  /* no type cast */
244
284
  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
285
  } 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 ));
286
+ /* Check argument type and store the coder pointer */
287
+ TypedData_Get_Struct(obj, t_pg_coder, &pg_coder_type, this->convs[i].cconv);
250
288
  }
251
289
  }
252
290
 
@@ -266,7 +304,7 @@ static VALUE
266
304
  pg_tmbc_coders(VALUE self)
267
305
  {
268
306
  int i;
269
- t_tmbc *this = DATA_PTR( self );
307
+ t_tmbc *this = RTYPEDDATA_DATA( self );
270
308
  VALUE ary_coders = rb_ary_new();
271
309
 
272
310
  for( i=0; i<this->nfields; i++){